Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/release-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ on:
type: string
required: true
version-file:
description: File holding the version (one line, without the tag prefix), or a package.json (its `version`).
description: File holding the version (one line, without the tag prefix), a package.json (its `version`) or a pyproject.toml (its `[project] version`).
type: string
required: true
tag-prefix:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-intent.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ on:
workflow_call:
inputs:
version-file:
description: File holding the version (one line, without the tag prefix), or a package.json (its `version`).
description: File holding the version (one line, without the tag prefix), a package.json (its `version`) or a pyproject.toml (its `[project] version`).
type: string
required: true
tag-prefix:
Expand Down
30 changes: 27 additions & 3 deletions .github/workflows/release-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ on:
workflow_call:
inputs:
version-file:
description: File holding the version (one line, without the tag prefix), or a package.json (its `version`).
description: File holding the version (one line, without the tag prefix), a package.json (its `version`) or a pyproject.toml (its `[project] version`).
type: string
required: true
tag-prefix:
Expand All @@ -35,6 +35,10 @@ on:
missing; never force-pushed.
type: string
default: ""
github-release:
description: Create the GitHub release of the tag (generated notes) after the tag.
type: boolean
default: false
harness-ref:
description: Ref of IronFlock/workflows the harness scripts are taken from.
type: string
Expand Down Expand Up @@ -89,9 +93,13 @@ jobs:
COMMIT_TITLE: ${{ github.event.head_commit.message }}
SHA: ${{ github.sha }}
run: '"$HARNESS/scripts/release.sh" mode'
# `released`: a re-run after the tag; the steps after the tag catch up
# (each passes when its work is already done).
- name: release App token (contents of this repository)
id: app
if: steps.version.outputs.mode == 'release'
if: >-
steps.version.outputs.mode == 'release' || (steps.version.outputs.mode == 'released' &&
(inputs.promote-branch != '' || inputs.github-release))
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
Expand All @@ -110,10 +118,26 @@ jobs:
MESSAGE=$(head -n1 <<<"$MESSAGE")
MESSAGE=${MESSAGE% (#*)} "$HARNESS/scripts/release.sh" tag
- name: fast-forward ${{ inputs.promote-branch }}
if: steps.version.outputs.mode == 'release' && inputs.promote-branch != ''
if: >-
(steps.version.outputs.mode == 'release' || steps.version.outputs.mode == 'released') &&
inputs.promote-branch != ''
env:
GH_TOKEN: ${{ steps.app.outputs.token }}
REPO: ${{ github.repository }}
BRANCH: ${{ inputs.promote-branch }}
SHA: ${{ github.sha }}
run: '"$HARNESS/scripts/release.sh" promote'
- name: GitHub release ${{ steps.version.outputs.tag }}
if: >-
(steps.version.outputs.mode == 'release' || steps.version.outputs.mode == 'released') &&
inputs.github-release
env:
GH_TOKEN: ${{ steps.app.outputs.token }}
REPO: ${{ github.repository }}
TAG: ${{ steps.version.outputs.tag }}
run: |
if gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1; then
echo "the GitHub release $TAG exists"
else
gh release create "$TAG" --repo "$REPO" --verify-tag --title "$TAG" --generate-notes
fi
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ With `promote-branch` set, the tag job then fast-forwards that branch to the
released commit (never a force push), for a hosting service that deploys from
a branch: only release merges reach it. Protect that branch with a ruleset
whose only bypass actor is the release App.
With `github-release: true` it also creates the GitHub release of the tag
(generated notes), with the same token, so callers need no write rights. Both
steps catch up on a re-run that finds the tag already set.

## Pull requests from a laptop

Expand Down
15 changes: 8 additions & 7 deletions scripts/pr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,21 @@ wait_s=${PR_WAIT_SECONDS:-20}

die() { echo "$*" >&2; exit 1; }

# version <file> [<rev>]: a package.json's `version`, otherwise the content
# without whitespace (same rule as release.sh).
# version <file> [<rev>]: a package.json's `version`, a pyproject.toml's
# `[project] version`, otherwise the content without whitespace (same rule as
# release.sh).
version() {
local content
if [ -n "${2:-}" ]; then
content=$(git show "$2:$1" 2>/dev/null) || return 0
else
content=$(cat "$1")
fi
if [ "$(basename "$1")" = package.json ]; then
jq -r '.version // empty' <<<"$content"
else
tr -d '[:space:]' <<<"$content"
fi
case "$(basename "$1")" in
package.json) jq -r '.version // empty' <<<"$content" ;;
pyproject.toml) awk '/^\[/ { p = ($0 ~ /^\[project\][[:space:]]*(#.*)?$/) } p && /^version[[:space:]]*=/ { sub(/^version[[:space:]]*=[[:space:]]*/, ""); sub(/[[:space:]]*#.*$/, ""); gsub(/["'"'"']/, ""); print; exit }' <<<"$content" ;;
*) tr -d '[:space:]' <<<"$content" ;;
esac
}

next_version() { # next_version <level> <x.y.z>
Expand Down
6 changes: 4 additions & 2 deletions scripts/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
# from the repository root of a full checkout (history and tags).
#
# release.sh version <file> [<rev>]
# print the version in <file>: a package.json's `version`, otherwise the
# file's content without whitespace. With <rev> the file is read at that
# print the version in <file>: a package.json's `version`, a
# pyproject.toml's `[project] version`, otherwise the file's content
# without whitespace. With <rev> the file is read at that
# commit; a file missing there prints nothing.
#
# release.sh intent
Expand Down Expand Up @@ -55,6 +56,7 @@ version() {
fi
case "$file" in
package.json | */package.json) jq -r '.version // empty' <<<"$content" ;;
pyproject.toml | */pyproject.toml) awk '/^\[/ { p = ($0 ~ /^\[project\][[:space:]]*(#.*)?$/) } p && /^version[[:space:]]*=/ { sub(/^version[[:space:]]*=[[:space:]]*/, ""); sub(/[[:space:]]*#.*$/, ""); gsub(/["'"'"']/, ""); print; exit }' <<<"$content" ;;
*) tr -d '[:space:]' <<<"$content" ;;
esac
}
Expand Down
10 changes: 10 additions & 0 deletions scripts/test_pr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ echo "just $*" >>"$STUB/log"
vf=$(cat "$STUB/vf")
if [ "$(basename "$vf")" = package.json ]; then
jq --arg v "$2" '.version = $v' "$vf" >"$vf.tmp" && mv "$vf.tmp" "$vf"
elif [ "$(basename "$vf")" = pyproject.toml ]; then
sed -i.bak "/^\[project\]/,/^\[/ s/^version = .*/version = \"$2\"/" "$vf" && rm -f "$vf.bak"
else
echo "$2" >"$vf"
fi
Expand All @@ -65,6 +67,8 @@ setup() {
if [ "$(basename "$1")" = package.json ]; then
mkdir -p "$repo/$(dirname "$1")"
printf '{\n "name": "x",\n "version": "%s"\n}\n' "$2" >"$repo/$1"
elif [ "$(basename "$1")" = pyproject.toml ]; then
printf '[project]\nname = "x"\nversion = "%s"\n\n[tool.later]\nversion = "9.9.9"\n' "$2" >"$repo/$1"
else
mkdir -p "$repo/$(dirname "$1")"
echo "$2" >"$repo/$1"
Expand Down Expand Up @@ -211,5 +215,11 @@ ci_tag v1.4.23
check "release: package.json in a subdirectory" 0 release patch reauth-login backend/package.json release.yml backend/package.json
expect "release: package.json at 1.4.23" test "$(git -C "$origin" show feat:backend/package.json | jq -r .version)" = 1.4.23

setup pyproject.toml 1.10.0
ci_tag v1.10.1
check "release: pyproject.toml" 0 release patch x pyproject.toml release.yml pyproject.toml
expect "release: [project] version at 1.10.1" grep -qx 'version = "1.10.1"' <(git -C "$origin" show feat:pyproject.toml)
expect "release: other tables untouched" grep -qx 'version = "9.9.9"' <(git -C "$origin" show feat:pyproject.toml)

[ "$fail" = 0 ] && echo "all pr.sh tests passed"
exit "$fail"
4 changes: 3 additions & 1 deletion scripts/test_release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ repo() {
setv() { # setv <dir> <file> <version>
case "$2" in
package.json) printf '{\n "name": "x",\n "version": "%s"\n}\n' "$3" > "$1/$2" ;;
# Other tables with a version key: only [project] counts.
pyproject.toml) printf '[tool.other]\nversion = "0.0.1"\n\n[project]\nname = "x"\nversion = "%s" # uv version\n\n[tool.later]\nversion = "9.9.9"\n' "$3" > "$1/$2" ;;
*) printf '%s\n' "$3" > "$1/$2" ;;
esac
}
Expand All @@ -60,7 +62,7 @@ intent() { # intent <dir> <file> <base> <head> <title>
(cd "$1" && VERSION_FILE=$2 TAG_PREFIX=v BASE_SHA=$3 HEAD_SHA=$4 TITLE=$5 "$script" intent)
}

for vf in VERSION package.json; do
for vf in VERSION package.json pyproject.toml; do
r="$work/intent-$vf"
repo "$r" "$vf" 1.2.3
base=$(git -C "$r" rev-parse HEAD)
Expand Down
Loading