Skip to content
Open
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
16 changes: 16 additions & 0 deletions .github/actions/ghcr-login/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Log in to the GitHub Container Registry
description: Authenticate Docker-compatible tools to GHCR.
inputs:
token:
description: A GitHub token with package access
required: true
runs:
using: composite
steps:
- name: Log in to the GitHub Container Registry
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
run: >-
printf '%s' "$GH_TOKEN" |
docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin
218 changes: 218 additions & 0 deletions .github/workflows/artifacts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
name: artifacts

on:
workflow_call:
inputs:
build:
description: The calculated release build identity
required: true
type: string

permissions:
contents: read

jobs:
artifacts:
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
actions: read
packages: read
concurrency:
group: artifacts-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
queue: max
env:
DRFED_RELEASE_BUILD: ${{ inputs.build }}
ARTIFACT_NAME: drfed-${{ github.run_id }}
steps:
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- uses: jdx/mise-action@v5.2.6
with:
cache: false
experimental: true
- uses: ./.github/actions/ghcr-login
with:
token: ${{ github.token }}
- name: Find the original verified artifacts from this run
id: original
env:
GH_TOKEN: ${{ github.token }}
run: |
artifact_id=$(gh api --paginate "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/artifacts" --jq '.artifacts[] | select(.name == env.ARTIFACT_NAME and .expired == false) | .id')
if [[ -n "$artifact_id" ]]; then
echo 'reuse=true' >> "$GITHUB_OUTPUT"
else
mise run release:ensure-unpublished
echo 'reuse=false' >> "$GITHUB_OUTPUT"
fi
- uses: actions/download-artifact@v8.0.2
if: steps.original.outputs.reuse == 'true'
with:
name: ${{ env.ARTIFACT_NAME }}
path: release-artifacts
- name: Apply the single calculated registry version before building
run: mise run release:apply
- name: Build the versioned packages
run: mise run build
- name: Pack the complete public package set
if: steps.original.outputs.reuse != 'true'
run: mise run release:pack
- name: Verify artifact identity and installed behavior
run: mise run release:verify && mise run --skip-deps test:packaging --artifacts release-artifacts
- uses: actions/upload-artifact@v7.0.2
if: steps.original.outputs.reuse != 'true'
with:
name: ${{ env.ARTIFACT_NAME }}
path: release-artifacts/
if-no-files-found: error
retention-days: 90
overwrite: false

image:
needs: [artifacts]
timeout-minutes: 45
permissions:
contents: read
actions: read
packages: read
concurrency:
group: image-${{ github.workflow }}-${{ github.ref }}-${{ matrix.arch }}
cancel-in-progress: false
queue: max
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: ubuntu-latest
- arch: arm64
runner: ubuntu-26.04-arm
runs-on: ${{ matrix.runner }}
env:
DRFED_RELEASE_BUILD: ${{ inputs.build }}
ARTIFACT_NAME: drfed-image-${{ github.run_id }}-${{ matrix.arch }}
steps:
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- uses: jdx/mise-action@v5.2.6
with:
cache: false
experimental: true
- uses: ./.github/actions/ghcr-login
with:
token: ${{ github.token }}
# A rerun keeps the layout that was tested first; a rebuild would not
# reproduce its digest. A version already in either registry must not get
# new image bytes.
- name: Find the original image layout from this run
id: original
env:
GH_TOKEN: ${{ github.token }}
run: |
artifact_id=$(gh api --paginate "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/artifacts" --jq '.artifacts[] | select(.name == env.ARTIFACT_NAME and .expired == false) | .id')
if [[ -n "$artifact_id" ]]; then
echo 'reuse=true' >> "$GITHUB_OUTPUT"
else
mise run release:ensure-unpublished
echo 'reuse=false' >> "$GITHUB_OUTPUT"
fi
- uses: actions/download-artifact@v8.0.2
if: steps.original.outputs.reuse != 'true'
with:
name: drfed-${{ github.run_id }}
path: release-artifacts
- name: Verify the package tarballs the image is built from
if: steps.original.outputs.reuse != 'true'
run: mise run release:verify
- uses: ./.github/actions/containerd-image-store
if: steps.original.outputs.reuse != 'true'
- name: Build the image from the verified tarballs
if: steps.original.outputs.reuse != 'true'
run: >-
mise run --skip-deps image:build --engine docker
--artifacts release-artifacts --platform "linux/${{ matrix.arch }}"
# The bytes to be published must also run in Podman.
- uses: ./.github/actions/pasta-apparmor
if: steps.original.outputs.reuse != 'true'
- name: Start the Podman API socket
if: steps.original.outputs.reuse != 'true'
run: systemctl --user start podman.socket
- name: Test the exact image layout with Docker, then Podman
if: steps.original.outputs.reuse != 'true'
run: mise run test:image --require
- uses: actions/upload-artifact@v7.0.2
if: steps.original.outputs.reuse != 'true'
with:
name: ${{ env.ARTIFACT_NAME }}
path: image-artifacts/linux-${{ matrix.arch }}/
if-no-files-found: error
compression-level: 0
retention-days: 90
overwrite: false

image-index:
needs: [artifacts, image]
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
actions: read
concurrency:
group: image-index-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
queue: max
env:
DRFED_RELEASE_BUILD: ${{ inputs.build }}
ARTIFACT_NAME: drfed-image-index-${{ github.run_id }}
steps:
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- uses: jdx/mise-action@v5.2.6
with:
cache: false
experimental: true
- name: Find the original image index from this run
id: original
env:
GH_TOKEN: ${{ github.token }}
run: |
artifact_id=$(gh api --paginate "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/artifacts" --jq '.artifacts[] | select(.name == env.ARTIFACT_NAME and .expired == false) | .id')
if [[ -n "$artifact_id" ]]; then
echo 'reuse=true' >> "$GITHUB_OUTPUT"
else
echo 'reuse=false' >> "$GITHUB_OUTPUT"
fi
- uses: actions/download-artifact@v8.0.2
with:
name: drfed-${{ github.run_id }}
path: release-artifacts
- uses: actions/download-artifact@v8.0.2
with:
name: drfed-image-${{ github.run_id }}-amd64
path: image-artifacts/linux-amd64
- uses: actions/download-artifact@v8.0.2
with:
name: drfed-image-${{ github.run_id }}-arm64
path: image-artifacts/linux-arm64
- uses: actions/download-artifact@v8.0.2
if: steps.original.outputs.reuse == 'true'
with:
name: ${{ env.ARTIFACT_NAME }}
path: image-artifacts/index
- name: Merge the platform images into one OCI image index
run: mise run release:image-index
- uses: actions/upload-artifact@v7.0.2
if: steps.original.outputs.reuse != 'true'
with:
name: ${{ env.ARTIFACT_NAME }}
path: image-artifacts/index/
if-no-files-found: error
compression-level: 0
retention-days: 90
overwrite: false
38 changes: 38 additions & 0 deletions .github/workflows/check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: check

on:
pull_request:
# Validate branch pushes even before a PR exists; PRs also cover forks.
push: # jactionlint ignore=duplicate-triggers
branches: ["**", "!main"]
workflow_call:

permissions:
contents: read

jobs:
check:
timeout-minutes: 30
concurrency:
group: check-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
queue: max
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- uses: jdx/mise-action@v5.2.6
with:
cache: true
experimental: true
log_level: ${{ runner.debug == '1' && 'trace' || 'info' }}
- name: Verify migration history against the PR base
if: github.event_name == 'pull_request'
run: mise run manifest:migrations --base "$MIGRATION_BASE"
env:
MIGRATION_BASE: ${{ github.event.pull_request.base.sha }}
- run: mise build && mise check
env:
MISE_LOG_LEVEL: ${{ runner.debug == '1' && 'trace' || 'info' }}
88 changes: 88 additions & 0 deletions .github/workflows/docs-canary.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: docs-canary

on:
workflow_call:
inputs:
build:
description: The calculated release build identity
required: true
type: string
secrets:
CLOUDFLARE_API_TOKEN:
required: true
CLOUDFLARE_ACCOUNT_ID:
required: true

permissions:
contents: read

jobs:
docs-canary:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
deployments: write
concurrency:
group: docs-canary
cancel-in-progress: false
queue: max
environment:
name: canary-docs
url: ${{ vars.CANARY_DOCS_URL }}
env:
DRFED_RELEASE_BUILD: ${{ inputs.build }}
# Nothing but Node.js and Wrangler is installed, and no step may run
# repository hooks or install anything else: every task runs with
# --no-deps and --skip-tools, so no project dependencies are installed
# either, and the deployment step finds Wrangler already installed.
MISE_NO_HOOKS: "1"
MISE_AUTO_INSTALL: "false"
steps:
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false
# Keep the Wrangler version in sync with the docs:deploy task in
# mise.toml. If they differ, the deployment fails without installing.
- uses: jdx/mise-action@v5.2.6
with:
cache: false
experimental: true
install_args: node npm:wrangler@4.149.0
- name: Stop unless this build is newer than the deployed docs
id: current
run: mise run --no-deps --skip-tools docs:verify-current
env:
GH_TOKEN: ${{ github.token }}
DRFED_DOCS_URL: ${{ vars.CANARY_DOCS_URL }}
# Outside the checkout: wrangler warns about, and records, a dirty tree.
- uses: actions/download-artifact@v8.0.2
if: steps.current.outputs.current == 'true'
with:
name: docs-${{ github.run_id }}
path: ${{ runner.temp }}/docs-dist
- name: Record the intent to deploy this build
id: intent
if: steps.current.outputs.current == 'true'
run: mise run --no-deps --skip-tools docs:record-intent "$RUNNER_TEMP/docs-dist"
env:
GH_TOKEN: ${{ github.token }}
# The task refuses anything that Cloudflare would run as code before it
# runs wrangler. Only this step receives the Cloudflare secrets, and it
# never receives a GitHub token.
- name: Deploy the documentation site to Cloudflare Pages
if: steps.current.outputs.current == 'true'
run: mise run --no-deps --skip-tools docs:deploy "$RUNNER_TEMP/docs-dist"
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_PROJECT_NAME: ${{ vars.CLOUDFLARE_PROJECT_NAME }}
DOCS_BRANCH: main
DOCS_COMMIT: ${{ github.sha }}
- name: Record the successful docs deployment
if: steps.current.outputs.current == 'true'
run: mise run --no-deps --skip-tools docs:record-deployment
env:
GH_TOKEN: ${{ github.token }}
DOCS_DEPLOYMENT_ID: ${{ steps.intent.outputs.deployment }}
DRFED_DOCS_URL: ${{ vars.CANARY_DOCS_URL }}
4 changes: 2 additions & 2 deletions .github/workflows/docs-preview.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: docs-preview
# Read "Pull request previews" in DEPLOY.md before changing this workflow.
on:
workflow_run: # jactionlint ignore=dangerous-triggers
workflows: [main]
workflows: [docs]
types: [completed]

permissions:
Expand All @@ -14,7 +14,7 @@ jobs:
if: >-
github.repository == 'fedify-dev/drfed' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.path == '.github/workflows/main.yaml' &&
github.event.workflow_run.path == '.github/workflows/docs.yaml' &&
github.event.workflow_run.conclusion != 'cancelled'
runs-on: ubuntu-latest
timeout-minutes: 15
Expand Down
Loading
Loading