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
29 changes: 29 additions & 0 deletions .github/workflows/binaries.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Binaries

# Reusable. Cross-compiles chisel + spread (via Canonical's
# ubuntu/go:1.25-26.04_edge builder) and fetches the upstream docker
# static CLI for both arches. Uploads cache/binaries/ + the matching
# .stamp/binaries so downstream jobs can short-circuit any rebuild.

on:
workflow_call:

jobs:
build:
runs-on: ubuntu-24.04
timeout-minutes: 30

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Build go binaries (chisel + spread + docker static)
run: make .stamp/binaries

- name: Upload cache/binaries + .stamp/binaries
uses: actions/upload-artifact@v6
with:
name: binaries-cache
path: |
cache/binaries/
.stamp/binaries
45 changes: 45 additions & 0 deletions .github/workflows/build-and-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Build and Test

# Reusable. Per-arch native runner builds all bread / bread-chisel-releases /
# bread-test images for its arch (no qemu, no cross-arch matrix entry per
# runner) and then runs spread-in-spread tests scoped to the same arch.

on:
workflow_call:

jobs:
build-and-test:
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
arch: amd64
- runner: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.runner }}
timeout-minutes: 30

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Restore cached binaries + stamp
uses: actions/download-artifact@v6
with:
name: binaries-cache
path: .

- name: Build images for ${{ matrix.arch }}
run: make build-bread build-bread-chisel-releases build-bread-test ARCH=${{ matrix.arch }}

- name: Install spread (host-side, for invoking the outer)
run: |
sudo apt-get update
sudo apt-get install -y golang-go
go install github.com/canonical/spread/cmd/spread@master
echo "$HOME/go/bin" >> $GITHUB_PATH

- name: Run spread-in-spread tests (${{ matrix.arch }} outer only)
working-directory: tests
run: spread "outer:ubuntu-26.04-${{ matrix.arch }}"
54 changes: 17 additions & 37 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,44 +1,24 @@
name: CI
run-name: CI for ${{ github.ref }}

# Build + test on PR and on push to main. No publishing.

on:
push:
pull_request:
push:
branches:
- main
workflow_dispatch:

jobs:
spread:
name: spread
runs-on: ubuntu-24.04

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker
uses: docker/setup-docker-action@v4

- uses: actions/setup-go@v3
with:
go-version: '>=1.17.0'

- name: Build spread
run: |
git clone \
--depth 1 \
--branch master \
https://github.com/canonical/spread \
_spread
(cd _spread && mkdir -p bin && go build -o bin/spread ./cmd/spread)
ln -s $GITHUB_WORKSPACE/_spread/bin/spread $GITHUB_WORKSPACE/spread
# Cancel in-flight runs on the same ref when a newer one starts.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

- name: Build images
run: |
make build-images
jobs:
binaries:
uses: ./.github/workflows/binaries.yaml

- name: Run spread tests
run: |
./spread -list
./spread

build-and-test:
needs: binaries
uses: ./.github/workflows/build-and-test.yaml
109 changes: 109 additions & 0 deletions .github/workflows/publish-ghcr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: Publish to GHCR

# Reusable. Per-arch native runner builds bread + bread-chisel-releases
# images normally (no qemu, docker driver, loaded into local daemon) and
# `docker save`s each to a docker-archive tarball. Tarballs upload as
# artefacts. A single stitch job downloads both arches' tarballs, builds
# a multiarch manifest list per (flavour, ver) via buildah, and pushes
# each to ghcr.io/<repo>/{bread,bread-chisel-releases}:<ver>.
#
# bread-test is intentionally not published (test-infra-only).

on:
workflow_call:

env:
REGISTRY: ghcr.io

jobs:
build-images:
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
arch: amd64
- runner: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.runner }}
timeout-minutes: 30

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Restore cached binaries + stamp
uses: actions/download-artifact@v6
with:
name: binaries-cache
path: .

- name: Build bread + bread-chisel-releases images for ${{ matrix.arch }}
run: make build-bread build-bread-chisel-releases ARCH=${{ matrix.arch }}

- name: Save images as docker-archive tarballs
run: |
set -e
mkdir -p images-out
for flavour in bread bread-chisel-releases; do
for ver in 24.04 25.10 26.04; do
tag="$flavour:$ver-${{ matrix.arch }}"
echo "==> saving $tag"
docker save "$tag" -o "images-out/$flavour-$ver-${{ matrix.arch }}.tar"
done
done

- name: Upload ${{ matrix.arch }} image tarballs
uses: actions/upload-artifact@v6
with:
name: images-${{ matrix.arch }}
path: images-out/

stitch-and-push:
needs: build-images
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
contents: read
packages: write

steps:
- name: Download amd64 image tarballs
uses: actions/download-artifact@v6
with:
name: images-amd64
path: amd64

- name: Download arm64 image tarballs
uses: actions/download-artifact@v6
with:
name: images-arm64
path: arm64

- name: Install buildah
run: |
sudo apt-get update
sudo apt-get install -y buildah

- name: Login to GHCR
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | \
buildah login --username "${{ github.actor }}" \
--password-stdin "$REGISTRY"

- name: Stitch + push multiarch manifests
run: |
set -e
for flavour in bread bread-chisel-releases; do
for ver in 24.04 25.10 26.04; do
m="$flavour-$ver-manifest"
buildah manifest create "$m"
buildah manifest add --arch amd64 "$m" \
"docker-archive:amd64/$flavour-$ver-amd64.tar"
buildah manifest add --arch arm64 "$m" \
"docker-archive:arm64/$flavour-$ver-arm64.tar"
buildah manifest push --format oci --all "$m" \
"docker://$REGISTRY/${{ github.repository }}/$flavour:$ver"
buildah manifest rm "$m"
done
done
65 changes: 65 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Release
run-name: Release ${{ github.ref_name }}

# Build + test + publish on push of a revision tag (r1, r2, ...).
# Rolling: each new rev tag replaces the previous GitHub release; only
# the latest release survives. ghcr image tags are versioned and stay.

on:
push:
tags:
- 'r[0-9]*'
workflow_dispatch:

jobs:
binaries:
uses: ./.github/workflows/binaries.yaml

build-and-test:
needs: binaries
uses: ./.github/workflows/build-and-test.yaml

publish-ghcr:
needs: [binaries, build-and-test]
uses: ./.github/workflows/publish-ghcr.yaml
permissions:
contents: read
packages: write

publish-release:
needs: [binaries, build-and-test]
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Regenerate inlined yamls
run: make inlined-yaml-files

- name: Delete prior r* releases (keep only this one)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KEEP: ${{ github.ref_name }}
run: |
set -e
gh release list --json tagName --jq '.[].tagName' | \
grep -E '^r[0-9]+$' | \
while read -r t; do
if [ "$t" != "$KEEP" ]; then
echo "Deleting prior release: $t"
gh release delete "$t" --yes --cleanup-tag || true
fi
done

- name: Create release w/ inlined yamls
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
files: inlined/*.yaml
make_latest: true
fail_on_unmatched_files: true
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.spread-worker-lock
.spread-worker-num
.spread-reuse.yaml
.spread-reuse.yaml
.stamp/
cache/
__pycache__/
*.pyc
Loading
Loading