Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f82dace4b2 | ||
|
|
81dced6ada | ||
|
|
62693935d0 | ||
|
|
c0b5ec385c | ||
|
|
84f6fbcfc8 | ||
|
|
4a2d234ba3 | ||
|
|
4841b04076 |
@@ -264,7 +264,27 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
release_api="${GITHUB_API_URL:-${GITHUB_SERVER_URL%/}/api/v1}/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets"
|
||||
raw_release_id="$(printf '%s' "${RELEASE_ID:-}" | sed 's/^[[:space:]]\+//; s/[[:space:]]\+$//')"
|
||||
if [[ "$raw_release_id" =~ ^%\!t\(string=(.*)\)$ ]]; then
|
||||
raw_release_id="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
|
||||
release_id="$(printf '%s' "$raw_release_id" | sed 's/^[[:space:]]\+//; s/[[:space:]]\+$//')"
|
||||
if ! [[ "$release_id" =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid release id from publish step: '${RELEASE_ID}'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
release_detail_api="${GITHUB_API_URL:-${GITHUB_SERVER_URL%/}/api/v1}/repos/${GITHUB_REPOSITORY}/releases/${release_id}"
|
||||
if ! curl --fail-with-body -sS \
|
||||
-H "Authorization: token ${RELEASE_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"$release_detail_api" >/dev/null; then
|
||||
echo "Resolved release endpoint is not accessible: ${release_detail_api}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
release_api="${GITHUB_API_URL:-${GITHUB_SERVER_URL%/}/api/v1}/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets"
|
||||
|
||||
for asset in dist/*; do
|
||||
name="$(basename "$asset")"
|
||||
@@ -298,9 +318,11 @@ jobs:
|
||||
env:
|
||||
TAG_NAME: ${{ steps.publish.outputs.tag }}
|
||||
RELEASE_VERSION: ${{ steps.publish.outputs.version }}
|
||||
PUBLISH_OUTCOME: ${{ steps.publish.outcome }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "${PUBLISH_OUTCOME}" == "success" ]]; then
|
||||
{
|
||||
echo "## Release Published"
|
||||
echo
|
||||
@@ -308,6 +330,14 @@ jobs:
|
||||
echo "- Release notes sourced from changelog entry ${RELEASE_VERSION}."
|
||||
echo "- Published assets: vociferate_${RELEASE_VERSION}_linux_amd64, vociferate_${RELEASE_VERSION}_linux_arm64, checksums.txt"
|
||||
} >> "$SUMMARY_FILE"
|
||||
else
|
||||
{
|
||||
echo "## Release Failed"
|
||||
echo
|
||||
echo "- Tag: ${TAG_NAME:-unknown}"
|
||||
echo "- Create or update release step did not complete successfully."
|
||||
} >> "$SUMMARY_FILE"
|
||||
fi
|
||||
|
||||
echo 'Summary'
|
||||
echo
|
||||
|
||||
24
AGENTS.md
24
AGENTS.md
@@ -4,15 +4,15 @@ This guide is for agentic coding partners that need to integrate the composite a
|
||||
|
||||
## Source Of Truth
|
||||
|
||||
Pin all action references to a released tag (for example `@v1.0.2`) and keep all vociferate references on the same tag in a workflow.
|
||||
Pin all action references to a released tag (for example `@v1.1.0`) and keep all vociferate references on the same tag in a workflow.
|
||||
|
||||
Published composite actions:
|
||||
|
||||
- `https://git.hrafn.xyz/aether/vociferate@v1.0.2` (root action)
|
||||
- `https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2`
|
||||
- `https://git.hrafn.xyz/aether/vociferate/publish@v1.0.2`
|
||||
- `https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2`
|
||||
- `https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2`
|
||||
- `https://git.hrafn.xyz/aether/vociferate@v1.1.0` (root action)
|
||||
- `https://git.hrafn.xyz/aether/vociferate/prepare@v1.1.0`
|
||||
- `https://git.hrafn.xyz/aether/vociferate/publish@v1.1.0`
|
||||
- `https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.1.0`
|
||||
- `https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.1.0`
|
||||
|
||||
## Action Selection Matrix
|
||||
|
||||
@@ -94,11 +94,11 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- id: prepare
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.1.0
|
||||
|
||||
publish:
|
||||
needs: prepare
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.1.0
|
||||
with:
|
||||
tag: ${{ needs.prepare.outputs.version }}
|
||||
secrets: inherit
|
||||
@@ -115,7 +115,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- id: publish
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/publish@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/publish@v1.1.0
|
||||
with:
|
||||
version: v1.2.3
|
||||
```
|
||||
@@ -136,7 +136,7 @@ jobs:
|
||||
- name: Run tests with coverage
|
||||
run: go test -covermode=atomic -coverprofile=coverage.out ./...
|
||||
- id: badge
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.1.0
|
||||
with:
|
||||
artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }}
|
||||
artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }}
|
||||
@@ -159,12 +159,12 @@ jobs:
|
||||
- name: Run tests with coverage
|
||||
run: go test -covermode=atomic -coverprofile=coverage.out ./...
|
||||
- id: badge
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.1.0
|
||||
with:
|
||||
artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }}
|
||||
artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }}
|
||||
- name: Decorate PR
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.1.0
|
||||
with:
|
||||
coverage-percentage: ${{ steps.badge.outputs.total }}
|
||||
badge-url: ${{ steps.badge.outputs.badge-url }}
|
||||
|
||||
17
CHANGELOG.md
17
CHANGELOG.md
@@ -13,6 +13,18 @@ A `### Breaking` section is used in addition to Keep a Changelog's standard sect
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
### Removed
|
||||
|
||||
### Fixed
|
||||
|
||||
## [1.1.0] - 2026-03-21
|
||||
|
||||
### Breaking
|
||||
|
||||
### Added
|
||||
|
||||
- Added changelog gate validation to `decorate-pr` action for enforcing changelog updates on qualifying code changes.
|
||||
- Changelog gate modes: `strict` (fails job on violation) and `soft` (warns via PR comment).
|
||||
- Docs-only PR exemption with customizable glob patterns for documentation files.
|
||||
@@ -156,9 +168,10 @@ A `### Breaking` section is used in addition to Keep a Changelog's standard sect
|
||||
- Project/automation rename from `releaseprep` to `vociferate` (entrypoint, package paths, outputs).
|
||||
- README guidance focused on primary cross-repository reuse workflows.
|
||||
|
||||
[Unreleased]: https://git.hrafn.xyz/aether/vociferate/compare/v1.0.2...main
|
||||
[Unreleased]: https://git.hrafn.xyz/aether/vociferate/compare/v1.1.0...main
|
||||
[1.1.0]: https://git.hrafn.xyz/aether/vociferate/compare/v1.0.2...v1.1.0
|
||||
[1.0.2]: https://git.hrafn.xyz/aether/vociferate/compare/v1.0.1...v1.0.2
|
||||
[1.0.1]: https://git.hrafn.xyz/aether/vociferate/compare/v1.0.0...v1.0.1
|
||||
[1.0.0]: https://git.hrafn.xyz/aether/vociferate/compare/v0.2.0...v1.0.0
|
||||
[0.2.0]: https://git.hrafn.xyz/aether/vociferate/compare/v0.1.0...v0.2.0
|
||||
[0.1.0]: https://git.hrafn.xyz/aether/vociferate/compare/2060af6...v0.1.0
|
||||
[0.1.0]: https://git.hrafn.xyz/aether/vociferate/compare/81dced6...v0.1.0
|
||||
|
||||
22
README.md
22
README.md
@@ -17,7 +17,7 @@ revision.
|
||||
## Use In Other Repositories
|
||||
|
||||
Vociferate ships composite actions covering release preparation, release publication, coverage badge publishing, and pull request decoration.
|
||||
Release tags now exist; pin all action and reusable-workflow references to the same released tag (for example, `@v1.0.2`) instead of `@main`.
|
||||
Release tags now exist; pin all action and reusable-workflow references to the same released tag (for example, `@v1.1.0`) instead of `@main`.
|
||||
|
||||
For agentic coding partners, see [`AGENTS.md`](AGENTS.md) for a direct integration playbook, selection matrix, and copy-paste workflow patterns.
|
||||
|
||||
@@ -41,13 +41,13 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2
|
||||
- uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.1.0
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
publish:
|
||||
needs: prepare
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.1.0
|
||||
with:
|
||||
tag: ${{ needs.prepare.outputs.version }}
|
||||
secrets: inherit
|
||||
@@ -61,7 +61,7 @@ For repositories that embed the version inside source code, pass `version-file`
|
||||
and `version-pattern`:
|
||||
|
||||
```yaml
|
||||
- uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2
|
||||
- uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.1.0
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_PAT }}
|
||||
version-file: internal/myapp/version/version.go
|
||||
@@ -86,7 +86,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.1.0
|
||||
with:
|
||||
tag: ${{ inputs.tag }}
|
||||
secrets: inherit
|
||||
@@ -105,7 +105,7 @@ assets after it runs:
|
||||
|
||||
```yaml
|
||||
- id: publish
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/publish@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/publish@v1.1.0
|
||||
|
||||
- name: Upload my binary
|
||||
run: |
|
||||
@@ -125,7 +125,7 @@ Run your coverage tests first, then call the action to generate `coverage.html`,
|
||||
run: go test -covermode=atomic -coverprofile=coverage.out ./...
|
||||
|
||||
- id: coverage
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.1.0
|
||||
with:
|
||||
artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }}
|
||||
artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }}
|
||||
@@ -150,14 +150,14 @@ with a clear message when token permissions are insufficient.
|
||||
run: go test -covermode=atomic -coverprofile=coverage.out ./...
|
||||
|
||||
- id: coverage
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.1.0
|
||||
with:
|
||||
artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }}
|
||||
artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }}
|
||||
|
||||
- name: Decorate pull request
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.1.0
|
||||
with:
|
||||
coverage-percentage: ${{ steps.coverage.outputs.total }}
|
||||
badge-url: ${{ steps.coverage.outputs.badge-url }}
|
||||
@@ -170,7 +170,7 @@ Enable changelog validation to enforce that code changes include `Unreleased` ch
|
||||
```yaml
|
||||
- name: Decorate pull request with changelog gate
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.1.0
|
||||
with:
|
||||
coverage-percentage: ${{ steps.coverage.outputs.total }}
|
||||
badge-url: ${{ steps.coverage.outputs.badge-url }}
|
||||
@@ -196,7 +196,7 @@ Decision outputs enable downstream workflow logic:
|
||||
- name: Decorate PR and check gate
|
||||
id: decorate
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2
|
||||
uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.1.0
|
||||
with:
|
||||
coverage-percentage: ${{ steps.coverage.outputs.total }}
|
||||
badge-url: ${{ steps.coverage.outputs.badge-url }}
|
||||
|
||||
@@ -95,12 +95,29 @@ runs:
|
||||
RELEASE_NOTES_FILE: ${{ steps.write-notes.outputs.notes_file }}
|
||||
GITHUB_API_URL: ${{ github.api_url }}
|
||||
GITHUB_SERVER_URL: ${{ github.server_url }}
|
||||
GITHUB_SHA: ${{ github.sha }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -z "${TOKEN:-}" ]]; then
|
||||
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
|
||||
@@ -111,25 +128,28 @@ runs:
|
||||
release_by_tag_api="${release_api}/tags/${TAG_NAME}"
|
||||
|
||||
status_code="$(curl -sS -o release-existing.json -w '%{http_code}' \
|
||||
-H "Authorization: token ${TOKEN}" \
|
||||
-H "Authorization: token ${api_token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${release_by_tag_api}")"
|
||||
|
||||
if [[ "$status_code" == "200" ]]; then
|
||||
existing_release_id="$(sed -n 's/.*"id"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' release-existing.json | head -n 1)"
|
||||
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
|
||||
|
||||
curl --fail-with-body \
|
||||
if ! curl --fail-with-body \
|
||||
-X PATCH \
|
||||
-H "Authorization: token ${TOKEN}" \
|
||||
-H "Authorization: token ${api_token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${release_api}/${existing_release_id}" \
|
||||
--data "{\"tag_name\":\"${TAG_NAME}\",\"target\":\"${GITHUB_SHA}\",\"name\":\"${TAG_NAME}\",\"body\":\"${escaped_release_notes}\",\"draft\":false,\"prerelease\":false}" \
|
||||
--output release.json
|
||||
--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
|
||||
@@ -137,15 +157,18 @@ runs:
|
||||
cat release-existing.json >&2
|
||||
exit 1
|
||||
else
|
||||
curl --fail-with-body \
|
||||
if ! curl --fail-with-body \
|
||||
-X POST \
|
||||
-H "Authorization: token ${TOKEN}" \
|
||||
-H "Authorization: token ${api_token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${release_api}" \
|
||||
--data "{\"tag_name\":\"${TAG_NAME}\",\"target\":\"${GITHUB_SHA}\",\"name\":\"${TAG_NAME}\",\"body\":\"${escaped_release_notes}\",\"draft\":false,\"prerelease\":false}" \
|
||||
--output release.json
|
||||
--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="$(sed -n 's/.*"id"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' release.json | head -n 1)"
|
||||
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
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.0.2
|
||||
1.1.0
|
||||
|
||||
Reference in New Issue
Block a user