Initial commit
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.DS_Store
|
||||
15
exercises/01-jenkins-installation/instructions.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Exercise 1
|
||||
|
||||
In this exercise, you will practice installing and configuring Jenkins on your machine.
|
||||
|
||||
## Installing Jenkins
|
||||
|
||||
1. Download the [latest stable Jenkins WAR file](http://mirrors.jenkins.io/war-stable/latest/jenkins.war). To download from the command line, use `wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war`.
|
||||
2. Open a terminal and navigate to the directory containing the WAR file.
|
||||
3. Run the command `java -jar jenkins.war` to start Jenkins on port 8080. Provide the `--httpPort` option if you experience a port conflict e.g. `java -jar jenkins.war --httpPort=9999`. After a couple of seconds you should see the message "Jenkins is fully up and running" in the log output.
|
||||
4. Open a browser of your choice and navigate to `localhost:<port>`. The default is `localhost:8080`.
|
||||
5. In the screen named "Unlock Jenkins", enter the password from the console output. Press the "Continue" button.
|
||||
6. In the screen named "Customize Jenkins", select the option "Install suggested plugins".
|
||||
7. In the screen named "Create First Admin User", enter all fields with credentials for your Jenkins administrator. Press the "Save and Continue" button.
|
||||
8. In the screen named "Instance Configuration", keep the default value. Press the "Save and Finish" button.
|
||||
9. You should see the message "Jenkins is ready!". Press the "Start using Jenkins" button. You'll be redirected to the Jenkins dashboard.
|
||||
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 743 KiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
145
exercises/01-jenkins-installation/solution/solution.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Solution
|
||||
|
||||
Download the WAR file with the help of `wget`.
|
||||
|
||||
```bash
|
||||
wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war
|
||||
--2019-08-09 16:06:23-- http://mirrors.jenkins.io/war-stable/latest/jenkins.war
|
||||
Resolving mirrors.jenkins.io (mirrors.jenkins.io)... 52.202.51.185
|
||||
Connecting to mirrors.jenkins.io (mirrors.jenkins.io)|52.202.51.185|:80... connected.
|
||||
HTTP request sent, awaiting response... 302 Found
|
||||
Location: http://mirror.xmission.com/jenkins/war-stable/2.176.2/jenkins.war [following]
|
||||
--2019-08-09 16:06:23-- http://mirror.xmission.com/jenkins/war-stable/2.176.2/jenkins.war
|
||||
Resolving mirror.xmission.com (mirror.xmission.com)... 2607:fa18:0:3::13, 198.60.22.13
|
||||
Connecting to mirror.xmission.com (mirror.xmission.com)|2607:fa18:0:3::13|:80... connected.
|
||||
HTTP request sent, awaiting response... 200 OK
|
||||
Length: 77379386 (74M) [application/java-archive]
|
||||
Saving to: ‘jenkins.war’
|
||||
|
||||
jenkins.war 100%[=================================================>] 73.79M 6.46MB/s in 14s
|
||||
|
||||
2019-08-09 16:06:37 (5.36 MB/s) - ‘jenkins.war’ saved [77379386/77379386]
|
||||
```
|
||||
|
||||
First, start the Jenkins server. Copy the password printed in the log output to the clipboard.
|
||||
|
||||
```bash
|
||||
$ java -jar jenkins.war
|
||||
Running from: /Users/bmuschko/dev/tools/jenkins-2.150.1/jenkins.war
|
||||
webroot: $user.home/.jenkins
|
||||
Jul 16, 2019 4:59:30 PM org.eclipse.jetty.util.log.Log initialized
|
||||
INFO: Logging initialized @501ms to org.eclipse.jetty.util.log.JavaUtilLog
|
||||
Jul 16, 2019 4:59:30 PM winstone.Logger logInternal
|
||||
INFO: Beginning extraction from war file
|
||||
Jul 16, 2019 4:59:32 PM org.eclipse.jetty.server.handler.ContextHandler setContextPath
|
||||
WARNING: Empty contextPath
|
||||
Jul 16, 2019 4:59:32 PM org.eclipse.jetty.server.Server doStart
|
||||
INFO: jetty-9.4.z-SNAPSHOT; built: 2019-02-15T16:53:49.381Z; git: eb70b240169fcf1abbd86af36482d1c49826fa0b; jvm 1.8.0_181-b13
|
||||
Jul 16, 2019 4:59:32 PM org.eclipse.jetty.webapp.StandardDescriptorProcessor visitServlet
|
||||
INFO: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
|
||||
Jul 16, 2019 4:59:32 PM org.eclipse.jetty.server.session.DefaultSessionIdManager doStart
|
||||
INFO: DefaultSessionIdManager workerName=node0
|
||||
Jul 16, 2019 4:59:32 PM org.eclipse.jetty.server.session.DefaultSessionIdManager doStart
|
||||
INFO: No SessionScavenger set, using defaults
|
||||
Jul 16, 2019 4:59:32 PM org.eclipse.jetty.server.session.HouseKeeper startScavenging
|
||||
INFO: node0 Scavenging every 660000ms
|
||||
Jenkins home directory: /Users/bmuschko/.jenkins found at: $user.home/.jenkins
|
||||
Jul 16, 2019 4:59:34 PM org.eclipse.jetty.server.handler.ContextHandler doStart
|
||||
INFO: Started w.@21ec5d87{Jenkins v2.176.1,/,file:///Users/bmuschko/.jenkins/war/,AVAILABLE}{/Users/bmuschko/.jenkins/war}
|
||||
Jul 16, 2019 4:59:34 PM org.eclipse.jetty.server.AbstractConnector doStart
|
||||
INFO: Started ServerConnector@388ffbc2{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
|
||||
Jul 16, 2019 4:59:34 PM org.eclipse.jetty.server.Server doStart
|
||||
INFO: Started @4486ms
|
||||
Jul 16, 2019 4:59:34 PM winstone.Logger logInternal
|
||||
INFO: Winstone Servlet Engine v4.0 running: controlPort=disabled
|
||||
Jul 16, 2019 4:59:35 PM jenkins.InitReactorRunner$1 onAttained
|
||||
INFO: Started initialization
|
||||
Jul 16, 2019 4:59:35 PM jenkins.InitReactorRunner$1 onAttained
|
||||
INFO: Listed all plugins
|
||||
Jul 16, 2019 4:59:36 PM jenkins.InitReactorRunner$1 onAttained
|
||||
INFO: Prepared all plugins
|
||||
Jul 16, 2019 4:59:36 PM jenkins.InitReactorRunner$1 onAttained
|
||||
INFO: Started all plugins
|
||||
Jul 16, 2019 4:59:36 PM jenkins.InitReactorRunner$1 onAttained
|
||||
INFO: Augmented all extensions
|
||||
Jul 16, 2019 4:59:37 PM jenkins.InitReactorRunner$1 onAttained
|
||||
INFO: Loaded all jobs
|
||||
Jul 16, 2019 4:59:37 PM hudson.model.AsyncPeriodicWork$1 run
|
||||
INFO: Started Download metadata
|
||||
Jul 16, 2019 4:59:37 PM hudson.util.Retrier start
|
||||
INFO: Attempt #1 to do the action check updates server
|
||||
Jul 16, 2019 4:59:38 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
|
||||
INFO: Refreshing org.springframework.web.context.support.StaticWebApplicationContext@54fe6e54: display name [Root WebApplicationContext]; startup date [Tue Jul 16 16:59:38 MDT 2019]; root of context hierarchy
|
||||
Jul 16, 2019 4:59:38 PM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
|
||||
INFO: Bean factory for application context [org.springframework.web.context.support.StaticWebApplicationContext@54fe6e54]: org.springframework.beans.factory.support.DefaultListableBeanFactory@3e77b308
|
||||
Jul 16, 2019 4:59:38 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
|
||||
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3e77b308: defining beans [authenticationManager]; root of factory hierarchy
|
||||
Jul 16, 2019 4:59:38 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
|
||||
INFO: Refreshing org.springframework.web.context.support.StaticWebApplicationContext@2b22ca16: display name [Root WebApplicationContext]; startup date [Tue Jul 16 16:59:38 MDT 2019]; root of context hierarchy
|
||||
Jul 16, 2019 4:59:38 PM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
|
||||
INFO: Bean factory for application context [org.springframework.web.context.support.StaticWebApplicationContext@2b22ca16]: org.springframework.beans.factory.support.DefaultListableBeanFactory@28d4e2d4
|
||||
Jul 16, 2019 4:59:38 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
|
||||
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@28d4e2d4: defining beans [filter,legacy]; root of factory hierarchy
|
||||
Jul 16, 2019 4:59:38 PM jenkins.install.SetupWizard init
|
||||
INFO:
|
||||
|
||||
*************************************************************
|
||||
*************************************************************
|
||||
*************************************************************
|
||||
|
||||
Jenkins initial setup is required. An admin user has been created and a password generated.
|
||||
Please use the following password to proceed to installation:
|
||||
|
||||
34155b26571e4a2eb6eca68ddc4d5749
|
||||
|
||||
This may also be found at: /Users/bmuschko/.jenkins/secrets/initialAdminPassword
|
||||
|
||||
*************************************************************
|
||||
*************************************************************
|
||||
*************************************************************
|
||||
|
||||
Jul 16, 2019 4:59:42 PM hudson.model.UpdateSite updateData
|
||||
INFO: Obtained the latest update center data file for UpdateSource default
|
||||
Jul 16, 2019 4:59:42 PM hudson.model.UpdateSite updateData
|
||||
INFO: Obtained the latest update center data file for UpdateSource default
|
||||
Jul 16, 2019 4:59:43 PM jenkins.InitReactorRunner$1 onAttained
|
||||
INFO: Completed initialization
|
||||
Jul 16, 2019 4:59:43 PM hudson.model.DownloadService$Downloadable load
|
||||
INFO: Obtained the updated data file for hudson.tasks.Maven.MavenInstaller
|
||||
Jul 16, 2019 4:59:43 PM hudson.util.Retrier start
|
||||
INFO: Performed the action check updates server successfully at the attempt #1
|
||||
Jul 16, 2019 4:59:43 PM hudson.model.AsyncPeriodicWork$1 run
|
||||
INFO: Finished Download metadata. 5,856 ms
|
||||
Jul 16, 2019 4:59:43 PM hudson.UDPBroadcastThread run
|
||||
INFO: Cannot listen to UDP port 33,848, skipping: java.net.SocketException: Can't assign requested address
|
||||
Jul 16, 2019 4:59:43 PM hudson.WebAppMain$3 run
|
||||
INFO: Jenkins is fully up and running
|
||||
```
|
||||
|
||||
Paste the password from the clipboard into the password field.
|
||||
|
||||

|
||||
|
||||
Select the option to install recommended plugins.
|
||||
|
||||

|
||||
|
||||
The installation process will run for a couple of minutes.
|
||||
|
||||

|
||||
|
||||
Enter credentials for your first admin user.
|
||||
|
||||

|
||||
|
||||
Skip over the instance configuration step.
|
||||
|
||||

|
||||
|
||||
Jenkins indicates that it is ready for use.
|
||||
|
||||

|
||||
|
||||
The installation process is complete. You should land on the dashboard.
|
||||
|
||||

|
||||
14
exercises/02-job-creation/instructions.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Exercise 2
|
||||
|
||||
In this exercise, you will create a new freestyle job and configure it to build with parameters. You'll also have a look at the Jenkins home directory to inspect the directory structure representing the job.
|
||||
|
||||
## Defining, Configuring and Organizing a Job
|
||||
|
||||
1. From the dashboard, click the "New Item" button.
|
||||
2. Enter the item name "my-freestyle-job" and select "Freestyle project". Press the "OK" button.
|
||||
3. In the job configuration, define the option to only keep the last 2 builds. Provide the description "A simple freestyle job". Upon building the project, a String parameter named `MESSAGE` should be provided. Press the "Save" button.
|
||||
4. Trigger a new build by pressing the "Build with Parameters" button. Enter a value for the `MESSAGE` parameter. The build should finish successfully. Locate the provided parameter value in the build information.
|
||||
5. Run the build two more times. What do you see?
|
||||
6. Create a new view named "test". Add the job to the view.
|
||||
7. Create a new folder named "freestyle" as part of the view. Move the job into the folder.
|
||||
8. Locate the build information in `$JENKINS_HOME`. Inspect the directory structure.
|
||||
BIN
exercises/02-job-creation/solution/images/build-history.png
Normal file
|
After Width: | Height: | Size: 834 KiB |
BIN
exercises/02-job-creation/solution/images/build-with-params.png
Normal file
|
After Width: | Height: | Size: 744 KiB |
BIN
exercises/02-job-creation/solution/images/job-configuration.png
Normal file
|
After Width: | Height: | Size: 770 KiB |
BIN
exercises/02-job-creation/solution/images/job-in-folder.png
Normal file
|
After Width: | Height: | Size: 803 KiB |
BIN
exercises/02-job-creation/solution/images/job-in-view.png
Normal file
|
After Width: | Height: | Size: 801 KiB |
BIN
exercises/02-job-creation/solution/images/move-job.png
Normal file
|
After Width: | Height: | Size: 770 KiB |
BIN
exercises/02-job-creation/solution/images/new-folder.png
Normal file
|
After Width: | Height: | Size: 898 KiB |
BIN
exercises/02-job-creation/solution/images/new-freestyle-job.png
Normal file
|
After Width: | Height: | Size: 865 KiB |
BIN
exercises/02-job-creation/solution/images/new-view.png
Normal file
|
After Width: | Height: | Size: 755 KiB |
66
exercises/02-job-creation/solution/solution.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Solution
|
||||
|
||||
We'll start by creating the new freestyle job.
|
||||
|
||||

|
||||
|
||||
Configure the job as follows.
|
||||
|
||||

|
||||
|
||||
The build will ask for a parameter value when triggered.
|
||||
|
||||

|
||||
|
||||
The build history only stores the previous two builds.
|
||||
|
||||

|
||||
|
||||
Create a new view.
|
||||
|
||||

|
||||
|
||||
After adding the job to the view, it will show up in a separate tab.
|
||||
|
||||

|
||||
|
||||
Create a new folder.
|
||||
|
||||

|
||||
|
||||
The job became a child of the folder after moving it there.
|
||||
|
||||

|
||||
|
||||
Navigating to the `job` directory under the Jenkins Home reveals the build history.
|
||||
|
||||
```bash
|
||||
$ cd /Users/bmuschko/.jenkins/jobs/freestyle/jobs
|
||||
$ tree my-freestyle-job
|
||||
my-freestyle-job
|
||||
├── builds
|
||||
│ ├── 1
|
||||
│ │ ├── build.xml
|
||||
│ │ ├── changelog.xml
|
||||
│ │ └── log
|
||||
│ ├── 2
|
||||
│ │ ├── build.xml
|
||||
│ │ ├── changelog.xml
|
||||
│ │ └── log
|
||||
│ ├── 3
|
||||
│ │ ├── build.xml
|
||||
│ │ ├── changelog.xml
|
||||
│ │ └── log
|
||||
│ ├── lastFailedBuild -> -1
|
||||
│ ├── lastStableBuild -> 3
|
||||
│ ├── lastSuccessfulBuild -> 3
|
||||
│ ├── lastUnstableBuild -> -1
|
||||
│ ├── lastUnsuccessfulBuild -> -1
|
||||
│ └── legacyIds
|
||||
├── config.xml
|
||||
├── lastStable -> builds/lastStableBuild
|
||||
├── lastSuccessful -> builds/lastSuccessfulBuild
|
||||
└── nextBuildNumber
|
||||
|
||||
8 directories, 15 files
|
||||
```
|
||||
12
exercises/03-build-trigger-and-steps/instructions.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Exercise 3
|
||||
|
||||
In this exercise, you will configure the job to build based on a cron definition. Moreover, you will create downstream job that should be built automatically if the upstream job is successful.
|
||||
|
||||
## Configuring Build Triggers and Steps for a Job
|
||||
|
||||
1. Add a default value for the build parameter named `MESSAGE` e.g. `Hello World!`.
|
||||
2. Create a build trigger that builds the project every minute.
|
||||
3. Add a build step that executes the shell command `echo "Message: $MESSAGE"`. The message is value of the parameter.
|
||||
4. After a minute the first execution should have been triggered. Check the log output of the build and find the rendered message.
|
||||
5. Create another freestyle project named `downstream-job` in the same folder.
|
||||
6. Configure the initial job to execute the `downstream-job` if it was stable.
|
||||
|
After Width: | Height: | Size: 1000 KiB |
|
After Width: | Height: | Size: 938 KiB |
|
After Width: | Height: | Size: 998 KiB |
|
After Width: | Height: | Size: 1013 KiB |
|
After Width: | Height: | Size: 972 KiB |
33
exercises/03-build-trigger-and-steps/solution/solution.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Solution
|
||||
|
||||
Modify the existing build parameter.
|
||||
|
||||

|
||||
|
||||
Add the cron build trigger and the build step.
|
||||
|
||||

|
||||
|
||||
The output render the interpolated value of the `echo` command.
|
||||
|
||||
```bash
|
||||
Started by timer
|
||||
Running as SYSTEM
|
||||
Building in workspace /Users/bmuschko/.jenkins/workspace/freestyle/my-freestyle-job
|
||||
[my-freestyle-job] $ /bin/sh -xe /var/folders/02/3dgzjkqj4kz0g7lnrk0w93c00000gn/T/jenkins3548490840940668236.sh
|
||||
+ echo "Message: Hello World!"
|
||||
Message: Hello World!
|
||||
Finished: SUCCESS
|
||||
```
|
||||
|
||||
Create a new job in the same folder.
|
||||
|
||||

|
||||
|
||||
Configure the downstream job from the initial job.
|
||||
|
||||

|
||||
|
||||
The downstream job indicates the upstream job.
|
||||
|
||||

|
||||
10
exercises/04-scm-configuration/instructions.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Exercise 4
|
||||
|
||||
In this exercise, you will create a new job that pulls the source code from a repository on GitHub. Upon triggering a build, the job will execute a Gradle build.
|
||||
|
||||
## Configuring a GitHub Repository
|
||||
|
||||
1. Create a new freestyle job named `gradle-initializr`.
|
||||
2. Configure Git as the SCM and use the repository URL `git@github.com:bmuschko/gradle-initializr.git`. Only build from the branch `master`.
|
||||
3. Add a build step to run the Gradle command `clean build` using the Wrapper.
|
||||
4. Trigger a build and look at the output.
|
||||
BIN
exercises/04-scm-configuration/solution/images/git-scm.png
Normal file
|
After Width: | Height: | Size: 1005 KiB |
|
After Width: | Height: | Size: 950 KiB |
BIN
exercises/04-scm-configuration/solution/images/new-job.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
71
exercises/04-scm-configuration/solution/solution.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Solution
|
||||
|
||||
Create a new job.
|
||||
|
||||

|
||||
|
||||
Configure the Git SCM and point the proper URL. The default is the `master` branch.
|
||||
|
||||

|
||||
|
||||
Create the Gradle build step.
|
||||
|
||||

|
||||
|
||||
The build log should look similar to the output below.
|
||||
|
||||
```bash
|
||||
Started by user Admin
|
||||
Running as SYSTEM
|
||||
Building in workspace /Users/bmuschko/.jenkins/workspace/gradle-initializr
|
||||
No credentials specified
|
||||
Cloning the remote Git repository
|
||||
Cloning repository git@github.com:bmuschko/gradle-initializr.git
|
||||
> git init /Users/bmuschko/.jenkins/workspace/gradle-initializr # timeout=10
|
||||
Fetching upstream changes from git@github.com:bmuschko/gradle-initializr.git
|
||||
> git --version # timeout=10
|
||||
> git fetch --tags --force --progress git@github.com:bmuschko/gradle-initializr.git +refs/heads/*:refs/remotes/origin/*
|
||||
> git config remote.origin.url git@github.com:bmuschko/gradle-initializr.git # timeout=10
|
||||
> git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
|
||||
> git config remote.origin.url git@github.com:bmuschko/gradle-initializr.git # timeout=10
|
||||
Fetching upstream changes from git@github.com:bmuschko/gradle-initializr.git
|
||||
> git fetch --tags --force --progress git@github.com:bmuschko/gradle-initializr.git +refs/heads/*:refs/remotes/origin/*
|
||||
> git rev-parse refs/remotes/origin/master^{commit} # timeout=10
|
||||
> git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
|
||||
Checking out Revision 8e725ea3507f5ac0f8251234e1ff0f214b228d3d (refs/remotes/origin/master)
|
||||
> git config core.sparsecheckout # timeout=10
|
||||
> git checkout -f 8e725ea3507f5ac0f8251234e1ff0f214b228d3d
|
||||
Commit message: "Update docs"
|
||||
First time build. Skipping changelog.
|
||||
[Gradle] - Launching build.
|
||||
[gradle-initializr] $ gradle clean build
|
||||
Starting a Gradle Daemon (subsequent builds will be faster)
|
||||
> Task :clean UP-TO-DATE
|
||||
> Task :compileJava
|
||||
> Task :compileGroovy NO-SOURCE
|
||||
> Task :processResources
|
||||
> Task :classes
|
||||
> Task :bootJar
|
||||
> Task :jar SKIPPED
|
||||
> Task :assemble
|
||||
> Task :compileTestJava NO-SOURCE
|
||||
> Task :compileTestGroovy
|
||||
> Task :processTestResources NO-SOURCE
|
||||
> Task :testClasses
|
||||
> Task :test
|
||||
> Task :compileIntegrationTestJava NO-SOURCE
|
||||
> Task :compileIntegrationTestGroovy
|
||||
> Task :processIntegrationTestResources NO-SOURCE
|
||||
> Task :integrationTestClasses
|
||||
> Task :integrationTest
|
||||
2019-07-17 10:07:48.803 INFO 67741 --- [ Thread-6] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
|
||||
> Task :check
|
||||
> Task :build
|
||||
|
||||
BUILD SUCCESSFUL in 30s
|
||||
8 actionable tasks: 7 executed, 1 up-to-date
|
||||
Build step 'Invoke Gradle script' changed build result to SUCCESS
|
||||
Finished: SUCCESS
|
||||
```
|
||||
|
||||
As a side note: The GitHub plugin is [currently broken](https://issues.jenkins-ci.org/browse/JENKINS-11337) if you wanted to build multiple branches with a single job. You will have to model it as a multi-branch pipeline job.
|
||||
14
exercises/05-test-execution-and-reporting/instructions.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Exercise 5
|
||||
|
||||
In this exercise, you will configure the existing job to execute tests. Furthermore, you'll enhance the job to process the test results and code coverage metrics.
|
||||
|
||||
## Displaying JUnit and JaCoCo Test Results
|
||||
|
||||
1. Configure the `gradle-initializr` project to parse the JUnit XML results for unit test. The files can be found in the directory `build/test-results/test`.
|
||||
2. Execute the build twice to generate a graph. Have a look at the executed tests in the test results.
|
||||
3. Include all test results (unit and integration tests) in the reporting.
|
||||
4. Have a look at how the test result trend changes.
|
||||
5. Install the JaCoCo plugin.
|
||||
6. Reconfigure the Gradle build step to also generate JaCoCo reports: `clean build jacocoTestReport jacocoIntegrationTestReport`.
|
||||
7. Add a post-build action for publish the JaCoCo reports. Use the following path to look for results: `build/jacoco/**.exec`.
|
||||
8. Execute the build twice to generate a graph. Have a look at the code coverage results.
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1010 KiB |
|
After Width: | Height: | Size: 869 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1000 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 997 KiB |
|
After Width: | Height: | Size: 998 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
@@ -0,0 +1,37 @@
|
||||
# Solution
|
||||
|
||||
Publish the JUnit reports by pointing to the exact directory containing the XML files.
|
||||
|
||||

|
||||
|
||||
After executing the build twice you will see a test result trend graph.
|
||||
|
||||

|
||||
|
||||
Publish the JUnit reporting by using a wild card.
|
||||
|
||||

|
||||
|
||||
The trend changes accordingly.
|
||||
|
||||

|
||||
|
||||
Install the JaCoCo plugin.
|
||||
|
||||

|
||||
|
||||
Change the task list executed by the Gradle build step.
|
||||
|
||||

|
||||
|
||||
Configure JaCoCo reporting.
|
||||
|
||||

|
||||
|
||||
The JaCoCo coverage trend renders after executing the build twice.
|
||||
|
||||

|
||||
|
||||
You can drill into the details of the report.
|
||||
|
||||

|
||||
15
exercises/07-artifacts/instructions.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Exercise 7
|
||||
|
||||
You will enhance the existing job to generate a JAR file and store it on Jenkins. The job should record the MD5 hash for the artifact. Later, you will configure a downstream job that should be able to reuse the existing artifact.
|
||||
|
||||
## Storing and Fingerprinting Artifacts
|
||||
|
||||
1. Create a post-build action for archiving JAR files with the pattern `build/libs/*.jar`. Enable the fingerprinting option.
|
||||
2. Execute the build. The build should list the artifact `gradle-initializr-1.0.0.jar`.
|
||||
3. Have a look at the recorded fingerprints of this build.
|
||||
4. Render the MD5 hash of the artifact and the usage of the artifact.
|
||||
5. Install the Copy Artifacts plugin.
|
||||
6. Create a downstream job named `consumer`.
|
||||
7. Configure the downstream job to use the artifact produced by the upstream job.
|
||||
8. Run the the build for the job `gradle-initializr`.
|
||||
9. Have a look at the fingerprints of the downstream job.
|
||||
BIN
exercises/07-artifacts/solution/images/archive-artifacts.png
Normal file
|
After Width: | Height: | Size: 848 KiB |
BIN
exercises/07-artifacts/solution/images/build-artifact.png
Normal file
|
After Width: | Height: | Size: 927 KiB |
BIN
exercises/07-artifacts/solution/images/copy-artifacts-plugin.png
Normal file
|
After Width: | Height: | Size: 707 KiB |
BIN
exercises/07-artifacts/solution/images/copy-artifacts.png
Normal file
|
After Width: | Height: | Size: 735 KiB |
BIN
exercises/07-artifacts/solution/images/fingerprint-details.png
Normal file
|
After Width: | Height: | Size: 696 KiB |
BIN
exercises/07-artifacts/solution/images/fingerprints-upstream.png
Normal file
|
After Width: | Height: | Size: 704 KiB |
BIN
exercises/07-artifacts/solution/images/recorded-fingerprint.png
Normal file
|
After Width: | Height: | Size: 772 KiB |
BIN
exercises/07-artifacts/solution/images/trigger-upstream.png
Normal file
|
After Width: | Height: | Size: 799 KiB |
29
exercises/07-artifacts/solution/solution.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Solution
|
||||
|
||||
In the job configuration, archive the artifact produced by the build. Check the box for generating fingerprints.
|
||||
|
||||

|
||||
|
||||
Execute the build and find the archived artifact.
|
||||
|
||||

|
||||
|
||||
Have a look at the details of the fingerprinting.
|
||||
|
||||

|
||||
|
||||
Install the Copy Artifacts plugin.
|
||||
|
||||

|
||||
|
||||
Trigger the downstream job upon success.
|
||||
|
||||

|
||||
|
||||
Copy artifacts from the upstream job.
|
||||
|
||||

|
||||
|
||||
You can see the full usage of the artifact in upstream and downstream jobs.
|
||||
|
||||

|
||||
11
exercises/08-matrix-security/instructions.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Exercise 8
|
||||
|
||||
In this exercise, you'll create a new user and assign read permissions. You will verify permissions for the admin user and the new user by logging into Jenkins with the appropriate credentials.
|
||||
|
||||
## Creating a User and Setting Permissions
|
||||
|
||||
1. Ensure that you are logged in as admin user.
|
||||
2. Create a new user named `miller`. Provide the relevant information.
|
||||
3. Configure Matrix Security by adding the admin user and the newly created user. The admin user should have all permissions. The `miller` user should only have read permissions for jobs and views.
|
||||
4. Log out of the system.
|
||||
5. Log in with the user `miller` and navigate to one of the jobs. Notice that you cannot edit the configuration or trigger a new build.
|
||||
BIN
exercises/08-matrix-security/solution/images/create-user.png
Normal file
|
After Width: | Height: | Size: 843 KiB |
BIN
exercises/08-matrix-security/solution/images/job-overview.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
BIN
exercises/08-matrix-security/solution/images/user-login.png
Normal file
|
After Width: | Height: | Size: 778 KiB |
BIN
exercises/08-matrix-security/solution/images/user-overview.png
Normal file
|
After Width: | Height: | Size: 881 KiB |
21
exercises/08-matrix-security/solution/solution.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Solution
|
||||
|
||||
Create the new user.
|
||||
|
||||

|
||||
|
||||
The new user is now listed.
|
||||
|
||||

|
||||
|
||||
Configure users and permissions.
|
||||
|
||||

|
||||
|
||||
Log in with new user.
|
||||
|
||||

|
||||
|
||||
The job doesn't allow any editing or build triggering operations.
|
||||
|
||||

|
||||
17
exercises/09-rest-api/instructions.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Exercise 9
|
||||
|
||||
This exercise explores the use of the REST API to trigger a build for an existing job. You will configure security features as necessary.
|
||||
|
||||
## Using the REST API for Common Operations
|
||||
|
||||
1. Create a new user named `buildbot`.
|
||||
2. Add adminstration permissions for the user.
|
||||
3. Log in with user `buildbot`.
|
||||
4. Generate the API token for the user.
|
||||
5. Generate a Jenkins crumb from the command line.
|
||||
6. Export the environment variables `JENKINS_CRUMB` and `JENKINS_API_TOKEN` with the correct values.
|
||||
7. Trigger a build of the job `gradle-initializr` with a `curl` command using the REST API.
|
||||
8. Disable the job `gradle-initializr` with a `curl` command using the REST API.
|
||||
9. Reenable the job `gradle-initializr` with a `curl` command using the REST API.
|
||||
10. Download the Jenkins CLI client.
|
||||
11. Trigger the build of the job `gradle-initializr` with a `curl` command using the Jenkins CLI.
|
||||
BIN
exercises/09-rest-api/solution/images/api-token.png
Normal file
|
After Width: | Height: | Size: 999 KiB |
BIN
exercises/09-rest-api/solution/images/build-by-user.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
exercises/09-rest-api/solution/images/create-user.png
Normal file
|
After Width: | Height: | Size: 846 KiB |
BIN
exercises/09-rest-api/solution/images/disabled-job.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
exercises/09-rest-api/solution/images/user-permissions.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
50
exercises/09-rest-api/solution/solution.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Solution
|
||||
|
||||
Create the new user.
|
||||
|
||||

|
||||
|
||||
Add user permissions.
|
||||
|
||||

|
||||
|
||||
Generate the API token.
|
||||
|
||||

|
||||
|
||||
Generate the Jenkins crumb from the CLI.
|
||||
|
||||
```bash
|
||||
$ curl -u "buildbot:pwd" 'http://localhost:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)'
|
||||
Jenkins-Crumb:890d0b4c9c1b111deb55b196813a0ae1
|
||||
$ export JENKINS_CRUMB=Jenkins-Crumb:890d0b4c9c1b111deb55b196813a0ae1
|
||||
$ export JENKINS_API_TOKEN=11e2f3c68399b6bc3a28bc06e002be104d
|
||||
```
|
||||
|
||||
Trigger a build with the `curl` command.
|
||||
|
||||
```bash
|
||||
$ curl -X POST -H "$JENKINS_CRUMB" http://buildbot:$JENKINS_API_TOKEN@localhost:8080/job/gradle-initializr/build
|
||||
```
|
||||
|
||||
Disable the job via the REST API. You will see that the job indicated its status.
|
||||
|
||||
```bash
|
||||
$ curl -X POST -H "$JENKINS_CRUMB" http://buildbot:$JENKINS_API_TOKEN@localhost:8080/job/gradle-initializr/disable
|
||||
```
|
||||
|
||||

|
||||
|
||||
Reenable the job.
|
||||
|
||||
```bash
|
||||
$ curl -X POST -H "$JENKINS_CRUMB" http://buildbot:$JENKINS_API_TOKEN@localhost:8080/job/gradle-initializr/enable
|
||||
```
|
||||
|
||||
Download the Jenkins URL by calling the URL `localhost:8080/jnlpJars/jenkins-cli.jar` from the browser.
|
||||
|
||||
In the terminal, navigate to the directory that contains the Jenkins CLI JAR file. Use the Jenkins CLI to trigger a build with the correct command. This simply provide the password instead of the API token.
|
||||
|
||||
```bash
|
||||
$ java -jar jenkins-cli.jar -s http://localhost:8080 -auth buildbot:pwd build gradle-initializr
|
||||
```
|
||||
35
exercises/10-distributed-builds/Vagrantfile
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# All Vagrant configuration is done below. The "2" in Vagrant.configure
|
||||
# configures the configuration version (we support older styles for
|
||||
# backwards compatibility). Please don't change it unless you know what
|
||||
# you're doing.
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "ubuntu/trusty64"
|
||||
|
||||
(1..2).each do |number|
|
||||
config.vm.define "jenkins-agent-#{number}" do |node|
|
||||
node.vm.network "forwarded_port", guest: 22, host: "909#{number}"
|
||||
node.vm.network "private_network", ip: "192.168.99.20#{number}"
|
||||
node.vm.hostname = "jenkins-agent-#{number}"
|
||||
end
|
||||
end
|
||||
|
||||
config.vm.provider "virtualbox" do |vb|
|
||||
vb.memory = "2048"
|
||||
end
|
||||
|
||||
config.vm.provision "shell", inline: <<-SHELL
|
||||
sudo add-apt-repository ppa:openjdk-r/ppa -y
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install openjdk-8-jdk
|
||||
sudo update-alternatives --config java
|
||||
sudo apt-get -y install git
|
||||
sudo useradd -m jenkins
|
||||
echo "jenkins:jenkins" | sudo chpasswd
|
||||
sudo keytool -importkeystore -srckeystore /etc/ssl/certs/java/cacerts -destkeystore /etc/ssl/certs/java/cacerts.jks -deststoretype JKS -srcstorepass changeit -deststorepass changeit -noprompt
|
||||
sudo mv /etc/ssl/certs/java/cacerts.jks /etc/ssl/certs/java/cacerts
|
||||
sudo /var/lib/dpkg/info/ca-certificates-java.postinst configure
|
||||
SHELL
|
||||
end
|
||||
17
exercises/10-distributed-builds/instructions.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Exercise 10
|
||||
|
||||
You will start a VM using Vagrant as practice environment to set up a distributed build with 2 agents.
|
||||
|
||||
## Configuring and Executing Jobs in a Distributed Build
|
||||
|
||||
1. Go to "Manage Jenkins" > "Manage Nodes". You should see a single `master` node.
|
||||
2. Configure the `master` node by setting the # of executor value to 0. That will take care of never using the `master` for job workload.
|
||||
3. Have other physical or virtual machines ready that can act as agent nodes. Log into the machine as `root` user and create a new user named `jenkins` with the commands `useradd -d /var/lib/jenkins jenkins` and `passwd jenkins`. From the `master` node, copy the contents of the `id_rsa.key` file to the clipboard. Paste the contents of the clipboard to the file `/var/lib/jenkins/.ssh/authorized_keys`.
|
||||
4. Add new nodes by clicking "New Nodes". Enter an appropriate name and select the option "Permanent Agent". Use the remote directory `/home/jenkins/jenkins_slave` and set the # of executors to 2. Enter the host and provide credentials by selecting "SSH Username with private key". To keep things easy select "Non verifying Verification Strategy".
|
||||
4. Trigger a build. You should see that the build is only executed on the agent and not the `master` node.
|
||||
5. Add at least one more agent.
|
||||
6. Trigger a build. You should see that the build can be executed on any of the agents.
|
||||
7. Configure one of the agents to only build jobs with a specific label e.g. `java`. Change the "Usage" field to "Only build jobs with label expressions matching this node".
|
||||
8. Configure the `gradle-initializr` job and assign the label `java`.
|
||||
9. Trigger a build of the `gradle-initializr` job. It is only executed by the dedicated agent.
|
||||
10. Trigger other jobs that do not have the label `java` assigned to them. They are waiting for an agent that can execute the build.
|
||||
BIN
exercises/10-distributed-builds/solution/images/agent-config.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1006 KiB |
|
After Width: | Height: | Size: 976 KiB |
|
After Width: | Height: | Size: 941 KiB |
BIN
exercises/10-distributed-builds/solution/images/queued-job.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
29
exercises/10-distributed-builds/solution/solution.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Solution
|
||||
|
||||
Configure the `master` node.
|
||||
|
||||

|
||||
|
||||
Add a new agent node.
|
||||
|
||||

|
||||
|
||||
You will see that the `master` node isn't even listed anymore in the executor overview.
|
||||
|
||||

|
||||
|
||||
Reconfigure the agent node to only build jobs with a specific label.
|
||||
|
||||

|
||||
|
||||
Reconfigure the job to only use agents that can handle a specific label.
|
||||
|
||||

|
||||
|
||||
A build of the job is now only handled by an agent with the assigned label.
|
||||
|
||||

|
||||
|
||||
Other jobs sit in a queue waiting for an agent that can handle the execution criteria.
|
||||
|
||||

|
||||
14
exercises/11-pipeline-job/instructions.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Exercise 11
|
||||
|
||||
In this exercise, you will set up a new multi-branch pipeline job and point it to an existing repository on GitHub. You will visualize the pipeline with the standard view and the Blue Ocean plugin.
|
||||
|
||||
## Creating a Pipeline Job
|
||||
|
||||
1. Have a look at the [repository](https://github.com/bmuschko/todo-spring-boot) `bmuschko/todo-spring-boot` on GitHub. The repository already contains the build definition in the form of a `Jenkinsfile`. Identify each of the steps.
|
||||
2. In Jenkins, set up the credentials `SONARCLOUD_TOKEN` and `HEROKU_API_KEY` if they don't exist yet.
|
||||
3. Create a new multi-branch pipeline job for the repository.
|
||||
4. The initial build is triggered automatically. Have a look at the pipeline in the standard view and its console output.
|
||||
5. Install the Blue Ocean plugin.
|
||||
6. Open the Blue Ocean pipeline visualization for the job. Manually trigger the deployment step. Open a browser with the deployed application on Heroku.
|
||||
7. Create a new branch named `bugfix` and push it to the remote repository. The code should be based off of `master`.
|
||||
8. Select "Scan Multibranch Pipeline Now". The job should build the new branch.
|
||||
|
After Width: | Height: | Size: 850 KiB |
BIN
exercises/11-pipeline-job/solution/images/blue-ocean-plugin.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
exercises/11-pipeline-job/solution/images/bugfix-branch.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1016 KiB |
BIN
exercises/11-pipeline-job/solution/images/credentials.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
exercises/11-pipeline-job/solution/images/finished-build.png
Normal file
|
After Width: | Height: | Size: 855 KiB |
BIN
exercises/11-pipeline-job/solution/images/job-only-master.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
exercises/11-pipeline-job/solution/images/job-scm.png
Normal file
|
After Width: | Height: | Size: 997 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
BIN
exercises/11-pipeline-job/solution/images/standard-pipeline.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 854 KiB |
97
exercises/11-pipeline-job/solution/solution.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Solution
|
||||
|
||||
The created credentials required for the job.
|
||||
|
||||

|
||||
|
||||
Create a new item from the dashboard.
|
||||
|
||||

|
||||
|
||||
Point the job to the SCM.
|
||||
|
||||

|
||||
|
||||
Upon pressing the OK button, the job will scan all available branches in the repository.
|
||||
|
||||
```bash
|
||||
Started
|
||||
[Thu Jul 18 09:23:53 MDT 2019] Starting branch indexing...
|
||||
> git --version # timeout=10
|
||||
> git ls-remote --symref git@github.com:bmuschko/todo-spring-boot.git # timeout=10
|
||||
Creating git repository in /Users/bmuschko/.jenkins/caches/git-a68a5e08a54549aaef01872e9adb6218
|
||||
> git init /Users/bmuschko/.jenkins/caches/git-a68a5e08a54549aaef01872e9adb6218 # timeout=10
|
||||
Setting origin to git@github.com:bmuschko/todo-spring-boot.git
|
||||
> git config remote.origin.url git@github.com:bmuschko/todo-spring-boot.git # timeout=10
|
||||
Fetching & pruning origin...
|
||||
Listing remote references...
|
||||
> git config --get remote.origin.url # timeout=10
|
||||
> git --version # timeout=10
|
||||
> git ls-remote -h git@github.com:bmuschko/todo-spring-boot.git # timeout=10
|
||||
Fetching upstream changes from origin
|
||||
> git config --get remote.origin.url # timeout=10
|
||||
> git fetch --tags --force --progress origin +refs/heads/*:refs/remotes/origin/* --prune
|
||||
Checking branches...
|
||||
Checking branch master
|
||||
‘Jenkinsfile’ found
|
||||
Met criteria
|
||||
Scheduled build for branch: master
|
||||
Processed 1 branches
|
||||
[Thu Jul 18 09:23:57 MDT 2019] Finished branch indexing. Indexing took 4 sec
|
||||
Finished: SUCCESS
|
||||
```
|
||||
|
||||
You can see the different stages of the pipeline in the standard view.
|
||||
|
||||

|
||||
|
||||
You can see the different stages of the pipeline in the standard view.
|
||||
|
||||

|
||||
|
||||
To console output allows for triggering or aborting the manual deployment step.
|
||||
|
||||

|
||||
|
||||
Install the Blue Ocean plugin.
|
||||
|
||||

|
||||
|
||||
The Blue Ocean pipeline view offers a UI element for triggering a manual step.
|
||||
|
||||

|
||||
|
||||
Press the button for processing with the manual step.
|
||||
|
||||

|
||||
|
||||
The finished pipeline in Blue Ocean.
|
||||
|
||||

|
||||
|
||||
Check out the repository and push a new branch.
|
||||
|
||||
```bash
|
||||
$ git clone git@github.com:bmuschko/todo-spring-boot.git
|
||||
Cloning into 'todo-spring-boot'...
|
||||
remote: Enumerating objects: 230, done.
|
||||
remote: Total 230 (delta 0), reused 0 (delta 0), pack-reused 230
|
||||
Receiving objects: 100% (230/230), 108.69 KiB | 452.00 KiB/s, done.
|
||||
Resolving deltas: 100% (105/105), done.
|
||||
$ cd todo-spring-boot
|
||||
$ git branch bugfix
|
||||
$ git checkout bugfix
|
||||
Switched to branch 'bugfix'
|
||||
$ git push origin bugfix
|
||||
Total 0 (delta 0), reused 0 (delta 0)
|
||||
remote:
|
||||
remote: Create a pull request for 'bugfix' on GitHub by visiting:
|
||||
remote: https://github.com/bmuschko/todo-spring-boot/pull/new/bugfix
|
||||
remote:
|
||||
To github.com:bmuschko/todo-spring-boot.git
|
||||
* [new branch] bugfix -> bugfix
|
||||
```
|
||||
|
||||
After scanning the repository, the new branch will be available and was triggered to build automatically.
|
||||
|
||||

|
||||
17
exercises/12-basic-jenkinsfile/instructions.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Exercise 12
|
||||
|
||||
In this exercise, you'll create a declarative pipeline for a Go-based project. The `Jenkinsfile` will use some of the basic features of the pipeline DSL.
|
||||
|
||||
## Writing a Basic Jenkinsfile
|
||||
|
||||
1. Create a new GitHub repository named `go-on-jenkins`.
|
||||
2. Create a new `Jenkinsfile` in the root directory of the repository as well as a simple `main.go` file. The main function just prints "Hello World!". Initialize the project via Go Modules.
|
||||
3. Commit the files and push them to the remote repository.
|
||||
4. Set up a new pipeline job for this repository in Jenkins.
|
||||
5. Install the [Jenkins Go plugin](https://plugins.jenkins.io/golang).
|
||||
6. Configure the latest Go runtime as global tool.
|
||||
7. Enhance the `Jenkinsfile` based on the following requirements. The Jenkinsfile should use the declarative syntax.
|
||||
* The job can run on all agents.
|
||||
* The job sets the environment variable `GO111MODULES=on`.
|
||||
* The job uses the Go runtime from the global tool definition.
|
||||
* The job specifies one build stage named "Build". The build stage executes the shell command `go build`.
|
||||
|
After Width: | Height: | Size: 906 KiB |
|
After Width: | Height: | Size: 706 KiB |
BIN
exercises/12-basic-jenkinsfile/solution/images/go-plugin.png
Normal file
|
After Width: | Height: | Size: 864 KiB |
BIN
exercises/12-basic-jenkinsfile/solution/images/job-scm.png
Normal file
|
After Width: | Height: | Size: 760 KiB |
BIN
exercises/12-basic-jenkinsfile/solution/images/new-job.png
Normal file
|
After Width: | Height: | Size: 902 KiB |
54
exercises/12-basic-jenkinsfile/solution/solution.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Solution
|
||||
|
||||
Create a new job.
|
||||
|
||||

|
||||
|
||||
Configure the appropriate SCM.
|
||||
|
||||

|
||||
|
||||
Install the Go plugin.
|
||||
|
||||

|
||||
|
||||
Configure a Go runtime as global tool.
|
||||
|
||||

|
||||
|
||||
The `main.go` file could similar to the one below.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("hello world")
|
||||
}
|
||||
```
|
||||
|
||||
The final `Jenkinsfile` looks similar to the solution below.
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
tools {
|
||||
go 'go-1.12'
|
||||
}
|
||||
environment {
|
||||
GO111MODULE = 'on'
|
||||
}
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'go build'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A build of the job installs the Go runtime and executes the build step.
|
||||
|
||||

|
||||
20
exercises/13-advanced-jenkinsfile/instructions.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Exercise 13
|
||||
|
||||
We'll want to enhance the pipeline by additional stages and implement a release workflow. The project is going to use an external tool called [GoReleaser](https://goreleaser.com/) to publish cross-compiled artifacts to [GitHub Releases](https://help.github.com/en/github/administering-a-repository/creating-releases). The binaries should only be released if the commit has been tagged.
|
||||
|
||||
## Enhancing a Pipeline With Advanced Features
|
||||
|
||||
1. Add stage named `Test` that executes the Go `test` command.
|
||||
* Add a build step that runs the shell command `go test ./...`.
|
||||
* Generate code coverage metrics by adding the option `-coverprofile=coverage.txt` to the build step.
|
||||
* Publish the code coverage metrics to CodeCov by sending a curl command `curl -s https://codecov.io/bash | bash -s -`.
|
||||
* Log into [CodeCov](https://codecov.io/), determine the CodeCov token for the repository (aka Repository Upload Token) and set it up as credential in Jenkins.
|
||||
* Retrieve the credential and set the value as environment variable named `CODECOV_TOKEN`.
|
||||
2. Add a stage named `Code Analysis` that uses [golangci-lint](https://github.com/golangci/golangci-lint) to detect issues with the code.
|
||||
* Add a build step for installing the `golangci-lint` with the shell command `curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.17.1`
|
||||
* Add a build step that runs `golangci-lint` with the shell command `golangci-lint run`.
|
||||
3. Add a stage named `Release` that uses [GoReleaser](https://github.com/goreleaser/goreleaser).
|
||||
* Only build this step if the commit has been tagged.
|
||||
* Set up a credential in Jenkins named `github_token` and set your GitHub token.
|
||||
* Retrieve the credential and set the value as environment variable named `GITHUB_TOKEN`.
|
||||
* Add a build step that runs the shell command `curl -sL https://git.io/goreleaser | bash`.
|
||||