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
15 changes: 15 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "restricted",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": [],
"privatePackages": {
"version": true,
"tag": true
}
}
18 changes: 18 additions & 0 deletions .changeset/initial-major-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
"@kethalia/workflows": major
---

Initial 1.0.0 release of the org-wide reusable workflows and composite actions.

Stabilizes the public surface so consumer repos can pin to `@v1`:

- `ci-build-lint-test.yml` β€” install/build/lint/format/typecheck/test matrix with coverage reporting and per-tool incremental caches.
- `ci-quality.yml` β€” changeset gate, pnpm audit, and optional `verify-command`, `sherif-command`, `knip-command`, `madge-command` hooks.
- `ci-changeset-check.yml`, `ci-publish-validation.yml` β€” standalone changeset gate and pkg-pr-new preview publishing.
- `release-changesets.yml` β€” versioning + npm publish with `published` / `published-packages` outputs.
- `build-stack.yml`, `build-and-push.yml`, `publish-docker-ghcr.yml`, `release-docker-stack.yml` β€” Docker build/publish flows with buildcache.
- `retag-stack.yml`, `retag-image.yml`, `verify-ghcr-tags.yml`, `ghcr-prune.yml` β€” release-time GHCR promotion, preflight verification, retention.
- `helm-lint.yml`, `resolve-runner.yml` β€” Helm linting and dynamic runner-label resolution.
- `actions/setup-pnpm`, `actions/build-and-upload` β€” composite actions for pnpm bootstrap and image build/upload.

Internal cross-references between workflows and composite actions are now version-pinned (rewritten by `scripts/sync-workflow-refs.mjs` during `changeset version`) so a release at `vX.Y.Z` references its own actions at `@vX.Y.Z`.
81 changes: 81 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Release

on:
push:
branches: [main]

permissions:
contents: write
pull-requests: write
id-token: write

jobs:
release:
name: Changesets
runs-on: ubuntu-latest
outputs:
published: ${{ steps.changesets.outputs.published }}
publishedPackages: ${{ steps.changesets.outputs.publishedPackages }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: pnpm/action-setup@v4
with:
version: 9.15.0

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- run: pnpm install --frozen-lockfile
Comment thread
b00ste marked this conversation as resolved.

- name: Changesets
id: changesets
uses: changesets/action@v1
with:
version: pnpm run version
publish: pnpm changeset tag
title: "chore(release): version packages"
commit: "chore(release): version packages"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

tag-major:
name: Move floating major tag
needs: release
if: needs.release.outputs.published == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Move v{major} and v{major}.{minor} tags
env:
PUBLISHED: ${{ needs.release.outputs.publishedPackages }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
VERSION="$(echo "$PUBLISHED" | jq -r '.[0].version')"
if [ -z "$VERSION" ] || [ "$VERSION" = "null" ]; then
echo "No version found in publishedPackages output; skipping."
exit 0
fi
MAJOR="v${VERSION%%.*}"
REST="${VERSION#*.}"
MINOR="${MAJOR}.${REST%%.*}"
echo "Tagging $MAJOR and $MINOR at $SHA"
# Capture the current remote tag SHAs (empty if the tag does not yet exist)
# so --force-with-lease only overwrites what we expect.
MAJOR_OLD="$(git ls-remote --tags origin "refs/tags/$MAJOR" | awk '{print $1}')"
MINOR_OLD="$(git ls-remote --tags origin "refs/tags/$MINOR" | awk '{print $1}')"
git tag -f "$MAJOR" "$SHA"
git tag -f "$MINOR" "$SHA"
git push --force-with-lease="refs/tags/$MAJOR:$MAJOR_OLD" origin "refs/tags/$MAJOR"
git push --force-with-lease="refs/tags/$MINOR:$MINOR_OLD" origin "refs/tags/$MINOR"
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ See also: [.github/docs/RUNNER-TIERING.md](.github/docs/RUNNER-TIERING.md) for t
## Table of Contents

- [Consumer-side alias pattern](#consumer-side-alias-pattern)
- [Versioning](#versioning)
- [Workflows](#workflows)
- [Reusable β€” Build and push Docker image to GHCR](#reusable--build-and-push-docker-image-to-ghcr) β€” `build-and-push.yml`
- [Reusable β€” Build stack of Docker images](#reusable--build-stack-of-docker-images) β€” `build-stack.yml`
Expand Down Expand Up @@ -43,6 +44,23 @@ jobs:

When the migration to `@v1` happens, you change the `uses:` line in this wrapper from `@main` to `@v1` and every workflow run in that repo picks up the pinned tag β€” no edits to caller jobs, no PR sprawl.

## Versioning

Releases are cut by [Changesets](https://github.com/changesets/changesets). On push to `main`, `release.yml` opens (or updates) a `chore(release): version packages` PR. Merging that PR:

1. Bumps `package.json`, regenerates `CHANGELOG.md`, and runs `scripts/sync-workflow-refs.mjs` so every internal `uses: kethalia/workflows/...@<ref>` cross-reference in this repo is rewritten to the new `@vX.Y.Z`. The released tag therefore references its own actions and workflows at the same version β€” no `@main` drift inside a release.
2. Creates the immutable `vX.Y.Z` tag.
3. The `tag-major` job force-moves the floating `vX` and `vX.Y` tags to the same SHA so consumers can pin to `@v1` or `@v1.0` and still receive non-breaking updates.

**Pinning recommendations for consumers:**

- `@vX.Y.Z` (e.g. `@v1.0.0`) β€” fully reproducible. Recommended for production callers.
- `@vX.Y` (e.g. `@v1.0`) β€” receives patch fixes automatically; no minor or major drift.
- `@vX` (e.g. `@v1`) β€” receives all non-breaking changes.
- `@main` β€” **not** a true "latest HEAD" snapshot. Because internal `uses:` refs are pinned by the version PR, `main` references the *previous* release's actions until the next release PR rewrites them. Use only for testing unreleased changes, and expect cross-workflow refs on `main` to lag behind HEAD.

Breaking changes ship as a new major (`v2`, `v3`, ...) and are announced via the Changesets release notes before merging.

## Workflows

### Reusable β€” Build and push Docker image to GHCR
Expand Down
20 changes: 20 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@kethalia/workflows",
"version": "0.1.0",
"private": true,
"description": "Org-wide reusable GitHub Actions workflows and composite actions shared across kethalia, chillwhales, and phlox-labs.",
"repository": {
"type": "git",
"url": "https://github.com/kethalia/workflows"
},
"license": "MIT",
"packageManager": "pnpm@9.15.0",
"devDependencies": {
"@changesets/cli": "^2.27.10"
},
"scripts": {
"changeset": "changeset",
"version": "changeset version && node scripts/sync-workflow-refs.mjs",
"release": "changeset tag"
}
}
Loading