Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ on:
branches: [main]
pull_request:
workflow_dispatch:
# platform.yml runs these first and only applies if they all pass.
workflow_call:

permissions:
contents: read
Expand Down
35 changes: 28 additions & 7 deletions .github/workflows/platform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
# monitoring"). The service playbooks still run from an operator's machine.
#
# pull request -> dry run (--check --diff) against the boxes
# merge to main -> the real run, once approved in the `production`
# merge to main -> the repo checks (ci.yml), then, only if they all pass,
# the real run, once approved in the `production`
# environment (required reviewers)
# manual -> either, optionally limited to some boxes
# manual -> either, optionally limited to some boxes; apply also
# waits for the checks
#
# Pull requests from forks get no secrets and are skipped.
name: platform
Expand Down Expand Up @@ -50,23 +52,34 @@ on:
permissions:
contents: read

# One run at a time against the boxes; never cancel one half-way.
concurrency:
group: platform
cancel-in-progress: false

env:
# ansible.cfg sets the yaml callback, which no installed collection provides
# here (see ci.yml).
ANSIBLE_STDOUT_CALLBACK: default
ANSIBLE_FORCE_COLOR: "true"

jobs:
# The same checks as ci.yml (lint, syntax, manifests, generated files,
# shellcheck), for this commit. The apply needs them, so a commit that fails
# them is never offered for approval. They run a second time on a merge,
# alongside ci.yml's own run: jobs cannot wait on another workflow.
checks:
if: >-
(github.event_name == 'push') ||
(github.event_name == 'workflow_dispatch' && inputs.mode == 'apply')
uses: ./.github/workflows/ci.yml

check:
if: >-
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) ||
(github.event_name == 'workflow_dispatch' && inputs.mode == 'check')
runs-on: ubuntu-latest
# A newer push to the same branch replaces its dry run. Kept apart from the
# apply's group: GitHub keeps one pending run per group, so a shared group
# let a pull request's dry run cancel an apply waiting for approval.
concurrency:
group: platform-check-${{ github.ref }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -88,10 +101,18 @@ jobs:
run: scripts/ci-platform.sh check "$LIMIT"

apply:
needs: checks
# No status function here, so GitHub adds success(): every job of the
# checks must have passed.
if: >-
(github.event_name == 'push') ||
(github.event_name == 'workflow_dispatch' && inputs.mode == 'apply')
runs-on: ubuntu-latest
# One apply at a time, never cancelled half-way. A newer merge waiting
# behind it replaces an older one still waiting: the latest main wins.
concurrency:
group: platform-apply
cancel-in-progress: false
# Required reviewers: nothing reaches the boxes until one approves.
environment: production
steps:
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1451,8 +1451,8 @@ does; the others still run from an operator's machine:
| When | What |
|---|---|
| Pull request touching it | `--check --diff` against the boxes (forks get no secrets and are skipped) |
| Merge to `main` | the real run, once a required reviewer approves it in the `production` environment |
| Actions → platform → Run workflow | `check` or `apply`, optionally `--limit`ed |
| Merge to `main` | the repo checks (`ci.yml`) for that commit, then, only if they all pass, the real run, once a required reviewer approves it in the `production` environment |
| Actions → platform → Run workflow | `check` or `apply` (apply also waits for the checks), optionally `--limit`ed |

It restarts nothing that serves traffic, so it runs every box in one batch: the
hub registers the others using what they produced earlier in the same run.
Expand Down Expand Up @@ -1528,7 +1528,8 @@ same path a deploy takes), so what is checked is what would be applied:
| `shellcheck scripts/*.sh` | the usual shell traps |

`platform.yml` also has its own workflow, which does talk to the boxes (see
"Argo CD and monitoring").
"Argo CD and monitoring"). It calls this one (`ci.yml` is also a reusable
workflow) and only applies once every job here has passed.

The Cloudflare range check is a separate weekly workflow rather than part of
this one, because it reaches `api.cloudflare.com`: an outage there should not
Expand Down
Loading