toys-release 0.2.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/docs/guide.md CHANGED
@@ -4,4 +4,1324 @@
4
4
 
5
5
  # Toys-Release User Guide
6
6
 
7
- (To be written)
7
+ Toys-Release is a release pipeline system built on GitHub Actions and the Toys
8
+ RubyGem. It interprets [conventional commit](https://conventionalcommits.org/)
9
+ message format to automate changelog generation and updates library versions
10
+ based on semantic versioning. It supports fine tuning and approval of releases
11
+ using GitHub pull requests.
12
+
13
+ Out of the box, Toys-Release knows how to tag GitHub releases, build and push
14
+ RubyGems packages, and build and publish documentation to gh-pages. You can
15
+ customize the build pipeline and many aspects of its behavior.
16
+
17
+ This user's guide covers all the features of Toys-Release in detail, including
18
+ installation, normal operations, release pipeline customization, and a full
19
+ configuration reference.
20
+
21
+ ## Conceptual overview
22
+
23
+ Toys-Release is a comprehensive release pipeline system. It includes a set of
24
+ **command line tools** (built using the Toys framework) and a set of
25
+ **GitHub actions** that can be integrated into a GitHub repository to provide a
26
+ way to release new versions of packages present in that repository.
27
+
28
+ Toys-Release depends on the repository utilizing the **conventional commits**
29
+ standard (https://conventionalcommits.org) to describe the changes made in each
30
+ commit to the repository. Using this information, it automatically generates
31
+ **changelog** entries and chooses a new package version to release, according
32
+ to the **semantic versioning** standard (https://semver.org/).
33
+
34
+ Releases are requested explicitly by a repository maintainer by running a
35
+ command line tool or triggering a GitHub action. Toys-Release will configure
36
+ the release and open a **release pull request** describing the release. When
37
+ this pull request is merged, Toys-Release will automatically perform the
38
+ release. The pull request can also be modified to customize the release, or
39
+ closed without merging to cancel the release.
40
+
41
+ Toys-Release depends on a **configuration file** to describe which packages are
42
+ present in a repository and how to release them. It supports repositories
43
+ containing either a single package, or multiple packages (i.e. "**monorepos**")
44
+ and can analyze a repository to identify changes applying to each package.
45
+
46
+ Toys-Release can build **GitHub releases**, publish **RubyGems packages**, and
47
+ build and publish documentation to **GitHub pages**.
48
+
49
+ Toys-Release uses the [Toys](https://dazuma.github.io/toys/gems/toys/latest)
50
+ RubyGem, but does not require familiarity with Toys.
51
+
52
+ ## Installation
53
+
54
+ Toys-Release must be installed into a GitHub repository. This involves:
55
+
56
+ * Installing a Toys tool;
57
+ * Writing a configuration file;
58
+ * Defining a set of GitHub Actions workflows and a set of GitHub labels
59
+ (a tool is provided to perform this step); and
60
+ * Providing necessary credentials.
61
+
62
+ ### Prerequisites
63
+
64
+ Toys-Release is written in Ruby, using the Toys framework. The installation
65
+ process requires these items to be installed locally, but normal operation
66
+ happens in GitHub Actions and does not require any local installation.
67
+
68
+ If you do not have Ruby or Toys installed locally, do so first. Install
69
+ Ruby 3.0 or later, and then install the Toys RubyGem using:
70
+
71
+ ```sh
72
+ gem install toys
73
+ ```
74
+
75
+ Toys-Release requires Toys 0.18 or later. If you have an older version of Toys,
76
+ update it using:
77
+
78
+ ```sh
79
+ toys system update
80
+ ```
81
+
82
+ Finally, you also need the GitHub command line tool, `gh`. Find installation
83
+ instructions at https://cli.github.com/. If you are running on MacOS, for
84
+ example, the easiest way to install it is via homebrew:
85
+
86
+ ```sh
87
+ brew install gh
88
+ ```
89
+
90
+ ### Install the release tool
91
+
92
+ The Toys-Release tool needs to be installed in your repository, as a Toys tool
93
+ loaded from the [toys-release](https://rubygems.org/gems/toys-release) gem.
94
+
95
+ Create `.toys/release.rb` (note the leading period in the directory name) in
96
+ your git repository. Use the following content:
97
+
98
+ ```ruby
99
+ load_gem "toys-release"
100
+ ```
101
+
102
+ This will cause Toys-Release to use the latest version of Toys-Release. You can
103
+ also pin to a specific version of Toys-Release by specifying version
104
+ requirements similar to how those requirements are specified in RubyGems or
105
+ Bundler:
106
+
107
+ ```ruby
108
+ load_gem "toys-release", "~> 0.3"
109
+ ```
110
+
111
+ Commit and push this change to your repository.
112
+
113
+ ### Write the configuration file
114
+
115
+ Next you will provide a configuration file for releases. This file is located
116
+ in your repository at `.toys/.data/releases.yml` (note the leading periods) and
117
+ lists all the releasable components (such as RubyGems packages) in your
118
+ repository, along with any customizations to the build/release process and
119
+ pipeline behavior.
120
+
121
+ To get you started, Toys-Release provides a config generation tool. Once the
122
+ release tool is installed as described above, you can run this from your local
123
+ repository clone directory:
124
+
125
+ ```sh
126
+ toys release gen-config
127
+ ```
128
+
129
+ This will analyze your repository and generate an initial configuration file
130
+ for you. It will make a guess as to what releasable components/RubyGems are
131
+ present in your repository. At this stage, you do not need to get every
132
+ configuration exactly correct, but feel free to begin editing it if you so
133
+ choose. The remaining sections in this user's guide will cover the release
134
+ capabilities that you may need to configure in this file, and the
135
+ [configuration reference](#configuration-reference) section below describes the
136
+ file format in detail.
137
+
138
+ ### Install workflows and labels
139
+
140
+ Once an initial configuration file is present, you can finish the rest of the
141
+ installation by creating some needed labels in your GitHub repository and
142
+ installing some needed GitHub Actions workflows. These are done on the command
143
+ line using the release tool.
144
+
145
+ To create the GitHub repo labels, run this from your local repo clone directory:
146
+
147
+ ```sh
148
+ toys release create-labels
149
+ ```
150
+
151
+ Then, to generate the GitHub Actions workflows, run:
152
+
153
+ ```sh
154
+ toys release gen-workflows
155
+ ```
156
+
157
+ This will generate files in a `.github/workflows` directory in your repository.
158
+ Commit and push this change (along with the configuration file) to your
159
+ repository.
160
+
161
+ ### Provide credentials
162
+
163
+ If Toys-Release will publish RubyGems packages, it will require credentials.
164
+ Provide those by creating a GitHub Actions Secret called `RUBYGEMS_API_KEY`.
165
+
166
+ In your GitHub repository web UI, go to the Settings tab, and choose
167
+ Secrets and Variables -> Actions in the left nav. Create a repository secret
168
+ called `RUBYGEMS_API_KEY` whose value is an API key from RubyGems with
169
+ "push rubygem" scope. You can also provide this secret at the organization
170
+ level.
171
+
172
+ ## Release operations
173
+
174
+ This section describes how Toys-Release manages releases and how you control
175
+ and interact with the process.
176
+
177
+ Overall, the process looks like this:
178
+
179
+ 1. During development, commit messages for all commits should be formatted
180
+ according to the [Conventional Commits](https://conventionalcommits.org)
181
+ standard. This allows Toys-Release (and other similar tools) to interpret
182
+ the semantics of your changes and configure releases accordingly.
183
+
184
+ 2. A maintainer schedules a release by triggering the "Open release request"
185
+ GitHub Action. This action analyzes the repository, looking for changes in
186
+ each component, deciding which components have releasable updates,
187
+ determining the semver version bump for each, and building a changelog. It
188
+ then opens a pull request with the version and changelog updates.
189
+
190
+ 3. The maintainer can either merge the pull request (possibly with manual
191
+ modifications to the changelogs and/or version numbers to release) or close
192
+ it unmerged.
193
+
194
+ 4. If the pull request is merged, the release is automatically processed by
195
+ additional GitHub Actions. The automation verifies that the GitHub checks
196
+ pass, and runs the release pipeline.
197
+
198
+ 5. The results of the run are reported back to the release pull request. If
199
+ the release failed, a GitHub issue is also automatically opened. A
200
+ maintainer can retry a failed release by triggering the "Retry release"
201
+ GitHub Action.
202
+
203
+ ### Commit message formatting
204
+
205
+ When using Toys-Release, you should format all commit messages according to the
206
+ [Conventional Commits](https://conventionalcommits.org) standard. This allows
207
+ Toys-Release (and other similar tools) to interpret the semantics of your
208
+ changes and configure releases accordingly. (Even if you are not using such
209
+ tools, Conventional Commits encapsulates good best practice for writing useful
210
+ commit messages.) Properly formatted conventional commit messages will
211
+ determine what kind of version bump Toys-Release uses when releasing those
212
+ changes, and the commit messages themselves will be used in the changelog that
213
+ Toys-Release generates.
214
+
215
+ Specifically, a change that adds a new feature, corresponding to a minor update
216
+ under [Semantic Versioning](https://semver.org), should have a commit message
217
+ tagged with `feat:`. For example:
218
+
219
+ ```
220
+ feat: You can now upload a cat photo
221
+ ```
222
+
223
+ A change that fixes a bug, corresponding to a patch change under Semver, should
224
+ have a commit message tagged with `fix:`. For example:
225
+
226
+ ```
227
+ fix: The app no longer crashes when a photo includes a dog instead of a cat
228
+ ```
229
+
230
+ A change that updates documentation should have a commit message tagged with
231
+ `docs:`. For example:
232
+
233
+ ```
234
+ docs: Emphasize that photos should include cats rather than dogs
235
+ ```
236
+
237
+ A breaking change, which would trigger a major update under Semver, can be
238
+ expressed using either the `BREAKING CHANGE:` tag, or an exclamation mark after
239
+ any other type of tag. Here are a few examples:
240
+
241
+ ```
242
+ BREAKING CHANGE: Rename the "add-photo" API to "add-cat-photo"
243
+ feat!: Raise an exception if a photo contains a dog instead of a cat
244
+ ```
245
+
246
+ A change that does not actually make any functional change, such as a git
247
+ repository configuration change, a CI change, or other admin-level change,
248
+ should be tagged with `chore:`. For example:
249
+
250
+ ```
251
+ chore: Attach a photo of a cat to the repo
252
+ ```
253
+
254
+ Other common tags might include `refactor:`, `style:`, `test:`, and others. See
255
+ https://conventionalcommits.org for more details and discussion.
256
+
257
+ By default, Toys-Release specifically recognizes the `feat:`, `fix:`, and
258
+ `docs:` tags, and uses them to configure releases and new versions. It also
259
+ recognizes breaking changes. It considers other tags to be non-significant for
260
+ release purposes. However, you can configure this behavior using the
261
+ **commit_tags** configuration field. See the
262
+ [configuration reference](#configuration-reference) for more details.
263
+
264
+ It is legal to have multiple conventional commit formatted messages in a single
265
+ commit message. Toys-Release will parse each commit message and use all
266
+ properly formatted conventional commit messages it finds. In most cases,
267
+ however, it is good practice to keep commits small and describable via a single
268
+ conventional commit message.
269
+
270
+ ### Requesting releases
271
+
272
+ To request a release, navigate to the Actions tab in the GitHub UI, select the
273
+ "Open release request" workflow, and click the "Run workflow" dropdown. This
274
+ will open a confirmation drop-down. Click the "Run workflow" button to confirm
275
+ and begin the automatic release analysis.
276
+
277
+ The dropdown provides an optional "Components to release" field. Often you can
278
+ leave this blank, and Toys-Release will analyze all components in the repository
279
+ and select the ones that have releasable changes pending. Alternatively, you
280
+ can choose which components to release by entering their names, space-delimited
281
+ in the field.
282
+
283
+ The field also supports setting the version number for each component, by
284
+ appending the version to the component name, separated by a colon.
285
+
286
+ For example, to request releases of the `toys` and `toys-release` components,
287
+ you can enter the following text into "Components to release":
288
+
289
+ toys toys-release
290
+
291
+ To make the above request but specifically request version 0.3.0 of the
292
+ `toys-release` component:
293
+
294
+ toys toys-release:0.3.0
295
+
296
+ ### Managing release pull requests
297
+
298
+ You can also specify which components get released and at which versions, by
299
+ modifying the release pull request. You can change the version in the pull
300
+ request, or even revert the version/changelog change for some components and/or
301
+ introduce version/changelog modifications for other components. The releases
302
+ that ultimately take place are simply dictated by what changes get introduced
303
+ by the commit introduced by merging the pull request.
304
+
305
+ **Important:** If you modify a release pull request, be sure to *squash* your
306
+ changes when you merge it. It is important that the entire pull request is
307
+ expressed in a single commit, because the automation will look only at the
308
+ changes in the most recent commit after merge.
309
+
310
+ You will also notice that the pull request opened by the "Open release request"
311
+ workflow will have the `release: pending` label applied. This label signals the
312
+ release automation that this is a release pull request. If you remove this
313
+ label, the automation will not process the release.
314
+
315
+ Finally, you can even create a release pull request manually, or using your own
316
+ tools or processes. You must simply ensure that:
317
+
318
+ * The pull request has the `release: pending` label applied
319
+ * The pull request merges as a single commit (i.e. "squashed")
320
+ * For each component you want to release, the version and changelog are
321
+ updated appropriately.
322
+
323
+ If you close a release pull request without merging, the release will be
324
+ canceled. The automation will apply the `release: aborted` label to indicate
325
+ this.
326
+
327
+ ### Monitoring progress and results
328
+
329
+ After a release pull request is merged, a GitHub Actions workflow will trigger
330
+ and begin processing the release. You can follow the workflow logs if you want
331
+ detailed information on the progress of the release. Additionally, updates will
332
+ be posted to the pull request when the workflow begins and when it completes.
333
+ These updates will include a link to the workflow logs for your convenience.
334
+
335
+ After a workflow finishes, it will apply a label to the pull request indicating
336
+ the final result. A successful release will have the `release: complete` label,
337
+ while an unsuccessful release will have the `release: error` label. If an error
338
+ occurred, the workflow will also open an issue in the repository reporting the
339
+ failed release.
340
+
341
+ Most of the useful workflow logs will appear in the "Process release request"
342
+ job under the workflow. If you follow the logs, you will see the release goes
343
+ through the following stages:
344
+
345
+ * First, it publishes a comment to the pull request indicating that the release
346
+ is starting.
347
+ * Second, it polls the GitHub checks for the merge commit. Toys-Release will
348
+ perform a release only if all required checks pass, so the release job will
349
+ wait for them to complete. If any checks fail, the release will fail.
350
+ * Third, it runs a set of sanity checks, for example that it is looking at the
351
+ correct repository and commit, that there are no locally modified files, and
352
+ that the version numbers are set as expected.
353
+ * Next, it runs the release pipeline itself. It first does an analysis of which
354
+ steps in the pipeline should run, then runs those steps in order.
355
+ * Finally, it publishes a comment to the pull request reporting the final
356
+ result of the release.
357
+
358
+ ### Troubleshooting and retrying releases
359
+
360
+ If a release fails, generally an issue will be opened in the repository, and
361
+ the pull request will have the `release: error` label applied. Releases can
362
+ fail for a number of reasons, including:
363
+
364
+ * The GitHub checks for the commit representing the merge of the release pull
365
+ request, have failed or did not complete in a timely manner.
366
+ * A failure during the release pipeline, such as an error during the build or
367
+ publication of a release artifact.
368
+ * An intermittent failure of the release pipeline infrastructure, such as a
369
+ failure to obtain a VM to execute a GitHub Actions workflow.
370
+
371
+ If a failure occurs, the release workflow may have published some basic
372
+ information on the cause, to the release pull request. You can also find more
373
+ detailed information in the release logs, a link to which should also have been
374
+ published in the pull request comments. You should use this information to
375
+ troubleshoot the release.
376
+
377
+ In many cases, you can retry the release, possibly after doing something to
378
+ address the cause. For example, if the release failed because of a flaky test
379
+ in the GitHub checks, you can rerun the check, and once it passes, retry the
380
+ release. Or, if the release failed because of expired RubyGems credentials, you
381
+ can rotate the credentials (see [above](#provide-credentials)) and then retry
382
+ the release.
383
+
384
+ To retry a release, navigate to the Actions tab in the GitHub UI, select the
385
+ "Retry release" workflow, and click the "Run workflow" dropdown. This will open
386
+ a confirmation drop-down with a field for "Release PR number". Enter the number
387
+ of the *release pull request* here, and then click the "Run workflow" button to
388
+ retry the release.
389
+
390
+ When a failure takes place, it is possible that the release partially completed
391
+ but did not fully complete. For example, a GitHub release and tag may already
392
+ have been created, but the gem was not successfully pushed to RubyGems. When
393
+ you retry a release, the release script will automatically detect which release
394
+ steps were already completed, and will skip them.
395
+
396
+ If you need to "roll back" a failed release so it can be retried from a
397
+ different commit, currently you must manually roll back the version number and
398
+ changelog modification (i.e. roll back the changes in the release pull
399
+ request). You might also need to remove an existing GitHub tag and release if
400
+ they were already created.
401
+
402
+ ## Other features
403
+
404
+ ### Documentation publication
405
+
406
+ One of the optional features of the release pipeline is publication of Yardoc
407
+ reference documentation to GitHub Pages. This lets you host reference
408
+ documentation for your Ruby gem on your GitHub Pages site, under github.io. As
409
+ an example, of what this looks like you can see the reference documentation for
410
+ the Toys gem at https://dazuma.github.io/toys/gems/toys.
411
+
412
+ The features of this system are:
413
+
414
+ * Host generated Yardoc (or rdoc) documentation for every version of the gem.
415
+ * Host documentation for multiple gems per repository.
416
+ * Permanent GitHub Pages (github.io) URL for each gem, which redirects to the
417
+ documentation for the latest version.
418
+ * Automatically publish documentation with each release.
419
+
420
+ #### Setting up documentation publication
421
+
422
+ To set up documentation, do the following:
423
+
424
+ * [Install the release tool](#install-the-release-tool) as documented in the
425
+ main setup procedure. This provides access to the Toys-Release command line.
426
+
427
+ * Make sure you have a release config file. See the section on
428
+ [writing the configuration file](#write-the-configuration-file) for how to
429
+ get started here.
430
+
431
+ * For each gem that you want documented, include the configuration setting
432
+ `gh_pages_enabled: true` in the component's configuration. Alternately, you
433
+ can set `gh_pages_enabled: true` at the top level of the configuration file
434
+ to enable documenting for all components.
435
+
436
+ * Create a starting gh-pages branch by running:
437
+
438
+ toys release gen-gh-pages
439
+
440
+ This will generate the gh-pages branch and push some key files to it, notably
441
+ a `404.html` that does the redirecting to the latest documentation version.
442
+ This may clobber any other gh-pages that you have present.
443
+
444
+ From this point on, any releases you do should also publish documentation to
445
+ your page. To find the page, use the URL
446
+ `https://<github-user>.github.io/<repo-name>/<component-name>`.
447
+
448
+ If you add or otherwise change your components, you can rerun the
449
+ `toys release gen-gh-pages` script to regenerate the files and update the
450
+ redirects. This will not affect any actual documentation you may have generated
451
+ previously.
452
+
453
+ #### Special configuration
454
+
455
+ There are a few configuration fields that affect documentation publication.
456
+
457
+ * **gh_pages_directory** is the directory name for this component in the
458
+ documentation URL. This takes the place of the `<component-name>` in the URL.
459
+ For example, if you set `gh_pages_directory: foo/bar` for your component, the
460
+ documentation will be generated under the URL:
461
+ `https://<github-user>.github.io/<repo-name>/foo/bar`.
462
+
463
+ Note that if you modify this field after previously generating documentation
464
+ for some releases, you will need to manually move the previous documentation
465
+ into the new directory.
466
+
467
+ * **gh_pages_version_var** is the name of the Javascript variable in the
468
+ `404.html` file that stores the latest version of this component's release.
469
+ You will generally not need to modify this unless the automatically-generated
470
+ variable name isn't unique for some reason.
471
+
472
+ See the [component configuration](#component-configuration) section for more
473
+ details.
474
+
475
+ ### Special commit messages
476
+
477
+ Several special cases can be handled via commit tags that are defined by
478
+ Toys-Release. These conventional commit messages can appear in a commit message
479
+ and affect the behavior of that and other commits.
480
+
481
+ * **semver-change:** This tag forces a certain semver change to apply to this
482
+ commit even if other commit tags say otherwise. For example, if a commit
483
+ describes a new feature, but you want it released as a patch version bump
484
+ rather than a minor version bump, you can include `semver-change: patch` in
485
+ the commit message. The full commit message might read thus:
486
+
487
+ feat: Add a small button that doesn't do a lot
488
+ semver-change: patch
489
+
490
+ Valid values for semver-change are `patch`, `minor`, `major`, and `none`.
491
+
492
+ The semver-change tag affects only the commit it is part of. If multiple
493
+ commits are included in a release, other commits in the release might still
494
+ upgrade the version bump to minor or higher.
495
+
496
+ * **revert-commit:** This tag indicates that the commit reverts, and thus
497
+ nullifies the effect of, an earlier commit, thus removing any version bump
498
+ and any changelog entries that would otherwise have been generated. Use the
499
+ SHA of the earlier commit as the content of the tag. For example:
500
+
501
+ revert-commit: b10c6fb3363bd1335dcfbd671bdceae53cd55716
502
+
503
+ A commit can combine revert-commit with other conventional commit tags. It
504
+ can even include multiple revert-commit tags if the commit reverts more than
505
+ one previous commit.
506
+
507
+ ### Running on the command line
508
+
509
+ The implementation of Toys-Release is done via Toys (i.e. command line) tools.
510
+ In most cases, you will use the GitHub Actions integration to manage your
511
+ releases, but you can also run the tools directly from the command line.
512
+
513
+ To do so, first make sure you have
514
+ [installed the release tool](#install-the-release-tool) as documented in the
515
+ main setup procedure. Then, the command line tools will be available as
516
+ subtools underneath `toys release`. For example, you could request a release
517
+ from the command line instead of a GitHub Action, by running the command
518
+ `toys release request`, and providing it the needed arguments and credentials.
519
+
520
+ As with all Toys-based tools, you can pass `--help` to any tool to get detailed
521
+ usage information. For example: `toys release request --help`. You can also run
522
+ `toys release --help` for a list of all the release-related tools.
523
+
524
+ The following are the available command line tools. You may recognize some of
525
+ these as tools you used during the [installation](#installation) procedure.
526
+
527
+ * **create-labels** Creates the GitHub labels used by the release system
528
+
529
+ * **gen-config** Generates an initial release configuration file
530
+
531
+ * **gen-gh-pages** Initializes the gh-pages branch for publishing documentation
532
+
533
+ * **gen-workflows** Generates the GitHub Actions workflows used by Toys-Release
534
+
535
+ * **perform** Runs the release pipeline from the command line. Assumes you have
536
+ already updated the version number and the changelog.
537
+
538
+ * **request** Analyzes the repository history and opens a release pull request
539
+ including any pending releases. This is the command line tool used by the
540
+ "Open release request" GitHub Action.
541
+
542
+ * **retry** Retries a failed release. This is the command line tool used by the
543
+ "Retry release" GitHub Action.
544
+
545
+ There are also internal (hidden) subtools called "_onclosed" and "_onpush".
546
+ These are the tools called by GitHub Actions automation in response to pull
547
+ request events, and you should generally not call them directly.
548
+
549
+ ## The release pipeline
550
+
551
+ Toys-Release features a highly configurable build pipeline. By default it is
552
+ configured to handle most RubyGems packages, and will:
553
+
554
+ * Tag and post a GitHub Release
555
+ * Build a RubyGems package and push it to rubygems.org
556
+ * Optionally build Yardoc documentation and push it to GitHub Pages
557
+
558
+ The pipeline system, however, lets you customize any aspect of the process, and
559
+ even replace it with an entirely different process altogether, possibly even
560
+ handling a completely different type of releasable artifact. This section
561
+ covers the build pipeline. See also the
562
+ [build step configuration](#build-step-configuration) section in the
563
+ configuration reference documentation.
564
+
565
+ ### Pipeline steps
566
+
567
+ A release pipeline is defined as an ordered series of **steps**. Each of these
568
+ steps may perform some task and/or exchange some data with other steps. For
569
+ example, a step might install a bundle, another might build a gem package, and
570
+ another might push a gem package built by a previous step to rubygems.org.
571
+
572
+ The behavior of a step is determined by the **type** of the step, and by
573
+ additional **configuration attributes** provided to the step. Each step also
574
+ has a unique **name** that lets you identify it and connect it to other steps.
575
+
576
+ When a pipeline is run, individual steps in the pipeline may or may not
577
+ actually execute, depending on whether they are needed. For example, the step
578
+ type that creates a GitHub release will always run if it is present in a
579
+ pipeline, but the step type that installs the bundle will normally run only if
580
+ another subsequent step *that will run* actually needs the bundle, and the step
581
+ type that builds the gem package will normally run only if a subsequent step
582
+ *that will run* actually uses the built package (e.g. to push it to RubyGems.)
583
+ The decision of whether or not a step will run depends on the step's
584
+ configuration, and the step dependencies configured into the pipeline.
585
+
586
+ We will cover, as an example, the [standard pipeline](#the-standard-pipeline)
587
+ for RubyGems releases below. First, however, we need to discuss how steps
588
+ depend on one another and pass data around.
589
+
590
+ ### Inter-step communication and dependencies
591
+
592
+ When a step runs, the working directory is set to the **component directory**
593
+ in a *clean* checkout of the release SHA in the repository. Any changes it
594
+ makes to the repository working directory are *not* preserved for other steps;
595
+ instead, it must explicitly "output" any files it needs to make available, and
596
+ other steps must explicitly access those files as "inputs". This is sometimes
597
+ done by the step's code, but can also be specified in the step's configuration.
598
+
599
+ For example, a step that builds a gem package should "output" the package so
600
+ that it is available to other steps that want to publish it. This simply
601
+ involves copying the relevant files to a special directory known as the output
602
+ directory for that step (identified by step name). The standard **build_gem**
603
+ step type does this in code. Alternatively, if you write a custom step that
604
+ builds an artifact, you can specify, via the **outputs** configuration, the
605
+ artifacts that you want made available. (See the
606
+ [output config reference](#step-output-configuration) for details.)
607
+
608
+ Then, a step can use a built artifact previously output by another step by
609
+ copying it from the previous step's output directory. Again, this can be done
610
+ in code, as by the standard **release_gem** step type. You can also specify,
611
+ via the **inputs** configuration, artifacts to copy from another step's output
612
+ into your working directory. (For details, see the
613
+ [input config reference](#step-input-configuration).)
614
+
615
+ When a step specifies the **inputs** configuration, any steps so referenced are
616
+ also automatically tagged as *dependencies* of the step. If the pipeline
617
+ determines the step should be run, then its dependencies are also marked as to
618
+ be run.
619
+
620
+ #### Inter-step communication example
621
+
622
+ Consider the following simple, if contrived, pipeline:
623
+
624
+ ```yaml
625
+ - name: create_file
626
+ type: command
627
+ command: ["touch", "my-file.txt"]
628
+ outputs:
629
+ - source_path: my-file.txt
630
+ - name: create_another_file
631
+ type: command
632
+ command: ["touch", "another-file.txt"]
633
+ outputs:
634
+ - source_path: another-file.txt
635
+ - name: show_file
636
+ type: command
637
+ command: ["cat", "my-file.txt"]
638
+ inputs:
639
+ - name: create_file
640
+ source_path: my-file.txt
641
+ run: true
642
+ ```
643
+
644
+ This pipeline includes three steps. After each step, the git repository gets
645
+ reset, so any files created by the step are not initially available to
646
+ subsequent steps unless the step explicitly accesses them via inputs. Also note
647
+ that all three steps are of type "command", which do not run by default unless
648
+ something else causes them to run.
649
+
650
+ Let's consider these steps starting with the last one.
651
+
652
+ The third step, named `show_file`, looks for a file `my-file.txt` in the
653
+ *first* step's outputs, copies it into its working directory, and prints its
654
+ contents to the logs. It includes the `run: true` configuration which forces it
655
+ to run.
656
+
657
+ Because the third step, `show_file`, copies an input from the first step,
658
+ `create_file`, the latter is a dependency of the former. And since the
659
+ `show_file` is forced to run, then `create_file` will also run. This step will
660
+ run first, because it is first in the list of steps, and it will create a file
661
+ and copy it to its outputs so the `show_file` can access it.
662
+
663
+ The second step, `create_another_file`, would create another file and copy it
664
+ to its outputs. However, it neither is forced to run via `run: true` nor is
665
+ listed as a dependency of any other step that will run. Therefore, the second
666
+ step never runs at all.
667
+
668
+ ### The standard pipeline
669
+
670
+ The default release pipeline illustrates the above features of steps. It
671
+ includes the following steps:
672
+
673
+ * **bundle**: Installs the bundle, and copies the `Gemfile.lock` to its output
674
+ directory. This step runs because the later step **build_yard** declares it
675
+ as a dependency and accesses the `Gemfile.lock`.
676
+ * **build_gem**: Builds the gem package, and copies the package file to its
677
+ output directory. This step runs because the later step **release_gem**
678
+ declares it as a dependency and accesses the built package.
679
+ * **build_yard**: Builds the Yardoc documentation. By default, this step uses
680
+ the `yard` gem from the bundle, and thus depends on the earlier **bundle**
681
+ step. It copies the `Gemfile.lock` output by the earlier step. After building
682
+ the documentation into the `doc` directory, it copies that directory to its
683
+ output directory. This step runs *if* the later step **push_gh_pages**, which
684
+ lists it as a dependency, runs.
685
+ * **release_github**: Pushes a release tag to GitHub and creates a GitHub
686
+ release. This step always runs and has no dependencies.
687
+ * **release_gem**: Pushes the built gem package to rubygems.org. This step
688
+ lists the earlier **build_gem** step as a dependency, and copies the built
689
+ gem package from that step's output.
690
+ * **push_gh_pages**: Pushes the built documentation to the `gh-pages` branch so
691
+ it shows up on the repository's GitHub Pages site. This step runs only if the
692
+ repository actually has a `gh-pages` branch and the release configuration
693
+ specifies that it should be pushed to. If this step does run, it lists the
694
+ earlier **build_yard** step as a dependency, and copies the built
695
+ documentation from that step's output.
696
+
697
+ Ultimately, this pipeline will create a GitHub release, push a RubyGems
698
+ package, and optionally push documentation.
699
+
700
+ ### Modifying the pipeline
701
+
702
+ If your releases have different requirements, you can modify the release
703
+ pipeline, by inserting steps, by modifying existing steps, or by replacing the
704
+ entire pipeline with a new pipeline. These modifications can be made globally
705
+ for all releases in a repository, or specifically for individual releasable
706
+ components, by adding configuration at the top level of the configuration (see
707
+ the [top level configuration reference](#top-level-configuration)) or
708
+ underneath a particular component's configuration (see the
709
+ [component configuration reference](#component-configuration)).
710
+
711
+ * To insert new steps, at the beginning or end of the pipeline, or before or
712
+ after specific named steps, use the **append_steps** and **prepend_steps**
713
+ configurations.
714
+ * To modify existing steps, use the **modify_steps** configuration. See the
715
+ reference on [build step modification](#build-step-modification).
716
+ * There is no specific way to delete an existing step. This is because a step
717
+ might be referenced by other steps. To ensure a step does not run, you can
718
+ modify it to change its type to `noop` (which has no behavior and does not
719
+ run by default) and ensure that no step depends on it.
720
+ * If your changes are more complex than can reasonably be expressed by
721
+ modifying the default pipeline, you can replace the pipeline completely using
722
+ the **steps** configuration.
723
+
724
+ #### Pipeline modification example
725
+
726
+ The `toys` gem itself has a customized release pipeline. This pipeline includes
727
+ a step that merges key classes from `toys-core`, such as DSL classes, into the
728
+ documentation for the `toys` gem.
729
+
730
+ The merging is actually performed by a toys tool called `copy-core-docs`
731
+ defined in the directory for the `toys` gem. The implementation itself isn't
732
+ important; what's important is that we want this merging to be part of the
733
+ release process.
734
+
735
+ The `releases.yml` for the toys repository includes this configuration for the
736
+ `toys` gem:
737
+
738
+ ```yaml
739
+ components:
740
+ - name: toys
741
+ prepend_steps:
742
+ - name: copy_core_docs
743
+ type: tool
744
+ tool: [copy-core-docs]
745
+ outputs: [core-docs]
746
+ modify_steps:
747
+ - name: build_yard
748
+ inputs: [copy_core_docs]
749
+ - name: build_gem
750
+ inputs: [copy_core_docs]
751
+ ```
752
+
753
+ Let's unpack what this is doing.
754
+
755
+ First, we note that we are not replacing the default pipeline completely; we
756
+ are only modifying it *for this one gem*. The other gems (`toys-core` and
757
+ `toys-release`) continue to use the default pipeline unmodified.
758
+
759
+ For the `toys` gem, then, we prepend one new step at the beginning of the
760
+ pipeline. The step is named `copy_core_docs`, and it runs the toys tool that
761
+ copies files (with some modifications to simplify them and make them suitable
762
+ for just documentation) from `toys-core` into the `toys` directory under the
763
+ `core-docs` subdirectory. This directory is not part of the include path, so
764
+ these files are not in the require path and do not interfere with the
765
+ functionality of the library. However, they are in the `.yardopts` file and are
766
+ used when documentation is built. We then copy this new directory to the
767
+ output for the `copy_core_docs` step, to preserve it for future steps.
768
+
769
+ Next, we modify the `build_yard` step to load the `copy_core_docs` output. This
770
+ brings those files back into our working directory when the Yardocs are built.
771
+ It also adds the `copy_core_docs` step to the dependencies of `build_yard` to
772
+ ensure it gets executed.
773
+
774
+ We also modify the `build_gem` step to load the `copy_core_docs` output. This
775
+ ensures that the files are also present when the gem is built, so that services
776
+ like rubydoc.info will have them available when they build the documentation.
777
+ Again, this also adds `copy_core_docs` to the dependencies of `build_gem`. As a
778
+ dependency of both `build_gem` and `build_yard`, this ensures that our new step
779
+ will indeed get executed. (It does not execute twice; Toys-Release ensures each
780
+ step is executed at most once, even if it is listed multiple times as a
781
+ dependency.)
782
+
783
+ #### Useful types for custom steps
784
+
785
+ The **command** and **tool** step types are both very useful when creating
786
+ custom steps. We've seen in the [example above](#pipeline-modification-example)
787
+ how a step of type **tool** is used in the customized release process for the
788
+ `toys` gem itself. The **command** type is similar; it executes a Unix command
789
+ rather than a Toys tool. These two types are very useful for performing
790
+ arbitrary behavior during a release.
791
+
792
+ Another step type that is occasionally useful is **noop**. This type has no
793
+ behavior; it doesn't *do* anything, but you can configure it with inputs and
794
+ outputs. This can be useful for consolidating data output by other steps. You
795
+ can, for example, configure a **noop** with multiple **inputs** from other
796
+ steps, configuring each input to copy to the noop's *output*. Now, all the
797
+ files from potentially multiple inputs are combined and can be referenced
798
+ conveniently via a single step's output.
799
+
800
+ See the reference below on [build step types](#build-step-types) for detailed
801
+ information on these and other step types and their configurations.
802
+
803
+ ## Configuration reference
804
+
805
+ The Toys-Release configuration file is a [YAML](https://yaml.org)-formatted
806
+ file located in your repository at `.toys/.data/releases.yml`. It controls all
807
+ aspects of the release process and behavior and is required.
808
+
809
+ This section will cover all keys in configuration file.
810
+
811
+ ### Top level configuration
812
+
813
+ The top level of the yaml file is a dictionary that can include the following
814
+ keys. Out of these, **repo**, **git_user_name**, and **git_user_email** are all
815
+ required. The rest are optional.
816
+
817
+ * **append_steps**: *array of [BuildStepConfig](#build-step-configuration)* (optional) --
818
+ A list of build steps to append to the end of the default build pipeline.
819
+ This can be used to modify the default build pipeline instead of redefining
820
+ the entire pipeline using the **steps** key.
821
+
822
+ * **breaking_change_header**: *string* (optional) --
823
+ A changelog entry prefix that appears when a change is marked as breaking.
824
+ Default is `BREAKING CHANGE`.
825
+
826
+ * **commit_tags**: *array of [CommitTagConfig](#commit-tag-configuration)* (optional) --
827
+ A set of configurations defining how to interpret
828
+ [conventional commit](https://conventionalcommits.org) tags, including how
829
+ they trigger releases, bump versions, and generate changelog entries. See
830
+ [commit tag configuration](#commit-tag-configuration) for details.
831
+ If not included, Toys-Release will use a default configuration as follows:
832
+
833
+ - tag: feat
834
+ semver: minor
835
+ header: ADDED
836
+ - tag: fix
837
+ semver: patch
838
+ header: FIXED
839
+ - tag: docs
840
+ semver: patch
841
+
842
+ * **components**: *array of [ComponentConfig](#component-configuration)* (optional) --
843
+ An array of releasable components, usually RubyGems packages. See
844
+ [Component Configuration](#component-configuration) for details on the format
845
+ of each component. You can also use the name **gems** for this config key.
846
+
847
+ * **coordinate_versions**: *boolean* (optional) --
848
+ If set to true, this is a shorthand for setting up a coordination group
849
+ containing all components in this repository. Defaults to *false*.
850
+
851
+ * **coordination_groups**: *array of array of string* (optional) --
852
+ A list of disjoint sets of component names. Each set defines a group of
853
+ components that will always be released together with the same version
854
+ number. That is, if one or more components in a set are released, the entire
855
+ set is released, even components with no changes. This is useful for sets of
856
+ gems, such as the Rails gems, that are always released together.
857
+
858
+ * **enable_release_automation**: *boolean* (optional) --
859
+ When enabled, the release pipeline runs automatically when a release pull
860
+ request is merged. Defaults to *true*.
861
+
862
+ * **gh_pages_enabled**: *boolean* (optional) --
863
+ Whether to globally enable gh-pages publication for all releases. Defaults to
864
+ *false*.
865
+
866
+ * **git_user_email**: *string* (required) --
867
+ The git `user.email` setting to use when making git commits.
868
+
869
+ * **git_user_name**: *string* (required) --
870
+ The git `user.name` setting to use when making git commits.
871
+
872
+ * **main_branch**: *string* (optional) --
873
+ The name of the main branch. Defaults to `main` if not provided.
874
+
875
+ * **modify_steps**: *array of [BuildStepModification](#build-step-modification)* (optional) --
876
+ A set of modifications to the default build steps. This can be used to modify
877
+ the default build pipeline instead of redefining the entire pipeline using
878
+ the **steps** key.
879
+
880
+ * **no_significant_updates_notice**: *string* (optional) --
881
+ A notice that appears in a changelog when a release is done but no other
882
+ changelog entries are present. Default is `No significant updates.`
883
+
884
+ * **prepend_steps**: *array of [BuildStepConfig](#build-step-configuration)* (optional) --
885
+ A list of build steps to prepend to the start of the default build pipeline.
886
+ This can be used to modify the default build pipeline instead of redefining
887
+ the entire pipeline using the **steps** key.
888
+
889
+ * **release_branch_prefix**: *string* (optional) --
890
+ The prefix for all release branch names. Defaults to `release`.
891
+
892
+ * **release_aborted_label**: *string* (optional) --
893
+ The name of the GitHub issue label that identifies aborted release pull
894
+ requests. Defaults to `release: aborted`.
895
+
896
+ * **release_complete_label**: *string* (optional) --
897
+ The name of the GitHub issue label that identifies successfully completed
898
+ release pull requests. Defaults to `release: complete`.
899
+
900
+ * **release_error_label**: *string* (optional) --
901
+ The name of the GitHub issue label that identifies release pull requests in
902
+ an error state. Defaults to `release: error`.
903
+
904
+ * **release_pending_label**: *string* (optional) --
905
+ The name of the GitHub issue label that identifies pending release pull
906
+ requests. Defaults to `release: pending`.
907
+
908
+ * **repo**: *string* (required) --
909
+ The GitHub repository name in the form `owner/repo`. For example, the Toys
910
+ repo is `dazuma/toys`.
911
+
912
+ * **required_checks**: *regexp/boolean* (optional) --
913
+ Identifies which GitHub checks must pass as a prerequisite for a release. If
914
+ a string is provided, it is interpreted as a Ruby regexp (PCRE) and
915
+ identifies the check names. A boolean value of *true* (the default) means all
916
+ checks must pass. A boolean value of *false* disables checking.
917
+
918
+ * **required_checks_timeout**: *integer* (optional) --
919
+ The time to wait, in seconds, for required checks to pass during release
920
+ processing. Defaults to 900 (i.e. 15 minutes).
921
+
922
+ * **signoff_commits**: *boolean* (optional) --
923
+ Whether to make commits with `--signoff`. Set this to true if your repository
924
+ has a policy that commits require signoff. Defaults to *false*.
925
+
926
+ * **steps**: *array of [BuildStepConfig](#build-step-configuration)* (optional) --
927
+ The build pipeline as a list of build steps. See
928
+ [build step configuration](#build-step-configuration) for details on how to
929
+ define the pipeline. If this is not included, Toys-Release will use a default
930
+ pipeline as follows:
931
+
932
+ - name: bundle
933
+ - name: build_gem
934
+ - name: build_yard
935
+ - name: release_github
936
+ - name: release_gem
937
+ source: build_gem
938
+ - name: push_gh_pages
939
+ source: build_yard
940
+
941
+ See the earlier section on [the standard pipeline](#the-standard-pipeline)
942
+ for a detailed description of the behavior of this default pipeline.
943
+
944
+ ### Commit tag configuration
945
+
946
+ A commit tag configuration specifies how the release system should handle a
947
+ particular [conventional commits](https://conventionalcommits.org) tag,
948
+ including what kind of [semver](https://semver.org) version bump it implies,
949
+ and how it should appear in the changelog. The format of the configuration is a
950
+ dictionary with the keys documented here. The **tag** key is required; the
951
+ remaining keys are optional and have defaults.
952
+
953
+ * **header**: *string,null* (optional) --
954
+ A prefix that appears before each changelog entry generated by this tag. The
955
+ special value *null* suppresses changelog entry generation for this scope.
956
+ Defaults to the tag itself in all caps.
957
+
958
+ * **scopes**: *array of [ScopeConfig](#scope-configuration)* (optional) --
959
+ Overrides for conventional commit scopes.
960
+
961
+ * **semver**: *string* (optional) --
962
+ The semver version bump implied by changes of this type. Possible values are
963
+ `patch`, `minor`, `major`, and `none`. Default is `none`.
964
+
965
+ * **tag**: *string* (required) -- The conventional commit tag.
966
+
967
+ #### Scope configuration
968
+
969
+ A scope configuration provides override behavior for a particular scope name
970
+ in a commit tag configuration. This lets you provide special behavior for
971
+ individual scopes. A common case might be `chore(deps):` which is used by some
972
+ dependency-updating bots. Typically, `chore:` does not indicate a significant
973
+ change that should trigger a release or appear in a changelog, but you might
974
+ choose different behavior for dependency changes.
975
+
976
+ * **header**: *string,null* (optional) --
977
+ A prefix that appears before each changelog entry generated by this tag. The
978
+ special value *null* suppresses changelog entry generation for this scope.
979
+ Defaults to the same setting used by the tag.
980
+
981
+ * **scope**: *string* (required) -- The scope name.
982
+
983
+ * **semver**: *string* (optional) --
984
+ The semver version bump implied by changes of this type. Possible values are
985
+ `patch`, `minor`, `major`, and `none`. Defaults to the same setting used by
986
+ the tag.
987
+
988
+ ### Component configuration
989
+
990
+ A component configuration specifies how a particular component (often a
991
+ RubyGems package) should be released. Its format is a dictionary with the keys
992
+ documented here.
993
+
994
+ * **append_steps**: *array of [BuildStepConfig](#build-step-configuration)* (optional) --
995
+ A list of build steps to append to the end of this component's build
996
+ pipeline. This can be used to modify the build pipeline instead of redefining
997
+ the entire pipeline using the **steps** key.
998
+
999
+ * **changelog_path**: *string* (optional) --
1000
+ The path to the component's changelog file, relative to the component's
1001
+ directory. Default is `CHANGELOG.md`.
1002
+
1003
+ * **directory**: *string* (optional) --
1004
+ The directory within the repository where this component is located. Defaults
1005
+ to the component name, unless there is exactly one component in this
1006
+ repository, in which case the default is the root of the repository, i.e.
1007
+ "`.`". This directory is used to identify when files related to this
1008
+ component have been changed, and is also used as a base directory for other
1009
+ paths related to the component.
1010
+
1011
+ * **exclude_globs**: *array of string* (optional) --
1012
+ An array of globs identifying files or directories that should be ignored
1013
+ when identifying changes to this component. These paths are relative to the
1014
+ repo root.
1015
+
1016
+ * **gh_pages_directory**: *string* (optional) --
1017
+ The directory in the `gh-pages` branch under which this component's
1018
+ documentation is published. The default is the component name.
1019
+
1020
+ * **gh_pages_enabled**: *boolean* (optional) --
1021
+ Whether gh-pages documentation publishing is enabled for this component.
1022
+ Default is *true* if either **gh_pages_directory** or **gh_pages_version_var**
1023
+ is set explicitly; otherwise *false*.
1024
+
1025
+ * **gh_pages_version_var**: *string* (optional) --
1026
+ The name of a Javascript variable within the `404.html` page under gh-pages
1027
+ that identifies the latest release of this component. Defaults to a variable
1028
+ name corresponding to the component name.
1029
+
1030
+ * **include_globs**: *array of string* (optional) --
1031
+ An array of globs identifying additional files or directories, not located in
1032
+ the component's directory itself, that should signal changes to this
1033
+ component. This can be used, for example, if the repo has global files shared
1034
+ by multiple components, where a change in such a file should trigger releases
1035
+ for all those components. These paths are relative to the repo root.
1036
+
1037
+ * **modify_steps**: *array of [BuildStepModification](#build-step-modification)* (optional) --
1038
+ A set of modifications to this component's build steps. This can be used to
1039
+ modify the build pipeline instead of redefining the entire pipeline using
1040
+ the **steps** key.
1041
+
1042
+ * **name**: *string* (required) --
1043
+ The name of the component, e.g. the name of the RubyGems package if this
1044
+ component represents a gem.
1045
+
1046
+ * **prepend_steps**: *array of [BuildStepConfig](#build-step-configuration)* (optional) --
1047
+ A list of build steps to prepend to the start of this component's build
1048
+ pipeline. This can be used to modify the build pipeline instead of redefining
1049
+ the entire pipeline using the **steps** key.
1050
+
1051
+ * **steps**: *array of [BuildStepConfig](#build-step-configuration)* (optional) --
1052
+ A way to override the complete build pipeline for this component. If not
1053
+ present, the default pipeline for the entire repository is used. (See the
1054
+ **steps** key under [Top level configuration](#top-level-configuration).)
1055
+
1056
+ * **version_constant**: *string* (optional) --
1057
+ The fully-qualified name of the version constant. This is used to determine
1058
+ the current version of the component. The default uses the module implied by
1059
+ the component name. For example, if the component (gem) name is
1060
+ `toys-release`, this defaults to `Toys::Release::VERSION`.
1061
+
1062
+ * **version_rb_path**: *string* (optional) --
1063
+ The path to a Ruby file that contains the current version of the component.
1064
+ This file *must* include Ruby code that looks like this:
1065
+
1066
+ VERSION = "1.2.3"
1067
+
1068
+ where the string is the latest released version. (Prior to the initial
1069
+ release, this version should be `0.0.0`.) Typically, `VERSION` is a constant
1070
+ defined in the "base module" for the Ruby library.
1071
+
1072
+ The default is `version.rb` within the lib path associated with the Ruby
1073
+ module implied by the component name. For example, if the component (gem)
1074
+ name is `toys-release`, this defaults to `lib/toys/release/version.rb`.
1075
+
1076
+ ### Build step configuration
1077
+
1078
+ A build step describes one step in the release process. Its format is a
1079
+ dictionary with the keys described below. Specific types of build steps may
1080
+ define additional keys as documented under the section
1081
+ [build step types](#build-step-types). For more introductory information, see
1082
+ the section on [the release pipeline](#the-release-pipeline) above.
1083
+
1084
+ * **name**: *string* (optional) --
1085
+ The unique name of this build step in the build pipeline. If not explicitly
1086
+ provided, a unique name will be generated.
1087
+
1088
+ * **type**: *string* (optional) --
1089
+ The type of build step, defining what it does. Possible values are:
1090
+ `build_gem`, `build_yard`, `bundle`, `command`, `noop`, `push_gh_pages`,
1091
+ `release_gem`, `release_github`, and `tool`. For more information, see the
1092
+ section [build step types](#build-step-types).
1093
+
1094
+ * **run**: *boolean* (optional) --
1095
+ Whether to force this step to run. Typically, build steps will run only if
1096
+ the build type determines that it should run, or if the step is a dependency
1097
+ of another step that will run. You can, however, force a step to run that
1098
+ would otherwise not do so by setting this key to *true*.
1099
+
1100
+ * **inputs**: *array of [InputConfig](#step-input-configuration)* (optional) --
1101
+ Inputs to this step, indicating dependencies on other steps and files to copy
1102
+ from those steps' outputs.
1103
+
1104
+ * **outputs**: *array of [OutputConfig](#step-output-configuration)* (optional) --
1105
+ Files to copy to this step's output so they become available to other steps.
1106
+
1107
+ #### Step input configuration
1108
+
1109
+ A step input represents a dependency on another step: if this (depending) step
1110
+ is run, that other (dependent) step will also be run. It also describes files
1111
+ that should be copied from the dependent step's output and made available to
1112
+ the depending step. This configuration is a dictionary with the following keys:
1113
+
1114
+ * **collisions**: *string* (optional) --
1115
+ A symbolic value indicating what to do if a collision occurs between incoming
1116
+ and existing files. Possible values are:
1117
+
1118
+ * `error`: (the default) Abort with an error
1119
+ * `keep`: Keep the existing file
1120
+ * `replace`: Replace the existing file with the incoming file
1121
+
1122
+ * **dest**: *string or false* (optional) --
1123
+ A symbolic value indicating where to copy the dependent step's output to.
1124
+ Possible values are:
1125
+
1126
+ * `component`: (the default) Copy files to the component directory
1127
+ * `repo_root`: Copy files to the repository root
1128
+ * `output`: Copy files to this step's output directory
1129
+ * `temp`: Copy files to this step's temp directory
1130
+ * `none`: Do not copy any files, but just declare a dependency
1131
+
1132
+ * **dest_path**: *string* (optional) --
1133
+ The path in the destination to copy to. If **source_path** is provided,
1134
+ **dest_path** is the corresponding path in the destination. If **source_path**
1135
+ is not provided, **dest_path** is a directory into which the source contents
1136
+ are copied. If **dest_path** is not provided, it defaults to the effective
1137
+ value of **source_path**, i.e. things are copied into the same locations
1138
+ within the destination as they were in the source.
1139
+
1140
+ * **name**: *string* (required) --
1141
+ The name of the step to depend on. The dependent step must be located earlier
1142
+ in the pipeline than the depending step.
1143
+
1144
+ * **source_path**: *string* (optional) --
1145
+ The path of the file or directory to copy from the source output. Only this
1146
+ item (recursively, if a directory) is copied. If this key is not provided,
1147
+ *all* contents of the source output are copied (e.g. the default is
1148
+ effectively "`.`")
1149
+
1150
+ #### Step output configuration
1151
+
1152
+ A step output represents files automatically copied to the step's output
1153
+ directory after the step runs. This configuration is a dictionary supporting
1154
+ the following keys:
1155
+
1156
+ * **collisions**: *string* (optional) --
1157
+ A symbolic value indicating what to do if a collision occurs between incoming
1158
+ and existing files. Possible values are:
1159
+
1160
+ * `error`: (the default) Abort with an error
1161
+ * `keep`: Keep the existing file
1162
+ * `replace`: Replace the existing file with the incoming file
1163
+
1164
+ * **dest_path**: *string* (optional) --
1165
+ The path in the output directory to copy to. If **source_path** is provided,
1166
+ **dest_path** is the corresponding path in the output. If **source_path** is
1167
+ not provided, **dest_path** is a directory into which the source contents are
1168
+ copied. If **dest_path** is not provided, it defaults to the effective value
1169
+ of **source_path**, i.e. things are copied into the same locations within the
1170
+ output as they were in the source.
1171
+
1172
+ * **source**: *string* (optional) --
1173
+ A symbolic value indicating where to copy from. Possible values are:
1174
+
1175
+ * `component`: (the default) Copy files from the component directory
1176
+ * `repo_root`: Copy files from the repository root
1177
+ * `temp`: Copy files from this step's temp directory
1178
+
1179
+ * **source_path**: *string* (optional) --
1180
+ The path of the file or directory to copy from the source. Only this item
1181
+ (recursively, if a directory) is copied. If this key is not provided, *all*
1182
+ contents of the source are copied (e.g. the default is effectively "`.`")
1183
+
1184
+ #### Build step types
1185
+
1186
+ This is a list of the available build step types, including their behavior and
1187
+ any additional configuration keys supported by each.
1188
+
1189
+ * **build_gem** -- A step that builds a gem package.
1190
+
1191
+ This step builds the gem described by the properly named gemspec file for
1192
+ this component. The built package file is copied to this step's output. Other
1193
+ steps (such as **release_gem**) can declare it as an input to get access to
1194
+ the built package. This step does not run unless it is declared as an input
1195
+ dependency, or unless it is requested explicitly using the **run**
1196
+ configuration.
1197
+
1198
+ * **build_yard** -- A step that builds Yardocs.
1199
+
1200
+ This step builds documentation using [YARD](https://yardoc.org). The built
1201
+ documentation is copied to this step's output in the directory `doc/`. Other
1202
+ steps (such as **push_gh_pages**) can declare it as an input to get access to
1203
+ the built documentation. This step does not run unless it is declared as an
1204
+ input dependency, or unless it is requested explicitly using the **run**
1205
+ configuration.
1206
+
1207
+ This step supports the following additional configuration keys:
1208
+
1209
+ * **bundle_step**: *string* (optional) --
1210
+ The name of the bundle step. Defaults to `bundle`. This is used if the
1211
+ **uses_gems** key is *not* provided.
1212
+
1213
+ * **uses_gems**: *array of (string or array of string)* (optional) --
1214
+ An array of gem specifications, each of which can be a simple gem name or
1215
+ an array including rubygems-style version requirements. These gems are
1216
+ provided to Yard, and can include gems such as `redcarpet` that may be
1217
+ needed for markup handling. If this key is included, the specified gems
1218
+ are installed directly; if not, the bundle step is declared as a
1219
+ dependency instead.
1220
+
1221
+ * **bundle** -- A step that installs the bundle in the component directory.
1222
+
1223
+ This step copies the resulting `Gemfile.lock` to its output. Other steps can
1224
+ declare it as an input to get access to the `Gemfile.lock`. This step
1225
+ does not run unless it is declared as an input dependency, or unless it is
1226
+ requested explicitly using the **run** configuration.
1227
+
1228
+ This step supports the following additional configuration keys:
1229
+
1230
+ * **chdir**: *string* (optional) --
1231
+ Change to the specified directory (relative to the component directory)
1232
+ when installing the bundle. By default, runs in the component directory.
1233
+
1234
+ * **command** -- A step that runs a command in the component directory.
1235
+
1236
+ This step supports the following additional configuration keys:
1237
+
1238
+ * **chdir**: *string* (optional) --
1239
+ Change to the specified directory (relative to the component directory)
1240
+ when running the command. By default, runs in the component directory.
1241
+
1242
+ * **command**: *array of string* (required) --
1243
+ The command to run
1244
+
1245
+ * **continue_on_error**: *boolean* (optional) --
1246
+ If *true*, continue to run the pipeline if the command exits abnormally.
1247
+ If *false* (the default), the pipeline aborts.
1248
+
1249
+ This step does not run unless it is requested explicitly using the **run**
1250
+ configuration, or it is declared as a dependency.
1251
+
1252
+ * **noop** -- A no-op step that does nothing. This type is usually configured
1253
+ with inputs and outputs and is used to collect or consolidate data from other
1254
+ steps.
1255
+
1256
+ This step does not run unless it is requested explicitly using the **run**
1257
+ configuration, or it is declared as a dependency.
1258
+
1259
+ * **push_gh_pages** -- A step that pushes documentation to the gh-pages branch.
1260
+
1261
+ The documentation to publish should be under `doc/` in the output directory
1262
+ of a "source" step, normally the **build_yard** step. This source step is
1263
+ automatically declared as a dependency.
1264
+
1265
+ This step supports the following additional configuration keys:
1266
+
1267
+ * **source**: *string* (optional) --
1268
+ The name of the source step. Defaults to `build_yard`.
1269
+
1270
+ This step runs if gh-pages publishing is enabled in the component.
1271
+
1272
+ * **release_gem** -- A step that pushes a gem package to rubygems.org.
1273
+
1274
+ The package must be provided under `pkg/` in the output directory of a
1275
+ "source" step, normally the **build_gem** step. This source step is
1276
+ automatically declared as a dependency.
1277
+
1278
+ This step supports the following additional configuration keys:
1279
+
1280
+ * **source**: *string* (optional) --
1281
+ The name of the source step. Defaults to `build_gem`.
1282
+
1283
+ This step runs if a correctly-named gemspec file is present in the component
1284
+ directory.
1285
+
1286
+ * **release_github** -- A step that creates a git tag and GitHub release.
1287
+
1288
+ This step always runs if present in the pipeline.
1289
+
1290
+ * **tool** -- A step that runs a Toys tool in the component directory.
1291
+
1292
+ This step supports the following additional configuration keys:
1293
+
1294
+ * **chdir**: *string* (optional) --
1295
+ Change to the specified directory (relative to the component directory)
1296
+ when running the tool. By default, runs in the component directory.
1297
+
1298
+ * **continue_on_error**: *boolean* (optional) --
1299
+ If *true*, continue to run the pipeline if the tool exits abnormally. If
1300
+ *false* (the default), the pipeline aborts.
1301
+
1302
+ * **tool**: *array of string* (required) --
1303
+ The tool to run
1304
+
1305
+ This step does not run unless it is requested explicitly using the **run**
1306
+ configuration, or it is declared as a dependency.
1307
+
1308
+ #### Build step modification
1309
+
1310
+ A build step modification is a dictionary that modifies one or more existing
1311
+ steps in the build pipeline. Its format is a dictionary with the keys described
1312
+ below.
1313
+
1314
+ The **name** and **type** fields filter the steps to modify. If neither is
1315
+ provided, *all* steps are modified.
1316
+
1317
+ * **name**: *string* (optional) --
1318
+ Modify only the step with this unique name.
1319
+
1320
+ * **type**: *string* (optional) --
1321
+ Modify only steps matching this type.
1322
+
1323
+ All other keys represent changes to the configuration of matching steps. You
1324
+ can provide either the *null* value to delete the key, or a new full value for
1325
+ the key. See [build step configuration](#build-step-configuration) and
1326
+ [build step types](#build-step-types) for details on the available keys and
1327
+ their formats.