File: index.md

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (376 lines) | stat: -rw-r--r-- 11,132 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
---
stage: Verify
group: Runner
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

# Tutorial: Set up CI/CD steps

This tutorial shows you how to create and use steps in your pipelines.

Steps are reusable and composable pieces of a job. Each step defines structured inputs and
outputs that can be consumed by other steps. You can configure steps in local files, GitLab.com repositories,
or any other Git source.

In this tutorial, use the GitLab CLI (`glab`) to:

1. Create a step that outputs "hello world".
1. Configure a pipeline to use the step.
1. Add multiple steps to a job.
1. Use a remote step to echo all the outputs.

## Before you begin

- You must install and sign in to the [GitLab CLI](../../editor_extensions/gitlab_cli/index.md) (`glab`).
- On GitLab.com and self-managed in GitLab 17.3 and later, you must include the
  `image: registry.gitlab.com/gitlab-org/step-runner:v0` runner image in the `.gitlab-ci.yml` file.

## Create a step

First, create a step with:

- An `exec` type.
- A `command` that's started by the executive API of the system.

1. Create a GitLab project named `zero-to-steps` in your namespace:

   ```shell
   glab project create zero-to-steps
   ```

1. Go to the root of the project repository:

   ```shell
   cd zero-to-steps
   ```

1. Create a `step.yml` file.

   ```shell
   touch step.yml
   ```

1. Use a text editor to add a specification to the `step.yml`:

   ```yaml
   spec:
     inputs:
       who:
         default: world
         type: string
   ```

   - `spec` has one input called `who`.
   - The input `who` is optional because there is a default value.

1. To add an implementation to the `step.yml`, add a second YAML document after `spec`, with the `exec` key:

   ```yaml
   spec:
     inputs:
       who:
         default: world
         type: string
   ---
   exec:
     command:
       - bash
       - -c
       - "echo hello ${{ inputs.who }}"
   ```

The triple em dash (`---`) separates the file into two YAML documents:

- The first document is the specification, like a function signature.
- The second document is the implementation, like a function body.

The `bash` and `-c` arguments start a Bash shell and take the script input from the command line arguments.
In addition to shell scripts, you can use `command` to execute programs like `docker` or `terraform`.

The `"echo hello ${{ input.name }}"` argument includes an expression inside `${{` and `}}`.
Expressions are evaluated at the last possible moment and have access to the current execution context.
This expression accesses `inputs` and reads the value of `who`:

- If `who` is provided by the caller, that value is substituted for the expression.
- If `who` is omitted, then the default `world` is substituted for the expression instead.

## Configure a pipeline to use the step

1. In the root of the repository, create a `.gitlab-ci.yml` file:

   ```shell
   touch .gitlab-ci.yml
   ```

1. In the `.gitlab-ci.yml`, add the following job:

   ```yaml
    hello-world:
      variables:
        STEPS:
          expand: false
          value: |
            - name: hello_world
              step: .
      image: registry.gitlab.com/gitlab-org/step-runner:v0
      script:
        - /step-runner ci
   ```

   - The steps are given in an environment variable called `STEPS`. `STEPS` is a list of step invocations.
     - Each invocation is given a `name` so you can reference the outputs in later steps.
     - Each invocations specifies a `step` to run. A local reference (`.`) points to the root of the repository.
   - The job script invokes `step-runner ci` which is in the `step-runner:v0` image.

   For an example of how this code should look in your repository, see [this example](https://gitlab.com/josephburnett/zero-to-steps/-/tree/part-1?ref_type=tags).

1. Commit both files and push the project repository. This triggers a pipeline that runs the job:

   ```shell
   git add .
   git commit -m 'Part 1 complete'
   git push --set-upstream origin master
   glab ci status
   ```

1. Follow the job under "View Logs" until the pipeline completes. Here's an example of a successful job:

   ```shell
   $ /step-runner ci
   hello world
   trace written to step-results.json
   Cleaning up project directory and file based variables
   Job succeeded
   ```

NOTE:
Usage of an environment variable is a temporary work-around until the `run` keyword is implemented.
See [the `run` keyword epic](https://gitlab.com/groups/gitlab-org/-/epics/11846).

You've now created and used your first step!

## Add multiple steps to a job

You can have more than one step in a job.

1. In the `.gitlab-ci.yml` file, add another step called `hello_steps` to your job:

   ```yaml
   hello-world:
     variables:
       STEPS:
         expand: false
         value: |
           - name: hello_world
             step: .
           - name: hello_steps
             step: .
             inputs:
               who: gitlab steps
     image: registry.gitlab.com/gitlab-org/step-runner:v0
     script:
       - /step-runner ci
   ```

   This `hello_steps` step provides a non-default input `who` of `gitlab steps`.

   For an example of how this code should look in your repository, see [this example](https://gitlab.com/josephburnett/zero-to-steps/-/tree/part-2-a?ref_type=tags).

1. Commit and push the changes:

   ```shell
   git commit -a -m 'Added another step'
   git push
   glab ci status
   ```

1. In the terminal, select **View Logs** and follow the pipeline until it completes. Here's an example of a successful output:

   ```shell
   $ /step-runner ci
   hello world
   hello gitlab steps
   trace written to step-results.json
   Cleaning up project directory and file based variables
   Job succeeded
   ```

## Refactor your step

To refactor your steps, move them from the `.gitlab-ci.yml` to a dedicated file:
To refactor your steps by moving them from CI Config into a dedicated file:

1. Move the first step you created to a directory called `hello`:

   ```shell
   mkdir hello
   mv step.yml hello/
   ```

1. Create a new step at the root of the repository.

   ```shell
   touch step.yml
   ```

1. Add the following configuration to the new `step.yml`:

   ```yaml
   spec: {}
   ---
   steps:
     - name: hello_world
       step: ./hello
     - name: hello_steps
       step: ./hello
       inputs:
         who: gitlab steps
   ```

   This new step has no inputs, so the `spec` is empty (`{}`).
   It is a `steps` type, which has the same syntax as steps in `.gitlab-ci.yml`.
   However, the local reference now points to your step in the `hello` directory.

1. To use the new step, modify `.gitlab-ci.yml`:

   ```yaml
   hello-world:
     variables:
        STEPS:
          expand: false
          value: |
            - name: hello_everybody
              step: .
     image: registry.gitlab.com/gitlab-org/step-runner:v0
     script:
       - /step-runner ci
   ```

   Now your job invokes only the new step with no inputs.
   You've refactored the details of the job into a separate file.

   For an example of how this code should look in your repository, see [this example](https://gitlab.com/josephburnett/zero-to-steps/-/tree/part-2-b?ref_type=tags).

1. Commit and push the changes:

   ```shell
   git add .
   git commit -m 'Refactored step config'
   git push
   glab ci status
   ```

1. In the terminal, select **View Logs**.
1. To verify that the refactored step performs the same function as the step you first created, view the log output. The log output should match the output of the step you created previously. Here's an example:

   ```shell
   $ /step-runner ci
   hello world
   hello gitlab steps
   trace written to step-results.json
   Cleaning up project directory and file based variables
   Job succeeded
   ```

### Add an output to the step

Add an output to your `hello` step.

1. In `hello/step.yml`, add an `outputs` structure to the `spec`:

   ```yaml
   spec:
     inputs:
       who:
         default: world
         type: string
     outputs:
       greeting:
         type: string
   ---
   exec:
     command:
       - bash
       - -c
       - "echo greeting=\"hello ${{ inputs.who }}\" | tee ${{ output_file }}"
   ```

   - In this `spec`, you've defined a single output `greeting` without a default. Because
     there is no default, the output `greeting` is required.
   - Outputs are written to a file `${{ output_file }}` (provided at run time) in the form `key=value`.
   - This step runs `echo greeting=\"hello ${{ inputs.name }}\"` and sends the output to the logs and the output file (`tee ${{ output_file }}`).

1. In `step.yml`, add an output to the step:

   ```yaml
   spec:
     outputs:
       all_greetings: {}
   ---
   steps:
     - name: hello_world
       step: ./hello
     - name: hello_steps
       step: ./hello
       inputs:
         who: gitlab steps
   outputs:
     all_greetings: "${{ steps.hello_world.outputs.greeting }} and ${{ steps.hello_steps.outputs.greeting }}"
   ```

You've now added an output to this step called `all_greetings`.

This output shows the use of a new expression syntax: `${{ steps.hello_world.outputs.greeting }}`.
This expression reads the `outputs` of the two sub-steps, `hello_world` and `hello_steps`.
Both sub-step outputs are concatenated into a single string output.

## Use a remote step

Before you commit and run your code, add another step to your job to see the final `all_greetings` output of your main `step.yml`.

This step invocation references a remote step named `echo-step`.
The echo step takes a single input `echo`, prints it to the logs, and outputs it as `echo`.

1. Edit the `.gitlab-ci.yml`:

   ```yaml
   hello-world:
     variables:
       STEPS:
         expand: false
         value: |
           - name: hello_everybody
             step: .
           - name: all_my_greetings
             step: gitlab.com/gitlab-org/ci-cd/runner-tools/echo-step@main
             inputs:
               echo: "all my greetings say ${{ steps.hello_everybody.outputs.all_greetings }}"
     image: registry.gitlab.com/gitlab-org/step-runner:v0
     script:
       - /step-runner ci
   ```

   For an example of how this code should look in your repository, see [this example](https://gitlab.com/josephburnett/zero-to-steps/-/tree/part-2-c?ref_type=tags).

1. Commit and push the changes:

   ```shell
   git commit -a -m 'Added outputs'
   git push
   glab ci status
   ```

1. Follow the job under "View Logs" until the pipeline completes. Here's an example of a successful output:

   ```shell
   $ /step-runner ci
   greeting=hello world
   greeting=hello gitlab steps
   echo=all my greetings say hello world and hello gitlab steps
   trace written to step-results.json
   Cleaning up project directory and file based variables
   Job succeeded
   ```

That's it! You've just created and implemented steps in your pipeline.
For more information about the syntax for steps, see [CI/CD Steps](../../ci/steps/index.md).