initial: action/image-deploy @v1
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# action/image-deploy
|
||||
|
||||
Composite Gitea Action that pins an image tag in `fritzlab/apps` via
|
||||
`kustomize edit set image`, validates the rendered manifests, and pushes
|
||||
to apps-repo `main`. Retries on push conflict.
|
||||
|
||||
This is the standard "deploy" step for image producers (chrony, profiles,
|
||||
runner). After `image-build` + `image-push`, this writes the new tag into
|
||||
the GitOps target so ArgoCD can sync it.
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: actions/checkout@v4
|
||||
- uses: https://code.fritzlab.net/action/image-build@v1
|
||||
with:
|
||||
image: code.fritzlab.net/fritzlab/chrony
|
||||
smoke-test: docker run --rm --entrypoint /usr/sbin/chronyd $IMAGE -v
|
||||
- uses: https://code.fritzlab.net/action/image-push@v1
|
||||
with:
|
||||
image: code.fritzlab.net/fritzlab/chrony
|
||||
token: ${{ secrets.CI_BOT_TOKEN }}
|
||||
org: fritzlab
|
||||
name: chrony
|
||||
- uses: https://code.fritzlab.net/action/image-deploy@v1
|
||||
with:
|
||||
image: code.fritzlab.net/fritzlab/chrony
|
||||
path: sjc001/infra/chrony/manifests
|
||||
token: ${{ secrets.CI_BOT_TOKEN }}
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Required | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `image` | yes | — | Full image name without tag. Must match an entry already in the target `kustomization.yaml` `images:` block. |
|
||||
| `tag` | no | `github.run_number` | Tag to pin. |
|
||||
| `path` | yes | — | Path inside `fritzlab/apps` to the manifests dir (e.g. `sjc001/infra/chrony/manifests`). |
|
||||
| `token` | yes | — | `CI_BOT_TOKEN` with write access to `fritzlab/apps`. |
|
||||
| `apps-repo` | no | `code.fritzlab.net/fritzlab/apps` | Apps repo URL without protocol. |
|
||||
| `message` | no | `deploy <name> #<tag>` | Commit message override. |
|
||||
|
||||
## Behavior
|
||||
|
||||
1. Shallow-clone `fritzlab/apps` to a temp dir.
|
||||
2. `cd <path>` and run `kustomize edit set image <image>=<image>:<tag>`.
|
||||
3. Run `kustomize build .` to validate the manifests still render. **Fails the
|
||||
workflow if validation breaks** — apps repo is left untouched.
|
||||
4. If no diff (apps repo already on this tag): exit 0 silently.
|
||||
5. Otherwise commit + push to `main`. On push rejection (concurrent CI race),
|
||||
`git pull --rebase` and retry up to 3 times with linear backoff.
|
||||
|
||||
## Notes
|
||||
|
||||
- The image entry must already exist in `kustomization.yaml`. This action only
|
||||
updates the tag; it does not add or remove image entries. To switch image
|
||||
registry paths, edit `kustomization.yaml` by hand once, commit, then let CI
|
||||
resume.
|
||||
- `git diff --quiet` skip means re-running the same CI run (or an earlier run)
|
||||
is idempotent.
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
name: Deploy Image (kustomize image-pin in apps repo)
|
||||
description: |
|
||||
Pin an image tag in fritzlab/apps via `kustomize edit set image`, validate the
|
||||
rendered manifests, and push to apps-repo main. Retries on push conflict.
|
||||
inputs:
|
||||
image:
|
||||
description: Full image name without tag (must match an entry in the target kustomization.yaml `images:` block)
|
||||
required: true
|
||||
tag:
|
||||
description: Tag to pin. Defaults to github.run_number when empty.
|
||||
required: false
|
||||
default: ''
|
||||
path:
|
||||
description: Path inside fritzlab/apps to the manifests dir (e.g. sjc001/infra/chrony/manifests)
|
||||
required: true
|
||||
token:
|
||||
description: CI_BOT_TOKEN with write access to fritzlab/apps
|
||||
required: true
|
||||
apps-repo:
|
||||
description: Apps repo URL (without protocol)
|
||||
required: false
|
||||
default: code.fritzlab.net/fritzlab/apps
|
||||
message:
|
||||
description: Commit message. Defaults to "deploy <name> #<tag>".
|
||||
required: false
|
||||
default: ''
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Pin image and push
|
||||
shell: bash
|
||||
env:
|
||||
IMAGE: ${{ inputs.image }}
|
||||
TAG_INPUT: ${{ inputs.tag }}
|
||||
PATH_IN_REPO: ${{ inputs.path }}
|
||||
TOKEN: ${{ inputs.token }}
|
||||
APPS_REPO: ${{ inputs.apps-repo }}
|
||||
MESSAGE: ${{ inputs.message }}
|
||||
RUN_NUMBER: ${{ github.run_number }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
TAG="${TAG_INPUT:-$RUN_NUMBER}"
|
||||
NAME="$(basename "$IMAGE")"
|
||||
MSG="${MESSAGE:-deploy ${NAME} #${TAG}}"
|
||||
|
||||
WORK="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
|
||||
git clone --depth 1 "https://ci-bot:${TOKEN}@${APPS_REPO}.git" "$WORK"
|
||||
cd "$WORK"
|
||||
git config user.name ci-bot
|
||||
git config user.email ci-bot@fritzlab.net
|
||||
|
||||
cd "$PATH_IN_REPO"
|
||||
kustomize edit set image "${IMAGE}=${IMAGE}:${TAG}"
|
||||
|
||||
# Validate the kustomization renders cleanly before we push.
|
||||
if ! kustomize build . > /dev/null; then
|
||||
echo "FATAL: kustomize build failed after image pin"
|
||||
git --no-pager diff
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if git -C "$WORK" diff --quiet; then
|
||||
echo "apps repo already on ${NAME}:${TAG}, skipping"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git -C "$WORK" add "${PATH_IN_REPO}/kustomization.yaml"
|
||||
git -C "$WORK" commit -m "$MSG"
|
||||
|
||||
# Push with rebase-on-conflict retry: concurrent CI from another image
|
||||
# repo could have pushed since our clone.
|
||||
ATTEMPTS=0
|
||||
until git -C "$WORK" push origin main; do
|
||||
ATTEMPTS=$((ATTEMPTS + 1))
|
||||
if [ "$ATTEMPTS" -ge 3 ]; then
|
||||
echo "FATAL: push to apps repo failed after ${ATTEMPTS} attempts"
|
||||
exit 1
|
||||
fi
|
||||
echo "push rejected, attempt ${ATTEMPTS}; rebasing and retrying"
|
||||
git -C "$WORK" pull --rebase origin main
|
||||
sleep $((ATTEMPTS * 2))
|
||||
done
|
||||
|
||||
echo "deployed ${NAME}:${TAG}"
|
||||
Reference in New Issue
Block a user