Replace the embedded python heredoc with python3 -c so the composite action remains valid YAML and shell across teacup parsing.
180 lines
6.5 KiB
YAML
180 lines
6.5 KiB
YAML
name: vociferate/publish
|
|
description: >
|
|
Extract release notes from the changelog and create or update a
|
|
Gitea/GitHub release. The repository must be checked out at the release
|
|
tag before this action runs.
|
|
|
|
inputs:
|
|
token:
|
|
description: >
|
|
Personal access token used to authenticate release API calls.
|
|
Required to support release updates across workflow boundaries.
|
|
required: true
|
|
version:
|
|
description: >
|
|
Semantic version to publish (with or without leading v). When omitted,
|
|
derived from the current git tag ref.
|
|
required: false
|
|
default: ''
|
|
changelog:
|
|
description: Path to changelog file relative to repository root.
|
|
required: false
|
|
default: CHANGELOG.md
|
|
|
|
outputs:
|
|
release-id:
|
|
description: Numeric ID of the created or updated release.
|
|
value: ${{ steps.create-release.outputs.id }}
|
|
tag:
|
|
description: The tag used for the release (e.g. v1.2.3).
|
|
value: ${{ steps.resolve-version.outputs.tag }}
|
|
version:
|
|
description: The bare version string without leading v (e.g. 1.2.3).
|
|
value: ${{ steps.resolve-version.outputs.version }}
|
|
|
|
runs:
|
|
using: composite
|
|
steps:
|
|
- name: Resolve release version
|
|
id: resolve-version
|
|
shell: bash
|
|
env:
|
|
INPUT_VERSION: ${{ inputs.version }}
|
|
GITHUB_REF_VALUE: ${{ github.ref }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
provided="$(printf '%s' "${INPUT_VERSION:-}" | sed 's/^[[:space:]]\+//; s/[[:space:]]\+$//')"
|
|
if [[ -n "$provided" ]]; then
|
|
normalized="${provided#v}"
|
|
tag="v${normalized}"
|
|
elif [[ "${GITHUB_REF_VALUE}" == refs/tags/* ]]; then
|
|
tag="${GITHUB_REF_VALUE#refs/tags/}"
|
|
normalized="${tag#v}"
|
|
elif head_tag="$(git describe --exact-match --tags HEAD 2>/dev/null)" && [[ -n "$head_tag" ]]; then
|
|
tag="$head_tag"
|
|
normalized="${tag#v}"
|
|
else
|
|
echo "A version input is required when the workflow is not running from a tag push" >&2
|
|
echo "Provide version via input or ensure HEAD is at a tagged commit." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
|
echo "version=$normalized" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Extract release notes
|
|
id: extract-notes
|
|
uses: ./run-vociferate
|
|
with:
|
|
root: ${{ github.workspace }}
|
|
changelog: ${{ inputs.changelog }}
|
|
version: ${{ steps.resolve-version.outputs.version }}
|
|
print-release-notes: 'true'
|
|
|
|
- name: Write release notes file
|
|
id: write-notes
|
|
shell: bash
|
|
env:
|
|
RELEASE_NOTES: ${{ steps.extract-notes.outputs.stdout }}
|
|
RUNNER_TEMP: ${{ runner.temp }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
notes_file="${RUNNER_TEMP}/release-notes.md"
|
|
printf '%s\n' "$RELEASE_NOTES" > "$notes_file"
|
|
|
|
printf 'notes_file=%s\n' "$notes_file" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Create or update release
|
|
id: create-release
|
|
shell: bash
|
|
env:
|
|
TOKEN: ${{ inputs.token }}
|
|
TAG_NAME: ${{ steps.resolve-version.outputs.tag }}
|
|
RELEASE_NOTES_FILE: ${{ steps.write-notes.outputs.notes_file }}
|
|
GITHUB_API_URL: ${{ github.api_url }}
|
|
GITHUB_SERVER_URL: ${{ github.server_url }}
|
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
parse_release_id() {
|
|
local json_file="$1"
|
|
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
python3 -c 'import json, sys; payload = json.load(open(sys.argv[1], encoding="utf-8")); value = payload.get("id"); print(value if isinstance(value, int) else "")' "$json_file"
|
|
return
|
|
fi
|
|
|
|
# Fallback for environments without python3.
|
|
sed -n 's/.*"id"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$json_file" | head -n 1
|
|
}
|
|
|
|
raw_token="$(printf '%s' "${TOKEN:-}" | sed 's/^[[:space:]]\+//; s/[[:space:]]\+$//')"
|
|
if [[ "$raw_token" =~ ^%\!t\(string=(.*)\)$ ]]; then
|
|
raw_token="${BASH_REMATCH[1]}"
|
|
fi
|
|
api_token="$(printf '%s' "$raw_token" | sed 's/^[[:space:]]\+//; s/[[:space:]]\+$//')"
|
|
|
|
if [[ -z "$api_token" ]]; then
|
|
echo "inputs.token is required (set to secrets.RELEASE_PAT)." >&2
|
|
exit 1
|
|
fi
|
|
|
|
release_notes="$(cat "$RELEASE_NOTES_FILE")"
|
|
escaped_release_notes="$(printf '%s' "$release_notes" | sed 's/\\/\\\\/g; s/"/\\"/g; :a;N;$!ba;s/\n/\\n/g')"
|
|
release_api="${GITHUB_API_URL:-${GITHUB_SERVER_URL%/}/api/v1}/repos/${GITHUB_REPOSITORY}/releases"
|
|
release_by_tag_api="${release_api}/tags/${TAG_NAME}"
|
|
|
|
status_code="$(curl -sS -o release-existing.json -w '%{http_code}' \
|
|
-H "Authorization: token ${api_token}" \
|
|
-H "Content-Type: application/json" \
|
|
"${release_by_tag_api}")"
|
|
|
|
if [[ "$status_code" == "200" ]]; then
|
|
existing_release_id="$(parse_release_id release-existing.json)"
|
|
if [[ -z "$existing_release_id" ]]; then
|
|
echo "Failed to parse existing release id for ${TAG_NAME}" >&2
|
|
cat release-existing.json >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! curl --fail-with-body \
|
|
-X PATCH \
|
|
-H "Authorization: token ${api_token}" \
|
|
-H "Content-Type: application/json" \
|
|
"${release_api}/${existing_release_id}" \
|
|
--data "{\"tag_name\":\"${TAG_NAME}\",\"name\":\"${TAG_NAME}\",\"body\":\"${escaped_release_notes}\",\"draft\":false,\"prerelease\":false}" \
|
|
--output release.json; then
|
|
cat release.json >&2 || true
|
|
exit 1
|
|
fi
|
|
|
|
echo "id=$existing_release_id" >> "$GITHUB_OUTPUT"
|
|
elif [[ "$status_code" != "404" ]]; then
|
|
echo "Unexpected response while checking release ${TAG_NAME}: HTTP ${status_code}" >&2
|
|
cat release-existing.json >&2
|
|
exit 1
|
|
else
|
|
if ! curl --fail-with-body \
|
|
-X POST \
|
|
-H "Authorization: token ${api_token}" \
|
|
-H "Content-Type: application/json" \
|
|
"${release_api}" \
|
|
--data "{\"tag_name\":\"${TAG_NAME}\",\"name\":\"${TAG_NAME}\",\"body\":\"${escaped_release_notes}\",\"draft\":false,\"prerelease\":false}" \
|
|
--output release.json; then
|
|
cat release.json >&2 || true
|
|
exit 1
|
|
fi
|
|
|
|
release_id="$(parse_release_id release.json)"
|
|
if [[ -z "$release_id" ]]; then
|
|
echo "Failed to parse release id from API response" >&2
|
|
cat release.json >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "id=$release_id" >> "$GITHUB_OUTPUT"
|
|
fi
|