diff --git a/.gitmodules b/.gitmodules index 0fa64a75d..973ac19eb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "labs/base/themes/hugo-theme-learn"] path = labs/base/themes/hugo-theme-learn url = https://github.com/matcornic/hugo-theme-learn.git +[submodule "labs/cloudbees-ci-pipeline/themes/hugo-theme-learn"] + path = labs/cloudbees-ci-pipeline/themes/hugo-theme-learn + url = https://github.com/matcornic/hugo-theme-learn/tree/3efb32712c5cc77e644852d13ce3525780374b10 diff --git a/labs/base/content/_index.md b/labs/base/content/_index.md index 9500c31b4..ad5902f28 100644 --- a/labs/base/content/_index.md +++ b/labs/base/content/_index.md @@ -7,4 +7,5 @@ weight: 1 # CloudBees Field Workshops [CloudBees CI Workshop](/cloubees-ci/) +[CloudBees CI Pipeline Workshop](/cloubees-ci-pipeline/) [CloudBees Feature Flags Workshop](/cloubees-feature-flags/) \ No newline at end of file diff --git a/labs/cloudbees-ci-pipeline/config.toml b/labs/cloudbees-ci-pipeline/config.toml new file mode 100644 index 000000000..48acec41b --- /dev/null +++ b/labs/cloudbees-ci-pipeline/config.toml @@ -0,0 +1,25 @@ +baseURL = "" +languageCode = "en-US" +defaultContentLanguage = "en" + +title = "CloudBees CI Pipeline Workshop" +theme = "hugo-theme-learn" +metaDataFormat = "yaml" + +[outputs] +home = [ "HTML", "RSS", "JSON"] + +[params] + # Change default color scheme with a variant one. Can be "red", "blue", "green". + themeVariant = "cloudbees" + editURL = "https://github.com/cloudbees-days/cloudbees-field-workshops/edit/main/labs/cloudbees-ci-pipeline/content/" + # Shows a checkmark for visited pages on the menu + showVisitedLinks = true + # Set this to true to disable copy-to-clipboard button for inline code. + disableInlineCopyToClipBoard = true + disableLandingPageButton = true + +[markup] + [markup.goldmark] + [markup.goldmark.renderer] + unsafe = true \ No newline at end of file diff --git a/labs/cloudbees-ci-pipeline/content/_index.md b/labs/cloudbees-ci-pipeline/content/_index.md new file mode 100644 index 000000000..26f6207cc --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/_index.md @@ -0,0 +1,18 @@ +--- +title: "CloudBees CI Pipeline Workshop" +chapter: true +weight: 1 +--- + +# CloudBees CI Pipeline Workshop + +This workshop will provide a basic understanding of how to create and manage Jenkins CI/CD Declarative Pipelines leveraging developer focused features of CloudBees CI. + +This repository contains instructions and learning materials for the workshop that is designed to teach the following key concepts: + + * How specific features of CloudBees CI on Kubernetes will accelerate your continuous delivery? + * Why you should *mostly* use [Declarative](https://jenkins.io/doc/book/pipeline/syntax/#declarative-pipeline) vs [Scripted](https://jenkins.io/doc/book/pipeline/syntax/#scripted-pipeline) pipelines? + * How reusable templates for Jenkins Declarative Pipelines can increase developer productivity? + * What are the key features of Declarative Pipelines? + +#### CloudBees CI Pipeline Workshop Slides diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/_index.md b/labs/cloudbees-ci-pipeline/content/getting-started/_index.md new file mode 100644 index 000000000..f0cb9944d --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/getting-started/_index.md @@ -0,0 +1,9 @@ +--- +title: "Getting Started" +chapter: true +weight: 1 +--- + +# Getting Started + +In order to complete the labs in this workshop you will need to have a personal GitHub Organization with the [CloudBees CI Pipeline Workshop GitHub App](https://github.com/apps/cloudbees-ci-pipeline-workshop) installed on it. Also, by completing the GitHub components of the workshop setup before the workshop we will be able to focus on the content covered in this workshop. \ No newline at end of file diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login.md b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login.md new file mode 100644 index 000000000..b91ec169e --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login.md @@ -0,0 +1,23 @@ +--- +title: "CloudBees CI Login" +chapter: false +weight: 3 +--- + +CloudBees CI for modern platforms takes advantage of Kubernetes to providing dynamic provisioning of team specific Jenkins instances we refer to as ***managed controllers***. In this lab you will provision a CloudBees ***managed controller*** (Jenkins instance) with an initial configuration provided by CloudBees CI Configuration-as-Code. + +>NOTE: If you haven't already received the link for the CloudBees CI Workshop cluster, then ask your instructor for it. + +## CloudBees CI Managed Controller + +### Login to CloudBees CI + +1. Login into the CloudBees CI Workshop cluster at: [https://cbci.workshop.cb-sa.io/cjoc/login](https://cbci.workshop.cb-sa.io/cjoc/login) +2. Enter the username and password, provided by your instructor, into the login screen and click the **Sign in** button. ![CloudBees CI Login](setup-login.png?width=40pc) +3. Click on the link of your CloudBees CI ***managed controller*** that will have the same name (lowercased) as the GitHub Organization you are using for this workshop. ![managed controller link](managed-controller-link.png?width=70pc) +4. NOTE: Depending on when you completed the pre-workshop setup your ***managed controller*** may still be **Starting** as seen below. ![managed controller starting](starting.png?width=60pc) +If that is the case you will have to wait until it is **Approved** and **Connected** as seen in the following screenshot. Once the **Status** is **Approved** and **Connected** click on the link for your managed controller. ![managed controller connnected](mc-connected.png?width=60pc) + +>NOTE: There are a number of ways to create a ***managed controller***. We take a very opinionated way to provision attendees ***managed controllers*** for this workshop in order to pre-configure the components that you will interact with during the workshop, allowing us to jump into the hands on content more quickly. + +**For instructor led workshops please return to the workshop slides** diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/create-team-form.png b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/create-team-form.png new file mode 100644 index 000000000..2b0855b79 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/create-team-form.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/create-team-link.png b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/create-team-link.png new file mode 100644 index 000000000..0096bba8e Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/create-team-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/github-org-caps.png b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/github-org-caps.png new file mode 100644 index 000000000..90a3d078e Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/github-org-caps.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/managed-controller-link.png b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/managed-controller-link.png new file mode 100644 index 000000000..784a8eda8 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/managed-controller-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/mc-connected.png b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/mc-connected.png new file mode 100644 index 000000000..be9d87133 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/mc-connected.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/registration-form.png b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/registration-form.png new file mode 100644 index 000000000..ca7164735 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/registration-form.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/setup-login.png b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/setup-login.png new file mode 100644 index 000000000..518631c6f Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/setup-login.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/starting.png b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/starting.png new file mode 100644 index 000000000..2eff88401 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/cloudbees-ci-login/starting.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup.md b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup.md new file mode 100644 index 000000000..9938b0dc8 --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup.md @@ -0,0 +1,45 @@ +--- +title: "Pre-Workshop Setup" +chapter: false +weight: 2 +--- +#### The pre-workshop setup should take you approximately 10 minutes to complete. + +If you are attending a CloudBees led workshop then these setup steps should be completed before the start of the workshop event. + +## GitHub Setup + +### Create a GitHub.com Account + +Feel free to use an existing GitHub.com account or create a new one: +1. In a new browser tab or window, visit [https://github.com/join](https://github.com/join) and fill in the required fields to create a GitHub.com user account. +2. Select "Unlimited public repositories for free" when choosing your plan. +3. Verify your email account to ensure you account is activated. An activated account will be **required** for the rest of this workshop. + +### Create a GitHub Organization + +We highly recommend creating a new GitHub Organization for the CloudBees CI Pipeline Workshop. We will be using a GitHub App based credential to enable authentication and authorization between your GitHub.com Organization for the workshop and CloudBees CI. +1. Ensure that you are logged into GitHub.com and then navigate to this [link to create a new (and free) GitHub Organization](https://github.com/account/organizations/new?coupon=&plan=team_free). +2. Enter a unique ***Organization account name***, a valid ***Contact email***, select **My personal account** for ***This organization belongs to*** and then click on the **Next** button.
![GitHub Org Set up](github-org-set-up.png?width=40pc) +3. On the **Welcome to GitHub** screen just click the **Complete setup** button.
![GitHub Org Set up](github-org-welcome.png?width=50pc) +4. On the final page you don't have to fill anything in/answer any questions (unless your really want to) and just scroll to the bottom of the page and click the **Submit** button. + +>NOTE: Even though you have to provide an email for billing, **you will NOT be charged anything** as long as you choose the free option. + +### Install the CloudBees CI Pipeline Workshop GitHub App + +1. Ensure that you are logged into GitHub.com and then navigate to [https://github.com/apps/cloudbees-ci-pipeline-workshop](https://github.com/apps/cloudbees-ci-pipeline-workshop).
![GitHub App](cbci-pipeline-github-app.png?width=60pc) +2. Click on the **Install** button. +3. Next, select the GitHub Organization you created above for the CloudBees CI Pipeline Workshop.
![GitHub App](github-app-select-org.png?width=50pc) +4. On the next screen, select **All repositories** and click the **Install** button.
![GitHub App](github-app-install.png?width=50pc) +5. You may be prompted for your GitHub password. Enter your GitHub.com password, for the GitHub account you are using for this workshop, to complete the installation of the CloudBees CI Workshop GitHub App into your workshop specific GitHub Organization. +6. The CloudBees CI Pipeline Workshop GitHub App is now installed on your workshop GitHub Organization.
![GitHub App Installed](installed-now.png?width=50pc) +7. A few minutes after you install the CloudBees CI Workshop GitHub App you should see the following repositories created in your workshop GitHub Organization. + - https://github.com/cloudbees-days/cloudbees-ci-config-bundle + - https://github.com/cloudbees-days/pipeline-library + - https://github.com/cloudbees-days/pipeline-template-catalog + - https://github.com/cloudbees-days/node-js ![GitHub App Installed](forked-repos.png?width=50pc) + +>NOTE: These repositories were created from GitHub template repositories in the [CloudBees Field Workshops GitHub Organization](https://github.com/cloudbees-days). + +**For instructor led workshops please return to the workshop slides** diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/cbci-pipeline-github-app.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/cbci-pipeline-github-app.png new file mode 100644 index 000000000..3783f308d Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/cbci-pipeline-github-app.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/forked-repos.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/forked-repos.png new file mode 100644 index 000000000..194d5efdf Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/forked-repos.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-app-install.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-app-install.png new file mode 100644 index 000000000..30b2ec6ab Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-app-install.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-app-select-org.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-app-select-org.png new file mode 100644 index 000000000..686fea57a Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-app-select-org.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-org-free.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-org-free.png new file mode 100644 index 000000000..b02b3f0ab Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-org-free.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-org-set-up.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-org-set-up.png new file mode 100644 index 000000000..f2be0ccdf Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-org-set-up.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-org-welcome.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-org-welcome.png new file mode 100644 index 000000000..c2dc6d062 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/github-org-welcome.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/installed-now.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/installed-now.png new file mode 100644 index 000000000..bb374cd7a Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/installed-now.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/setup-create-account-success.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/setup-create-account-success.png new file mode 100644 index 000000000..264e01a3e Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/setup-create-account-success.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/setup-github-new-org.png b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/setup-github-new-org.png new file mode 100644 index 000000000..12d46ae6b Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/getting-started/pre-workshop-setup/setup-github-new-org.png differ diff --git a/labs/cloudbees-ci-pipeline/content/getting-started/prerequisites.md b/labs/cloudbees-ci-pipeline/content/getting-started/prerequisites.md new file mode 100644 index 000000000..1f908e76d --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/getting-started/prerequisites.md @@ -0,0 +1,14 @@ +--- +title: "Prerequisites" +chapter: false +weight: 1 +--- + +* Internet access to include access to [https://github.com](https://github.com) and to include the ability to access and use the [GitHub File Editor](https://help.github.com/articles/editing-files-in-your-repository). + * Access to https://app.slack.com +* An account on [https://github.com](https://github.com) and a basic understanding of how to use GitHub to edit files in the web UI, and create and work with pull requests. If you are new to GitHub or just new to using GitHub pull requests then you should review [this GitHub documentation](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests) before the workshop. +* A basic understanding of [Jenkins Pipelines](https://jenkins.io/doc/book/pipeline/getting-started/) +* A basic understanding of [Kubernetes](https://kubernetes.io/docs/tutorials/kubernetes-basics/) + * Understand the concept of a [Kubernetes Pod](https://kubernetes.io/docs/concepts/workloads/pods/) and how it is different than a Docker container +* Finally, we highly recommend using the Google Chrome browser to work through the lab content. + diff --git a/labs/cloudbees-ci-pipeline/content/labs/_index.md b/labs/cloudbees-ci-pipeline/content/labs/_index.md new file mode 100644 index 000000000..6de428c38 --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/_index.md @@ -0,0 +1,21 @@ +--- +title: "Labs" +chapter: true +weight: 1 +--- + +# Labs + +This workshop will provide a basic understanding of how to create and manage Jenkins CI/CD Declarative Pipelines while leveraging some of the developer focused features of CloudBees CI. + +The labs covered in this workshop are: + +1. Introduction to Declarative Pipelines with CloudBees CI +2. Stage Specific Agents +3. Custom Pipeline Pod Templates +4. Conditional Execution Using the `when` Directive +5. Environment Variables and Credentials +6. CloudBees Cross Team Collaboration +7. Pipelines with Interactive Input +8. CloudBees Pipeline Template Catalogs + diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates.md b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates.md new file mode 100644 index 000000000..c12babebe --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates.md @@ -0,0 +1,41 @@ +--- +title: "CloudBees Pipeline Template Catalogs" +chapter: false +weight: 8 +--- + +Pipeline Template Catalogs provide version controlled parameterized templates for Multi-branch and stand-alone Pipeline jobs. In this exercise we will use [Pipeline Template Catalogs](https://github.com/cloudbees-days/pipeline-template-catalog/tree/master/templates/nodejs-app) to create a templatized Multibranch Pipeline project of your workshop copy of the **helloworld-nodejs** repository. All you will need to do is fill in a few simple parameters and you will end up with a complete end-to-end CI/CD Pipeline for the **helloworld-nodejs** application - and it won't be using the `Jenkinsfile` from your repository. + +## Create a Multibranch Project from a Pipeline Template Catalog +[Jenkins Configurations as Code](https://wiki.jenkins.io/display/JENKINS/Configuration+as+Code+Plugin) (JCasC) was used to pre-configure a Pipeline Template Catalog on everyone's Managed Controller and there is a **template-jobs** folder on your Managed Controller that has been configured with [CloudBees Folders Plus folder item filtering](https://go.cloudbees.com/docs/plugins/folders-plus/#folders-plus-sect-restrict) to only allow the creation of certain job types. Now we will create a templatized end-to-end CI/CD Pipeline Multibranch project for your copy of the **helloworld-nodejs** repository. + +1. On your CloudBees CI Managed Controller navigate to the **template-jobs** folder and then lick on the ***New Node.js App Multibranch Pipeline*** link in the left menu. ![Create Job from Template](create-template-job-link.png?width=50pc) +2. Enter an item name of your **[GitHub username]-hello**, select **Node.js App Multibranch Pipeline** and click the **OK** button. ![New Item Form](new-item-form.png?width=50pc) +3. Fill out the template parameters: + 1. **Repository Owner**: the GitHub Organization your created for the CloudBees CI Pipeline Workshop. + 2. Use the default values for the rest of the parameters. + 3. Click the **Save** button. ![Template Parameters](template-parameters.png?width=50pc) +4. The initial scan won't find any branches because you have to add the [custom markerfile](https://go.cloudbees.com/docs/cloudbees-core/cloud-admin-guide/pipeline/#_multibranch_pipeline_options_in_template_yaml) `.nodejs-app` to any branch that you want a job to be created. The [template we are using has a markerFile parameter set to .nodejs-app](https://github.com/cloudbees-days/pipeline-template-catalog/blob/master/templates/nodejs-app/template.yaml#L29), so we need to add that file to at least one branch of your copy of the **helloworld-nodejs** repository. +5. Make sure you are on the **development** branch and click on the **Create new file** button towards the top right of the screen. +6. Name the file `.nodejs-app` and commit the empty file to your **development** branch. +7. You may need to refresh the Multibranch job screen, but you should eventually have **one** job - for the **development** branch. ![One Job](one-job.png?width=50pc) + +## Web Browser Tests with Testcafe + +Executing [Testcafe](http://devexpress.github.io/testcafe/) driven browser tests for the **helloworld-nodejs** app in our Pipeline. + +1. After you add the custom marker file, your **development** branch job will run and it will fail. On the job details screen for the failed run we can see that there was a test failure. Click on the **Test Result** link to see the specific test error. ![Job Details Failed Test](job-details-failed-test.png?width=50pc) +2. On the **Test Result** page, expand the **Initial page.Check message header** test and then expand the **Stack Trace** and you will see that there is a slight typo in the **helloworld-nodejs** app. ![Test Results Failure](test-results-failure.png?width=50pc) +3. In GitHub, open editor for the `hello.js` file on the **development** branch of your forked copy of the **helloworld-nodejs** repository, fix the misspelling of **Worlld** to **World** and then commit the changes. ![Fix Error](fix-error.png?width=50pc) +4. Navigate to the **development** branch of your **helloworld-nodejs** job on your Managed Controller and your job should already be running as a GitHub webhook triggered it when you committed the changes for the `hello.js` file in the **helloworld-nodejs** repository. The tests should pass and the job should complete successfully. ![Test Passed](test-passed.png?width=50pc) + +## Deploy to Staging +Now that you have fixed the small bug in the **helloworld-nodejs** application, we will create a Pull Request and merge the change to the **main** branch of your copy of the **helloworld-nodejs** repository. + +1. Navigate to your copy of the **helloworld-nodejs** repository in GitHub - click on the **New pull request** button. ![Test Passed](new-pull-request.png?width=50pc) +2. On the next screen add a comment and then click the **Create pull request** button. +3. A job will be created for the pull request and once it has completed successfully your pull request will show that **All checks have passed**. Go ahead and click the **Merge pull request** button and then click the **Confirm merge** button but **DO NOT DELETE** the **development** branch. ![Merge PR](merge-pr.png?width=50pc) +4. Navigate to the **helloworld-nodejs** Pipeline Template Catalog job on your Managed Controller and the job for the **main** branch should be running or queued to run. +5. The templated job will build a Docker image for your **helloworld-nodejs** application, push the image to the Google Container Registry (GCR), and then deploy your containerized application to a staging environment in Kubernetes - a link to your application will be available in the logs of your job. All of this after only filling in a few parameters to create the job in CloudBees CI. + + diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/create-template-job-link.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/create-template-job-link.png new file mode 100644 index 000000000..aa7552a43 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/create-template-job-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/fix-error.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/fix-error.png new file mode 100644 index 000000000..fd88d61a6 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/fix-error.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/job-details-failed-test.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/job-details-failed-test.png new file mode 100644 index 000000000..063520e1c Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/job-details-failed-test.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/merge-pr.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/merge-pr.png new file mode 100644 index 000000000..6c457d313 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/merge-pr.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/new-item-form.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/new-item-form.png new file mode 100644 index 000000000..4be57f381 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/new-item-form.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/new-pull-request.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/new-pull-request.png new file mode 100644 index 000000000..3de99d613 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/new-pull-request.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/one-job.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/one-job.png new file mode 100644 index 000000000..1421a4139 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/one-job.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/template-parameters.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/template-parameters.png new file mode 100644 index 000000000..f2afbe606 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/template-parameters.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/test-passed.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/test-passed.png new file mode 100644 index 000000000..d194e5eee Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/test-passed.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/test-results-failure.png b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/test-results-failure.png new file mode 100644 index 000000000..47faaea6c Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/catalog-templates/test-results-failure.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/conditional-when.md b/labs/cloudbees-ci-pipeline/content/labs/conditional-when.md new file mode 100644 index 000000000..f0d4d8f1a --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/conditional-when.md @@ -0,0 +1,150 @@ +--- +title: "Conditional Execution Using the when Directive" +chapter: false +weight: 4 +--- + +## Conditional Stages Using the When Directive + +In this lab we will edit the `Jenkinsfile` file in your **helloworld-nodejs** repository with conditional execution using the [when directive](https://jenkins.io/doc/book/pipeline/syntax/#when). We will accomplish this by adding a branch specific `stage` to the `Jenkinsfile` in your **helloworld-nodejs** repository. + +1. Navigate to and open the GitHub editor for the `Jenkinsfile` file in the **development** branch of your **helloworld-nodejs** repository. +2. Insert the ***Build and Push Image*** stage after the existing **Test** stage. +``` + stage('Build and Push Image') { + when { + beforeAgent true + branch 'main' + } + steps { + echo "TODO - build and push image" + } + } +``` + +Note the `beforeAgent true` option - this setting will result in the `when` condition being evaluated before acquiring and using a `stage` specific `agent`. The `branch` condition is a built-in condition that allows executing stages only for specific branches - in this case the ***Build and Push Image*** `stage` will only execute for the **main** branch. The entire Pipeline should match what is below: + + ``` + pipeline { + agent none + stages { + stage('Test') { + agent { label 'nodejs-app' } + steps { + container('nodejs') { + echo 'Hello World!' + sh 'node --version' + } + } + } + stage('Build and Push Image') { + when { + beforeAgent true + branch 'main' + } + steps { + echo "TODO - build and push image" + } + } + } + } + ``` + +3. Commit the changes and then navigate to the **helloworld-nodejs** job on your Managed Controller and the job for the **development** branch should be running or queued to run. Note that the ***Build and Push Image*** `stage` was skipped. ![Conditional Stage Skipped](conditional-skipped-stage.png?width=50pc) +4. Now we will create a [Pull Request](https://help.github.com/en/articles/creating-a-pull-request) between the **development** branch and **main** branch of your **helloworld-nodejs** repository. Navigate to your **helloworld-nodejs** repository in GitHub, make sure you are on the `development` branch and click the **Pull request** link to create a new pull request or PR. ![Create Pull request link](create-pr-link.png?width=50pc) +5. Make sure that the **base repository** is the **main** branch of your **helloworld-nodejs** repository, add a comment and then click the **Create pull request** button. ![Create Pull request](create-pr.png?width=50pc) +6. A job will be created for the pull request and once it has completed successfully your pull request will show that **All checks have passed**. Go ahead and click the **Merge pull request** button and then click the **Confirm merge** button but **DO NOT** delete the **development** branch. ![Merge Pull request](merge-pr.png?width=50pc) +7. Navigate to the **helloworld-nodejs** job on your CloudBees CI Managed Controller and the job for the **main** branch should be running or queued to run. Click on the run and after it has completed notice that the ***Build and Push Image*** stage was not skipped. ![Stage Not Skipped](stage-not-skipped.png?width=50pc) + +## Using the When Directive with Nested Stages + +In this lab we will learn how you can combine nested stages with the when directive so that you don't have repeat a when condition for every stage it applies. We will also update the ***Test*** stage so it will only execute when the condition is false. + +1. Navigate to and open the GitHub editor for the `Jenkinsfile` file in the **main** branch of your **helloworld-nodejs** repository. +2. Replace the entire pipeline with the following: +``` +pipeline { + agent none + stages { + stage('Test') { + when { + beforeAgent true + not { branch 'main' } + } + agent { label 'nodejs-app' } + steps { + container('nodejs') { + echo 'Hello World!' + sh 'node --version' + } + } + } + stage('Main Branch Stages') { + when { + beforeAgent true + branch 'main' + } + stages { + stage('Build and Push Image') { + steps { + echo "TODO - build and push image" + } + } + stage('Deploy') { + steps { + echo "TODO - deploy" + } + } + } + } + } +} +``` + +By wrapping the ***Build and Push Image*** and ***Deploy*** stages in the ***Main Branch Stages*** the `when` directive for the `main` branch only has to be specified once. Also, by using the `not` nesting condition, the ***Test*** stage will only be executed when the branch being processed in **not** the `main` branch. + +3. Commit the changes and then navigate to the **helloworld-nodejs** job on your Managed Controller and the job for the **main** branch should be running or queued to run. Once the run completes you will see that the ***Test*** `stage` was skipped but the **Main Branch Stages** were not. ![Conditional Nested Stage](conditional-nested-stage.png?width=50pc) + +## Next Lesson + +Before moving on to the next lesson make sure that your **Jenkinsfile** Pipeline script on the **main** branch of your copy of the **helloworld-nodejs** repository matches the one from below: + +### Finished Jenkinsfile for *Conditional Execution using the `when` directive* lab +``` +pipeline { + agent none + stages { + stage('Test') { + when { + beforeAgent true + not { branch 'main' } + } + agent { label 'nodejs-app' } + steps { + container('nodejs') { + echo 'Hello World!' + sh 'node --version' + } + } + } + stage('Main Branch Stages') { + when { + beforeAgent true + branch 'main' + } + stages { + stage('Build and Push Image') { + steps { + echo "TODO - build and push image" + } + } + stage('Deploy') { + steps { + echo "TODO - deploy" + } + } + } + } + } +} +``` diff --git a/labs/cloudbees-ci-pipeline/content/labs/conditional-when/conditional-nested-stage.png b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/conditional-nested-stage.png new file mode 100644 index 000000000..9ac0bc5c8 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/conditional-nested-stage.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/conditional-when/conditional-skipped-stage.png b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/conditional-skipped-stage.png new file mode 100644 index 000000000..8b12a5d35 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/conditional-skipped-stage.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/conditional-when/create-pr-link.png b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/create-pr-link.png new file mode 100644 index 000000000..99ae011bb Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/create-pr-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/conditional-when/create-pr.png b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/create-pr.png new file mode 100644 index 000000000..61bffc9a5 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/create-pr.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/conditional-when/merge-pr.png b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/merge-pr.png new file mode 100644 index 000000000..3fb35cc50 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/merge-pr.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/conditional-when/stage-not-skipped.png b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/stage-not-skipped.png new file mode 100644 index 000000000..27b338f2e Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/conditional-when/stage-not-skipped.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration.md b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration.md new file mode 100644 index 000000000..edcd97cd4 --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration.md @@ -0,0 +1,119 @@ +--- +title: "CloudBees Cross Team Collaboration" +chapter: false +weight: 6 +--- + +In this lab we will explore the [CloudBees CI Cross Team Collaboration feature](https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/cross-team-collaboration). Cross Team Collaboration simplifies the cumbersome and complicated tasks of triggering downstream jobs by eliminating the need to identify and maintain the full path for every downstream job. Simply put it, this proprietary feature connects pipelines, increasing automation and collaboration. Prior to this feature, the details of every downstream job (Jenkins instance ID, full job name, Git branch name) all had to be meticulously specified in the upstream job. If the job name changed, the upstream job had to be refactored, creating a maintenance burden and discouraging the adoption of event-based triggers. + +## Cross Team Collaboration Events + +The [Cross Team Collaboration feature](https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/cross-team-collaboration) is designed to greatly improve team collaboration by connecting team Pipelines to deliver software faster. It essentially allows a Pipeline to create a notification event which will be consumed by other Pipelines waiting on it. It consists of a **[Publishing Event](https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/cross-team-collaboration#cross-team-event-publishers)** and a **[Trigger Condition](https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/cross-team-collaboration#cross-team-event-triggers)**. + +The Cross Team Collaboration feature has a configurable router for routing events and it needs to be configured on your Managed Controllers before you will be able to receive the event published by another Managed Controller. Once again, CasC was used to pre-configure this for everyone, but you can still review the configuration by going to the top-level of your Managed Controller and click on the **Manage Jenkins** left menu link and then click on **Configure Notification**. ![Configure Notification Link](config-notification-link.png?width=50pc) + + You should see the following configuration: ![Notification Configuration](notification-config.png?width=50pc) + + +1. To use Cross Team Collaboration we will need to update the **helloworld-nodejs** Jenkinsfile to listen for a notification event to be published by the upstream, or publishing, job. We will do that by adding a `trigger` directive to your **Jenkinsfile** Pipeline script. +2. Open the GitHub editor for the **Jenkinsfile** file in the **main** branch of your copy of the **helloworld-nodejs** repository. +3. Add the following `trigger` block just above the top-level `stages` block: + +```groovy + triggers { + eventTrigger simpleMatch('hello-api-deploy-event') + } +``` + +4. Commit the changes and then navigate to the **main** branch of your **helloworld-nodejs** project on your Managed Controller and view the configuration for that job by click the **View Configuration** link on the **Branch main** job page. ![View Configuration Link](view-config-link.png?width=50pc) +5. Click on the **Build Triggers** tab on the job configuration page for the **main** branch job and you will the **Build whenever the specified event is seen** trigger is checked and configured with a **Simple Event**. ![View Configuration Link](event-trigger-config.png?width=50pc) +>**NOTE:**After first adding a new `trigger` you must run the job at least once so that the `trigger` is saved to the Jenkins job configuration (similar to setting the `buildDiscarder` `option`). +6. Next, your instructor will set up a Pipeline project with the following **[simple event](https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/cross-team-collaboration#cross-team-event-types)**: + +``` +publishEvent simpleEvent('hello-api-deploy-event') +``` + +The entire Jenkins Pipeline containing the publishing event: +``` +pipeline { + agent none + stages { + stage('Build') { + steps { + echo 'build' + } + } + stage('Deploy') { + steps { + echo 'deploy' + publishEvent simpleEvent('hello-api-deploy-event') + } + } + } +} +``` + +That event will be published **across all Managed Controllers in the Workshop cluster** via the CloudBees CI Cloud Operations Center event router triggering everyones' **helloworld-nodejs** Pipelines to run. + +7. Now, once that change is committed, and the **helloworld-api** job runs, everyone will see the **main** branch of their **helloworld-nodejs** job triggered by the `hello-api-deploy-event` simple event. ![View Configuration Link](triggered-by-event.png?width=50pc) + + +## Next Lesson + +Before moving on to the next lesson make sure that your **Jenkinsfile** Pipeline script on the **main** branch of your forked **helloworld-nodejs** repository matches the one from [below](#finished-jenkinsfile-for-pipeline-pod-templates-and-cross-team-collaboration). + +### Finished Jenkinsfile for *Pipeline Pod Templates and Cross Team Collaboration* Lab +``` +pipeline { + agent none + environment { + FAVORITE_COLOR = 'RED' + } + triggers { + eventTrigger simpleMatch('hello-api-deploy-event') + } + stages { + stage('Test') { + when { + beforeAgent true + not { branch 'main' } + } + agent { + kubernetes { + yamlFile 'nodejs-pod.yaml' + } + } + steps { + container('nodejs') { + sh 'node --version' + } + } + } + stage('Main Branch Stages') { + when { + beforeAgent true + branch 'main' + } + stages { + stage('Build and Push Image') { + steps { + echo "FAVORITE_COLOR is $FAVORITE_COLOR" + echo "TODO - build and push image" + } + } + stage('Deploy') { + agent any + environment { + FAVORITE_COLOR = 'BLUE' + SERVICE_CREDS = credentials('example-service-username-password') + } + steps { + sh 'echo TODO - deploy to $FAVORITE_COLOR with SERVICE_CREDS: username=$SERVICE_CREDS_USR password=$SERVICE_CREDS_PSW' + } + } + } + } + } +} +``` diff --git a/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/config-notification-link.png b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/config-notification-link.png new file mode 100644 index 000000000..63e728baa Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/config-notification-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/event-trigger-config.png b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/event-trigger-config.png new file mode 100644 index 000000000..27be70d8d Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/event-trigger-config.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/notification-config.png b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/notification-config.png new file mode 100644 index 000000000..ee33afab7 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/notification-config.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/triggered-by-event.png b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/triggered-by-event.png new file mode 100644 index 000000000..0e0de9a27 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/triggered-by-event.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/view-config-link.png b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/view-config-link.png new file mode 100644 index 000000000..36cbb3dca Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/cross-team-collaboration/view-config-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates.md b/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates.md new file mode 100644 index 000000000..3e5b90a40 --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates.md @@ -0,0 +1,187 @@ +--- +title: "Custom Pipeline Pod Templates" +chapter: false +weight: 3 +--- + +## Kubernetes Pod Templates Defined in Pipeline Script + +In this lab we will create a custom Kubernetes Pod Template containing a NodeJS **container** and an additional Docker **container** for executing tests. We also want to use a different version of the **node** container than the one provided by the **nodejs-app** Kubernetes *Pod Template* [defined for us on our Managed Controller](https://go.cloudbees.com/docs/cloudbees-core/cloud-admin-guide/agents/#_editing_pod_templates_per_team_using_masters). In order to be able to control what `containers` and what container `image` version we use in our Pipeline we will update the **Jenkinsfile** Pipeline script with an inline [Kubernetes Pod Template definition](https://github.com/jenkinsci/kubernetes-plugin#declarative-pipeline). + +1. The [Jenkins Kubernetes plugin](https://github.com/jenkinsci/kubernetes-plugin#using-yaml-to-define-pod-templates) allows you to use standard Kubernetes Pod yaml configuration to define Pod Templates directly in your Pipeline script, either as a string or a file. We will do just that by creating a new `nodejs-pod.yaml` file and then adding a `yamlFile` parameter to the `agent` declaration with a value of the the repository relative path to that yaml file. The file provides the [Pod spec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#pod-v1-core) to be used for the Pod Template based agent. Navigate to your workshop **helloworld-nodejs** repository in your workshop GitHub Organization, make sure you are on the `development` branch, then click the **Add file** button towards the top right of the screen and then select **Create new file**. **IMPORTANT:** Make sure you are on the `development` branch (the ***Test*** stage will not execute for the `main` branch). ![Create Pod Template File](create-pod-template-file.png?width=50pc) +2. Name the file `nodejs-pod.yaml` and add the following content: +``` +kind: Pod +metadata: + name: nodejs-app +spec: + containers: + - name: nodejs + image: node:15.10.0-alpine + command: + - cat + tty: true + - name: testcafe + image: gcr.io/technologists/testcafe:0.0.2 + command: + - cat + tty: true + securityContext: + runAsUser: 1000 +``` +*This is a standard Kubernetes Pod Specification.* + +3. At the bottom of the screen enter a commit message, leave **Commit directly to the `development` branch** selected and click the **Commit new file** button. +4. Now we need to update our Pipeline to use that file. Open the GitHub editor for the **Jenkinsfile** Pipeline script in the **development** branch of your workshop **helloworld-nodejs** repository. ![Update Jenkinsfile](update-jenkinsfile.png?width=50pc) +5. Replace the `agent` section of the **Test** `stage` with the following - note that the value of the `yamlFile` parameter is the name of the pod template file we created: +``` + agent { + kubernetes { + yamlFile 'nodejs-pod.yaml' + } + } +``` +Your complete `development` branch Jenkinsfile should match the following: +``` +pipeline { + agent none + stages { + stage('Test') { + agent { + kubernetes { + yamlFile 'nodejs-pod.yaml' + } + } + steps { + container('nodejs') { + echo 'Hello World!' + sh 'node --version' + } + } + } + } +} +``` + +6. Commit the changes and then navigate to the **development** branch of your **helloworld-nodejs** job on your CloudBees CI Managed Controller. The job will run successfully. Also, note the output of the `sh 'node --version'` step - it is `v15.10.0` instead of `v8.12.0`: ![Update Node Container Tag](pod-template-update-image-tag.png?width=50pc) Also notice that the final Kubernetes pod spec for the agent is printed out in the logs and is merge of a default template (with the **jnlp** container) and the pod spec from your **helloworld-nodejs** repository: +``` +--- +apiVersion: "v1" +kind: "Pod" +metadata: + annotations: + buildUrl: "http://teams-cbci-pipeline.sda.svc.cluster.local/teams-cbci-pipeline/job/cbci-pipeline/job/helloworld-nodejs/job/development/12/" + runUrl: "job/cbci-pipeline/job/helloworld-nodejs/job/development/12/" + labels: + jenkins: "slave" + jenkins/label-digest: "b81583b250d254ab64fbc7b5e5d06a264e17b05f" + jenkins/label: "cbci-pipeline_helloworld-nodejs_development_12-2qpz0" + cloudbees.com/master: "teams-cbci-pipeline" + name: "cbci-pipeline-helloworld-nodejs-development-12-2qpz0-s1rv-f9nc6" +spec: + affinity: + podAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: "com.cloudbees.cje.type" + operator: "In" + values: + - "master" + - "cjoc" + topologyKey: "kubernetes.io/hostname" + weight: 1 + containers: + - command: + - "cat" + image: "gcr.io/technologists/testcafe:0.0.2" + name: "testcafe" + tty: true + volumeMounts: + - mountPath: "/home/jenkins/agent" + name: "workspace-volume" + readOnly: false + workingDir: "/home/jenkins/agent" + - command: + - "cat" + image: "node:15.10.0-alpine" + name: "nodejs" + tty: true + volumeMounts: + - mountPath: "/home/jenkins/agent" + name: "workspace-volume" + readOnly: false + workingDir: "/home/jenkins/agent" + - args: + - "/var/jenkins_config/jenkins-agent" + command: + - "/bin/sh" + env: + - name: "JENKINS_SECRET" + value: "********" + - name: "JENKINS_AGENT_NAME" + value: "cbci-pipeline-helloworld-nodejs-development-12-2qpz0-s1rv-f9nc6" + - name: "JENKINS_WEB_SOCKET" + value: "true" + - name: "JENKINS_NAME" + value: "cbci-pipeline-helloworld-nodejs-development-12-2qpz0-s1rv-f9nc6" + - name: "JENKINS_AGENT_WORKDIR" + value: "/home/jenkins/agent" + - name: "JENKINS_URL" + value: "http://teams-cbci-pipeline.sda.svc.cluster.local/teams-cbci-pipeline/" + image: "gcr.io/core-workshop/k8s-jnlp-agent@sha256:28490f8659bcfdae8159286d6c88fdd7365d6928255103e7500f05dd527bdc8f" + imagePullPolicy: "IfNotPresent" + name: "jnlp" + resources: + limits: {} + requests: {} + tty: false + volumeMounts: + - mountPath: "/var/jenkins_config" + name: "volume-0" + readOnly: false + - mountPath: "/home/jenkins/agent" + name: "workspace-volume" + readOnly: false + workingDir: "/home/jenkins/agent" + hostNetwork: false + nodeSelector: + kubernetes.io/os: "linux" + restartPolicy: "Never" + securityContext: + runAsGroup: 1000 + runAsUser: 1000 + serviceAccount: "jenkins" + volumes: + - configMap: + name: "jenkins-agent" + optional: false + name: "volume-0" + - emptyDir: + medium: "" + name: "workspace-volume" + +``` + +### Finished Jenkinsfile for *Custom Pipeline Pod Templates* Lab +``` +pipeline { + agent none + stages { + stage('Test') { + agent { + kubernetes { + yamlFile 'nodejs-pod.yaml' + } + } + steps { + container('nodejs') { + echo 'Hello World!' + sh 'node --version' + } + } + } + } +} +``` diff --git a/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates/create-pod-template-file.png b/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates/create-pod-template-file.png new file mode 100644 index 000000000..071b6764e Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates/create-pod-template-file.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates/pod-template-update-image-tag.png b/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates/pod-template-update-image-tag.png new file mode 100644 index 000000000..cd70a9f2f Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates/pod-template-update-image-tag.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates/update-jenkinsfile.png b/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates/update-jenkinsfile.png new file mode 100644 index 000000000..4330872fb Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/custom-pipeline-pod-templates/update-jenkinsfile.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics.md b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics.md new file mode 100644 index 000000000..7379419bc --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics.md @@ -0,0 +1,121 @@ +--- +title: "Introduction to Declarative Pipelines with CloudBees CI" +chapter: false +weight: 2 +--- + +In this first lab we will [create a GitHub Org Folder Pipeline project](https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/github-branch-source-plugin) and get an overview of the [basic fundamentals of the Declarative Pipeline syntax](#basic-declarative-syntax-structure). + +## Create a GitHub Organization Folder Pipeline Project + +In this exercise we are going to create a special type of Jenkins Pipeline project referred to as an **[Organization Folder](https://jenkins.io/doc/book/pipeline/multibranch/#organization-folders)** and sometimes more specifically a *GitHub Organization* project (this type of project is also [available for Bitbucket](https://plugins.jenkins.io/cloudbees-bitbucket-branch-source) and there is [unofficial support for GitLab](https://github.com/Argelbargel/gitlab-branch-source-plugin)). The Jenkins *GitHub Organization* project will scan a GitHub Organization to discover the Organization’s repositories, automatically creating **managed** [Multibranch Pipeline jobs](https://jenkins.io/doc/book/pipeline/multibranch/#creating-a-multibranch-pipeline) for any repository with at least one branch containing a *Jenkins Pipeline project recognizer* - typically **Jenkinsfile**. We will use the GitHub Organization that you created in **[Setup - Create a GitHub Organization](/getting-started/pre-workshop-setup/#create-a-github-organization)**. A Jenkins *GitHub Organization* project will also utilize a GitHub Organization level ***webhook it creates*** to automatically manage Jenkins jobs - both individual branch jobs and Multibranch Pipeline jobs associated to repositories - when a branch or a repository is deleted from or added to the GitHub Organization. + +1. Navigate to the top-level of the CloudBees CI Operations Center - **Dashboard** - and click on the link for your ***Managed Controller*** (it will have the same names as your workshop GitHub Organization). ![Managed Controller link](managed-controller-link.png?width=60pc) +2. At the top-level of your CloudBees CI Managed Controller click on **New Item** in the left menu. ![New Item](new-item.png?width=50pc) +3. Enter your GitHub Organization name as the **Item Name** and select **GitHub Organization** as the item type and click the **OK** button. ![New GitHub Organization Folder](github-org-folder-item.png?width=50pc) +4. Select the **CloudBees CI Pipeline Workshop GitHub App** credential from the **Credentials** drop down, make sure that the **Owner** field matches the name of your workshop GitHub Organization and then click the **Save** button ![Configure and Save GitHub Organization Folder](github-org-folder-save.png?width=50pc) +5. After the Organization scan completes, click on the bread-crumb link to go back to your **GitHub Organization** Jenkins Pipeline project folder. When the scan is complete your **GitHub Organization** Jenkins Pipeline project should be **empty**! ![Empty GitHub Organization Folder](empty-github-org-folder.png?width=50pc) +6. CloudBees configuration-as-code was used to create a GitHub Organization webhook for your workshop GitHub Organization. Verify that the webhook was created in Github by checking the **Webhooks** within your GitHub Organization **Settings**. *NOTE: This webhook will be used to automatically create new branch and Pull Request Pipeline jobs, and trigger those jobs on new commits.* ![GitHub Organization Webhook](github-org-webhook.png?width=50pc) +7. The reason why the scan did not find any repositories is because there were no branches in any repository with a `Jenkinsfile` in it, so let's fix that. Navigate to your copy of the **helloworld-nodejs** repository in your workshop GitHub Organization and click on the **Add file** button towards the top right of the screen and then select **Create new file**. ![Create Jenkinsfile](create-jenkinsfile.png?width=50pc) +8. Name the file `Jenkinsfile` and add the following content: +``` +pipeline { + +} +``` +![Jenkinsfile in GitHub Editor](jenkinsfile-github-editor.png?width=50pc) +9. At the bottom of the screen enter a commit message, such as ***initial Jenkinsfile***, select the **Create a new branch for this commit and start a pull request**, name the branch **development** and click the **Propose new file** button. **IMPORTANT: Do Not Create a Pull Request on the next screen after saving**. ![Commit Jenkinsfile](commit-jenkinsfile.png?width=50pc) +10. Navigate back to your new **GitHub Organization** Jenkins Pipeline project folder on your CloudBees CI Managed Controller and refresh your browser. You should now have a Pipeline Multi-branch project for your **helloworld-nodejs** repository and a new failed job for the **development** branch you just added the `Jenkinsfile`. Don't worry that it failed, that is expected and something we will fix in the next lab. *NOTE: If you do not have a new **helloworld-nodejs** Multibranch project then click on the **Scan Repository Now** link in the left menu and then refresh your browser.*![Job Failed](job-failed.png?width=50pc) + +## Basic Declarative Syntax Structure + +In the previous lesson your Pipeline ran and will have failed. + +In this exercise we will update the Jenkinsfile Declarative Pipeline in your copy of the **helloworld-nodejs** repository using the GitHub file editor so the Pipeline job will complete successfully, as opposed to resulting in the following syntax errors: + +``` +WorkflowScript: 1: Missing required section "stages" @ line 1, column 1. + pipeline { + ^ + +WorkflowScript: 1: Missing required section "agent" @ line 1, column 1. + pipeline { + ^ + +2 errors +``` + +[Declarative Pipelines](https://jenkins.io/doc/book/pipeline/syntax/#declarative-pipeline) must be enclosed within a `pipeline` block - which we have. But Declarative Pipelines must also contain a top-level `agent` declaration, and must contain exactly one `stages` block at the top level. The `stages` block must have at least one `stage` block but can have an unlimited number of additional `stage` blocks. Each `stage` block must have exactly one `steps` block. + +1. We will use the GitHub file editor to update the `Jenkinsfile` file in your copy of the **helloworld-nodejs** repository. Navigate to the `Jenkinsfile` file in the **development** branch of your **helloworld-nodejs** repository and then click on the pencil icon in the upper right to edit that file. **IMPORTANT:** Make sure you are editing the `Jenkinsfile` on your `development` branch** and **NOT the `main` branch**. ![Edit Basic Syntax](github-edit-basic-syntax.png?width=50pc) +2. Replace the contents of that file with the following Declarative Pipeline: + +```groovy +pipeline { + agent any + stages { + stage('Say Hello') { + steps { + echo 'Hello World!' + sh 'java -version' + } + } + } +} +``` +![Basic Syntax Commit](basic-syntax-commit.png?width=50pc) + +3. Add a commit description and then click the **Commit Changes** button with the default selection of *Commit directly to the `development` branch* selected. +4. Navigate back to the **helloworld-nodejs** *development* branch job on your CloudBees CI Managed Controller and the job will complete successfully. Note some things from the log: + + i. The `Jenkinsfile` is being pulled from the **development** branch of your forked **helloworld-nodejs** repository. + + ii. The agent is being provisioned from a Kubernetes Pod Template (more on this in the next lesson): + + ``` + ... + Agent default-jnlp-sx8fz is provisioned from template default-jnlp + ... + ``` + + iii. Your copy of the **helloworld-nodejs** repository is being checked out, even though you did not put any steps in the `Jenkinsfile` to do so: + + ``` + ... + Cloning repository https://github.com/cbci-pipeline/helloworld-nodejs.git + ... + ``` + + iv. The agent has a Java version of `1.8.0_191`: + +``` +... +[Pipeline] sh ++ java -version +openjdk version "1.8.0_191" +OpenJDK Runtime Environment (IcedTea 3.10.0) (Alpine 8.191.12-r0) +OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode) +... +``` + +> **NOTE:** You may have noticed that your Pipeline GitHub repository is being checked out even though you didn't specify that in your Jenkinsfile. Declarative Pipeline checks out source code by default without the need to explicitly include the `checkout scm` step. Furthermore, this automatic checkout will occur in every `stage` that uses a different agent. + +## Next Lesson + +Before moving on to the next lesson make sure that your **Jenkinsfile** Pipeline script on the **development** branch of your copy **helloworld-nodejs** repository matches the one from below. + + +### Finished Jenkinsfile for *Introduction to Pipelines with CloudBees Core* +``` +pipeline { + agent any + stages { + stage('Say Hello') { + steps { + echo 'Hello World!' + sh 'java -version' + } + } + } +} +``` diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/basic-syntax-commit.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/basic-syntax-commit.png new file mode 100644 index 000000000..2a16b47ac Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/basic-syntax-commit.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/commit-jenkinsfile.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/commit-jenkinsfile.png new file mode 100644 index 000000000..d5fcce834 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/commit-jenkinsfile.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/create-jenkinsfile.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/create-jenkinsfile.png new file mode 100644 index 000000000..cb2aef516 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/create-jenkinsfile.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/empty-github-org-folder.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/empty-github-org-folder.png new file mode 100644 index 000000000..7669a807c Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/empty-github-org-folder.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-edit-basic-syntax.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-edit-basic-syntax.png new file mode 100644 index 000000000..7aad3fb84 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-edit-basic-syntax.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-org-folder-item.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-org-folder-item.png new file mode 100644 index 000000000..29aa6ef0b Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-org-folder-item.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-org-folder-save.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-org-folder-save.png new file mode 100644 index 000000000..212e272fd Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-org-folder-save.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-org-webhook.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-org-webhook.png new file mode 100644 index 000000000..1323745dd Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/github-org-webhook.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/jenkinsfile-github-editor.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/jenkinsfile-github-editor.png new file mode 100644 index 000000000..d747245fc Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/jenkinsfile-github-editor.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/job-failed.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/job-failed.png new file mode 100644 index 000000000..65713053b Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/job-failed.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/managed-controller-link.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/managed-controller-link.png new file mode 100644 index 000000000..6aaf0d214 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/managed-controller-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/new-item.png b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/new-item.png new file mode 100644 index 000000000..aa4198506 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/declarative-basics/new-item.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/environment-credentials.md b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials.md new file mode 100644 index 000000000..8a129c6a0 --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials.md @@ -0,0 +1,189 @@ +--- +title: "Environment Variables and Credentials" +chapter: false +weight: 5 +--- + +The Declarative Pipeline syntax provides an [environment directive](https://www.jenkins.io/doc/book/pipeline/syntax/#environment) that allows specifying key-value pairs at the global Pipeline or `stage` level. In addition to providing environment variables, the `environment` directive also [integrates with Jenkins credentials](https://www.jenkins.io/doc/book/pipeline/syntax/#supported-credentials-type) to provide a simpler way of securely injecting credentials into your Jenkins Pipeline. In this lab we will explore both types of Pipeline environment variables. + +## Global and Stage Pipeline Environment Variables + +1. We will add a global environment variable that will be accessible by all the stages of our Jenkins Pipeline. Navigate to and open the GitHub editor for the `Jenkinsfile` file in the **main** branch of your **helloworld-nodejs** repository. ![Edit Jenkinsfile](edit-jenksinfile.png?width=50pc) +2. Next, at the global `pipeline` level, add the following `environment` block under the `agent none` directive: +``` + environment { + FAVORITE_COLOR = 'RED' + } +``` +3. Add the following `echo` step right before the existing `echo` step in the **Build and Push Image** stage. +``` + echo "FAVORITE_COLOR is $FAVORITE_COLOR" +``` + +5. Next, we will override the `FAVORITE_COLOR` variable for the **Deploy** stage and adding an `echo` step. Replace the entire **Deploy** stage with the following: +``` + stage('Deploy') { + environment { + FAVORITE_COLOR = 'BLUE' + } + steps { + echo "TODO - deploy to $FAVORITE_COLOR" + } + } +``` + +The complete Pipeline should match the following: +``` +pipeline { + agent none + environment { + FAVORITE_COLOR = 'RED' + } + stages { + stage('Test') { + when { + beforeAgent true + not { branch 'main' } + } + agent { + kubernetes { + yamlFile 'nodejs-pod.yaml' + } + } + steps { + container('nodejs') { + sh 'node --version' + } + } + } + stage('Main Branch Stages') { + when { + beforeAgent true + branch 'main' + } + stages { + stage('Build and Push Image') { + steps { + echo "FAVORITE_COLOR is $FAVORITE_COLOR" + echo "TODO - build and push image" + } + } + stage('Deploy') { + environment { + FAVORITE_COLOR = 'BLUE' + } + steps { + echo "TODO - deploy to $FAVORITE_COLOR" + } + } + } + } + } +} +``` + +6. At the bottom of the screen enter a commit message, leave **Commit directly to the `main` branch** selected and click the **Commit new file** button. +7. Navigate to the **main** branch job of the **helloworld-nodejs** project on your Managed Controller and the job should be running or queued to run. Once it completes you should see the value for the **FAVORITE_COLOR** variable printed out in the logs and it should have a different value. ![Variable in Test Stage](favorite-color-red-or-blue.png?width=50pc) + + +## Credentials as Environment Variables + +In this lab we will use the `environment` directive to inject a username/password credential into are Jenkins Pipeline. We will also explore some best practices around injecting sensitive environmental variables into a Jenkins Pipeline. + +1. Navigate to and open the GitHub editor for the `Jenkinsfile` file in the **main** branch of your **helloworld-nodejs** repository. ![Edit Jenkinsfile](edit-jenksinfile.png?width=50pc) +2. We will add another environment variable to the `environment` directive of the **Deploy** stage, but this time we will use the special helper method `credentials()` to create an environment variable from a username/password credential and we will then update the `echo` step to print out the values of the variable. Replace the entire **Deploy** stage with the following: +``` + stage('Deploy') { + environment { + FAVORITE_COLOR = 'BLUE' + SERVICE_CREDS = credentials('example-service-username-password') + } + steps { + echo "TODO - deploy to $FAVORITE_COLOR with SERVICE_CREDS: username=$SERVICE_CREDS_USR password=$SERVICE_CREDS_PSW" + } + } +``` + +Note that the `credentials` helper automatically creates two environment variables use the variable name we provided as a prefix and add `_USR` for the credential username and `_PSW` for the credential password. The credential variable without either suffix will provide the value in the format `username:password`. + +3. At the bottom of the screen enter a commit message, leave **Commit directly to the `main` branch** selected and click the **Commit new file** button. +4. Navigate to the **main** branch job of the **helloworld-nodejs** project on your Managed Controller and the job should be running or queued to run. Once it completes, review the logs for the **Deploy** stage. ![Deploy Stage Logs with Secret Warning](deploy-logs-secret-warning.png?width=50pc) +Note that there is a warning regarding *Groovy String interpolation* for the **SERVICE_CREDS** environment variable. This is referring to the fact that the the sensitive environment variable will be interpolated during Groovy evaluation and the value could be made available earlier than intended, resulting in sensitive data leaking in various contexts. + +5. To fix this, navigate back to and open the GitHub editor for the `Jenkinsfile` file in the **main** branch of your **helloworld-nodejs** repository. ![Edit Jenkinsfile](edit-jenksinfile.png?width=50pc) +6. We will update the `echo` step of the **Deploy** stage so it does not use Groovy String interpolation to inject the username/password credential. Replace the entire **Deploy** stage with the following: +``` + stage('Deploy') { + agent any + environment { + FAVORITE_COLOR = 'BLUE' + SERVICE_CREDS = credentials('example-service-username-password') + } + steps { + sh 'echo TODO - deploy to $FAVORITE_COLOR with SERVICE_CREDS: username=$SERVICE_CREDS_USR password=$SERVICE_CREDS_PSW' + } + } +``` + +We were able to remove Groovy String interpolation on the controller by replacing the `echo` step with an `sh` step that executes **echo** on the agent and replacing the double-quotes with single-quotes so no Groovy String interpolation. We also had to add an `agent` because the `sh` step requires an agent to run on. +7. At the bottom of the screen enter a commit message, leave **Commit directly to the `main` branch** selected and click the **Commit new file** button. +8. Navigate to the **main** branch job of the **helloworld-nodejs** project on your Managed Controller and the job should be running or queued to run. Once it completes, review the logs for the **Deploy** stage. ![Deploy Stage Logs No Secret Warning](deploy-logs-no-secret-warning.png?width=50pc) + +There should no longer be a warning regarding *Groovy String interpolation*. + + +>NOTE: By default warnings are configured to be displayed on the build and log pages when there might be insecure interpolation. To configure these warnings set `org.jenkinsci.plugins.workflow.cps.DSL.UNSAFE_GROOVY_INTERPOLATION` to the following values: +>1) `ignore`: no warnings will be displayed on the log or build page. +>2) `fail`: build failure when the build encounters the first interpolated groovy string that contains a secret. + +### Finished Jenkinsfile for the *Environment Variables and Credentials* Lab +``` +pipeline { + agent none + environment { + FAVORITE_COLOR = 'RED' + } + stages { + stage('Test') { + when { + beforeAgent true + not { branch 'main' } + } + agent { + kubernetes { + yamlFile 'nodejs-pod.yaml' + } + } + steps { + container('nodejs') { + sh 'node --version' + } + } + } + stage('Main Branch Stages') { + when { + beforeAgent true + branch 'main' + } + stages { + stage('Build and Push Image') { + steps { + echo "FAVORITE_COLOR is $FAVORITE_COLOR" + echo "TODO - build and push image" + } + } + stage('Deploy') { + agent any + environment { + FAVORITE_COLOR = 'BLUE' + SERVICE_CREDS = credentials('example-service-username-password') + } + steps { + sh 'echo TODO - deploy to $FAVORITE_COLOR with SERVICE_CREDS: username=$SERVICE_CREDS_USR password=$SERVICE_CREDS_PSW' + } + } + } + } + } +} +``` diff --git a/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/create-pr-link.png b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/create-pr-link.png new file mode 100644 index 000000000..8e852d537 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/create-pr-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/deploy-logs-no-secret-warning.png b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/deploy-logs-no-secret-warning.png new file mode 100644 index 000000000..5ab12934c Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/deploy-logs-no-secret-warning.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/deploy-logs-secret-warning.png b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/deploy-logs-secret-warning.png new file mode 100644 index 000000000..6a94c13df Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/deploy-logs-secret-warning.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/edit-jenksinfile.png b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/edit-jenksinfile.png new file mode 100644 index 000000000..6f87b49d2 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/edit-jenksinfile.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/favorite-color-red-or-blue.png b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/favorite-color-red-or-blue.png new file mode 100644 index 000000000..99223e7cb Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/favorite-color-red-or-blue.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/variable-test-stage.png b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/variable-test-stage.png new file mode 100644 index 000000000..8b2d8f649 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/variable-test-stage.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/view-config-link.png b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/view-config-link.png new file mode 100644 index 000000000..646cd35ba Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/environment-credentials/view-config-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/input.md b/labs/cloudbees-ci-pipeline/content/labs/input.md new file mode 100644 index 000000000..0a452dc02 --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/input.md @@ -0,0 +1,133 @@ +--- +title: "Pipelines with Interactive Input" +chapter: false +weight: 7 +--- + +In this lab, we will see how you can capture interactive input in your Jenkins Pipeline while it is running by using the `input` step and some pitfalls you will want to avoid when using the `input` step. + +1. Use the GitHub file editor to update the **Jenkinsfile** file in the **main** branch of your copy of the **helloworld-nodejs** repository and update the **Deploy** `stage` by adding the following between `environment` directive and `steps` block: + +``` + when { + environment name: 'FAVORITE_COLOR', value: 'BLUE' + } + input { + message "Should we continue with deployment?" + } +``` + +Note that we added a new `when` condition that will result in the **Deploy** stage being skipped. We also added an `input` directive instead of an `input` step in the `steps` block. This ensures that the `input` will be displayed before the agent is used. *Also note that even though we are setting the `FAVORITE_COLOR` environment variable value to `BLUE` in the **Deploy** stage that does not get executed until after the `when` condition is checked; so the value is still `RED` for the `when` condition.* + +2. Commit the changes and then navigate to the **main** branch of your **helloworld-nodejs** project on your Managed Controller. +3. There will be an `input` prompt for the `Deploy` stage (*the `input` prompt is also available in the Console log*). ![Configure Notification Link](input-prompt.png?width=50pc) Go ahead and click the **Proceed** button and you will see that the **Deploy** stage is skipped. +4. Return to the the **Jenkinsfile** file in the **main** branch of your copy of the **helloworld-nodejs** repository in GitHub and use the GitHub file editor to update the **Deploy** `stage` by adding a special [beforeInput](https://www.jenkins.io/doc/book/pipeline/syntax/#evaluating-when-before-the-input-directive) `when` condition set to `true` after the `environment` condition. The updated `when` directive should match the following: +``` + when { + environment name: 'FAVORITE_COLOR', value: 'BLUE' + beforeInput true + } +``` + +5. Commit the changes and then navigate to the **main** branch of your **helloworld-nodejs** project on your Managed Controller. The **Deploy** stage will be skipped before prompting for input. +6. Return to the the **Jenkinsfile** file in the **main** branch of your copy of the **helloworld-nodejs** repository in GitHub and use the GitHub file editor to update the **Deploy** `stage`. Replace the entire **Deploy** stage with the following: +``` + stage('Deploy') { + agent any + environment { + FAVORITE_COLOR = 'BLUE' + SERVICE_CREDS = credentials('example-service-username-password') + } + input { + message "Should we continue with deployment?" + } + steps { + sh 'echo TODO - deploy to $FAVORITE_COLOR with SERVICE_CREDS: username=$SERVICE_CREDS_USR password=$SERVICE_CREDS_PSW' + } + } +``` + +7. Commit the changes, navigate to the **main** branch of your **helloworld-nodejs** project on your Managed Controller and you will eventually see a `input` prompt for the `Deploy` stage. +8. If you don't click on either the **Proceed** or **Abort** button in the `input` prompt, the Managed Controller would have waited indefinitely for a user response. Let's fix that by setting a timeout for the **Deploy** stage. We will add a `timeout` `option` for the **Deploy** `stage` using the [stage options directive](https://jenkins.io/doc/book/pipeline/syntax/#stage-options). Update the **Deploy** `stage` to match the following in the **main** branch and then commit the changes: + +``` + stage('Deploy') { + agent any + environment { + FAVORITE_COLOR = 'BLUE' + SERVICE_CREDS = credentials('example-service-username-password') + } + options { + timeout(time: 30, unit: 'SECONDS') + } + input { + message "Should we continue with deployment?" + } + steps { + sh 'echo TODO - deploy to $FAVORITE_COLOR with SERVICE_CREDS: username=$SERVICE_CREDS_USR password=$SERVICE_CREDS_PSW' + } + } +``` + +9. Navigate to the **main** branch of your **helloworld-nodejs** project on your Managed Controller and wait at least 30 seconds after the 'Deploy' `stage` starts. Your pipeline will be automatically **aborted** 30 seconds after the 'Deploy' `stage` starts. ![Input Timeout](input-timeout.png?width=50pc) + +### Finished Jenkinsfile for *Pipeline Approvals with Interactive Input* Lab +``` +pipeline { + agent none + environment { + FAVORITE_COLOR = 'RED' + } + triggers { + eventTrigger simpleMatch('hello-api-deploy-event') + } + stages { + stage('Test') { + when { + beforeAgent true + not { branch 'main' } + } + agent { + kubernetes { + yamlFile 'nodejs-pod.yaml' + } + } + steps { + container('nodejs') { + sh 'node --version' + } + } + } + stage('Main Branch Stages') { + when { + beforeAgent true + branch 'main' + } + stages { + stage('Build and Push Image') { + steps { + echo "FAVORITE_COLOR is $FAVORITE_COLOR" + echo "TODO - build and push image" + } + } + stage('Deploy') { + agent any + environment { + FAVORITE_COLOR = 'BLUE' + SERVICE_CREDS = credentials('example-service-username-password') + } + options { + timeout(time: 30, unit: 'SECONDS') + } + input { + message "Should we continue with deployment?" + } + steps { + sh 'echo TODO - deploy to $FAVORITE_COLOR with SERVICE_CREDS: username=$SERVICE_CREDS_USR password=$SERVICE_CREDS_PSW' + } + } + } + } + } +} +``` diff --git a/labs/cloudbees-ci-pipeline/content/labs/input/groups-link.png b/labs/cloudbees-ci-pipeline/content/labs/input/groups-link.png new file mode 100644 index 000000000..3dc6c7296 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/input/groups-link.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/input/input-prompt.png b/labs/cloudbees-ci-pipeline/content/labs/input/input-prompt.png new file mode 100644 index 000000000..8d9b7eb46 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/input/input-prompt.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/input/input-timeout.png b/labs/cloudbees-ci-pipeline/content/labs/input/input-timeout.png new file mode 100644 index 000000000..51ce58608 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/input/input-timeout.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/kubernetes-agents.md b/labs/cloudbees-ci-pipeline/content/labs/kubernetes-agents.md new file mode 100644 index 000000000..b9207be74 --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/kubernetes-agents.md @@ -0,0 +1,62 @@ +# Kubernetes Agents with CloudBees Core +## Introduction Jenkins Kubernetes plugin + +In this exercise we will get an introduction to the [Jenkins Kubernetes plugin](https://github.com/jenkinsci/kubernetes-plugin/blob/master/README.md) for running dynamic and ephemeral agents in a Kubernetes cluster - [leveraging the scaling abilities of Kubernetes to schedule build agents](https://kurtmadel.com/posts/cicd-with-kubernetes/autoscaling-jenkins-agents-with-kubernetes/). + +CloudBees Core has OOTB support for Kubernetes build agents and allow Kubernetes agent templates - called Pod Templates - to be defined at either [the Operations Center level](https://go.cloudbees.com/docs/cloudbees-core/cloud-admin-guide/agents/#_globally_editing_pod_templates_in_operations_center) or at [the Team Master level](https://go.cloudbees.com/docs/cloudbees-core/cloud-admin-guide/agents/#_editing_pod_templates_per_team_using_masters). The Kubernetes based agent is contained in a [Kubernetes pod](https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/), where a pod is a group of one or more containers sharing a common storage system and network. A pod is the smallest deployable unit of computing that Kubernetes can create and manage (you can read more about pods in the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/pods/pod/)). + +>NOTE: One of the **containers** in a **Pod Template** must host the actual Jenkins build agent that communicates with the Jenkins Master (the `slave.jar` file that is used for communication between the CloudBees Team Master and the agent). By convention, this container always exists (and is automatically added to any Pod Templates that do not define a **Container Template** with the name ***jnlp*** ). Again, this special container has the ***Name*** `jnlp` and default execution of the Pipeline always happens in this `jnlp` container (as it did when we used `agent any` above) - unless you declare otherwise with a special Pipeline step provided by the Kuberentes plugin - [the `container` step](https://github.com/jenkinsci/kubernetes-plugin#pipeline-support). If needed, this automatically provided `jnlp` container may be overridden by specifying a **Container Template** with the ***Name*** `jnlp` - but that **Container Template** must be able to connect to the Team Master via JNLP with a version of the Jenkins `slave.jar` that corresponds to the Team Master Jenkins verion or the Pod Template will fail to connect to the Team Master. You can learn more about the `jnlp` container and additioal functionality in the [Jenkins Kubernetes Plugin documentation on GitHub](https://github.com/jenkinsci/kubernetes-plugin#pipeline-support). + +We will use the Kubernetes plugin [Pipeline `container` block](https://jenkins.io/doc/pipeline/steps/kubernetes/#container-run-build-steps-in-a-container) to run Pipeline `steps` inside a specific container configured as part of a Jenkins Kubernetes Agent Pod template. In our initial Pipeline, we used `agent any` which required at least one Jenkins agent configured to *Use this node as much as possible* - resulting in the use of a Pod Template that only had a `jnlp` container. But now we want to use Node.js in our Pipeline. [Jenkins CasC](https://github.com/jenkinsci/configuration-as-code-plugin) was used to pre-configure the [CloudBees Kube Agent Management plugin](https://go.cloudbees.com/docs/cloudbees-core/cloud-admin-guide/agents/#_editing_pod_templates_per_team_using_masters) to include a [Kubernetes Pod Template at the Team Master level to provide a Node.js container](https://github.com/kypseli/cb-core-mm/blob/kube-workshop/config-as-code.yml#L45). Go to the top-level of your Team Master, click on the **Manage Jenkins** link and then scroll down and click on the **Kubernetes Pod Templates** item. If not at the top, scroll down to the ***Kubernetes Pod Template*** with the **Name** **'nodejs-app'**
Take note of the ***Labels*** field with a value of ***nodejs-app*** and the **Container Template** ***Name*** field with a value of ***nodejs*** - both of these are important and we will need those values to configure our Pipeline to use this **Pod Template** and **Container Template** in your `Jenkinsfile`. + +1. Navigate to and click on the `Jenkinsfile` file in the **development** branch of your forked **helloworld-nodejs** repository +2. Click on the **Edit this file** button (pencil) +3. First, we need to update the `agent any` directive with the following so that we will get the correct Kubernetes Pod Template - configured with the **Container Template** that includes the `node:8.12.0-alpine` Docker image: +``` + agent { label 'nodejs-app' } +``` +4. Commit that change and navigate to the **Activity** view of your **helloworld-nodejs** job in Blue Ocean on your Team Master. The build logs should be almost the same as before - we are still using the default `jnlp` container.
+5. Let's change that by replacing the **Say Hello** `stage` with the following **Test** `stage` so the steps run in the **nodejs** `container`. Edit the `Jenkinsfile` file in the **development** branch of your forked **helloworld-nodejs** repository so the entire pipeline looks like the following: + +```groovy +pipeline { + agent { label 'nodejs-app' } + stages { + stage('Test') { + steps { + container('nodejs') { + echo 'Hello World!' + sh 'java -version' + } + } + } + } +} +``` + + All of the Pipeline steps within that `container` block will run in the container specified by the **Name** of the **Container Template** - and in this case that **Container Template** is using the `node:8.12.0-alpine` container image as we saw above. Commit the changes and the **helloworld-nodejs** job will run - it will result in an error because the `nodejs` container does not have Java installed (and why should it).
+ +>NOTE: If you waited for your job to complete in Blue Ocean before you navigated to the [Pipeline Runs Details View](https://jenkins.io/doc/book/blueocean/pipeline-run-details/#pipeline-run-details-view) you will discover a nice feature where if a particular step fails, the tab with the failed step will be automatically expanded, showing the console log for the failed step as you can see in the image above. + +1. We will fix the error in the **Test** `stage` we added above by replacing the `sh 'java -version'` step with the `sh 'node --version'` step and moving the `sh 'java -version'` step above the `container` block in the `Jenkinsfile` file in the **development** branch of your forked **helloworld-nodejs** repository so the entire pipeline looks like the following: +``` +pipeline { + agent { label 'nodejs-app' } + stages { + stage('Test') { + steps { + sh 'java -version' + container('nodejs') { + echo 'Hello World!' + sh 'node --version' + } + } + } + } +} +``` +7. Commit the changes and the **helloworld-nodejs** job will run and it will complete successfully with the following output:
+ +>**NOTE:** The sh 'java -version' step before the `container('nodejs')` completed successfully this time because it used the default `jnlp` container to execute any steps not in the `container` block. + +You may proceed to the next set of [**labs**](./README.md#workshop-labs) - when your are you ready with this lab. diff --git a/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents.md b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents.md new file mode 100644 index 000000000..45ffc40d6 --- /dev/null +++ b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents.md @@ -0,0 +1,105 @@ +--- +title: "Stage Specific Agents" +chapter: false +weight: 2 +--- + +In this lab we will get an introduction to the [Jenkins Kubernetes plugin](https://github.com/jenkinsci/kubernetes-plugin/blob/master/README.md) that enables the use of dynamic and ephemeral agents with CloudBees CI on a Kubernetes cluster - allowing you to [leverage the scaling capabilities of Kubernetes to schedule build agents](https://kurtmadel.com/posts/cicd-with-kubernetes/autoscaling-jenkins-agents-with-kubernetes/). + +CloudBees CI has out-of-the-box support for Kubernetes build agents and allow Kubernetes agent templates - called Pod Templates - to be defined at either [the Cloud Operations Center level](https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/agents#_globally_editing_pod_templates_in_operations_center) to be shared by multiple controllers or at [the Managed Controller level](https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/agents#_editing_pod_templates_per_team_using_masters). The Kubernetes based agent is contained in a [Kubernetes pod](https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/), where a pod is a group of one or more containers sharing a common storage system and network. A pod is the smallest deployable unit of computing that Kubernetes can create and manage (you can read more about pods in the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/pods/pod/)). + +>NOTE: One of the **containers** in a **Pod Template** must host the actual Jenkins build agent that communicates with the Jenkins controller (the `agent.jar` file that is used for communication between the CloudBees Managed Controller and the agent). By convention, this container always exists (and is automatically added to any Pod Templates that do not define a **Container Template** with the name ***jnlp*** ). Again, this special container has the ***Name*** `jnlp` and default execution of the Pipeline always happens in this `jnlp` container (as it did when we used `agent any` in our initial Declarative Pipeline) - unless you declare otherwise with a special Pipeline step provided by the Kubernetes plugin - [the container step](https://github.com/jenkinsci/kubernetes-plugin#pipeline-support). If needed, this automatically provided `jnlp` container may be overridden by specifying a **Container Template** with the ***Name*** `jnlp` - but that **Container Template** must be able to connect to the Managed Controller via a JNLP or websocket connection with a version of the Jenkins `agent.jar` that works with the the Managed Controller Jenkins version or the Pod based agent will fail to connect to the Managed Controller. You can learn more about the `jnlp` container and additional functionality in the [Jenkins Kubernetes Plugin documentation on GitHub](https://github.com/jenkinsci/kubernetes-plugin#pipeline-support). + +We will use the Kubernetes plugin [Pipeline container block](https://jenkins.io/doc/pipeline/steps/kubernetes/#container-run-build-steps-in-a-container) to run Pipeline `steps` inside a specific container configured as part of a Jenkins Kubernetes Agent Pod template. In our initial Pipeline, we used `agent any` which required at least one Jenkins agent configured to *Use this node as much as possible* - resulting in the use of a Pod Template that only had a `jnlp` container. But now we want to use Node.js in our Pipeline. [Jenkins CasC](https://github.com/jenkinsci/configuration-as-code-plugin) was used to pre-configure the [CloudBees Kube Agent Management plugin](https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/agents#_editing_pod_templates_per_team_using_masters) to include a [Kubernetes Pod Template at the Managed Controller level](https://github.com/cloudbees-days/cloudbees-ci-config-bundle/blob/pipeline-workshop/jenkins.yaml#L33) to provide a Node.js container. + +1. Go to the top-level of your Managed Controller, click on the **Manage Jenkins** link and then scroll down and click on the **Kubernetes Pod Templates** item. ![Controller Pod Templates](controller-pod-templates.png?width=50pc) +2. On the next screen, click on the **Pod Template details...** button for the ***Kubernetes Pod Template*** with the **Name** **'nodejs-app'**. ![Kubernetes Node.js Agent Template](k8s-nodejs-agent-template.png?width=50pc) +Take note of the ***Labels*** field with a value of ***nodejs-app*** and the **Container Template** ***Name*** field with a value of ***nodejs*** - both of these are important and we will need those values to configure our Pipeline to use this **Pod Template** and **Container Template** in your `Jenkinsfile`. Also note the **Docker image** being specified: `node:8.12.0-alpine`. +3. Navigate to and click on the `Jenkinsfile` file in the **development** branch of your **helloworld-nodejs** repository and click on the **Edit this file** button (pencil) and replace the global `agent` section with the following: +``` + agent none +``` + +4. Next, in the **Say Hello** `stage` add the following `agent` section right above the `steps` section so that we will get the Kubernetes Pod Template configured for your Managed Controller with the **Container Template** that includes the `node:8.12.0-alpine` Docker(container) image above: +``` + agent { label 'nodejs-app' } +``` +{{%expand "expand for complete Jenkinsfile" %}} +``` +pipeline { + agent none + stages { + stage('Say Hello') { + agent { label 'nodejs-app' } + steps { + echo 'Hello World!' + sh 'java -version' + } + } + } +} +``` +{{% /expand%}} + +5. Commit that change to the `development` branch and navigate to your **helloworld-nodejs** job on your Managed Controller. The build logs should be almost the same as before because we are still using the default `jnlp` container. ![Build with Agent Template](build-agent-template.png?width=50pc) +6. Let's change that by replacing the **Say Hello** `stage` with the following **Test** `stage` so the steps run in the **nodejs** `container`. Edit the `Jenkinsfile` file in the **development** branch of your forked **helloworld-nodejs** repository so the entire pipeline looks like the following: + +``` +pipeline { + agent none + stages { + stage('Test') { + agent { label 'nodejs-app' } + steps { + container('nodejs') { + echo 'Hello World!' + sh 'java -version' + } + } + } + } +} +``` + + All of the Pipeline steps within the `container` block will run in the container specified by the **Name** of the **Container Template** - and in this case that **Container Template** is using the `node:8.12.0-alpine` container image as we saw above. Commit the changes and the **helloworld-nodejs** job will run - it will result in an error because the `nodejs` container does not have Java installed (and why should it). Hover over the failed stage in the **Stage View** of your development branch job and click on the **Logs** button. ![Open Logs](stage-view-logs-button.png?width=50pc) Next, expand the last step - `sh 'java -version'` - to see the error. ![Java Error](agent-java-error.png?width=50pc) +7. We will fix the error in the **Test** `stage` we added above by replacing the `sh 'java -version'` step with the `sh 'node --version'` step and moving the `sh 'java -version` step above the `container` block in the `Jenkinsfile` file in the **development** branch of your forked **helloworld-nodejs** repository so the entire pipeline looks like the following: +``` +pipeline { + agent none + stages { + stage('Test') { + agent { label 'nodejs-app' } + steps { + sh 'java -version' + container('nodejs') { + echo 'Hello World!' + sh 'node --version' + } + } + } + } +} +``` +8. Commit the changes and the **helloworld-nodejs** job will run and it will complete successfully with the following output: ![Agent Success](agent-java-success.png?width=50pc) + +>**NOTE:** The sh 'java -version' step before the `container('nodejs')` completed successfully this time because it used the default `jnlp` container to execute any steps not in the `container` block. + +### Finished Jenkinsfile for *Stage Specific Agents* Lab +**Important**: For the finished Jenkinsfile for this stage, remove the `sh 'java -version'` step and make sure you copy the Pipeline as below and replace yours. + +``` +pipeline { + agent none + stages { + stage('Test') { + agent { label 'nodejs-app' } + steps { + container('nodejs') { + echo 'Hello World!' + sh 'node --version' + } + } + } + } +} +``` diff --git a/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/agent-java-error.png b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/agent-java-error.png new file mode 100644 index 000000000..fb4f03383 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/agent-java-error.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/agent-java-success.png b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/agent-java-success.png new file mode 100644 index 000000000..4e4d5098e Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/agent-java-success.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/build-agent-template.png b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/build-agent-template.png new file mode 100644 index 000000000..6587040d7 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/build-agent-template.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/controller-pod-templates.png b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/controller-pod-templates.png new file mode 100644 index 000000000..87f7aa716 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/controller-pod-templates.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/k8s-nodejs-agent-template.png b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/k8s-nodejs-agent-template.png new file mode 100644 index 000000000..d998cafe4 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/k8s-nodejs-agent-template.png differ diff --git a/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/stage-view-logs-button.png b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/stage-view-logs-button.png new file mode 100644 index 000000000..b49370d93 Binary files /dev/null and b/labs/cloudbees-ci-pipeline/content/labs/stage-specific-agents/stage-view-logs-button.png differ diff --git a/labs/cloudbees-ci/config.toml b/labs/cloudbees-ci/config.toml index a0758e2c5..2baed3be3 100644 --- a/labs/cloudbees-ci/config.toml +++ b/labs/cloudbees-ci/config.toml @@ -17,6 +17,8 @@ home = [ "HTML", "RSS", "JSON"] showVisitedLinks = true # Set this to true to disable copy-to-clipboard button for inline code. disableInlineCopyToClipBoard = true + # If set to false, a Home button will appear below the search bar on the menu. + disableLandingPageButton = true [markup] [markup.goldmark]