diff --git a/.github/actions/bump-manifest-image/README.md b/.github/actions/bump-manifest-image/README.md new file mode 100644 index 0000000..85f346d --- /dev/null +++ b/.github/actions/bump-manifest-image/README.md @@ -0,0 +1,99 @@ +# Bump manifest image + +Opens a pull request that bumps a container's image tag in a Kubernetes +deployment manifest, for a single environment. Domain-agnostic — the caller +supplies the manifest path, container name, image repo, and tag. It is +semver-aware (never downgrades), skips pre-releases for `prod`, and can enable +auto-merge on the PR it opens. Call it from a matrix over environments to fan a +single release out to staging and prod. + +## Inputs + + + +| INPUT | TYPE | REQUIRED | DEFAULT | DESCRIPTION | +|----------------|--------|----------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| auto-merge | string | false | `"false"` | Enable GitHub auto-merge (squash) on the
opened PR. | +| base-branch | string | false | `"main"` | Base branch for the PR. | +| container-name | string | true | | Name of the container whose image
tag is tracked. | +| environment | string | true | | Target environment. "prod" skips pre-release tags. | +| image-repo | string | true | | Image repo without tag (e.g. ghcr.io/loft-sh/revops-events-api). | +| manifest-path | string | true | | Path to the deployment manifest to
edit. | +| tag | string | true | | Release tag to roll out (e.g. v0.2.0 or 0.2.0-rc1). | +| token | string | true | | PAT used to open the PR
and (if enabled) enable auto-merge. Must be
a PAT or App token, not
GITHUB_TOKEN: a GITHUB_TOKEN merge emits no
events, so downstream merge-triggered workflows would
never run. | + + + +## Outputs + + + +| OUTPUT | TYPE | DESCRIPTION | +|---------------------|--------|----------------------------------------------------------------------| +| pull-request-number | string | Number of the opened PR (empty when no update). | +| updated | string | true when a PR was opened
(a newer applicable version existed). | + + + +## Usage + +```yaml +on: + repository_dispatch: + types: [update-my-app-version] + workflow_dispatch: + inputs: + tag: + description: 'Image tag to roll out (e.g. v0.2.0)' + required: true + +jobs: + bump: + runs-on: ubuntu-latest + strategy: + matrix: + environment: [staging, prod] + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: loft-sh/github-actions/.github/actions/bump-manifest-image@bump-manifest-image/v1 + with: + tag: ${{ github.event.client_payload.tag || inputs.tag }} + environment: ${{ matrix.environment }} + manifest-path: kubernetes/manifests/${{ matrix.environment }}/my-app/deployment.yaml + container-name: my-app + image-repo: ghcr.io/loft-sh/my-app + auto-merge: ${{ matrix.environment == 'staging' }} + token: ${{ secrets.GH_ACCESS_TOKEN }} +``` + +### Auth + +`token` must be a Personal Access Token or GitHub App token (not +`GITHUB_TOKEN`). It opens the PR and, when `auto-merge` is enabled, performs +the merge. A merge performed with `GITHUB_TOKEN` emits no events, so any +downstream merge-triggered workflow (for example a deploy notification) would +never run. + +### Behaviour + +- **Semver-aware** — the PR is only opened when `tag` is strictly newer than + the tag currently in the manifest. Equal or older versions are a no-op. +- **Prod safety** — pre-release tags (anything that is not a bare `X.Y.Z`) are + skipped when `environment` is `prod`. +- **PR shape** — title and branch are derived from the image repo's last path + segment, e.g. `chore(my-app): bump staging to v0.2.0` on branch + `update-staging-my-app-0.2.0`. + +## Testing + +```bash +make test-bump-manifest-image +``` + +Runs the bats suites in `test/` against the `src/` scripts. `yq` must be on +`PATH` (pre-installed on GitHub hosted runners). diff --git a/.github/actions/bump-manifest-image/action.yml b/.github/actions/bump-manifest-image/action.yml new file mode 100644 index 0000000..032793a --- /dev/null +++ b/.github/actions/bump-manifest-image/action.yml @@ -0,0 +1,112 @@ +name: Bump manifest image +description: | + Opens a pull request that bumps a container's image tag in a Kubernetes + deployment manifest, for a single environment. Domain-agnostic: the caller + supplies the manifest path, container name, image repo, and tag. Skips + pre-releases for prod, never downgrades (semver-aware), and optionally + enables auto-merge. Designed to be called from a matrix over environments. +inputs: + tag: + description: 'Release tag to roll out (e.g. v0.2.0 or 0.2.0-rc1).' + required: true + environment: + description: 'Target environment. "prod" skips pre-release tags.' + required: true + manifest-path: + description: 'Path to the deployment manifest to edit.' + required: true + container-name: + description: 'Name of the container whose image tag is tracked.' + required: true + image-repo: + description: 'Image repo without tag (e.g. ghcr.io/loft-sh/revops-events-api).' + required: true + auto-merge: + description: 'Enable GitHub auto-merge (squash) on the opened PR.' + required: false + default: 'false' + base-branch: + description: 'Base branch for the PR.' + required: false + default: 'main' + token: + description: | + PAT used to open the PR and (if enabled) enable auto-merge. Must be a PAT + or App token, not GITHUB_TOKEN: a GITHUB_TOKEN merge emits no events, so + downstream merge-triggered workflows would never run. + required: true +outputs: + updated: + description: 'true when a PR was opened (a newer applicable version existed).' + value: ${{ steps.decide.outputs.should_update }} + pull-request-number: + description: 'Number of the opened PR (empty when no update).' + value: ${{ steps.pr.outputs.pull-request-number }} +runs: + using: composite + steps: + - name: Resolve version + id: resolve + shell: bash + env: + RAW_TAG: ${{ inputs.tag }} + IMAGE_REPO: ${{ inputs.image-repo }} + run: ${{ github.action_path }}/src/resolve-version.sh + + - name: Decide whether to update + id: decide + shell: bash + env: + MANIFEST_PATH: ${{ inputs.manifest-path }} + CONTAINER_NAME: ${{ inputs.container-name }} + NEW_VERSION: ${{ steps.resolve.outputs.new_version }} + IS_STABLE: ${{ steps.resolve.outputs.is_stable }} + ENVIRONMENT: ${{ inputs.environment }} + run: ${{ github.action_path }}/src/should-update.sh + + - name: Apply image bump + if: steps.decide.outputs.should_update == 'true' + shell: bash + env: + MANIFEST_PATH: ${{ inputs.manifest-path }} + CONTAINER_NAME: ${{ inputs.container-name }} + IMAGE_REPO: ${{ inputs.image-repo }} + NEW_TAG: ${{ steps.resolve.outputs.new_tag }} + run: ${{ github.action_path }}/src/apply-bump.sh + + - name: Create pull request + id: pr + if: steps.decide.outputs.should_update == 'true' + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 + with: + token: ${{ inputs.token }} + base: ${{ inputs.base-branch }} + committer: Loft Bot + commit-message: "chore(${{ steps.resolve.outputs.app_name }}): bump ${{ inputs.environment }} to ${{ steps.resolve.outputs.new_tag }}" + title: "chore(${{ steps.resolve.outputs.app_name }}): bump ${{ inputs.environment }} to ${{ steps.resolve.outputs.new_tag }}" + body: | + Automated image bump. + + - Environment: `${{ inputs.environment }}` + - Image: `${{ inputs.image-repo }}:${{ steps.resolve.outputs.new_tag }}` + - Manifest: `${{ inputs.manifest-path }}` + + Opened by the `bump-manifest-image` action. + branch: "update-${{ inputs.environment }}-${{ steps.resolve.outputs.app_name }}-${{ steps.resolve.outputs.new_version }}" + delete-branch: true + + - name: Enable auto-merge + if: steps.decide.outputs.should_update == 'true' && inputs.auto-merge == 'true' && steps.pr.outputs.pull-request-number + shell: bash + env: + # PAT, not GITHUB_TOKEN: the merge event must trigger downstream workflows. + GH_TOKEN: ${{ inputs.token }} + PR_NUMBER: ${{ steps.pr.outputs.pull-request-number }} + run: gh pr merge "$PR_NUMBER" --squash --auto + + - name: Summary + shell: bash + env: + ENVIRONMENT: ${{ inputs.environment }} + REASON: ${{ steps.decide.outputs.reason }} + run: echo "$ENVIRONMENT - $REASON" diff --git a/.github/actions/bump-manifest-image/src/apply-bump.sh b/.github/actions/bump-manifest-image/src/apply-bump.sh new file mode 100755 index 0000000..b5aafa8 --- /dev/null +++ b/.github/actions/bump-manifest-image/src/apply-bump.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Rewrites the tracked container's image tag in the manifest, in place. +# +# Inputs (env): +# MANIFEST_PATH Path to the deployment manifest. +# CONTAINER_NAME Container whose image is rewritten. +# IMAGE_REPO Image repo without tag (e.g. ghcr.io/loft-sh/app). +# NEW_TAG Tag to pin (leading v preserved). +set -euo pipefail + +: "${MANIFEST_PATH:?MANIFEST_PATH is required}" +: "${CONTAINER_NAME:?CONTAINER_NAME is required}" +: "${IMAGE_REPO:?IMAGE_REPO is required}" +: "${NEW_TAG:?NEW_TAG is required}" + +export NEW_IMAGE="${IMAGE_REPO}:${NEW_TAG}" +export CN="$CONTAINER_NAME" + +yq eval \ + '(.spec.template.spec.containers[] | select(.name == env(CN)) | .image) = env(NEW_IMAGE)' \ + -i "$MANIFEST_PATH" + +echo "set ${CONTAINER_NAME} image to ${NEW_IMAGE} in ${MANIFEST_PATH}" diff --git a/.github/actions/bump-manifest-image/src/resolve-version.sh b/.github/actions/bump-manifest-image/src/resolve-version.sh new file mode 100755 index 0000000..b8deb4d --- /dev/null +++ b/.github/actions/bump-manifest-image/src/resolve-version.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Normalises a release tag and derives the bits the downstream steps need. +# +# Inputs (env): +# RAW_TAG Release tag as received (e.g. v0.2.0 or 0.2.0-rc1). +# IMAGE_REPO Full image repo (e.g. ghcr.io/loft-sh/revops-events-api). +# Outputs ($GITHUB_OUTPUT): +# new_tag The tag verbatim, leading v preserved (image tags keep it). +# new_version Tag with any leading v stripped (for semver comparison). +# is_stable true when new_version is a bare X.Y.Z (no pre-release suffix). +# app_name Last path segment of IMAGE_REPO (used in PR title/branch). +set -euo pipefail + +: "${RAW_TAG:?RAW_TAG is required}" +: "${IMAGE_REPO:?IMAGE_REPO is required}" + +new_tag="$RAW_TAG" +new_version="${new_tag#v}" + +if [[ "$new_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + is_stable=true +else + is_stable=false +fi + +app_name="${IMAGE_REPO##*/}" + +{ + echo "new_tag=${new_tag}" + echo "new_version=${new_version}" + echo "is_stable=${is_stable}" + echo "app_name=${app_name}" +} >> "$GITHUB_OUTPUT" diff --git a/.github/actions/bump-manifest-image/src/should-update.sh b/.github/actions/bump-manifest-image/src/should-update.sh new file mode 100755 index 0000000..724328e --- /dev/null +++ b/.github/actions/bump-manifest-image/src/should-update.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# Decides whether the target manifest should be bumped to NEW_VERSION. +# +# Inputs (env): +# MANIFEST_PATH Path to the deployment manifest. +# CONTAINER_NAME Container whose image tag is tracked. +# NEW_VERSION Incoming version, v-stripped (e.g. 0.2.0). +# IS_STABLE true|false — whether NEW_VERSION is a stable release. +# ENVIRONMENT Target environment (prod skips pre-releases). +# Outputs ($GITHUB_OUTPUT): +# should_update true when a newer, applicable version warrants a PR. +# current_tag Existing image tag found in the manifest (empty if none). +# reason Human-readable explanation for the decision. +set -euo pipefail + +: "${MANIFEST_PATH:?MANIFEST_PATH is required}" +: "${CONTAINER_NAME:?CONTAINER_NAME is required}" +: "${NEW_VERSION:?NEW_VERSION is required}" +: "${IS_STABLE:?IS_STABLE is required}" +: "${ENVIRONMENT:?ENVIRONMENT is required}" + +emit() { + { + echo "should_update=$1" + echo "current_tag=${2:-}" + echo "reason=$3" + } >> "$GITHUB_OUTPUT" + echo "$3" +} + +if [ ! -f "$MANIFEST_PATH" ]; then + emit false "" "manifest not found at ${MANIFEST_PATH}" + exit 0 +fi + +# Prod never tracks pre-releases. +if [ "$ENVIRONMENT" = "prod" ] && [ "$IS_STABLE" != "true" ]; then + emit false "" "pre-release skipped for prod" + exit 0 +fi + +current_image=$(CN="$CONTAINER_NAME" yq eval \ + '.spec.template.spec.containers[] | select(.name == env(CN)) | .image' \ + "$MANIFEST_PATH") +if [ -z "$current_image" ] || [ "$current_image" = "null" ]; then + emit false "" "container ${CONTAINER_NAME} not found in ${MANIFEST_PATH}" + exit 0 +fi + +current_tag="${current_image##*:}" +current_version="${current_tag#v}" + +# Greater-than test via version sort. Equal returns false (no churn). +verlt() { + [ "$1" != "$2" ] && [ "$1" = "$(printf '%s\n%s' "$1" "$2" | sort -V | head -n1)" ] +} + +if [ "$NEW_VERSION" = "$current_version" ]; then + emit false "$current_tag" "already at ${current_tag}" +elif verlt "$current_version" "$NEW_VERSION"; then + emit true "$current_tag" "newer than ${current_tag}, will bump" +else + emit false "$current_tag" "${NEW_VERSION} is not newer than ${current_tag}" +fi diff --git a/.github/actions/bump-manifest-image/test/apply-bump.bats b/.github/actions/bump-manifest-image/test/apply-bump.bats new file mode 100644 index 0000000..fafdf3f --- /dev/null +++ b/.github/actions/bump-manifest-image/test/apply-bump.bats @@ -0,0 +1,35 @@ +#!/usr/bin/env bats +# Coverage for apply-bump.sh: rewrites only the target container's tag. + +SCRIPT="$BATS_TEST_DIRNAME/../src/apply-bump.sh" +FIXTURE="$BATS_TEST_DIRNAME/fixtures/deployment.yaml" + +setup() { MANIFEST="$(mktemp)"; cp "$FIXTURE" "$MANIFEST"; } +teardown() { rm -f "$MANIFEST"; } + +image_of() { + CN="$1" yq eval '.spec.template.spec.containers[] | select(.name == env(CN)) | .image' "$MANIFEST" +} + +@test "rewrites the tracked container image" { + run env \ + MANIFEST_PATH="$MANIFEST" CONTAINER_NAME=revops-events-api \ + IMAGE_REPO=ghcr.io/loft-sh/revops-events-api NEW_TAG=v0.2.0 "$SCRIPT" + [ "$status" -eq 0 ] + [ "$(image_of revops-events-api)" = "ghcr.io/loft-sh/revops-events-api:v0.2.0" ] +} + +@test "leaves other containers untouched" { + run env \ + MANIFEST_PATH="$MANIFEST" CONTAINER_NAME=revops-events-api \ + IMAGE_REPO=ghcr.io/loft-sh/revops-events-api NEW_TAG=v0.2.0 "$SCRIPT" + [ "$status" -eq 0 ] + [ "$(image_of sidecar)" = "ghcr.io/loft-sh/sidecar:v9.9.9" ] +} + +@test "missing NEW_TAG fails" { + run env \ + MANIFEST_PATH="$MANIFEST" CONTAINER_NAME=revops-events-api \ + IMAGE_REPO=ghcr.io/loft-sh/revops-events-api "$SCRIPT" + [ "$status" -ne 0 ] +} diff --git a/.github/actions/bump-manifest-image/test/fixtures/deployment.yaml b/.github/actions/bump-manifest-image/test/fixtures/deployment.yaml new file mode 100644 index 0000000..2b836f5 --- /dev/null +++ b/.github/actions/bump-manifest-image/test/fixtures/deployment.yaml @@ -0,0 +1,12 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: revops-events-api +spec: + template: + spec: + containers: + - name: revops-events-api + image: ghcr.io/loft-sh/revops-events-api:v0.1.0 + - name: sidecar + image: ghcr.io/loft-sh/sidecar:v9.9.9 diff --git a/.github/actions/bump-manifest-image/test/resolve-version.bats b/.github/actions/bump-manifest-image/test/resolve-version.bats new file mode 100644 index 0000000..a9e0ace --- /dev/null +++ b/.github/actions/bump-manifest-image/test/resolve-version.bats @@ -0,0 +1,46 @@ +#!/usr/bin/env bats +# Coverage for resolve-version.sh: tag normalisation, stability, app name. + +SCRIPT="$BATS_TEST_DIRNAME/../src/resolve-version.sh" + +setup() { export GITHUB_OUTPUT; GITHUB_OUTPUT="$(mktemp)"; } +teardown() { rm -f "$GITHUB_OUTPUT"; } + +run_script() { + run env RAW_TAG="$1" IMAGE_REPO="$2" GITHUB_OUTPUT="$GITHUB_OUTPUT" "$SCRIPT" +} + +assert_kv() { + local want="$1=$2" actual + actual=$(grep "^$1=" "$GITHUB_OUTPUT" | tail -n1) + [ "$actual" = "$want" ] || { echo "want: $want"; echo "got: $actual"; cat "$GITHUB_OUTPUT"; return 1; } +} + +@test "v-prefixed stable tag" { + run_script 'v0.2.0' 'ghcr.io/loft-sh/revops-events-api' + [ "$status" -eq 0 ] + assert_kv new_tag v0.2.0 + assert_kv new_version 0.2.0 + assert_kv is_stable true + assert_kv app_name revops-events-api +} + +@test "bare stable tag (no v)" { + run_script '1.4.2' 'ghcr.io/loft-sh/app' + [ "$status" -eq 0 ] + assert_kv new_tag 1.4.2 + assert_kv new_version 1.4.2 + assert_kv is_stable true +} + +@test "pre-release tag is not stable" { + run_script 'v1.0.0-rc1' 'ghcr.io/loft-sh/app' + [ "$status" -eq 0 ] + assert_kv is_stable false + assert_kv new_version 1.0.0-rc1 +} + +@test "missing RAW_TAG fails" { + run env IMAGE_REPO='ghcr.io/loft-sh/app' GITHUB_OUTPUT="$GITHUB_OUTPUT" "$SCRIPT" + [ "$status" -ne 0 ] +} diff --git a/.github/actions/bump-manifest-image/test/should-update.bats b/.github/actions/bump-manifest-image/test/should-update.bats new file mode 100644 index 0000000..3be5226 --- /dev/null +++ b/.github/actions/bump-manifest-image/test/should-update.bats @@ -0,0 +1,62 @@ +#!/usr/bin/env bats +# Decision-table coverage for should-update.sh. + +SCRIPT="$BATS_TEST_DIRNAME/../src/should-update.sh" +FIXTURE="$BATS_TEST_DIRNAME/fixtures/deployment.yaml" + +setup() { + export GITHUB_OUTPUT; GITHUB_OUTPUT="$(mktemp)" + # Work on a copy so the fixture is never mutated. + MANIFEST="$(mktemp)"; cp "$FIXTURE" "$MANIFEST" +} +teardown() { rm -f "$GITHUB_OUTPUT" "$MANIFEST"; } + +run_script() { + # args: new_version is_stable environment [manifest] [container] + run env \ + MANIFEST_PATH="${4:-$MANIFEST}" CONTAINER_NAME="${5:-revops-events-api}" \ + NEW_VERSION="$1" IS_STABLE="$2" ENVIRONMENT="$3" \ + GITHUB_OUTPUT="$GITHUB_OUTPUT" "$SCRIPT" +} + +assert_kv() { + local want="$1=$2" actual + actual=$(grep "^$1=" "$GITHUB_OUTPUT" | tail -n1) + [ "$actual" = "$want" ] || { echo "want: $want"; echo "got: $actual"; cat "$GITHUB_OUTPUT"; return 1; } +} + +@test "newer stable version → should_update true" { + run_script 0.2.0 true staging + [ "$status" -eq 0 ]; assert_kv should_update true; assert_kv current_tag v0.1.0 +} + +@test "same version → should_update false" { + run_script 0.1.0 true staging + [ "$status" -eq 0 ]; assert_kv should_update false +} + +@test "older version → should_update false (no downgrade)" { + run_script 0.0.9 true staging + [ "$status" -eq 0 ]; assert_kv should_update false +} + +@test "pre-release to prod → skipped" { + run_script 0.2.0-rc1 false prod + [ "$status" -eq 0 ]; assert_kv should_update false + assert_kv reason "pre-release skipped for prod" +} + +@test "pre-release to staging → allowed when newer" { + run_script 0.2.0-rc1 false staging + [ "$status" -eq 0 ]; assert_kv should_update true +} + +@test "missing manifest → false with reason" { + run_script 0.2.0 true staging /no/such/file.yaml + [ "$status" -eq 0 ]; assert_kv should_update false +} + +@test "unknown container → false" { + run_script 0.2.0 true staging "$MANIFEST" not-a-container + [ "$status" -eq 0 ]; assert_kv should_update false +} diff --git a/.github/workflows/test-bump-manifest-image.yaml b/.github/workflows/test-bump-manifest-image.yaml new file mode 100644 index 0000000..5412680 --- /dev/null +++ b/.github/workflows/test-bump-manifest-image.yaml @@ -0,0 +1,22 @@ +name: Test bump-manifest-image + +on: + pull_request: + paths: + - '.github/workflows/test-bump-manifest-image.yaml' + - '.github/actions/bump-manifest-image/**' + +permissions: + contents: read + +jobs: + bats: + name: Run bats tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: bats-core/bats-action@77d6fb60505b4d0d1d73e48bd035b55074bbfb43 # 4.0.0 + with: + tests: .github/actions/bump-manifest-image/test diff --git a/Makefile b/Makefile index 9717582..d7b2e23 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: test test-semver-validation test-linear-pr-commenter test-release-notification test-linear-release-sync test-aws-test-infra test-cleanup-head-charts test-ci-test-notify test-auto-approve-bot-prs test-ai-pr-review test-ai-step test-publish-helm-chart test-govulncheck test-go-licenses test-run-ginkgo test-sticky-pr-comment test-repository-dispatch build-linear-release-sync lint install-auto-doc generate-docs check-docs help +.PHONY: test test-semver-validation test-linear-pr-commenter test-release-notification test-linear-release-sync test-aws-test-infra test-cleanup-head-charts test-ci-test-notify test-auto-approve-bot-prs test-ai-pr-review test-ai-step test-publish-helm-chart test-govulncheck test-go-licenses test-run-ginkgo test-sticky-pr-comment test-repository-dispatch test-bump-manifest-image build-linear-release-sync lint install-auto-doc generate-docs check-docs help ACTIONS_DIR := .github/actions WORKFLOWS_DIR := .github/workflows @@ -93,7 +93,7 @@ check-docs: generate-docs ## verify docs are up to date (fails if drift detected help: ## show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-30s %s\n", $$1, $$2}' -test: test-semver-validation test-linear-pr-commenter test-release-notification test-linear-release-sync test-aws-test-infra test-cleanup-head-charts test-auto-approve-bot-prs test-ai-pr-review test-ai-step test-ci-test-notify test-go-licenses test-publish-helm-chart test-govulncheck test-run-ginkgo test-sticky-pr-comment test-repository-dispatch ## run all action tests +test: test-semver-validation test-linear-pr-commenter test-release-notification test-linear-release-sync test-aws-test-infra test-cleanup-head-charts test-auto-approve-bot-prs test-ai-pr-review test-ai-step test-ci-test-notify test-go-licenses test-publish-helm-chart test-govulncheck test-run-ginkgo test-sticky-pr-comment test-repository-dispatch test-bump-manifest-image ## run all action tests test-semver-validation: ## run semver-validation unit tests cd $(ACTIONS_DIR)/semver-validation && npm ci --silent && NODE_OPTIONS=--experimental-vm-modules npx jest --ci --coverage --watchAll=false @@ -143,6 +143,9 @@ test-sticky-pr-comment: ## run sticky-pr-comment bats tests test-repository-dispatch: ## run repository-dispatch bats tests bats $(ACTIONS_DIR)/repository-dispatch/test/*.bats +test-bump-manifest-image: ## run bump-manifest-image bats tests + bats $(ACTIONS_DIR)/bump-manifest-image/test/*.bats + build-linear-release-sync: ## build linear-release-sync binary (linux/amd64) cd $(ACTIONS_DIR)/linear-release-sync/src && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" -o ../linear-release-sync-linux-amd64 .