diff --git a/.github/workflows/_build-image.yml b/.github/workflows/_build-image.yml new file mode 100644 index 0000000..c9bbbe8 --- /dev/null +++ b/.github/workflows/_build-image.yml @@ -0,0 +1,68 @@ +# Reusable workflow that builds and publishes a single service's Docker image +# to ghcr.io. Called by docker.yml (manual workflow_dispatch) and release.yml +# (tag-triggered release pipeline). Filename is prefixed with `_` to mark it +# as internal-use-only — it is not invoked directly by event triggers. +name: Build image + +on: + workflow_call: + inputs: + service: + description: Service name (alerter or indexer) + required: true + type: string + +env: + CARGO_INCREMENTAL: 0 + CARGO_TERM_COLOR: always + +jobs: + build: + name: ${{ inputs.service }} + runs-on: ubuntu-24.04 + permissions: + packages: write + + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 + with: + # Limit concurrency so it can complete with small official runners + buildkitd-config-inline: | + [worker.oci] + max-parallelism = 1 + + - name: Log into registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 + with: + images: | + ghcr.io/${{ github.repository_owner }}/chain-${{ inputs.service }} + tags: | + type=ref,event=tag + type=ref,event=branch + type=sha,format=long + flavor: | + latest=false + suffix= + + - name: Build and push chain-${{ inputs.service }} image + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + with: + file: docker/${{ inputs.service }}.Dockerfile + # TODO: Add linux/amd64/v4 when runner supports it + platforms: linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64 + pull: true + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1d85b9a..c41b149 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,9 +1,12 @@ -# This action builds an alerter container image. +# Manual Docker image build for a chosen service. Use this for one-off +# rebuilds of an image from main outside of the normal tag-triggered release +# flow (release.yml). The actual build steps live in the reusable +# _build-image.yml workflow. # -# Container images are only marked as "latest" in GitHub Container Registry for pushes to `main` and tags (including release tags). +# Container images are only marked as "latest" in GitHub Container Registry +# for pushes to `main` and tags (including release tags). name: Docker build -# This action is triggered for workflow_dispatch. on: workflow_dispatch: inputs: @@ -16,59 +19,10 @@ on: run-name: Docker build for ${{ inputs.service }} -# Incremental compilation here isn't helpful -env: - CARGO_INCREMENTAL: 0 - CARGO_TERM_COLOR: always - jobs: - # This will build container images - docker-build: - name: ${{ inputs.service }} - runs-on: ubuntu-24.04 + build: + uses: ./.github/workflows/_build-image.yml + with: + service: ${{ inputs.service }} permissions: packages: write - - steps: - - name: Set up QEMU - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - with: - # Limit concurrency so it can complete with small official runners - buildkitd-config-inline: | - [worker.oci] - max-parallelism = 1 - - - name: Log into registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ github.token }} - - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 - with: - images: | - ghcr.io/${{ github.repository_owner }}/chain-${{ inputs.service }} - tags: | - type=ref,event=tag - type=ref,event=branch - type=sha,format=long - flavor: | - latest=false - suffix= - - - name: Build and push chain-${{ inputs.service }} image - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 - with: - file: docker/${{ inputs.service }}.Dockerfile - # TODO: Add linux/amd64/v4 when runner supports it - platforms: linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64 - pull: true - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..4382fb3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,65 @@ +# Release pipeline. Fires on a tag push of the form vX.Y.Z, asserts the tag +# matches [workspace.package].version in the root Cargo.toml, builds and +# publishes Docker images for both services to ghcr.io (via the reusable +# _build-image.yml workflow), and creates a draft GitHub release with +# auto-generated notes for human review and publish. +name: Release + +on: + push: + tags: + - 'v*.*.*' + +env: + CARGO_INCREMENTAL: 0 + CARGO_TERM_COLOR: always + +jobs: + verify-version: + name: verify-version + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Assert tag matches [workspace.package].version + env: + TAG: ${{ github.ref_name }} + run: | + set -euo pipefail + expected="v$(awk -F\" '/^\[workspace\.package\]/{w=1} w && /^version[[:space:]]*=/{print $2; exit}' Cargo.toml)" + if [[ "$TAG" != "$expected" ]]; then + echo "::error::tag $TAG does not match Cargo workspace version $expected" >&2 + exit 1 + fi + echo "tag $TAG matches Cargo workspace version" + + build-images: + needs: verify-version + strategy: + fail-fast: false + matrix: + service: [alerter, indexer] + uses: ./.github/workflows/_build-image.yml + with: + service: ${{ matrix.service }} + permissions: + packages: write + + create-release: + name: create-release + needs: build-images + runs-on: ubuntu-24.04 + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Create draft release with auto-generated notes + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + run: gh release create "$TAG" --draft --generate-notes diff --git a/Cargo.lock b/Cargo.lock index 4367967..e824033 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -295,7 +295,7 @@ dependencies = [ [[package]] name = "alerter" -version = "1.1.1" +version = "1.2.0" dependencies = [ "clap", "env_logger", @@ -3217,7 +3217,7 @@ dependencies = [ [[package]] name = "indexer" -version = "0.1.0" +version = "1.2.0" dependencies = [ "actix-cors", "actix-web", @@ -6103,7 +6103,7 @@ dependencies = [ [[package]] name = "shared" -version = "0.1.0" +version = "1.2.0" dependencies = [ "futures-util", "log", diff --git a/Cargo.toml b/Cargo.toml index 84fedaf..fdd4ac2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace.package] +version = "1.2.0" edition = "2024" authors = ["Subspace Labs "] homepage = "https://subspace.network" diff --git a/alerter/Cargo.toml b/alerter/Cargo.toml index 0fa04e9..5e05064 100644 --- a/alerter/Cargo.toml +++ b/alerter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "alerter" -version = "1.1.1" +version.workspace = true edition.workspace = true authors.workspace = true homepage.workspace = true diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml index 3483b25..033c304 100644 --- a/indexer/Cargo.toml +++ b/indexer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "indexer" -version = "0.1.0" +version.workspace = true edition.workspace = true authors.workspace = true homepage.workspace = true diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 33cded8..786a533 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shared" -version = "0.1.0" +version.workspace = true edition.workspace = true authors.workspace = true homepage.workspace = true