Jenkins Day 3-4 学习笔记

Jenkins Day 3-4 学习笔记

第一个Freestyle项目 — 从零到完整 CI 流程


一、今日学习目标总览

1
2
3
4
5
6
7
8
9
10
Day 3-4 你将掌握:

├── 准备本地 Git 仓库作为练习项目
├── 创建 Freestyle Project 并关联 Git
├── 配置源码管理(SCM)
├── 配置构建触发器(手动/定时/轮询/远程)
├── 编写 Shell 构建步骤
├── 配置构建后操作(产物归档、邮件通知)
├── 理解构建状态和构建历史
└── 完整体验一次"代码提交→自动构建"的 CI 流程

二、准备练习用的 Git 仓库

2.1 为什么要先准备 Git 仓库

1
2
3
4
5
6
7
8
在 Day 1-2 中,我们创建的项目没有关联任何代码仓库,
只是手动执行了一段 Shell 脚本。

真实的 CI 流程是:

代码仓库(Git)──→ Jenkins 拉取代码 ──→ 编译测试 ──→ 产出结果

所以我们需要一个 Git 仓库来模拟真实的工作场景。

2.2 在虚拟机中安装 Git(如果还没有)

1
2
3
4
5
6
7
8
9
# 检查是否已安装
git --version

# 如果没有,安装它
# Ubuntu/Debian
sudo apt update && sudo apt install git -y

# CentOS/RHEL
sudo yum install git -y

2.3 配置 Git 用户信息

1
2
3
4
5
6
# 配置全局用户名和邮箱(必须配置,否则无法提交)
git config --global user.name "Your Name"
git config --global user.email "your-email@example.com"

# 验证配置
git config --list

2.4 创建练习项目

我们创建一个模拟的 Java 项目来练习:

1
2
3
4
5
6
# 创建项目目录
mkdir -p /home/LX/jenkins_demo/demo-java-app
cd /home/LX/jenkins_demo/demo-java-app

# 初始化 Git 仓库
git init

创建项目结构:

1
2
3
4
# 创建目录结构
mkdir -p src/main/java/com/demo
mkdir -p src/test/java/com/demo
mkdir -p scripts

Step 1:创建 Java 源文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat > src/main/java/com/demo/App.java << 'EOF'
package com.demo;

public class App {
public static void main(String[] args) {
System.out.println("===================================");
System.out.println(" Demo Java Application v1.0");
System.out.println("===================================");
System.out.println("Application started successfully!");
}

public static int add(int a, int b) {
return a + b;
}

public static int subtract(int a, int b) {
return a - b;
}
}
EOF

Step 2:创建简单的测试文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
cat > src/test/java/com/demo/AppTest.java << 'EOF'
package com.demo;

public class AppTest {
public static void main(String[] args) {
System.out.println("Running tests...");

// 测试 add 方法
int result1 = App.add(2, 3);
assert result1 == 5 : "add(2,3) should be 5, but got " + result1;
System.out.println("✅ Test add(2,3) = 5: PASSED");

// 测试 subtract 方法
int result2 = App.subtract(10, 4);
assert result2 == 6 : "subtract(10,4) should be 6, but got " + result2;
System.out.println("✅ Test subtract(10,4) = 6: PASSED");

// 测试边界情况
int result3 = App.add(0, 0);
assert result3 == 0 : "add(0,0) should be 0, but got " + result3;
System.out.println("✅ Test add(0,0) = 0: PASSED");

System.out.println("");
System.out.println("All tests passed! ✅");
}
}
EOF

Step 3:创建构建脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
cat > scripts/build.sh << 'EOF'
#!/bin/bash
set -e

echo "========================================"
echo " Step 1: 编译源代码"
echo "========================================"

# 创建输出目录
mkdir -p build/classes

# 编译 Java 文件
javac -d build/classes \
src/main/java/com/demo/App.java

echo "✅ 编译成功"
echo ""

echo "========================================"
echo " Step 2: 运行单元测试"
echo "========================================"

# 编译测试文件
javac -d build/classes \
-cp build/classes \
src/test/java/com/demo/AppTest.java

# 运行测试
java -cp build/classes \
-ea \
com.demo.AppTest

echo ""
echo "========================================"
echo " Step 3: 打包"
echo "========================================"

# 创建 JAR 包
cd build/classes
jar cf ../demo-app.jar .
cd ../..

echo "✅ 打包成功: build/demo-app.jar"
echo ""

echo "========================================"
echo " Step 4: 验证 JAR 包"
echo "========================================"

# 运行 JAR 包
java -cp build/demo-app.jar com.demo.App

echo ""
echo "🎉 构建全部完成!"
echo "产物文件: build/demo-app.jar"
ls -lh build/demo-app.jar
EOF

chmod +x scripts/build.sh

Step 4:创建 README 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
cat > README.md << 'EOF'
# Demo Java App

一个用于学习 Jenkins CI 的示例 Java 项目。

## 项目结构
demo-java-app/
├── src/
│ ├── main/java/com/demo/
│ │ └── App.java # 主程序
│ └── test/java/com/demo/
│ └── AppTest.java # 测试程序
├── scripts/
│ └── build.sh # 构建脚本
├── build/ # 构建产物(不提交到 Git)
└── README.md

## 本地构建

bash scripts/build.sh

EOF

Step 5:创建 .gitignore 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat > .gitignore << 'EOF'
# 构建产物
build/

# IDE 文件
.idea/
*.iml
.vscode/

# 编译文件
*.class

# OS 文件
.DS_Store
Thumbs.db

# 日志
*.log
EOF

2.5 提交代码到本地仓库

1
2
3
4
5
6
7
8
9
10
11
# 查看所有文件状态
git status

# 添加所有文件
git add .

# 再次确认
git status

# 提交
git commit -m "初始化项目:Java Demo App"

你应该看到:

1
2
3
4
5
6
7
[master (root-commit) abc1234] 初始化项目:Java Demo App
5 files changed, 123 insertions(+)
create mode 100644 .gitignore
create mode 100644 README.md
create mode 100644 scripts/build.sh
create mode 100644 src/main/java/com/demo/App.java
create mode 100644 src/test/java/com/demo/AppTest.java

2.6 先在本地验证构建脚本能正常工作

1
2
3
# 先手动执行一次构建,确保脚本没问题
cd ~/demo-java-app
bash scripts/build.sh

你应该看到编译、测试、打包全部成功。如果失败,检查 Java 是否安装:

1
2
3
4
5
6
7
java -version
javac -version

# 如果没有安装
sudo apt install openjdk-17-jdk -y # Ubuntu/Debian
# 或
sudo yum install java-17-openjdk-devel -y # CentOS/RHEL

确认构建成功后,清理构建产物:

1
rm -rf build/

2.7 多提交几个版本(模拟开发迭代)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 提交 2:修改 App.java,增加一个乘法方法 multiply 方法
cat > src/main/java/com/demo/App.java << 'EOF'
package com.demo;

public class App {
public static void main(String[] args) {
System.out.println("===================================");
System.out.println(" Demo Java Application v1.0");
System.out.println("===================================");
System.out.println("Application started successfully!");
}

public static int add(int a, int b) {
return a + b;
}

public static int subtract(int a, int b) {
return a - b;
}

public static int multiply(int a, int b) {
return a * b;
}
}
EOF

cat > src/test/java/com/demo/AppTest.java << 'EOF'
package com.demo;

public class AppTest {
public static void main(String[] args) {
System.out.println("Running tests...");

int result1 = App.add(2, 3);
assert result1 == 5 : "add(2,3) should be 5, but got " + result1;
System.out.println("✅ Test add(2,3) = 5: PASSED");

int result2 = App.subtract(10, 4);
assert result2 == 6 : "subtract(10,4) should be 6, but got " + result2;
System.out.println("✅ Test subtract(10,4) = 6: PASSED");

int result3 = App.multiply(3, 4);
assert result3 == 12 : "multiply(3,4) should be 12, but got " + result3;
System.out.println("✅ Test multiply(3,4) = 12: PASSED");

System.out.println("");
System.out.println("All tests passed! ✅");
}
}
EOF
1
2
git add -A
git commit -m "feat: 新增 multiply 方法"
1
2
3
4
5
# 提交 3:修改 README

sed -i 's/一个用于学习 Jenkins CI 的示例 Java 项目。/一个用于学习 Jenkins CI 的示例 Java 项目,支持加减乘运算。/' README.md
git add -A
git commit -m "docs: 更新 README 描述"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 提交 4:修改 build.sh,增加构建耗时统计

cat > scripts/build.sh << 'EOF'
#!/bin/bash
set -e

echo "========================================"
echo " Step 1: 编译源代码"
echo "========================================"

mkdir -p build/classes
javac -d build/classes \
src/main/java/com/demo/App.java

echo "✅ 编译成功"
echo ""

echo "========================================"
echo " Step 2: 运行单元测试"
echo "========================================"

javac -d build/classes \
-cp build/classes \
src/test/java/com/demo/AppTest.java

java -cp build/classes \
-ea \
com.demo.AppTest

echo ""
echo "========================================"
echo " Step 3: 打包"
echo "========================================"

cd build/classes
jar cf ../demo-app.jar .
cd ../..

echo "✅ 打包成功: build/demo-app.jar"
echo ""

echo "========================================"
echo " Step 4: 验证 JAR 包"
echo "========================================"

java -cp build/demo-app.jar com.demo.App

echo ""
echo "🎉 构建全部完成!"
echo "产物文件: build/demo-app.jar"
ls -lh build/demo-app.jar

echo ""
echo "========================================"
echo " 构建统计"
echo "========================================"
echo "完成时间: $(date)"
EOF
1
2
git add -A
git commit -m "build: 增加构建耗时统计"

验证我们有了多个提交:

1
git log --oneline

输出应该类似:

1
2
3
4
d4e5f6a build: 增加构建耗时统计
c3d4e5f docs: 更新 README 描述
b2c3d4e feat: 新增 multiply 方法
a1b2c3d 初始化项目:Java Demo App

三、创建 Freestyle 项目并关联 Git

3.1 创建项目

1
2
3
4
5
6
7
8
9
10
11
操作步骤:

1. 在 Jenkins Dashboard 页面,点击左侧 [ New Item ]

2. 在 "Enter an item name" 输入框中填写:
demo-java-freestyle

3. 选择项目类型:
○ Freestyle project ← 选这个

4. 点击 [ OK ]

3.2 配置项目 — General(常规设置)

进入项目配置页面后,你会看到多个配置区域。我们从上到下逐一配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
┌─────────────────────────────────────────────────────────────┐
│ │
│ General(常规设置) │
│ │
│ Description(描述): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Jenkins 学习项目 - Java Demo App │ │
│ │ 用于练习 Freestyle 项目的配置 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ☐ Discard old builds(丢弃旧构建) │
│ 勾选后可以配置: │
│ ├── 保持构建的天数:30 │
│ └── 保持构建的最大数量:5 │
│ (建议勾选,防止磁盘被构建日志撑满) │
│ │
│ ☐ GitHub project │
│ (如果项目在 GitHub 上,填写 GitHub 项目 URL) │
│ │
│ ☐ This project is parameterized(参数化构建) │
│ (Day 5-6 会详细讲解) │
│ │
│ ☐ Throttle builds(限流构建) │
│ (防止频繁构建) │
│ │
│ ☐ Disable this project(禁用项目) │
│ (临时禁用,不会被触发构建) │
│ │
└─────────────────────────────────────────────────────────────┘

推荐配置:

1
2
3
4
5
6
Description:
Jenkins 学习项目 - Java Demo App

Discard old builds
保持构建的最大数量: 5
保持构建的天数: 30

3.3 配置项目 — Source Code Management(源码管理)⭐ 重点

1
2
3
4
5
6
7
8
9
┌─────────────────────────────────────────────────────────────┐
│ │
Source Code Management(源码管理) │
│ │
│ ○ None — 不关联代码仓库(Day 1-2 用的) │
│ ● Git — 关联 Git 仓库(选这个) │
│ ○ Subversion — 关联 SVN 仓库 │
│ │
└─────────────────────────────────────────────────────────────┘

选择 Git 后,展开以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
┌─────────────────────────────────────────────────────────────┐
│ │
│ Repositories(仓库配置) │
│ │
│ Repository URL(仓库地址): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ /home/你的用户名/demo-java-app │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ (这里填写本地 Git 仓库的绝对路径) │
│ │
│ Credentials(凭据): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ - none - ← 本地仓库不需要 │ │
│ └─────────────────────────────────────────────────────┘ │
│ (如果是远程仓库,需要添加用户名密码凭据) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Branch Specifier(分支指定): │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ */master │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ (默认是 */main,如果你的仓库用 master 分支, │ │ │
│ │ 改成 */master) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Repository browser(仓库浏览器): │
│ └── Auto(自动检测) │
│ │
└─────────────────────────────────────────────────────────────┘

如何确认你的仓库路径和分支名:

1
2
3
4
5
6
7
8
9
10
# 查看仓库路径(在仓库目录中执行)
cd ~/demo-java-app
pwd
# 输出类似:/home/john/demo-java-app

# 查看当前分支名
git branch
# 输出类似:* master
# 或者:
# * main

填写说明:

1
2
3
4
5
6
7
8
9
10
11
如果你的分支是 master:
Branch Specifier 填: */master

如果你的分支是 main:
Branch Specifier 填: */main

如果你想拉取所有分支:
Branch Specifier 填: **

多个分支用逗号分隔:
*/main, */develop, */release/*

3.4 配置项目 — Build Triggers(构建触发器)⭐ 重点

这是 CI 的核心配置,决定了”什么时候自动触发构建”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌─────────────────────────────────────────────────────────────┐
│ │
Build Triggers(构建触发器) │
│ │
│ ☐ Trigger builds remotely (e.g., from scripts) │
│ 远程触发构建(通过 URL/API 触发) │
│ │
│ ☐ Build after other projects are built │
│ 其他项目构建完成后触发 │
│ │
│ ☐ Build periodically │
│ 定时构建(不管代码有没有变化) │
│ │
│ ☐ GitHub hook trigger for GITScm polling │
│ GitHub Webhook 触发(需要安装 GitHub 插件) │
│ │
│ ☐ Poll SCM │
│ 轮询代码仓库(定时检查代码是否有变化) │
│ │
└─────────────────────────────────────────────────────────────┘

3.4.1 Trigger remotely(远程触发)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
用途:通过 HTTP 请求触发构建
场景:从脚本、其他系统、Webhook 触发

配置方式:
1. 勾选 "Trigger builds remotely"
2. 填写 Authentication Token(自定义一个令牌,比如 my-build-token)

触发 URL 格式:
http://<Jenkins地址>/job/<项目名>/build?token=<令牌>

示例:
http://192.168.40.30:8080/job/demo-java-freestyle/build?token=my-build-token

在虚拟机中测试:
curl -X POST http://192.168.40.30:8080/job/demo-java-freestyle/build?token=my-build-token

3.4.2 Build periodically(定时构建)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
用途:不管代码有没有变化,按固定时间触发构建
场景:夜间构建、每日构建报告

使用 CRON 表达式(5 个字段):

┌────────── 分钟 (0-59)
│ ┌────────── 小时 (0-23)
│ │ ┌────────── 日 (1-31)
│ │ │ ┌────────── 月 (1-12)
│ │ │ │ ┌────────── 星期几 (0-7, 0和7都是周日)
│ │ │ │ │
* * * * *

常用示例:

每天早上 8:30 构建:
30 8 * * *

每天晚上 23:00 构建(夜间构建):
0 23 * * *

工作日每天 9:00 构建(周一到周五):
0 9 * * 1-5

每 30 分钟构建一次:
H/30 * * * *

每周一早上 9:00 构建:
H 9 * * 1

Jenkins 特殊符号 H:
├── H 表示"在指定时间范围内哈希分散"
├── H 0 * * * 表示"每天在 0:00-0:59 之间的某个随机时刻"
├── 目的:避免多个项目同时构建,分散服务器压力
└── H/15 * * * * 表示"每 15 分钟,但起始分钟由 Job 名称哈希随机决定"

3.4.3 Poll SCM(轮询代码仓库)⭐ 最常用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
用途:定时检查 Git 仓库是否有新的提交,有变化才触发构建
场景:最基础的 CI 触发方式

和 Build periodically 的区别:
├── Build periodically:不管有没有变化,时间到了就构建
└── Poll SCM:先检查有没有新提交,有才构建,没有就跳过

配置方式:
1. 勾选 "Poll SCM"
2. 填写 CRON 表达式

推荐配置:

5 分钟检查一次(适合学习阶段):
H/5 * * * *

2 分钟检查一次(快速验证):
H/2 * * * *

15 分钟检查一次(生产环境常用):
H/15 * * * *

每小时检查一次:
H * * * *

**现在先勾选 Poll SCM,填写 H/2 * * * ***(每 2 分钟检查一次,方便我们快速验证效果)。

3.5 配置项目 — Build Environment(构建环境)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────────────┐
│ │
│ Build Environment(构建环境) │
│ │
│ ☐ Delete workspace before build starts │
│ 构建前清理工作空间(确保干净构建) │
│ │
│ ☐ Use secret text(s) or file(s) │
│ 使用秘密文本或文件(用于传递敏感信息) │
│ │
│ ☐ Terminate a build if it's stuck │
│ 构建卡住时中止(防止无限等待) │
│ 推荐勾选,设置超时时间:15 分钟 │
│ │
│ ☐ Add timestamps to the Console Output │
│ 在控制台输出中添加时间戳(推荐勾选) │
│ │
│ ☐ With Ant │
│ 使用 Ant 构建工具 │
│ │
└─────────────────────────────────────────────────────────────┘

推荐勾选:

1
2
3
4
5
6
7
8
9
☑ Delete workspace before build starts
(每次构建前清空工作空间,避免旧文件影响)

☑ Terminate a build if it's stuck
Timeout minutes: 15
(防止构建卡死)

☑ Add timestamps to the Console Output
(日志中显示时间戳,方便排查问题)

3.6 配置项目 — Build(构建步骤)⭐ 核心

这是整个配置中最核心的部分,定义了”构建时具体做什么”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌─────────────────────────────────────────────────────────────┐
│ │
Build(构建步骤)
│ │
│ [ Add build step ▼ ] │
│ │
│ 下拉菜单中的选项: │
│ ├── Execute shell — 执行 Shell 脚本(Linux) │
│ ├── Execute Windows batch — 执行批处理脚本(Windows) │
│ ├── Invoke Ant — 调用 Ant 构建 │
│ ├── Invoke Gradle script — 调用 Gradle 构建 │
│ ├── Invoke top-level Maven targets — 调用 Maven 构建 │
│ └── ... │
│ │
└─────────────────────────────────────────────────────────────┘

点击 Add build step → 选择 Execute shell

在命令框中输入以下脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash
set -e # 任何命令失败立即退出

echo "========================================"
echo " Jenkins 构建开始"
echo "========================================"
echo "构建号: ${BUILD_NUMBER}"
echo "工作空间: ${WORKSPACE}"
echo "当前时间: $(date)"
echo "========================================"
echo ""

# 进入工作空间(Jenkins 已经自动 cd 到这里了)
cd ${WORKSPACE}

# 执行项目的构建脚本
bash scripts/build.sh

echo ""
echo "========================================"
echo " 构建产物信息"
echo "========================================"

# 列出构建产物
if [ -f build/demo-app.jar ]; then
echo "✅ 构建产物存在"
ls -lh build/demo-app.jar
else
echo "❌ 构建产物不存在"
exit 1
fi

echo ""
echo "========================================"
echo " 构建完成"
echo "========================================"

解释这段脚本做了什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
脚本执行流程:

1. set -e
└── 如果任何命令执行失败(返回非 0),脚本立即停止
Jenkins 会将这次构建标记为 FAILURE

2. 打印构建信息
└── 显示构建号、工作空间路径、当前时间
这些信息在排查问题时非常有用

3. cd ${WORKSPACE}
└── 进入 Jenkins 的工作空间目录
Jenkins 在执行构建步骤前,会自动把代码拉到这个目录
${WORKSPACE} 是 Jenkins 自动设置的环境变量

4. bash scripts/build.sh
└── 执行我们项目中的构建脚本
包含:编译 → 测试 → 打包

5. 检查构建产物
└── 确认 JAR 包已成功生成
如果不存在,返回错误码 1,Jenkins 标记构建失败

3.7 配置项目 — Post-build Actions(构建后操作)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌─────────────────────────────────────────────────────────────┐
│ │
│ Post-build Actions(构建后操作) │
│ │
│ [ Add post-build action ▼ ] │
│ │
│ 常用选项: │
│ ├── Archive the artifacts — 归档构建产物 │
│ ├── Publish JUnit test result — 发布测试报告 │
│ ├── E-mail Notification — 邮件通知 │
│ ├── Build other projects — 触发其他项目构建 │
│ └── ... │
│ │
└─────────────────────────────────────────────────────────────┘

3.7.1 归档构建产物

1
2
3
4
5
6
7
8
9
10
11
12
点击 [ Add post-build action ] → 选择 "Archive the artifacts"

Files to archive(要归档的文件):
┌─────────────────────────────────────────────────────────────┐
│ build/*.jar │
└─────────────────────────────────────────────────────────────┘

☑ Fingerprint all archived artifacts
(为所有归档产物生成指纹,用于追踪)

☑ If archived artifacts show then mark build as unstable
(如果没有找到要归档的文件,将构建标记为不稳定)

3.7.2 邮件通知(基础版)

1
2
3
4
5
6
7
8
9
10
11
12
点击 [ Add post-build action ] → 选择 "E-mail Notification"

Recipients(收件人):
┌─────────────────────────────────────────────────────────────┐
│ your-email@example.com │
└─────────────────────────────────────────────────────────────┘

☑ Send e-mail for every unstable build
(每次构建不稳定时发送邮件)

☑ Send separate e-mails to individuals who broke the build
(向导致构建失败的人单独发送邮件)

注意: 邮件通知需要先在 Manage Jenkins → System 中配置 SMTP 服务器。如果没有配置邮件服务器,这一步可以先跳过。

3.8 保存项目配置

1
2
3
4
5
6
7
8
9
10
11
12
13
所有配置完成后,点击页面底部的 [ Save ] 按钮。

你会进入项目的主页,页面上显示:
├── 项目名称:demo-java-freestyle
├── Description:Jenkins 学习项目 - Java Demo App
├── Build History:(空的,还没有构建过)
└── 左侧菜单:
├── Status — 项目状态
├── Changes — 代码变更
├── Workspace — 工作空间
├── Build Now — 立即构建 ⭐
├── Configure — 修改配置
└── Delete Project — 删除项目

四、执行第一次构建

4.1 手动触发构建

1
2
3
4
5
6
7
8
9
10
11
12
13
操作步骤:

1. 在项目主页,点击左侧 [ Build Now ]

2. 等几秒钟,Build History 区域会出现一个构建记录
├── #1(构建号)
├── 蓝色圆点 = 构建中(或构建成功)
├── 黄色圆点 = 构建不稳定
└── 红色圆点 = 构建失败

3. 点击构建记录 #1,进入构建详情页

4. 点击 [ Console Output ] 查看实时日志

4.2 理解控制台输出

你应该看到类似这样的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Started by user admin
Building in /var/lib/jenkins/workspace/demo-java-freestyle
The recommended git tool is: NONE
using credential xxx
> git rev-parse --resolve-inside-dir refs/remotes/origin/master
> git rev-parse origin/master^{commit}
Checking out Revision abc1234 (origin/master)
Commit message: "build: 增加构建耗时统计"
> git config core.sparsecheckout
> git checkout -f abc1234
First time build. Skipping changelog.

[timestamp] ========================================
[timestamp] Jenkins 构建开始
[timestamp] ========================================
[timestamp] 构建号: 1
[timestamp] 工作空间: /var/lib/jenkins/workspace/demo-java-freestyle
[timestamp] 当前时间: Mon Jul 14 14:30:00 CST 2025
[timestamp] ========================================

[timestamp] ========================================
[timestamp] Step 1: 编译源代码
[timestamp] ========================================
[timestamp] ✅ 编译成功

[timestamp] ========================================
[timestamp] Step 2: 运行单元测试
[timestamp] ========================================
[timestamp] Running tests...
[timestamp] ✅ Test add(2,3) = 5: PASSED
[timestamp] ✅ Test subtract(10,4) = 6: PASSED
[timestamp] ✅ Test add(0,0) = 0: PASSED
[timestamp] ✅ Test multiply(3,4) = 12: PASSED
[timestamp]
[timestamp] All tests passed! ✅

[timestamp] ========================================
[timestamp] Step 3: 打包
[timestamp] ========================================
[timestamp] ✅ 打包成功: build/demo-app.jar

[timestamp] ========================================
[timestamp] Step 4: 验证 JAR 包
[timestamp] ========================================
[timestamp] ===================================
[timestamp] Demo Java Application v1.0
[timestamp] ===================================
[timestamp] Application started successfully!
[timestamp]
[timestamp] 🎉 构建全部完成!

[timestamp] ========================================
[timestamp] 构建产物信息
[timestamp] ========================================
[timestamp] ✅ 构建产物存在
[timestamp] -rw-r--r-- 1 jenkins jenkins 1.2K ... build/demo-app.jar

[timestamp] ========================================
[timestamp] 构建完成
[timestamp] ========================================

Archiving artifacts
Finished: SUCCESS

理解日志中的关键信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Started by user admin
└── 谁触发了这次构建(admin 用户手动触发)

Building in /var/lib/jenkins/workspace/demo-java-freestyle
└── Jenkins 在哪个目录执行构建

> git checkout -f abc1234
└── Jenkins 从 Git 仓库拉取了哪个版本的代码

Commit message: "build: 增加构建耗时统计"
└── 拉取的是最新一次提交

Archiving artifacts
└── 正在归档构建产物

Finished: SUCCESS
└── 构建结果:成功 ✅

4.3 查看构建产物

1
2
3
4
5
6
7
8
9
10
11
构建成功后,你可以通过两种方式查看归档的产物:

方式一:在构建详情页
├── 点击构建记录 #1
├── 页面中会显示 "Build Artifacts" 区域
├── 点击 build/demo-app.jar 可以下载
└── URL 类似:http://IP:8080/job/demo-java-freestyle/1/artifact/build/demo-app.jar

方式二:在项目主页
├── 项目主页左侧有 "Last Successful Artifacts"
└── 直接下载最近一次成功构建的产物

4.4 查看工作空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在项目主页,点击左侧 [ Workspace ]

你会看到项目的文件结构:
├── .git/ — Git 仓库数据
├── .gitignore
├── README.md
├── build/ — 构建产物目录
│ ├── classes/ — 编译后的 class 文件
│ ├── demo-app.jar — 打包的 JAR 文件
├── scripts/
│ └── build.sh — 构建脚本
└── src/
├── main/java/com/demo/
│ └── App.java
└── test/java/com/demo/
└── AppTest.java

五、验证自动触发(Poll SCM)

5.1 触发一次新的代码提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# 回到项目目录
cd ~/demo-java-app

# 修改 App.java,增加一个除法方法
# 先找到文件中 multiply 方法的 } 后面,添加新方法
cat >> src/main/java/com/demo/App.java << 'EOF'

public static double divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("Division by zero!");
}
return (double) a / b;
}
EOF

# 注意:需要修正 App.java 中的 } 位置
# 因为 append 会把代码加到文件最后,而不是正确的位置
# 我们重新生成整个 App.java 文件

cat > src/main/java/com/demo/App.java << 'EOF'
package com.demo;

public class App {
public static void main(String[] args) {
System.out.println("===================================");
System.out.println(" Demo Java Application v1.0");
System.out.println("===================================");
System.out.println("Application started successfully!");
}

public static int add(int a, int b) {
return a + b;
}

public static int subtract(int a, int b) {
return a - b;
}

public static int multiply(int a, int b) {
return a * b;
}

public static double divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("Division by zero!");
}
return (double) a / b;
}
}
EOF

# 更新测试文件
cat > src/test/java/com/demo/AppTest.java << 'EOF'
package com.demo;

public class AppTest {
public static void main(String[] args) {
System.out.println("Running tests...");

// 测试 add 方法
int result1 = App.add(2, 3);
assert result1 == 5 : "add(2,3) should be 5, but got " + result1;
System.out.println("✅ Test add(2,3) = 5: PASSED");

// 测试 subtract 方法
int result2 = App.subtract(10, 4);
assert result2 == 6 : "subtract(10,4) should be 6, but got " + result2;
System.out.println("✅ Test subtract(10,4) = 6: PASSED");

// 测试 multiply 方法
int result3 = App.multiply(3, 4);
assert result3 == 12 : "multiply(3,4) should be 12, but got " + result3;
System.out.println("✅ Test multiply(3,4) = 12: PASSED");

// 测试 divide 方法
double result4 = App.divide(10, 3);
assert Math.abs(result4 - 3.333333) < 0.001 : "divide(10,3) ≈ 3.333";
System.out.println("✅ Test divide(10,3) ≈ 3.333: PASSED");

// 测试边界情况
int result5 = App.add(0, 0);
assert result5 == 0 : "add(0,0) should be 0, but got " + result5;
System.out.println("✅ Test add(0,0) = 0: PASSED");

System.out.println("");
System.out.println("All tests passed! ✅");
}
}
EOF

# 提交
git add -A
git commit -m "feat: 新增 divide 除法方法及测试"

5.2 等待自动触发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
我们配置了 Poll SCM 2 分钟检查一次。

操作步骤:

1. 提交代码后,回到 Jenkins 的项目主页

2. 等待最多 2 分钟(Poll SCM 的间隔时间)

3. 观察 Build History 区域
├── 你会看到一个新的构建 #2 自动出现
├── 这次触发原因不再是 "Started by user admin"
└── 而是 "Started by an SCM change"

4. 点击构建 #2,查看 Console Output
├── 你会看到 Jenkins 检测到了新的 Git 提交
├── Commit message: "feat: 新增 divide 除法方法及测试"
└── 测试输出中包含了 divide 方法的测试结果

5.3 理解 Poll SCM 的工作原理

1
2
3
4
5
6
7
8
9
10
11
12
13
Poll SCM 的工作机制:

Jenkins 每隔 2 分钟执行一次:
1. git ls-remote <仓库地址> ← 只检查远程仓库的最新提交 SHA
2. 和上次记录的 SHA 对比
3. 如果相同 → 不做任何事,继续等待
4. 如果不同 → 触发一次完整构建

注意:
├── Poll SCM 不会拉取完整代码来对比
├── 只是比较提交 SHA,非常轻量
├── 即使仓库有变化,也要等到下一个轮询周期才会触发
└── 所以最快也是"轮询间隔"后才触发(这里是 2 分钟)

六、构建触发器进阶

6.1 远程触发构建

Step 1:配置远程触发

1
2
3
4
5
6
7
8
9
10
1. 进入项目配置页面(点击左侧 [ Configure ])

2. 找到 Build Triggers 区域

3. 勾选 "Trigger builds remotely (e.g., from scripts)"

4. 在 Authentication Token 输入框中填写:
my-secret-token-2025

5. 点击 [ Save ]

Step 2:通过命令触发构建

1
2
3
4
5
6
7
8
9
10
11
# 在虚拟机中执行(无认证方式)
curl -X POST "http://localhost:8080/job/demo-java-freestyle/build?token=my-secret-token-2025"

# 如果 Jenkins 启用了安全认证,需要带上用户名和 API Token
# 先获取 API Token:
# Jenkins → 点击右上角用户名 → Configure → API Token → Add new Token

# 使用 API Token 触发
curl -X POST \
"http://localhost:8080/job/demo-java-freestyle/build?token=my-secret-token-2025" \
--user admin:你的API-Token

Step 3:验证

1
2
3
4
5
执行 curl 命令后,回到 Jenkins 项目主页,
你会看到一个新的构建被触发了。

查看控制台输出,触发原因显示:
Started by remote host (触发器:远程触发)

6.2 定时构建

1
2
3
4
5
6
7
8
9
10
11
12
操作步骤:

1. 进入项目配置页面

2. Build Triggers 区域,勾选 "Build periodically"

3. 填写 CRON 表达式:
H 10 * * 1-5

含义:工作日(周一到周五)每天上午 10:00-10:59 之间的某个时刻构建

4. 点击 [ Save ]

常用 CRON 速查表:

1
2
3
4
5
6
7
8
9
10
11
12
┌──────────────────────────────┬────────────┬─────────────────────┐
│ 场景 │ CRON 表达式 │ 说明 │
├──────────────────────────────┼────────────┼─────────────────────┤
│ 每天早上 8:30 │ 30 8 * * * │ 固定时间 │
│ 每天晚上 23:00 │ 0 23 * * * │ 夜间构建 │
│ 工作日每天 9:00 │ 0 9 * * 1-5│ 周一到周五 │
│ 每周一早上 9:00 │ 0 9 * * 1 │ 每周一次 │
│ 每小时一次 │ H * * * * │ 使用 H 分散压力 │
│ 每 15 分钟 │ H/15 * * * *│ 频繁轮询 │
│ 每天凌晨 2:00 │ 0 2 * * * │ 深夜低峰 │
│ 每月 1 号 9:00 │ 0 9 1 * * │ 月度构建 │
└──────────────────────────────┴────────────┴─────────────────────┘

6.3 触发其他项目构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
场景:项目 A 构建成功后,自动触发项目 B 的构建

操作步骤:

1. 创建第二个项目(比如 demo-java-deploy)

2. 在第一个项目 demo-java-freestyle 的配置中:
Post-build Actions → Add post-build action
Build other projects

Projects to build: demo-java-deploy
Trigger only if build is stable: ☑

3. 保存后,当 demo-java-freestyle 构建成功,
demo-java-deploy 会自动被触发

这种方式可以实现简单的"管道"

demo-java-freestyle ──构建成功──→ demo-java-deploy ──构建成功──→ ...

七、构建状态与构建历史

7.1 三种构建状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Jenkins 构建状态:

🟢 SUCCESS(成功)
├── 所有构建步骤都执行成功
├── 返回码为 0
├── 在 UI 上显示为蓝色圆点(Blue Ocean 风格是绿色)
└── 含义:代码可以正常编译、测试通过、打包成功

🟡 UNSTABLE(不稳定)
├── 构建过程本身没有出错
├── 但某些检查不通过(比如测试失败、代码质量不达标)
├── 在 UI 上显示为黄色圆点
└── 含义:需要关注,但不是致命问题

🔴 FAILURE(失败)
├── 构建步骤执行失败
├── 某个命令返回非 0 状态码
├── 在 UI 上显示为红色圆点
└── 含义:必须修复,代码有问题

⚫ ABORTED(中止)
├── 构建被用户手动取消
├── 或被其他构建替换
├── 在 UI 上显示为灰色圆点
└── 含义:不是因为代码问题,是被中断了

7.2 构建历史页面详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
项目主页的 Build History 区域:

┌────────────────────────────────────┐
Build History │
│ │
│ 🔵 #3 14:35 (2 min ago) │ ← 最新构建
│ 🔵 #2 14:30 (7 min ago) │ ← Poll SCM 触发
│ 🔵 #1 14:25 (12 min ago) │ ← 手动触发
│ │
│ [Enable auto refresh] │ ← 开启自动刷新
│ │
└────────────────────────────────────┘

点击任意一个构建记录,进入构建详情页:

┌────────────────────────────────────┐
│ demo-java-freestyle #2 │
│ │
│ Status: ✅ SUCCESS │
│ Duration: 5 sec │
│ Started: Mon Jul 14 14:30:00
│ Changes: 1 change │
│ │
│ Console Output ← 查看日志│
│ Edit Build Information │
│ Delete Build #2 │
│ Rebuild Now │ ← 用相同参数重新构建
│ │
Build Artifacts: │
│ 📦 build/demo-app.jar │ ← 下载产物
│ │
└────────────────────────────────────┘

7.3 查看代码变更

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在构建详情页,点击 "Changes",可以看到:

┌────────────────────────────────────┐
│ Changes │
│ │
│ Summary of changes:
│ │
│ 📝 d4e5f6a │
build: 增加构建耗时统计 │
Author: Your Name │
│ │
│ (只显示上次构建之后的新提交) │
└────────────────────────────────────┘

这个功能的价值:
├── 快速定位是哪次代码提交导致了构建失败
├── 方便 Code Review
└── 追溯变更历史

7.4 构建详情页的其他功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
构建详情页左侧菜单:

Console Output(控制台输出)
├── 查看完整的构建日志
├── 实时显示(构建中时也能看到)
└── 这是排查问题最重要的工具

Edit Build Information(编辑构建信息)
├── 给构建添加描述
└── 标记构建状态(Good/Bad

Rebuild Now(重新构建)
├── 用相同的参数重新触发一次构建
└── 适合修复后重新验证

Delete Build(删除构建)
└── 删除这个构建记录

Back to Project(返回项目)
└── 回到项目主页

八、工作空间管理

8.1 理解工作空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
工作空间(Workspace)是 Jenkins 执行构建的目录:

路径格式:
/var/lib/jenkins/workspace/<项目名>/

对于我们的项目:
/var/lib/jenkins/workspace/demo-java-freestyle/

工作空间中包含:
├── Jenkins 从 Git 拉取的所有源代码
├── 构建过程中生成的中间文件
├── 最终的构建产物
└── 任何构建步骤产生的文件

重要概念:
├── 每个项目有独立的工作空间
├── 默认情况下,工作空间在构建之间保留
├── 可以配置"构建前清理工作空间"(我们已经勾选了)
└── 工作空间的路径可以通过 ${WORKSPACE} 环境变量获取

8.2 在虚拟机中直接查看工作空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查看工作空间内容
ls -la /var/lib/jenkins/workspace/demo-java-freestyle/

# 查看构建产物
ls -lh /var/lib/jenkins/workspace/demo-java-freestyle/build/

# 查看 Jenkins 数据目录结构
ls -la /var/lib/jenkins/jobs/demo-java-freestyle/
├── builds/ — 构建记录
│ ├── 1/ — 第 1 次构建
│ │ ├── build.xml — 构建元数据
│ │ ├── log — 构建日志
│ │ └── archive/ — 归档产物
│ ├── 2/
│ └── ...
├── config.xml — 项目配置文件(XML 格式)
├── nextBuildNumber — 下一次构建号
└── lastSuccessful — 最后一次成功构建的符号链接

8.3 清理工作空间

1
2
3
4
5
6
7
8
9
# 方法一:通过 Jenkins UI
# 项目主页 → 左侧 [ Workspace ] → [ Wipe Out Current Workspace ]

# 方法二:通过命令行
rm -rf /var/lib/jenkins/workspace/demo-java-freestyle/

# 方法三:通过 Jenkins CLI
java -jar jenkins-cli.jar -s http://localhost:8080/ \
clear-queue demo-java-freestyle

九、进阶练习

9.1 练习 1:模拟构建失败

1
2
3
4
5
6
7
8
9
10
11
12
# 修改 build.sh,故意引入一个错误
cd ~/demo-java-app

# 在 build.sh 的编译步骤后添加一行会导致失败的命令
# 在 "bash scripts/build.sh" 之前,先修改 build.sh
sed -i '/echo "✅ 编译成功"/a\
\
echo "测试构建失败..."\
exit 1 # 故意返回非 0 状态码' scripts/build.sh

git add -A
git commit -m "test: 故意引入构建失败"

等待 Poll SCM 触发,观察构建状态变为 红色(FAILURE)

1
2
3
4
5
# 修复构建失败
# 恢复 build.sh
cd ~/demo-java-app
git revert HEAD --no-edit
# 或者手动编辑 build.sh 删除 exit 1 那行

观察要点:

1
2
3
4
5
6
构建失败时你会看到:
├── Build History 中的圆点变红
├── 控制台输出中显示错误信息
├── 最后一行显示 "Finished: FAILURE"
├── 如果配置了邮件通知,会收到失败邮件
└── Jenkins 会标记是哪一步失败的

9.2 练习 2:查看构建趋势

1
2
3
4
5
6
7
8
在项目主页,你会看到一个 Build History 的趋势图(如果有多个构建):

├── 蓝色/绿色 = SUCCESS
├── 黄色 = UNSTABLE
├── 红色 = FAILURE
└── 灰色 = ABORTED

这个趋势图让你一眼看出项目的健康状况。

9.3 练习 3:配置项目视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
当 Jenkins 中有多个项目时,可以用视图来组织:

1. 在 Dashboard 页面,点击左侧 [ + ] 按钮(在 My Views 旁边)

2. 选择 "New View"

3. 输入视图名称:Java Projects

4. 选择视图类型:List View

5. 配置过滤条件:
├── 勾选要显示的项目
└── 或使用正则表达式过滤:java.*

6. 点击 [ OK ]

现在你有了一个只显示 Java 相关项目的视图。

十、Day 3-4 自检清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
环境准备
├── [ ] Git 已安装并配置了用户信息
├── [ ] Java 已安装(java -version 和 javac -version)
├── [ ] 成功创建了 demo-java-app 本地 Git 仓库
├── [ ] Git 仓库中有至少 4 个提交记录
└── [ ] build.sh 在本地能正常执行

Freestyle 项目配置
├── [ ] 成功创建了 demo-java-freestyle 项目
├── [ ] 正确配置了 Git 源码管理(仓库路径和分支名)
├── [ ] 正确配置了构建触发器(至少配置了 Poll SCM)
├── [ ] 正确配置了构建步骤(Execute shell)
├── [ ] 正确配置了构建后操作(Archive artifacts)
└── [ ] 项目配置已保存

构建执行
├── [ ] 手动触发了第一次构建(Build Now)
├── [ ] 构建状态为 SUCCESS(蓝色)
├── [ ] 能查看并理解控制台输出
├── [ ] 构建产物已正确归档(build/*.jar)
├── [ ] 能从 Jenkins 下载归档的产物
└── [ ] 能在虚拟机中查看工作空间目录

自动触发
├── [ ] 配置了 Poll SCM(H/2 * * * *)
├── [ ] 提交新代码后,Jenkins 自动触发了构建
├── [ ] 理解 Poll SCM 的工作原理
├── [ ] 能区分手动触发和自动触发的构建日志
└── [ ] 配置了远程触发(Trigger remotely)并测试成功

概念理解
├── [ ] 理解四种构建状态(SUCCESS/UNSTABLE/FAILURE/ABORTED)
├── [ ] 理解工作空间(Workspace)的概念
├── [ ] 理解构建触发器的类型和适用场景
├── [ ] 能读懂 CRON 表达式
├── [ ] 知道如何查看代码变更和构建趋势
└── [ ] 知道 Jenkins 数据目录的结构

十一、常见问题排查

Q1:Jenkins 拉取本地 Git 仓库报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
错误信息:
stderr: fatal: '/home/xxx/demo-java-app' does not appear to be a git repository

原因:Jenkins 运行用户(jenkins)没有权限访问你的 home 目录

解决方案:

# 方案一:修改目录权限(推荐用于学习环境)
sudo chmod -R 755 /home/你的用户名/
sudo chmod -R 755 /home/你的用户名/demo-java-app/

# 方案二:将仓库移到 Jenkins 有权限的目录
sudo cp -r ~/demo-java-app /var/lib/jenkins/
sudo chown -R jenkins:jenkins /var/lib/jenkins/demo-java-app/

# 然后在 Jenkins 项目配置中修改仓库路径为:
# /var/lib/jenkins/demo-java-app

# 方案三:将 jenkins 用户加入你的用户组
sudo usermod -aG 你的用户组 jenkins
sudo systemctl restart jenkins

Q2:构建时提示 javac: command not found

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
原因:Jenkins 的环境变量中没有包含 Java 的路径

解决方案:

# 1. 找到 javac 的路径
which javac
# 输出类似:/usr/lib/jvm/java-17-openjdk-amd64/bin/javac

# 2. 在构建脚本中设置 PATH
# 修改 Jenkins 项目配置中的 Execute shell,在脚本最前面添加:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH

# 3. 或者在 Manage Jenkins → System → Shell 中
# 设置全局的环境变量

# 4. 或者在 Manage Jenkins → Tools 中
# 配置 JDK 自动安装

Q3:Poll SCM 不触发构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
排查步骤:

1. 确认 Poll SCM 已正确配置
└── 项目配置 → Build Triggers → Poll SCM → CRON 表达式

2. 确认确实有新的 Git 提交
cd ~/demo-java-app
git log --oneline
└── 确认最新提交是在配置 Poll SCM 之后的

3. 查看轮询日志
└── 项目主页 → 左下角 "Polling Log"
└── 这里会显示每次轮询的结果

4. 检查 Jenkins 系统日志
sudo journalctl -u jenkins -f
└── 看有没有错误信息

5. 手动触发轮询
└── 项目主页 → 左侧 [ Poll Now ]
└── 不用等 CRON 周期,立即检查一次

6. 确认 Git 路径正确
└── Jenkins 可能找不到 git 命令
└── Manage Jenkins → Tools → Git installations
└── 确认 Git 路径配置正确(通常是 /usr/bin/git)

Q4:构建产物归档失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
错误信息:
ERROR: No artifacts found that match the file pattern "build/*.jar"

原因:
├── 构建脚本没有生成 JAR 文件
├── JAR 文件路径不对
└── 构建失败了,没有产物

排查:
1. 查看控制台输出,确认构建步骤是否成功
2. 在 Workspace 中确认文件是否存在
3. 确认归档路径是否正确(相对于工作空间根目录)

# 在虚拟机中检查
ls -la /var/lib/jenkins/workspace/demo-java-freestyle/build/

Q5:构建触发了但没有代码变更

1
2
3
4
5
6
7
8
9
10
11
原因:Poll SCM Build periodically 搞混了

├── Poll SCM:检查到代码变化才构建
├── Build periodically:时间到了就构建(不管有没有变化)

如果你勾选了 Build periodically,
即使代码没有变化,也会定期触发构建。

解决:
├── 只勾选 Poll SCM(推荐)
└── 或者两个都勾选,但理解它们的区别

十二、下一步预告

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Day 5-6 学习内容预告:

├── 安装和管理 Jenkins 插件
│ ├── 搜索和安装插件
│ ├── 更新和卸载插件
│ └── 常用插件推荐清单

├── 配置全局工具
│ ├── JDK 配置(多版本管理)
│ ├── Maven 配置
│ ├── Node.js 配置
│ └── Git 配置

├── 配置凭据管理
│ ├── 用户名密码凭据
│ ├── SSH 密钥凭据
│ ├── Secret Text 凭据
│ └── 凭据作用域

└── 构建后操作进阶
├── 邮件通知配置(SMTP 设置)
├── 发送 HTML 格式的构建报告
└── 构建触发其他项目


Jenkins Day 3-4 学习笔记
http://bote798.github.io/2026/04/02/Jenkins Day 3-4 学习笔记/
作者
bote798
发布于
2026年4月2日
更新于
2026年4月2日
许可协议