initial: action/cascade-from @v1
This commit is contained in:
@@ -0,0 +1,61 @@
|
|||||||
|
# action/cascade-from
|
||||||
|
|
||||||
|
Composite Gitea Action that bumps a `FROM <image>:<tag>` line in a target
|
||||||
|
repo's Dockerfile, then commits and pushes. The target repo's CI fires on
|
||||||
|
that push, rebuilding against the new base.
|
||||||
|
|
||||||
|
The only consumer today is `fritzlab/base` triggering a rebuild of
|
||||||
|
`fritzlab/runner` whenever the base image changes. This action is the
|
||||||
|
generalization of that pattern.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: https://code.fritzlab.net/action/image-build@v1
|
||||||
|
with:
|
||||||
|
image: code.fritzlab.net/fritzlab/base
|
||||||
|
- uses: https://code.fritzlab.net/action/image-push@v1
|
||||||
|
with:
|
||||||
|
image: code.fritzlab.net/fritzlab/base
|
||||||
|
token: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
org: fritzlab
|
||||||
|
name: base
|
||||||
|
- uses: https://code.fritzlab.net/action/cascade-from@v1
|
||||||
|
with:
|
||||||
|
target-repo: fritzlab/runner
|
||||||
|
image: code.fritzlab.net/fritzlab/base
|
||||||
|
token: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| Name | Required | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `target-repo` | yes | — | Target repo to edit (e.g. `fritzlab/runner`). |
|
||||||
|
| `image` | yes | — | Image to look for in the FROM line. |
|
||||||
|
| `tag` | no | `github.run_number` | New tag to write into FROM. |
|
||||||
|
| `file` | no | `Dockerfile` | File inside target-repo to edit. |
|
||||||
|
| `token` | yes | — | `CI_BOT_TOKEN` with write to target-repo. |
|
||||||
|
| `host` | no | `code.fritzlab.net` | Gitea host without protocol. |
|
||||||
|
| `message` | no | `bump <name> to #<tag>` | Commit message override. |
|
||||||
|
|
||||||
|
## Behavior
|
||||||
|
|
||||||
|
1. Shallow-clone target-repo to a temp dir.
|
||||||
|
2. `sed -i "s|^FROM <image>:.*|FROM <image>:<tag>|" <file>`.
|
||||||
|
3. Verify sed actually matched a line — fail if not (catches typos in image
|
||||||
|
name).
|
||||||
|
4. If no diff (target already on this tag): exit 0 silently.
|
||||||
|
5. Otherwise commit + push to `main` with rebase-on-conflict retry up to
|
||||||
|
3 times.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Only matches lines starting with `FROM <image>:` (anchored to start). Multi-stage
|
||||||
|
Dockerfiles with a non-anchored `FROM <image>:tag AS stage` will be missed —
|
||||||
|
add the AS-aware pattern as a future enhancement if needed.
|
||||||
|
- Pushing to target-repo triggers its CI, which produces a new image of its
|
||||||
|
own. There is no end-to-end orchestration: the upstream repo's CI completes
|
||||||
|
the moment cascade-from pushes, regardless of whether the downstream build
|
||||||
|
succeeds.
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
name: Cascade FROM bump
|
||||||
|
description: |
|
||||||
|
Bump a `FROM <image>:<tag>` line in a target repo's Dockerfile to trigger that
|
||||||
|
repo's CI. Used when a base image rebuild needs to cascade rebuilds in
|
||||||
|
downstream image repos.
|
||||||
|
inputs:
|
||||||
|
target-repo:
|
||||||
|
description: Target repo to edit (e.g. fritzlab/runner)
|
||||||
|
required: true
|
||||||
|
image:
|
||||||
|
description: Image referenced in the target file's FROM line (e.g. code.fritzlab.net/fritzlab/base)
|
||||||
|
required: true
|
||||||
|
tag:
|
||||||
|
description: New tag. Defaults to github.run_number when empty.
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
file:
|
||||||
|
description: File path inside target-repo to edit
|
||||||
|
required: false
|
||||||
|
default: Dockerfile
|
||||||
|
token:
|
||||||
|
description: CI_BOT_TOKEN with write access to target-repo
|
||||||
|
required: true
|
||||||
|
host:
|
||||||
|
description: Gitea host (without protocol)
|
||||||
|
required: false
|
||||||
|
default: code.fritzlab.net
|
||||||
|
message:
|
||||||
|
description: Commit message override. Defaults to "bump <image> to #<tag>".
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Clone, edit, push
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
TARGET_REPO: ${{ inputs.target-repo }}
|
||||||
|
IMAGE: ${{ inputs.image }}
|
||||||
|
TAG_INPUT: ${{ inputs.tag }}
|
||||||
|
FILE: ${{ inputs.file }}
|
||||||
|
TOKEN: ${{ inputs.token }}
|
||||||
|
HOST: ${{ inputs.host }}
|
||||||
|
MESSAGE: ${{ inputs.message }}
|
||||||
|
RUN_NUMBER: ${{ github.run_number }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TAG="${TAG_INPUT:-$RUN_NUMBER}"
|
||||||
|
NAME="$(basename "$IMAGE")"
|
||||||
|
MSG="${MESSAGE:-bump ${NAME} to #${TAG}}"
|
||||||
|
|
||||||
|
WORK="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$WORK"' EXIT
|
||||||
|
|
||||||
|
git clone --depth 1 "https://ci-bot:${TOKEN}@${HOST}/${TARGET_REPO}.git" "$WORK"
|
||||||
|
cd "$WORK"
|
||||||
|
git config user.name ci-bot
|
||||||
|
git config user.email ci-bot@fritzlab.net
|
||||||
|
|
||||||
|
if [ ! -f "$FILE" ]; then
|
||||||
|
echo "FATAL: ${FILE} not found in ${TARGET_REPO}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape forward slashes for sed pattern
|
||||||
|
ESC_IMAGE="${IMAGE//\//\\/}"
|
||||||
|
sed -i "s|^FROM ${IMAGE}:.*|FROM ${IMAGE}:${TAG}|" "$FILE"
|
||||||
|
|
||||||
|
if ! grep -q "^FROM ${IMAGE}:${TAG}\b" "$FILE"; then
|
||||||
|
echo "FATAL: sed did not match a FROM line for ${IMAGE} in ${FILE}"
|
||||||
|
grep "^FROM" "$FILE" || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if git diff --quiet; then
|
||||||
|
echo "${TARGET_REPO} already on ${NAME}:${TAG}, skipping"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
git add "$FILE"
|
||||||
|
git commit -m "$MSG"
|
||||||
|
|
||||||
|
ATTEMPTS=0
|
||||||
|
until git push origin main; do
|
||||||
|
ATTEMPTS=$((ATTEMPTS + 1))
|
||||||
|
if [ "$ATTEMPTS" -ge 3 ]; then
|
||||||
|
echo "FATAL: push to ${TARGET_REPO} failed after ${ATTEMPTS} attempts"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "push rejected, attempt ${ATTEMPTS}; rebasing and retrying"
|
||||||
|
git pull --rebase origin main
|
||||||
|
sleep $((ATTEMPTS * 2))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "cascaded ${NAME}:${TAG} → ${TARGET_REPO}"
|
||||||
Reference in New Issue
Block a user