Move best practices to global-jjb
[releng/global-jjb.git] / docs / best-practices.rst
1 .. _global-jjb-best-practices:
2
3 ##############
4 Best Practices
5 ##############
6
7 JJB YAML Layout
8 ===============
9
10 .. note::
11
12     While some of this applies to the Global JJB project other recommendations
13     are generally useful to projects that might be defining JJB templates.
14
15 The Global JJB project is a useful example project to look at so we recommend
16 referring to the Maven job definitions as an example as you read the
17 documentation below:
18
19 https://github.com/lfit/releng-global-jjb/blob/master/jjb/lf-maven-jobs.yaml
20
21 We recommend sectioning off the template into 3 general sections in order:
22
23 1. Job Groups (optional)
24 2. Common Functions
25 3. Job Template Definitions
26
27 In section 1) not all configurations need this so is an optional section. Job
28 groups are useful in cases where there are jobs that are generally useful
29 together. For example the OpenDaylight uses a lot of Merge and Verify job
30 combinations so every new project will want both job types defined in their
31 project.
32
33 In section 2) we want to define all common functions (anchors, aliases, macros)
34 that are generally useful to all jobs in the file. This allows job template
35 developers to look at the top of the file to see if there are useful functions
36 already defined that they can reuse.
37
38 In section 3) we can declare our job definitions. In the Global JJB project we
39 create Gerrit and GitHub versions of the jobs so the format we use here
40 might look strange at first but is well layed out for code reuse if we need to
41 define 2 or more versions of the same job template for different systems. We
42 will define this in more detail in the next section.
43
44 Job Template Layout
45 -------------------
46
47 1. Comment of Job Template Name
48 2. Macro containing build definition of the job
49    a. Macro named after job
50    b. Complete documentation of the job parameters
51    c. Default parameters defined by the job
52    d. Job configuration
53 3. job-template definition containing build triggers
54
55 In section 1) we need to declare a in large comment text to identify the job
56 section.
57
58 In section 2) we declare the actual job definition. This is so that we have a
59 single macro that we call in all the real job-template sections that is
60 reusable and not duplicating any code. First we declare the macro as the job
61 name. Then in 2.b) we provide the complete documentation of the job parameters
62 this is so that we can link users of the job to this file and they can
63 understand fully what options they can configure for this particular job.
64 Then we define defaults for any parameters that are optional. The last section
65 we define the job configuration which completes the macro.
66
67 In section 3) we declare the actual job-template. Because of all the
68 preparations above job template definitions should be small and simple. It
69 needs to define the scm and job triggers. The Global JJB project needs to
70 support both Gerrit and GitHub versions of the same job so the job definitions
71 there have 2 templates for each job defined.
72
73
74 Passing parameters to shell scripts
75 ===================================
76
77 There are 2 ways to pass parameters into scripts:
78
79 1) JJB variables in the format {var}
80 2) Environment variables in the format ${VAR}
81
82 We recommend avoiding using method 1 (Pass JJB variables) into shell scripts
83 and instead always use method 2 (Environment variables). This makes
84 troubleshooting JJB errors easier and does not require escaping curly braces.
85
86 This method requires 3 steps:
87
88 1) Declare a parameter section or inject the variable as properties-content.
89 2) Invoke the shell script with `include-raw-escape` instead of `include-raw`.
90 3) Use the shell variable in shell script.
91
92
93 The benefit of this method is that parameters will always be at the top
94 of the job page and when clicking the Build with Parameters button in Jenkins
95 we can see the parameters before running the job. We can review the
96 parameters retro-actively by visiting the job parameters page
97 ``job/lastSuccessfulBuild/parameters/``. Injecting variables as
98 properties-content makes the variable local to the specific macro, while
99 declaring it as parameter makes the variable global.
100
101 .. note::
102
103     When a macro which invokes a shell script has no JJB parameters defined
104     `!include-raw-escape` will insert extra curly braces, in such cases its
105     recommended to use `!include-raw`.
106
107 Usage of config-file-provider
108 =============================
109
110 When using the config-file-provider plugin in Jenkins to provide a config file.
111 We recommend using a macro so that we can configure the builder to
112 remove the config file as a last step. This ensures
113 that credentials do not exist on the system for longer than it needs to.
114
115 ship-logs example:
116
117 .. code-block:: yaml
118
119     - builder:
120         name: lf-ship-logs
121         builders:
122           - config-file-provider:
123               files:
124                 - file-id: jenkins-log-archives-settings
125                   variable: SETTINGS_FILE
126           - shell: !include-raw:
127               - ../shell/logs-get-credentials.sh
128           - shell: !include-raw:
129               - ../shell/lftools-install.sh
130               - ../shell/logs-deploy.sh
131           - shell: !include-raw:
132               - ../shell/logs-clear-credentials.sh
133           - description-setter:
134               regexp: '^Build logs: .*'
135
136 In this example the script logs-deploy requires a config file to authenticate
137 with Nexus to push logs up. We declare a macro here so that we can ensure that
138 we remove credentials from the system after the scripts
139 complete running via the logs-clear-credentials.sh script. This script contains
140 3 basic steps:
141
142 1. Provide credentials via config-file-provider
143 2. Run the build scripts in this case lftools-install.sh and logs-deploy.sh
144 3. Remove credentials provided by config-file-provider
145
146 Preserving Objects in Variable References
147 =========================================
148
149 JJB has an option to preserve a data structure object when you want to pass
150 it to a template.
151 https://docs.openstack.org/infra/jenkins-job-builder/definition.html#variable-references
152
153 One thing that is not explicitly covered is the format of the variable name
154 that you pass the object to. When you use the `{obj:key}` notation to preserve
155 the original data structure object, it will not work if the variable name has a
156 dash `-` in it. The standard that we follow, and recommend, is to use an underscore
157 `_` instead of a dash.
158
159 Example:
160
161 .. code-block:: yaml
162
163     - triggers:
164        - lf-infra-github-pr-trigger:
165            trigger-phrase: ^remerge$
166            status-context: JJB Merge
167            permit-all: false
168            github-hooks: true
169            github-org: '{github-org}'
170            github_pr_whitelist: '{obj:github_pr_whitelist}'
171            github_pr_admin_list: '{obj:github_pr_admin_list}'
172
173 In the above example note the use of underscores in `github_pr_admin_list` and
174 `github_pr_admin_list`.
175
176 Using single quotes around variables
177 ====================================
178
179 Its recommended to use single quotes around JJB variables '{variable}-field'
180 during variable substitution or when using a variable in a string field, in
181 other cases its recommended to drop the single quotes.
182
183 Example:
184
185 .. code-block:: yaml
186
187     - builder:
188         name: lf-user-logs
189         builders:
190           - inject:
191               properties-content: |
192                   'HOME={user-home}'
193           - build-file:
194               settings: '{settings-file}'
195               file-version: '{file-version}'