Repository navigation
feat: shared CI workflows, release automation, Renovate presets and org defaults #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
9ef7dfe
ci: shared reusable workflows for image builds, PR image cleanup and …
sleidig ab5f526
feat(renovate): shared org preset
sleidig 69fd96f
ci(pr-image-cleanup): cancel and wait for unfinished PR builds before…
sleidig bd95c45
docs(renovate): name the options that are concatenated, not replaced
sleidig 31a778b
ci(pr-image-cleanup): serialize per PR instead of per package
sleidig 8a6184f
Merge branch 'feat/renovate-preset' into feat/reusable-workflows
sleidig b62fb20
feat(docker-image): native-runner builds and deletion of replaced images
sleidig 9d347ab
docs(workflows): zizmor ignore comment for the pr-title-lint caller's…
sleidig 2ee376f
feat(release): shared semantic-release workflow for releases and edge…
sleidig 8f88611
feat(image-prune): delete old prerelease images after a full release
sleidig 3236da7
docs: org-wide default issue templates, SECURITY.md and CONTRIBUTING.md
sleidig 8feee81
docs: document release, image-prune, native runners, replaced-image c…
sleidig 749a528
docs(workflows): precise conditions for replaced-image deletion and p…
sleidig 7e0da8f
fix(docker-image): avoid A && B || C for the shellcheck version on th…
sleidig 1d5c2ae
fix(release,docker-image): skip release job off the default branch, s…
sleidig 5d56cde
feat(docker-image): optional BUILD_SECRETS secret forwarded as BuildK…
sleidig b1974b7
simplify issue templates
sleidig b36aa45
refactor(docker-image): replace cleanup-replaced with an untagged swe…
sleidig 594417c
ci: move v1 automatically after each merge and update the actions wit…
sleidig 6482aa7
docs(workflows): merging is the release step, not necessarily a review
sleidig b68b4e3
docs: shorten the workflows README to what callers need
sleidig 66db168
feat: edge builds without prereleases (edge-version.yml), release.yml…
sleidig 2ce5d0a
chore(deps): update cycjimmy/semantic-release-action to v8.1.2
sleidig c581ac3
docs: Renovate presets README in the renovate folder; edge builds hav…
sleidig a011666
refactor(docker-image)!: native runners only, simpler registry login …
sleidig 9f2ded8
refactor!: combine image-prune.yml and pr-image-cleanup.yml into imag…
sleidig 59a775b
refactor(edge-version): always output a plain version, also after `v`…
sleidig File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| --- | ||
| name: Bug report | ||
| about: Report a problem, something that does not work as expected | ||
| title: "" | ||
| labels: "" | ||
| type: "Bug" | ||
| assignees: "" | ||
| --- | ||
|
|
||
| <!-- | ||
| No personal data, credentials, instance names, hostnames or other client-specific details here. | ||
| Scrub logs and screenshots before adding them; link to internal sources (e.g. a Sentry issue) instead. | ||
| Security vulnerabilities: do not open an issue, see SECURITY.md (report them privately). | ||
| --> | ||
|
|
||
|
|
||
| What happens, and what you expected to happen instead. | ||
|
|
||
|
|
||
| ## How to reproduce | ||
|
|
||
| <!-- Steps, request or configuration that triggers it. | ||
| Version (app version or image tag), relevant configuration, (scrubbed) logs or a link to the error in monitoring. --> | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| --- | ||
| name: Feature request | ||
| about: Suggest a new functionality | ||
| title: "" | ||
| labels: "" | ||
| type: "New Feature" | ||
| assignees: "" | ||
| --- | ||
|
|
||
| <!-- | ||
| No personal data, credentials, instance names, hostnames or other client-specific details here. | ||
| Scrub logs and screenshots before adding them; link to internal sources (e.g. a Sentry issue) instead. | ||
| Keep this description short and readable for non-developers. Technical details go into the | ||
| implementation plan comment (see the guidelines at the end of this template). | ||
| --> | ||
|
|
||
| ## What | ||
|
|
||
| <!-- The intended outcome, as observable behaviour: who can do what afterwards? | ||
| e.g. "As an administrator I want to ... in order to ..." | ||
| Also state what is explicitly out of scope. --> | ||
|
|
||
| ## Why | ||
|
|
||
| <!-- The problem or use case behind it, and who is affected (users, administrators, operators). --> | ||
|
|
||
| ## How | ||
|
|
||
| <!-- The proposed approach in a few sentences, and alternatives considered. | ||
| A small table or list helps to compare options. --> | ||
|
|
||
| --- | ||
|
|
||
| Implementation plan: <!-- link to the plan comment, added once the objective is agreed --> | ||
|
|
||
| <!-- | ||
| IMPLEMENTATION PLAN (not part of this description) | ||
|
|
||
| Once the objective above is agreed, post the implementation plan as ONE comment on this issue and | ||
| link it above. It is for the developer or agent implementing the change and must be | ||
| self-contained: someone who reads only that comment and the code can implement it without the | ||
| rest of the discussion. When decisions change, edit that comment in place instead of adding new | ||
| ones; change this description only if the objective changes. | ||
|
|
||
| ## Implementation plan | ||
|
|
||
| ### Context | ||
| The current state, verified against the code: file paths, how it behaves today. Anything assumed | ||
| but not verified is marked as such. | ||
|
|
||
| ### Decisions | ||
| Each decision with its reason and the rejected alternative, including how risks are handled. | ||
|
|
||
| ### Changes | ||
| Concrete steps: files, config keys, snippets where precision matters, then the tests and docs to | ||
| add or change. | ||
|
|
||
| ### Open questions | ||
| What is still undecided and how it gets settled. Omit when there are none. | ||
| --> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| --- | ||
| name: Technical task | ||
| about: A technical improvement, e.g. operations, observability, dependencies, CI or infrastructure | ||
| title: "" | ||
| labels: "" | ||
| type: "Task" | ||
| assignees: "" | ||
| --- | ||
|
|
||
| <!-- | ||
| No personal data, credentials, instance names, hostnames or other client-specific details here. | ||
| Scrub logs and screenshots before adding them; link to internal sources (e.g. a Sentry issue) instead. | ||
| Keep this description short and readable for reviewers. Technical details go into the | ||
| implementation plan comment (see the guidelines at the end of this template). | ||
| For pure refactorings without behaviour change, set the issue type to "Code Quality / Refactoring". | ||
| --> | ||
|
|
||
|
|
||
| - [ ] step 1 | ||
| - [ ] step 2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| # Shared GitHub Actions workflows | ||
|
|
||
| Reusable workflows for all Aam-Digital repositories, so that each repository keeps only what is specific to it. | ||
| Inputs, secrets and outputs are documented in the `workflow_call` section at the top of each file. | ||
|
|
||
| | Workflow | What it does | Typical trigger in the caller | Permissions of the calling job | Check name | | ||
| | --- | --- | --- | --- | --- | | ||
| | [`docker-image.yml`](docker-image.yml) | Builds and pushes a container image (PR, edge, release), each platform on a native runner | `pull_request`, `push`, `release: published` | `contents: read`, `packages: write` | `<job> / build (<platform>)`, `<job> / merge` | | ||
| | [`edge-version.yml`](edge-version.yml) | Computes the version of an edge build (`1.4.1-edge.5`) | `push` to the default branch | `contents: read` | `<job> / version` | | ||
| | [`release.yml`](release.yml) | Creates the next full release with semantic-release | `push` to the default branch, or `workflow_dispatch` | `contents: read` (+ PAT as secret `token`) | `<job> / release` | | ||
| | [`image-cleanup.yml`](image-cleanup.yml) | Deletes the `pr-<n>` image when a PR closes, or the edge images (`tags: "*-edge.*"`) after a full release; then untagged images older than 2 days | `pull_request: closed`, `release: published` | `actions: write`, `packages: write` | `<job> / cleanup` | | ||
| | [`pr-title-lint.yml`](pr-title-lint.yml) | Checks that PR titles follow Conventional Commits | `pull_request_target` | `pull-requests: read` | `<job> / Validate PR title` | | ||
| | [`actionlint.yml`](actionlint.yml) | Lints the repository's workflows (with shellcheck) | `pull_request`, `push` | `contents: read` | `<job> / actionlint` | | ||
|
|
||
| `ci.yml` is this repository's own CI; it is not meant to be called. | ||
|
|
||
| ## Calling a workflow | ||
|
|
||
| ```yaml | ||
| permissions: {} # nothing at the top level; each job grants what it needs | ||
|
|
||
| jobs: | ||
| build: | ||
| uses: Aam-Digital/.github/.github/workflows/docker-image.yml@v1 | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| with: | ||
| images: ghcr.io/aam-digital/my-service | ||
| tags: pr-${{ github.event.number }} | ||
| platforms: linux/amd64 | ||
| ``` | ||
|
|
||
| - Always reference **`@v1`**, never a branch. | ||
| - The calling job must grant the **permissions** from the table. A called workflow cannot get more, and the run fails | ||
| before it starts. `permissions: {}` at the top level keeps `qlty check` (checkov) happy. | ||
| - The caller's **secrets and `env` are not passed on**: pass secrets explicitly under `secrets:`, everything else as | ||
| inputs. | ||
| - **Check names** become `<caller job> / <called job>`. Moving an existing job into a shared workflow renames its | ||
| check, so update the required checks of the ruleset when that PR merges. Skipped jobs (e.g. `merge` when `push` is | ||
| false) count as passed. | ||
| - `pr-title-lint.yml` only works with squash-only merging and the PR title as commit title. Call it on | ||
| `pull_request_target` with the comment `# zizmor: ignore[dangerous-triggers]` on that line, otherwise `qlty check` | ||
| fails. | ||
| - PR images carry only their `pr-<n>` tag (otherwise the cleanup keeps them). PRs from forks build with `push: false`. | ||
|
|
||
| Complete examples: [replication-backend](https://github.com/Aam-Digital/replication-backend/tree/master/.github/workflows) | ||
| (auto release mode, PR images) and [ndb-core](https://github.com/Aam-Digital/ndb-core/tree/master/.github/workflows) | ||
| (manual release mode, two registries, web app built in an earlier job and passed as an artifact). | ||
|
|
||
| ## Release model | ||
|
|
||
| Every push to the default branch builds an **edge** image; full releases come from Conventional Commit PR titles via | ||
| [semantic-release](https://semantic-release.gitbook.io/) (plugins in each repository's own `.releaserc*`). | ||
|
|
||
| - **Edge build:** `edge-version.yml` computes `<last release, patch + 1>-edge.<commits since>`, e.g. `1.4.1-edge.5`. | ||
| The image is tagged with it, but there is no git tag and no GitHub release. Move the `edge` image tag only if | ||
| `is-head` is `true`, and give the image job a `concurrency` group with `cancel-in-progress: true`, so that an older | ||
| run never moves `edge` back. | ||
| - **Full release**, in one of two modes: **auto** (`release.yml` on every push; a `fix`/`feat`/breaking change is | ||
| released right away) or **manual** (`release.yml` via `workflow_dispatch`). Releases are created with a PAT, because | ||
| releases created with the `GITHUB_TOKEN` trigger no workflows. The `release: published` event builds the image, and | ||
| `image-cleanup.yml` then deletes the edge images of the finished cycle. | ||
|
|
||
| | Build | Image tags | | ||
| | --- | --- | | ||
| | push to the default branch | `1.4.1-edge.5`, `edge` | | ||
| | full release `1.4.1` | `1.4.1`, `stable`, `latest` | | ||
| | pull request #123 | `pr-123` | | ||
|
|
||
| Pass `stable: ${{ !github.event.release.prerelease }}` for release images; never derive it from the version string. | ||
|
|
||
| ## Versioning (`v1`) | ||
|
|
||
| There are no releases of this repository. After every push to `main`, CI moves `v1` to the new commit once actionlint | ||
| has passed, so a merged PR (Renovate's included) reaches every repository on its next run. Merging here is the release | ||
| step: check what a change does to the callers before merging. | ||
|
|
||
| A change that breaks callers needs `v2`: set `MAJOR_TAG: v2` in `ci.yml` in the same PR, so that `v1` stays where it | ||
| is, then switch the callers one by one. Breaking means: | ||
|
|
||
| - removing or renaming an input, output or secret, or changing an input's default or meaning; | ||
| - renaming a job id or job `name` (this changes check names); | ||
| - requiring more permissions from the caller; | ||
| - changing which image tags are produced for the same inputs. | ||
|
|
||
| To test a change before merging, point a caller PR at the branch (`@<branch>`), and switch back to `@v1` before | ||
| merging it. In an emergency, `v1` can be reset by hand: | ||
| `gh api -X PATCH repos/Aam-Digital/.github/git/refs/tags/v1 -f sha=<good commit> -F force=true`. | ||
|
|
||
| ## Rules for the workflows here | ||
|
|
||
| - Keep shell inline; never fetch scripts from this repository at runtime. | ||
| - Pass inputs to `run:` scripts via `env:`, never by `${{ }}` interpolation into the script. | ||
| - Actions of large trusted providers (`actions/*`, `docker/*`, `github/*`, …) use their major tag; other actions are | ||
| pinned to a commit SHA with a `# vX.Y.Z` comment. Renovate (`renovate.json` in the repository root) updates both. | ||
| - Steps shared between jobs of one workflow are written once and reused with YAML anchors (`&name` / `*name`). | ||
| - Explain *why* in comments in the workflow file, next to the code; keep this README to what callers need. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # Lints the calling repository's GitHub Actions workflows with actionlint | ||
| # (including shellcheck on `run:` scripts). | ||
| name: actionlint | ||
|
|
||
| on: | ||
| workflow_call: | ||
|
|
||
| jobs: | ||
| # The job id is part of the check name (`<caller job> / actionlint`). Do not rename it within v1. | ||
| actionlint: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: actionlint | ||
| uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2.2.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # CI of this repository: lints the shared workflows themselves and, on `main`, moves the major tag that consumers | ||
| # reference (`@v1`) to the new commit. Every merge to `main` therefore reaches all repositories on their next run. | ||
| name: CI | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: | ||
| - main | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| env: | ||
| # The major tag that follows `main`. For a breaking change (see README.md in .github/workflows), set this to the | ||
| # next major (`v2`) in the same PR: the old tag then stays where it is, and consumers switch one by one. | ||
| MAJOR_TAG: v1 | ||
|
|
||
| jobs: | ||
| # Check name: `actionlint / actionlint` (required by the ruleset of `main`; do not rename) | ||
| actionlint: | ||
| uses: ./.github/workflows/actionlint.yml | ||
|
|
||
| move-major-tag: | ||
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | ||
| needs: actionlint | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write # move the tag | ||
| # Pushes are handled in order, so that an older run never moves the tag back. | ||
| concurrency: | ||
| group: move-major-tag | ||
| cancel-in-progress: false | ||
| steps: | ||
| - name: Move ${{ env.MAJOR_TAG }} to this commit | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: | | ||
| if current=$(gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/$MAJOR_TAG" --jq .object.sha 2>/dev/null); then | ||
| status=$(gh api "repos/$GITHUB_REPOSITORY/compare/$current...$GITHUB_SHA" --jq .status) | ||
| case "$status" in | ||
| identical) | ||
| echo "$MAJOR_TAG already points to $GITHUB_SHA" | ||
| exit 0 | ||
| ;; | ||
| ahead) ;; | ||
| *) | ||
| echo "::warning::$GITHUB_SHA is not ahead of $MAJOR_TAG ($current, compare status '$status'), so the tag is not moved" | ||
| exit 0 | ||
| ;; | ||
| esac | ||
| gh api --silent -X PATCH "repos/$GITHUB_REPOSITORY/git/refs/tags/$MAJOR_TAG" -f sha="$GITHUB_SHA" -F force=true | ||
| echo "Moved $MAJOR_TAG from $current to $GITHUB_SHA" | ||
| else | ||
| gh api --silent -X POST "repos/$GITHUB_REPOSITORY/git/refs" -f ref="refs/tags/$MAJOR_TAG" -f sha="$GITHUB_SHA" | ||
| echo "Created $MAJOR_TAG at $GITHUB_SHA" | ||
| fi |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.