Compare commits
9
Commits
30ff44c33b
...
v1.20.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4300baaa19 | ||
|
|
eef6d305dd | ||
|
|
a9c5e56a24 | ||
|
|
4e765e5c64 | ||
|
|
50dc06f634 | ||
|
|
992d3630e9 | ||
|
|
b8b5648d00 | ||
|
|
503c02b24c | ||
|
|
fce2468b2b |
@@ -24,6 +24,9 @@ jobs:
|
||||
git add VERSION
|
||||
git diff --cached --quiet || git commit -m "chore: bump version [skip ci]"
|
||||
version=$(cat VERSION)
|
||||
major="${version%%.*}"
|
||||
git tag "v${version}"
|
||||
git tag -f "v${major}"
|
||||
git push
|
||||
git push --tags
|
||||
git push origin "refs/tags/v${version}"
|
||||
git push --force origin "refs/tags/v${major}"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
ACTIONS := \
|
||||
docker \
|
||||
node \
|
||||
claude/check-shared-block \
|
||||
git/create_tag \
|
||||
git/promotion-gate \
|
||||
helm/diff \
|
||||
helm/template \
|
||||
helm/upgrade \
|
||||
|
||||
@@ -4,6 +4,12 @@ Reusable composite actions for Gitea CI/CD pipelines.
|
||||
|
||||
## Actions
|
||||
|
||||
### Claude
|
||||
|
||||
| Action | Description |
|
||||
|---|---|
|
||||
| [claude/check-shared-block](claude/check-shared-block/README.md) | Fails when a repo's shared CLAUDE.md block has drifted from the canonical copy in stat-tackler-infra |
|
||||
|
||||
### Docker
|
||||
|
||||
| Action | Description |
|
||||
@@ -15,6 +21,7 @@ Reusable composite actions for Gitea CI/CD pipelines.
|
||||
| Action | Description |
|
||||
|---|---|
|
||||
| [git/create_tag](git/create_tag/README.md) | Create and push a git tag in the current repository |
|
||||
| [git/promotion-gate](git/promotion-gate/README.md) | Enforce which source branches may merge into which target branches |
|
||||
|
||||
### Helm
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Check Shared CLAUDE.md Block
|
||||
|
||||
<!-- action-docs-description source="action.yml" -->
|
||||
## Description
|
||||
|
||||
Fails when a repo's shared CLAUDE.md block has drifted from the canonical copy in stat-tackler-infra
|
||||
<!-- action-docs-description source="action.yml" -->
|
||||
|
||||
<!-- action-docs-inputs source="action.yml" -->
|
||||
## Inputs
|
||||
|
||||
| name | description | required | default |
|
||||
| --- | --- | --- | --- |
|
||||
| `TARGET` | <p>Path to the CLAUDE.md file to check</p> | `false` | `CLAUDE.md` |
|
||||
| `CANONICAL_URL` | <p>Raw URL of the canonical shared fragment</p> | `false` | `https://gitea.pixelparasol.com/stat-tackler/stat-tackler-infra/raw/branch/main/docs/CLAUDE.shared.md` |
|
||||
| `GITEA_TOKEN` | <p>Gitea token with read access to stat-tackler-infra, if it is private</p> | `false` | `""` |
|
||||
<!-- action-docs-inputs source="action.yml" -->
|
||||
|
||||
<!-- action-docs-runs source="action.yml" -->
|
||||
## Runs
|
||||
|
||||
This action is a `composite` action.
|
||||
<!-- action-docs-runs source="action.yml" -->
|
||||
|
||||
## Running locally
|
||||
|
||||
The check logic has no dependency on the composite action wrapper beyond
|
||||
`curl`, `awk`, and `diff` on `PATH`. From a repo's root:
|
||||
|
||||
```bash
|
||||
CANONICAL_URL=https://gitea.pixelparasol.com/stat-tackler/stat-tackler-infra/raw/branch/main/docs/CLAUDE.shared.md \
|
||||
TARGET=CLAUDE.md sh -c '
|
||||
extract() { awk "/<!-- SHARED:BEGIN/{f=1} f{print} /SHARED:END -->/{f=0}" "$1"; }
|
||||
tmp=$(mktemp)
|
||||
curl -sfSL "$CANONICAL_URL" -o "$tmp"
|
||||
extract "$tmp" > "$tmp.canon"
|
||||
extract "$TARGET" > "$tmp.mine"
|
||||
diff -u "$tmp.canon" "$tmp.mine" && echo "matches canonical"
|
||||
rm -f "$tmp" "$tmp.canon" "$tmp.mine"
|
||||
'
|
||||
```
|
||||
|
||||
`GITEA_TOKEN` is only needed if `stat-tackler-infra` becomes private; it is
|
||||
otherwise safe to omit.
|
||||
@@ -0,0 +1,75 @@
|
||||
name: Check Shared CLAUDE.md Block
|
||||
description: Fails when a repo's shared CLAUDE.md block has drifted from the canonical copy in stat-tackler-infra
|
||||
|
||||
inputs:
|
||||
TARGET:
|
||||
description: "Path to the CLAUDE.md file to check"
|
||||
default: "CLAUDE.md"
|
||||
CANONICAL_URL:
|
||||
description: "Raw URL of the canonical shared fragment"
|
||||
default: "https://gitea.pixelparasol.com/stat-tackler/stat-tackler-infra/raw/branch/main/docs/CLAUDE.shared.md"
|
||||
GITEA_TOKEN:
|
||||
description: "Gitea token with read access to stat-tackler-infra, if it is private"
|
||||
default: ""
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check shared CLAUDE.md block
|
||||
shell: sh
|
||||
env:
|
||||
TARGET: ${{ inputs.TARGET }}
|
||||
CANONICAL_URL: ${{ inputs.CANONICAL_URL }}
|
||||
GITEA_TOKEN: ${{ inputs.GITEA_TOKEN }}
|
||||
run: |
|
||||
set -e
|
||||
|
||||
if [ ! -f "$TARGET" ]; then
|
||||
echo "::error::$TARGET not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
extract() {
|
||||
# Everything between the markers, markers included.
|
||||
awk '/<!-- SHARED:BEGIN/{f=1} f{print} /SHARED:END -->/{f=0}' "$1"
|
||||
}
|
||||
|
||||
mine=$(extract "$TARGET")
|
||||
if [ -z "$mine" ]; then
|
||||
echo "::error::$TARGET has no SHARED:BEGIN/SHARED:END block."
|
||||
echo "Copy it from $CANONICAL_URL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tmp=$(mktemp)
|
||||
if [ -n "$GITEA_TOKEN" ]; then
|
||||
curl -sfSL -H "Authorization: token $GITEA_TOKEN" "$CANONICAL_URL" -o "$tmp"
|
||||
else
|
||||
curl -sfSL "$CANONICAL_URL" -o "$tmp"
|
||||
fi
|
||||
|
||||
theirs=$(extract "$tmp")
|
||||
if [ -z "$theirs" ]; then
|
||||
echo "::error::Could not read the canonical block from $CANONICAL_URL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$mine" = "$theirs" ]; then
|
||||
echo "Shared CLAUDE.md block matches the canonical copy."
|
||||
rm -f "$tmp"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "::error::The shared CLAUDE.md block has drifted from the canonical copy."
|
||||
echo "Canonical: $CANONICAL_URL"
|
||||
echo
|
||||
echo "--- canonical"
|
||||
echo "+++ $TARGET"
|
||||
printf '%s\n' "$theirs" > "$tmp.canon"
|
||||
printf '%s\n' "$mine" > "$tmp.mine"
|
||||
diff -u "$tmp.canon" "$tmp.mine" || true
|
||||
rm -f "$tmp" "$tmp.canon" "$tmp.mine"
|
||||
exit 1
|
||||
@@ -0,0 +1,21 @@
|
||||
# Promotion Gate
|
||||
|
||||
<!-- action-docs-description source="action.yml" -->
|
||||
## Description
|
||||
|
||||
Enforce which source branches may merge into which target branches
|
||||
<!-- action-docs-description source="action.yml" -->
|
||||
|
||||
<!-- action-docs-inputs source="action.yml" -->
|
||||
## Inputs
|
||||
|
||||
| name | description | required | default |
|
||||
| --- | --- | --- | --- |
|
||||
| `rules` | <p>One rule per line: "target:allowed1,allowed2,…". Targets not listed are unrestricted. Allowed entries may use a trailing glob, e.g. <code>hotfix-*</code>. Leave empty (default) to skip entirely.</p> | `false` | `""` |
|
||||
<!-- action-docs-inputs source="action.yml" -->
|
||||
|
||||
<!-- action-docs-runs source="action.yml" -->
|
||||
## Runs
|
||||
|
||||
This action is a `composite` action.
|
||||
<!-- action-docs-runs source="action.yml" -->
|
||||
@@ -0,0 +1,75 @@
|
||||
name: Promotion Gate
|
||||
description: Enforce which source branches may merge into which target branches
|
||||
inputs:
|
||||
rules:
|
||||
description: |
|
||||
One rule per line: "target:allowed1,allowed2,...". Targets not
|
||||
listed are unrestricted. Allowed entries may use a trailing glob,
|
||||
e.g. `hotfix-*`. Leave empty (default) to skip entirely.
|
||||
default: ""
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Check merge source is allowed for target branch
|
||||
shell: sh
|
||||
env:
|
||||
BASE: ${{ gitea.event.pull_request.base.ref }}
|
||||
HEAD: ${{ gitea.event.pull_request.head.ref }}
|
||||
RULES: ${{ inputs.rules }}
|
||||
run: |
|
||||
if [ -z "$RULES" ]; then
|
||||
echo "No promotion rules configured — skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rc=0
|
||||
found=0
|
||||
|
||||
oldIFS=$IFS
|
||||
IFS='
|
||||
'
|
||||
set -f
|
||||
set -- $RULES
|
||||
set +f
|
||||
IFS=$oldIFS
|
||||
|
||||
for line in "$@"; do
|
||||
if [ -z "$line" ]; then
|
||||
continue
|
||||
fi
|
||||
target=${line%%:*}
|
||||
allowed=${line#*:}
|
||||
if [ "$target" = "$line" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ "$BASE" = "$target" ]; then
|
||||
found=1
|
||||
matched=0
|
||||
innerIFS=$IFS
|
||||
IFS=','
|
||||
for pat in $allowed; do
|
||||
IFS=$innerIFS
|
||||
case "$HEAD" in
|
||||
$pat)
|
||||
matched=1
|
||||
;;
|
||||
esac
|
||||
IFS=','
|
||||
done
|
||||
IFS=$innerIFS
|
||||
|
||||
if [ "$matched" -eq 1 ]; then
|
||||
echo "Allowed: '$HEAD' -> '$BASE' (matches: $allowed)"
|
||||
else
|
||||
echo "::error::$BASE only accepts merges from: $allowed — got '$HEAD'"
|
||||
rc=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$found" -eq 0 ]; then
|
||||
echo "No promotion-source restriction configured for base '$BASE'"
|
||||
fi
|
||||
|
||||
exit $rc
|
||||
@@ -38,5 +38,9 @@ runs:
|
||||
git config user.email "gitea-actions@gitea.pixelparasol.com"
|
||||
git config user.name "Gitea Actions"
|
||||
git add releases/versions.yaml
|
||||
if git diff --cached --quiet; then
|
||||
echo "No version change for ${{ inputs.service }}, skipping commit"
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "chore: update ${{ inputs.service }} to ${{ inputs.tag }}"
|
||||
git push
|
||||
|
||||
Reference in New Issue
Block a user