|
| 1 | +# Workflow |
| 2 | + |
| 3 | +The current workflow definition has many shortcomings when looking at the future. There are numerous features that can't be addressed by the current design including: branch specific jobs, detached jobs/workflows, rollback, initial job definition, etc. |
| 4 | + |
| 5 | +This documentation covers a design proposal for a revised workflow/screwdriver.yaml configuration. |
| 6 | + |
| 7 | +## Syntax |
| 8 | + |
| 9 | +### Determining order |
| 10 | + |
| 11 | +| Job attribute | Description | |
| 12 | +| ---------- | ------------- | |
| 13 | +| `requires: ~pr` | Triggered by a pull request | |
| 14 | +| `requires: ~commit` | Triggered by a commit | |
| 15 | +| `requires: ~commit:staging` | Triggered by a commit on the `staging` SCM branch only | |
| 16 | +| `requires: [A]` __OR__ `requires: A` | Triggered if `A` is successful (_aka. sequential_); should be okay to drop the `[]` if it is a single job | |
| 17 | +| `requires: [A,B,C]` | Triggered after `A`, `B`, and `C` are successful. (_aka. join_) | |
| 18 | + |
| 19 | +_Note: If no `requires` is designated, the job is ignored._ |
| 20 | + |
| 21 | +### Special features |
| 22 | + |
| 23 | +| Job annotation | Description | |
| 24 | +| ---------- | ------------- | |
| 25 | +| `rebuild_on: [A, sd@123:staging]` | Rebuild if `A` or `sd@123:staging` job is rerun successfully | |
| 26 | +| `blocked_by: [A, sd@123:staging]` | Blocked if `A` or `sd@123:staging` job is running | |
| 27 | +| `build_periodically: H 4 * * *` | Build periodically ([CRON FORMAT][cron-format]) | |
| 28 | +| `freeze_windows: [‘* * ? * MON,FRI’]` | Freeze Windows. Do not run the job during this time. ([CRON FORMAT][cron-format]) | |
| 29 | + |
| 30 | + |
| 31 | +## Functionality |
| 32 | + |
| 33 | +### Sequential |
| 34 | + |
| 35 | + |
| 36 | + |
| 37 | +When a commit is merged, build A starts. When build A finishes successfully, build B starts. When build B finishes successfully, build C starts. |
| 38 | + |
| 39 | +```yaml |
| 40 | +jobs: |
| 41 | + A: |
| 42 | + requires: ~commit |
| 43 | + B: |
| 44 | + requires: A |
| 45 | + C: |
| 46 | + requires: B |
| 47 | +``` |
| 48 | +
|
| 49 | +### Join |
| 50 | +
|
| 51 | + |
| 52 | +
|
| 53 | +When a commit is merged, build A starts. When build A finishes successfully, build B and build C start. When build B and build C both finish successfully, build D starts. |
| 54 | +
|
| 55 | +```yaml |
| 56 | +jobs: |
| 57 | + A: |
| 58 | + requires: ~commit |
| 59 | + B: |
| 60 | + requires: A |
| 61 | + C: |
| 62 | + requires: A |
| 63 | + D: |
| 64 | + requires: [B,C] |
| 65 | +``` |
| 66 | +
|
| 67 | +_Note: `requires` will work like an AND; all jobs listed under the `requires` keyword need to finish building successfully before the job will run._ |
| 68 | + |
| 69 | + |
| 70 | + |
| 71 | +### Pull request |
| 72 | + |
| 73 | +To specify a chain of jobs to run when a pull request is opened, use the `requires: ~pr` job attribute. If no job is specified for the pull request build, the `requires: ~commit` job will be run. |
| 74 | + |
| 75 | +```yaml |
| 76 | +jobs: |
| 77 | + A: |
| 78 | + requires: ~pr |
| 79 | + B: |
| 80 | + requires: A |
| 81 | +``` |
| 82 | + |
| 83 | +### SCM Branch-specific jobs |
| 84 | + |
| 85 | +Use a regex filter after `~commit:` to denote a job only run when code changes are made to branches matching that pattern (eg: `/^staging$/`, `/^user-.*$/`). |
| 86 | + |
| 87 | +```yaml |
| 88 | +jobs: |
| 89 | + A: |
| 90 | + requires: ~commit:staging |
| 91 | + B: |
| 92 | + requires: ~commit:user-.* |
| 93 | +``` |
| 94 | + |
| 95 | + |
| 96 | +### Blocked_by |
| 97 | + |
| 98 | +If job C or D are running, do not run job A. |
| 99 | + |
| 100 | +```yaml |
| 101 | +jobs: |
| 102 | + A: |
| 103 | + requires: ~commit |
| 104 | + annotations: |
| 105 | + blocked_by: [C, D] |
| 106 | +``` |
| 107 | + |
| 108 | +Similar logic to [jobLock](https://github.com/taskrabbit/node-resque/blob/master/lib/plugins/jobLock.js#L30-L38). |
| 109 | + |
| 110 | +If job A is blocked_by job C and job D: |
| 111 | +- In the before_perform hook, keeps polling job C & D every x seconds |
| 112 | +- If both are not done, reEnqueue job A |
| 113 | +- If both are done, return |
| 114 | + |
| 115 | +_Note: `blocked_by` is an OR; if any of the jobs listed under `blocked_by` is running, then it is blocked._ |
| 116 | + |
| 117 | +### Rebuild_on |
| 118 | + |
| 119 | +If job C or D finishes running successfully, rerun job A. |
| 120 | + |
| 121 | +```yaml |
| 122 | +jobs: |
| 123 | + A: |
| 124 | + requires: ~commit |
| 125 | + annotations: |
| 126 | + rebuild_on: [C, D] |
| 127 | +``` |
| 128 | + |
| 129 | +_Note: Rebuild_on is an OR. If any of the jobs listed under `rebuild_on` finishes running successfully, then the job is rerun._ |
| 130 | + |
| 131 | +### Freeze Windows |
| 132 | + |
| 133 | +Jobs will not start except during a user configured time period. Jobs will be queued outside of that time period and run when the window is open. |
| 134 | + |
| 135 | +```yaml |
| 136 | +jobs: |
| 137 | + A: |
| 138 | + requires: ~commit |
| 139 | + annotations: |
| 140 | + freeze_windows: |
| 141 | + - "* * ? * MON,FRI" |
| 142 | + - "* 6-17 * * ?" |
| 143 | + - "0-59 1 1 1 ? 2015" |
| 144 | +``` |
| 145 | + |
| 146 | + |
| 147 | + |
| 148 | + |
| 149 | +### Build Periodically |
| 150 | + |
| 151 | +Jobs will run on a user defined schedule. |
| 152 | + |
| 153 | +```yaml |
| 154 | +jobs: |
| 155 | + A: |
| 156 | + requires: ~commit |
| 157 | + annotations: |
| 158 | + build_periodically: H 4 * * * |
| 159 | +``` |
| 160 | + |
| 161 | + |
| 162 | + |
| 163 | + |
| 164 | +### Collapse |
| 165 | + |
| 166 | + |
| 167 | + |
| 168 | +If COMMIT1 is merged, it triggers build A1 to start. If COMMIT2 and COMMIT3 are merged while A1 is still building, their corresponding A builds will be collapsed into one: build A3, which will be put into the queue. Once build A1 has completed, A3 will start. If COMMIT4 is merged while B3 is building, the workflow will be as normal as long as the same jobs don’t run at the same time. If they are, they will be collapsed into the most recent commit event. |
| 169 | + |
| 170 | + |
| 171 | + |
| 172 | +When jobs are run in parallel for a join operation, the joined jobs act as one unit, not triggering the next job until both have successfully completed. Jobs that trigger a parallel join, or are triggered by a parallel join could collapse their triggers. |
| 173 | + |
| 174 | + |
| 175 | + |
| 176 | +If JobD were a very long running task, it could also collapse multiple sets of join event results, just like JobA can collapse incoming commit triggers. |
| 177 | + |
| 178 | +### Detached Jobs |
| 179 | + |
| 180 | + |
| 181 | + |
| 182 | +Detached jobs are standalone jobs, or are not automatically triggered by commits. This gets into a realm of multiple distinct workflows, and is not yet well-defined. See also Build Periodically for an example UML. |
| 183 | + |
| 184 | +In this example, A is triggered by a commit. Job B is a detached job. Job C will run when job B finishes successfully. |
| 185 | + |
| 186 | +```yaml |
| 187 | +jobs: |
| 188 | + A: |
| 189 | + requires: ~commit |
| 190 | + B |
| 191 | + C: |
| 192 | + requires: B |
| 193 | +``` |
| 194 | + |
| 195 | +_Note: Jobs that do not have the `requires` keyword are by default detached jobs._ |
| 196 | + |
| 197 | +### Matrix Jobs |
| 198 | + |
| 199 | +Matrix jobs will work very similar to join/parallel builds. |
| 200 | + |
| 201 | + |
| 202 | + |
| 203 | +## Contributing |
| 204 | + |
| 205 | +If you make changes to the architecture, please be sure to update this document. To update any architecture diagrams rendered from `.puml` files, just run `npm run diagrams` (you will need to have [graphviz](http://graphviz.org/) installed locally). To update diagrams generated from `.wsd` files use [web sequence diagrams](https://www.websequencediagrams.com/). |
| 206 | + |
| 207 | +## Resources |
| 208 | + |
| 209 | +- [Workflow issue](https://github.com/screwdriver-cd/screwdriver/issues/654) |
| 210 | +- [Circleci workflows](http://circleci.com/docs/2.0/workflows) |
| 211 | +- [Concourse workflows](http://concourse.ci/pipelines.html) |
| 212 | +- [Queue design doc (to keep implementation in mind)](https://github.com/screwdriver-cd/screwdriver/blob/master/design/queue.md) |
| 213 | + |
| 214 | +[cron-format]: http://www.nncron.ru/help/EN/working/cron-format.htm |
0 commit comments