11name : test-release
22
3- # This workflow creates a GitHub Release when a tag is pushed and builds/distributes:
4- # - Multi-architecture (x86_64 + aarch64) Linux Docker images and binary tarballs
5- # - A universal (fat) macOS binary (combining aarch64 + x86_64) packaged as a tarball
6- # - Multi-arch container manifest referencing per-arch images
7- #
8- # Key notes / caveats:
9- # - Tag filter currently uses a regex-like pattern string ("v[0-9]+.[0-9]+.[0-9]+") but GitHub interprets these as globs, not regex.
10- # This pattern will literally match tags containing brackets/plus signs only if such tags are pushed. Consider replacing with 'v*.*.*'.
11- # - Additional explicit tag 'test' triggers a non-latest release (see Create Release step logic).
12- # - Runner label 'ubuntu-24.04-arm' may not exist in GitHub-hosted runners at all times; verify actual available ARM labels.
13- # - Docker images are only tagged as latest-<arch>; version-specific per-arch tags are not produced (manifest step synthesizes version tag from those latest-* tags).
14- # - Release creation is not idempotent on reruns (gh release create fails if release already exists). Consider guarding or using 'gh release view || gh release edit'.
15- # - Using nightly Rust on macOS; unless nightly features are required, stable may improve reproducibility.
16- # - No build caching is configured (Cargo + Docker) which could lengthen CI times.
17- # - Security hardening (e.g., minimal permissions, SBOM, provenance attestations) could be added in future.
18- # - File now contains verbose comments for clarity; functional YAML content unchanged.
3+ # Simplified test workflow: builds per-arch Docker images (GHCR + Docker Hub org),
4+ # packages Linux and macOS artifacts, and creates multi-arch manifests – only for tag 'test'.
195
206on :
217 push :
228 tags :
23- - test # Special test tag to exercise the pipeline without marking release as latest.
9+ - test
2410
25- permissions : {} # Explicitly sets default job permissions to none (principle of least privilege). Each job grants what it needs.
11+ permissions : {}
2612
2713env :
28- CARGO_TERM_COLOR : always # Ensures colored Cargo output in logs.
29- RELEASE_BIN : mira-oxide # Canonical binary name used across packaging steps.
30- REGISTRY : ghcr.io # Container registry host (GitHub Container Registry).
31- DOCKERHUB_ORG : cdcgov # Docker Hub org/team namespace
32- # Docker Hub credentials expected: DOCKERHUB_USERNAME / DOCKERHUB_TOKEN
14+ CARGO_TERM_COLOR : always
15+ RELEASE_BIN : mira-oxide
16+ REGISTRY : ghcr.io
17+ DOCKERHUB_ORG : cdcgov
3318
3419jobs :
35- create-release :
36- name : Create New Release
37- runs-on : ubuntu-latest # Standard Linux runner for release orchestration.
38- permissions :
39- contents : write # Required to create a GitHub Release and upload assets.
40- outputs :
41- upload_url : ${{ steps.create_release.outputs.upload_url }} # (Currently unused downstream; could remove if not consumed.)
42- steps :
43- - uses : actions/checkout@v4 # Fetch repository code to access changelog script and metadata.
44-
45- - name : Extract Changelog
46- id : extract_changelog
47- shell : bash
48- run : perl .github/scripts/last_release_notes.pl > $RUNNER_TEMP/release_notes.md # Generates notes for this release.
49-
50- - name : Create Release
51- id : create_release
52- if : startsWith(github.ref_name, 'v') # Only create a release for version tags, skip entirely for 'test'.
53- shell : bash
54- run : |
55- # Create the GitHub Release using GitHub CLI. Fails if release with same tag already exists.
56- gh release create "${{ github.ref_name }}" \
57- --title "${RELEASE_BIN} ${{ github.ref_name }}" \
58- --notes-file "$RUNNER_TEMP/release_notes.md"
59- env :
60- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} # GitHub-provided token with contents:write permission.
61-
6220 build-release-image-and-linux-artifacts :
6321 name : Build Linux Artifacts and Images
64- needs : [create-release] # Ensures the release exists before uploading assets.
6522 strategy :
6623 matrix :
6724 include :
6825 - arch : x86_64
69- runner : ubuntu-latest # Standard x86_64 runner.
26+ runner : ubuntu-latest
7027 - arch : aarch64
71- runner : ubuntu-24.04-arm # Intended ARM64 runner label (verify availability; may differ, e.g., ubuntu-22.04-arm64).
72- runs-on : ${{ matrix.runner }} # Dynamically select runner based on matrix entry.
28+ runner : ubuntu-24.04-arm
29+ runs-on : ${{ matrix.runner }}
7330 permissions :
74- contents : write # Needed to upload release assets.
75- packages : write # Needed to push images to GHCR.
31+ contents : read
32+ packages : write
7633 steps :
77- - uses : actions/checkout@v4 # Source code for Docker build context.
34+ - uses : actions/checkout@v4
7835
7936 - name : Log in to GHCR
8037 uses : docker/login-action@v3
8138 with :
82- registry : ${{ env.REGISTRY }} # ghcr.io
83- username : ${{ github.actor }} # Actor initiating the workflow (token auth is sufficient).
84- password : ${{ secrets.GITHUB_TOKEN }} # Token automatically scoped to repo; sufficient for GHCR push.
39+ registry : ${{ env.REGISTRY }}
40+ username : ${{ github.actor }}
41+ password : ${{ secrets.GITHUB_TOKEN }}
8542
8643 - name : Log in to Docker Hub
8744 uses : docker/login-action@v3
@@ -97,107 +54,53 @@ jobs:
9754 ${{ env.REGISTRY }}/${{ github.repository }}
9855 docker.io/${{ env.DOCKERHUB_ORG }}/mira-oxide
9956 tags : |
100- type=raw,value=latest-${{ matrix.arch }},enable=${{ startsWith(github.ref_name, 'v') }}
101- type=raw,value=${{ github.ref_name }}-${{ matrix.arch }},enable=${{ startsWith(github.ref_name, 'v') }}
102- type=raw,value=test-${{ matrix.arch }},enable=${{ github.ref_name == 'test' }}
103-
104- - name : Debug Git ref
105- run : |
106- # Helpful diagnostic output to confirm tag context and repository naming.
107- echo "GITHUB_REF: $GITHUB_REF"
108- echo "GITHUB_REF_NAME: $GITHUB_REF_NAME"
109- echo "GITHUB_SHA: $GITHUB_SHA"
110- echo "GITHUB_REPOSITORY: $GITHUB_REPOSITORY"
57+ type=raw,value=test-${{ matrix.arch }}
11158
11259 - name : Build and push Docker image
11360 uses : docker/build-push-action@v6
11461 with :
115- file : Dockerfile # Uses repository Dockerfile at root.
116- context : . # Full repo as build context.
117- push : true # Push images to registry.
118- tags : ${{ steps.meta.outputs.tags }} # Tag list from metadata action (only latest-arch currently).
119- # Potential enhancements: buildx cache-from/to for faster rebuilds; provenance/SBOM generation.
62+ file : Dockerfile
63+ context : .
64+ push : true
65+ tags : ${{ steps.meta.outputs.tags }}
12066
12167 - name : Prepare Linux Binary
12268 shell : bash
12369 run : |
124- # Pull the just-built image tag matching this architecture and extract the compiled binary from /app.
12570 IMAGE_TAG=$(echo "${{ steps.meta.outputs.tags }}" | grep -- '-${{ matrix.arch }}$' | head -n 1)
12671 docker create --name temp-container $IMAGE_TAG \
127- && docker cp temp-container:/app/${RELEASE_BIN} ./${RELEASE_BIN} \
128- && docker rm temp-container
129-
130- # If this is a version tag (v*), append the version to the binary filename inside the archive.
131- if [[ "${GITHUB_REF_NAME}" == v* ]]; then
132- mv "${RELEASE_BIN}" "${RELEASE_BIN}-${GITHUB_REF_NAME}"
133- BIN_NAME="${RELEASE_BIN}-${GITHUB_REF_NAME}"
134- else
135- BIN_NAME="${RELEASE_BIN}"
136- fi
137-
138- tar -czf ${RELEASE_BIN}-linux-${{ matrix.arch }}-${{ github.ref_name }}.tar.gz "$BIN_NAME"
139-
140- - name : Upload Linux Release Asset
141- if : startsWith(github.ref_name, 'v') # Only upload to a GitHub Release for version tags.
142- shell : bash
143- run : |
144- # Upload architecture-specific Linux binary tarball to the existing GitHub Release.
145- gh release upload "${{ github.ref_name }}" ${RELEASE_BIN}-linux-${{ matrix.arch }}-${{ github.ref_name }}.tar.gz
146- env :
147- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
72+ && docker cp temp-container:/app/${RELEASE_BIN} ./${RELEASE_BIN} \
73+ && docker rm temp-container
74+ tar -czf ${RELEASE_BIN}-linux-${{ matrix.arch }}-test.tar.gz ${RELEASE_BIN}
14875
14976 - name : Upload Linux Test Artifact
150- if : github.ref_name == 'test' # For test tag, store as workflow artifact instead of release asset.
15177 uses : actions/upload-artifact@v4
15278 with :
15379 name : ${{ env.RELEASE_BIN }}-linux-${{ matrix.arch }}-test
154- path : ${{ env.RELEASE_BIN }}-linux-${{ matrix.arch }}-${{ github.ref_name }} .tar.gz
80+ path : ${{ env.RELEASE_BIN }}-linux-${{ matrix.arch }}-test .tar.gz
15581
15682 create-image-manifest :
15783 name : Create Image Manifest
158- needs : build-release-image-and-linux-artifacts # Wait until both arch images are pushed.
84+ needs : build-release-image-and-linux-artifacts
15985 runs-on : ubuntu-latest
16086 permissions :
161- packages : write # Required to push multi-arch manifests.
162- contents : read # Minimal read (not strictly required here, but harmless).
87+ packages : write
88+ contents : read
16389 steps :
16490 - name : Log in to GHCR
16591 uses : docker/login-action@v3
16692 with :
16793 registry : ${{ env.REGISTRY }}
16894 username : ${{ github.actor }}
169- password : ${{ secrets.GITHUB_TOKEN }} # Token automatically scoped to repo; sufficient for GHCR push.
95+ password : ${{ secrets.GITHUB_TOKEN }}
17096
17197 - name : Log in to Docker Hub
17298 uses : docker/login-action@v3
17399 with :
174100 username : ${{ secrets.DOCKERHUB_USERNAME }}
175101 password : ${{ secrets.DOCKERHUB_TOKEN }}
176102
177- - name : Create and push manifests (version tags)
178- if : startsWith(github.ref_name, 'v')
179- shell : bash
180- run : |
181- REPO=$(echo "${{ env.REGISTRY }}/${{ github.repository }}" | tr '[A-Z]' '[a-z]')
182- VERSION=${REPO}:${{ github.ref_name }}
183- LATEST=${REPO}:latest
184- docker manifest create $VERSION --amend ${VERSION}-x86_64 --amend ${VERSION}-aarch64 || \
185- docker manifest create $VERSION --amend ${LATEST}-x86_64 --amend ${LATEST}-aarch64
186- docker manifest push $VERSION
187- docker manifest create $LATEST --amend ${LATEST}-x86_64 --amend ${LATEST}-aarch64
188- docker manifest push $LATEST
189-
190- DH_REPO="docker.io/${{ env.DOCKERHUB_ORG }}/mira-oxide"
191- DH_VERSION=${DH_REPO}:${{ github.ref_name }}
192- DH_LATEST=${DH_REPO}:latest
193- docker manifest create $DH_VERSION --amend ${DH_VERSION}-x86_64 --amend ${DH_VERSION}-aarch64 || \
194- docker manifest create $DH_VERSION --amend ${DH_LATEST}-x86_64 --amend ${DH_LATEST}-aarch64
195- docker manifest push $DH_VERSION
196- docker manifest create $DH_LATEST --amend ${DH_LATEST}-x86_64 --amend ${DH_LATEST}-aarch64
197- docker manifest push $DH_LATEST
198-
199- - name : Create and push manifests (test tag)
200- if : github.ref_name == 'test'
103+ - name : Create and push test manifests
201104 shell : bash
202105 run : |
203106 REPO=$(echo "${{ env.REGISTRY }}/${{ github.repository }}" | tr '[A-Z]' '[a-z]')
@@ -212,57 +115,32 @@ jobs:
212115
213116 build-mac-artifacts :
214117 name : Build Mac Artifacts
215- needs : create-release # Independent of Linux build path; both upload assets to same release.
216118 runs-on : macos-latest
217-
218119 permissions :
219- contents : write # Needed for asset upload.
220-
120+ contents : read
221121 steps :
222- - uses : actions/checkout@v4 # Fetch code.
122+ - uses : actions/checkout@v4
223123
224- - name : Install latest nightly Rust
124+ - name : Install Rust
225125 run : |
226- # Nightly toolchain installation; replace with stable if not using nightly-only features.
227- rustup update nightly
228- rustup default nightly
126+ rustup update stable
127+ rustup default stable
229128 rustup target add aarch64-apple-darwin x86_64-apple-darwin
230129
231- - name : Build
130+ - name : Build (both archs)
232131 run : |
233- # Compile both target architectures in release mode.
234- cargo build --release --target aarch64-apple-darwin --target x86_64-apple-darwin
235-
236- - name : Package Binary
237- shell : bash
238- run : |
239- # Combine the two architecture-specific binaries into one universal (fat) binary via lipo.
240- lipo -create -output ${{ env.RELEASE_BIN }} \
241- target/aarch64-apple-darwin/release/${{ env.RELEASE_BIN }} \
242- target/x86_64-apple-darwin/release/${{ env.RELEASE_BIN }}
243-
244- # Rename binary to include version if tag is v*
245- if [[ "${GITHUB_REF_NAME}" == v* ]]; then
246- mv "${{ env.RELEASE_BIN }}" "${{ env.RELEASE_BIN }}-${GITHUB_REF_NAME}"
247- MAC_BIN="${{ env.RELEASE_BIN }}-${GITHUB_REF_NAME}"
248- else
249- MAC_BIN="${{ env.RELEASE_BIN }}"
250- fi
251-
252- tar -czf ${{ env.RELEASE_BIN }}-apple-universal-${{ github.ref_name }}.tar.gz "$MAC_BIN"
132+ cargo build --release --target aarch64-apple-darwin --target x86_64-apple-darwin
253133
254- - name : Upload Release Asset
255- if : startsWith(github.ref_name, 'v') # Only upload to release for version tags.
134+ - name : Create universal binary
256135 shell : bash
257136 run : |
258- # Upload macOS universal binary tarball (wildcard allows potential accompanying files; could be made explicit).
259- gh release upload "${{ github.ref_name }}" ${{ env.RELEASE_BIN }} -apple-universal-${{ github.ref_name }}.*
260- env :
261- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN } }
137+ lipo -create -output ${RELEASE_BIN} \
138+ target/aarch64 -apple-darwin/release/${RELEASE_BIN} \
139+ target/x86_64-apple-darwin/release/${RELEASE_BIN}
140+ tar -czf ${RELEASE_BIN}-apple-universal-test.tar.gz ${RELEASE_BIN }
262141
263142 - name : Upload Mac Test Artifact
264- if : github.ref_name == 'test'
265143 uses : actions/upload-artifact@v4
266144 with :
267145 name : ${{ env.RELEASE_BIN }}-apple-universal-test
268- path : ${{ env.RELEASE_BIN }}-apple-universal-${{ github.ref_name }} .tar.gz
146+ path : ${{ env.RELEASE_BIN }}-apple-universal-test .tar.gz
0 commit comments