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
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ jobs:
- uses: nurdsoft/ci-workflows/actions/build@v2
with:
run: <your build command> # or rely on `make build`
output: artifact
output: cache
cache-key: build-${{ github.sha }}-${{ github.run_id }}

deploy:
needs: [build]
Expand All @@ -70,11 +71,19 @@ jobs:
- uses: nurdsoft/ci-workflows/actions/deploy@v2
with:
run: <your deploy command> # or rely on `make deploy`
download-artifact: "true"
restore-cache: "true"
cache-key: build-${{ github.sha }}-${{ github.run_id }}
gcp-wif-provider: ${{ secrets.WIF_PROVIDER }}
gcp-service-account: ${{ secrets.SERVICE_ACCOUNT }}
```

The build output is handed to deploy through the Actions cache: `build` saves
`build-output-path` under `cache-key`, and `deploy` restores it. Pass the same
**run-unique** `cache-key` to both (include `github.run_id` so re-runs and
concurrent runs don't collide). The restore is an exact-key match and fails the
deploy on a miss, so an evicted or missing cache surfaces as a loud failure
rather than a silent empty deploy.

**App pipeline — Docker + Cloud Run (release, build, deploy)**

Activated by passing `image-name` to `build` and `cloudrun-service` to `deploy`. The static-build and static-deploy steps are skipped automatically — existing callers are unaffected.
Expand Down
37 changes: 21 additions & 16 deletions actions/build/action.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
name: Build
description: >-
Produce a deployable artifact. Runs `run` if given, otherwise `<runner> build`
Produce a deployable build. Runs `run` if given, otherwise `<runner> build`
(default make) -- so no Makefile is required when `run` is supplied. Optionally
prepares a Node/Expo toolchain and authenticates to a cloud (for registry
pushes performed by the build command). Can upload the output as an artifact.
pushes performed by the build command). Can hand the output to the deploy job
via the Actions cache (output: cache).

Cache handoff: output: cache saves the build output under a caller-supplied
cache-key. The key must be unique per run (e.g. include github.run_id) and
match the deploy side; deploy restores it with an exact-key lookup and fails on
a miss, so a cache eviction surfaces as a loud failure rather than a silent
empty deploy.

Docker path: when `image-name` is set the action switches to a Docker build+push
flow -- authenticates via WIF, optionally fetches build-time env vars from Secret
Expand Down Expand Up @@ -45,21 +52,20 @@ inputs:
required: false
default: ""
output:
description: "Artifact handling: artifact | none."
description: "Output handling: cache | none."
required: false
default: none
artifact-name:
description: Name of the uploaded artifact (when output is artifact).
required: false
default: build-output
build-output-path:
description: Directory uploaded as the artifact.
description: Directory saved to the cache (when output is cache).
required: false
default: out
artifact-retention-days:
description: Artifact retention.
cache-key:
description: >-
Cache key for the build output when output is cache. Must be unique per
run (e.g. include github.sha and github.run_id) and match the deploy
side's cache-key. Required when output is cache.
required: false
default: "7"
default: ""

# -- Shared cloud auth inputs -----------------------------------------------
gcp-wif-provider:
Expand Down Expand Up @@ -171,13 +177,12 @@ runs:
$RUNNER build ENV="$ENV"
fi

- name: Upload artifact
if: inputs.output == 'artifact' && inputs.image-name == '' && inputs.ghcr-image == ''
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- name: Save build cache
if: inputs.output == 'cache' && inputs.image-name == '' && inputs.ghcr-image == ''
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
name: ${{ inputs.artifact-name }}
path: ${{ inputs.build-output-path }}
retention-days: ${{ inputs.artifact-retention-days }}
key: ${{ inputs.cache-key }}

# -- Docker build path -----------------------------------------------------
- name: Configure Docker for Artifact Registry (build path)
Expand Down
51 changes: 36 additions & 15 deletions actions/deploy/action.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
name: Deploy
description: >-
Ship the build. Runs `run` if given, otherwise `<runner> deploy` (default make)
-- no Makefile required when `run` is supplied. Optionally downloads a build
artifact, prepares a Node/Expo toolchain, and authenticates to a cloud.
-- no Makefile required when `run` is supplied. Optionally restores the build
output from the Actions cache (restore-cache), prepares a Node/Expo toolchain,
and authenticates to a cloud.

Cache restore: restore-cache pairs with the build action's output: cache. It
restores build-output-path using an exact cache-key match and fails the deploy
on a cache miss, so an evicted or missing cache never results in a silent empty
deploy. cache-key must match the build side.

Cloud Run service path: when `cloudrun-service` is set the action switches to a
Cloud Run service deploy flow -- authenticates via WIF, optionally fetches runtime
Expand Down Expand Up @@ -35,18 +41,23 @@ inputs:
description: Expo token, forwarded to setup for EAS submit/update.
required: false
default: ""
download-artifact:
description: Download a build artifact before deploying.
required: false
default: "false"
artifact-name:
description: Artifact to download.
required: false
default: build-output
build-output-path:
description: Local path the artifact is unpacked to.
description: Local path the cache is restored to.
required: false
default: out
restore-cache:
description: >-
Restore the build output from the Actions cache before deploying.
Fails the deploy on a cache miss.
required: false
default: "false"
cache-key:
description: >-
Cache key to restore the build output from when restore-cache is true.
Restored with an exact-key match and must equal the build side's cache-key;
a miss fails the deploy. Required when restore-cache is true.
required: false
default: ""

# -- Shared cloud auth inputs -----------------------------------------------
gcp-wif-provider:
Expand Down Expand Up @@ -130,12 +141,22 @@ runs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

# -- Static path -----------------------------------------------------------
- name: Download artifact
if: inputs.download-artifact == 'true' && inputs.cloudrun-service == '' && inputs.cloudrun-job == ''
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- name: Restore build cache
id: restore-cache
if: inputs.restore-cache == 'true' && inputs.cloudrun-service == '' && inputs.cloudrun-job == ''
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
name: ${{ inputs.artifact-name }}
path: ${{ inputs.build-output-path }}
key: ${{ inputs.cache-key }}

- name: Fail on build cache miss
if: inputs.restore-cache == 'true' && inputs.cloudrun-service == '' && inputs.cloudrun-job == '' && steps.restore-cache.outputs.cache-hit != 'true'
shell: bash
env:
CACHE_KEY: ${{ inputs.cache-key }}
run: |
echo "ERROR: build cache '$CACHE_KEY' not found — refusing to deploy a missing build." >&2
exit 1

- name: Setup toolchain
if: inputs.node-version != '' && inputs.cloudrun-service == '' && inputs.cloudrun-job == ''
Expand Down