Split template build and release workflows
Some checks failed
Build / validate (push) Failing after 3s
Some checks failed
Build / validate (push) Failing after 3s
This commit is contained in:
parent
d13be54cb4
commit
bcb6e01e58
3 changed files with 304 additions and 222 deletions
|
|
@ -1,240 +1,44 @@
|
|||
# Release Workflow
|
||||
# Build Workflow
|
||||
#
|
||||
# Creates a versioned release with build artifacts.
|
||||
# Currently includes:
|
||||
# - Documentation site (Quartz static build)
|
||||
# - Changelog (built from towncrier fragments)
|
||||
# Generic CI validation for template-based repositories.
|
||||
# By default this runs the repo's prek checks, which already cover:
|
||||
# - workflow linting
|
||||
# - docs integrity checks
|
||||
# - formatting/linting hooks configured by the project
|
||||
#
|
||||
# Usage:
|
||||
# 1. Go to Actions > Build > Run workflow
|
||||
# 2. Select version bump type (patch/minor/major) or choose specific version
|
||||
# 3. The workflow creates a release with attached artifacts
|
||||
# Projects can extend this with an optional executable hook at:
|
||||
# .forgejo/scripts/build
|
||||
#
|
||||
# The optional hook is the place for project-specific validation such as:
|
||||
# - unit/integration tests
|
||||
# - package builds
|
||||
# - schema validation
|
||||
# - language-specific linters
|
||||
|
||||
name: Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version_type:
|
||||
description: 'Version bump type'
|
||||
required: true
|
||||
default: 'BUMP_PATCH'
|
||||
type: choice
|
||||
options:
|
||||
- BUMP_PATCH
|
||||
- BUMP_MINOR
|
||||
- BUMP_MAJOR
|
||||
- SPECIFIC_VERSION
|
||||
specific_version:
|
||||
description: 'Specific version (only used when version_type is SPECIFIC_VERSION, e.g., v1.2.0)'
|
||||
required: false
|
||||
default: ''
|
||||
type: string
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
validate:
|
||||
runs-on: k8s
|
||||
steps:
|
||||
- name: Resolve version
|
||||
id: version
|
||||
run: |
|
||||
VERSION_TYPE="${{ inputs.version_type }}"
|
||||
SPECIFIC_VERSION="${{ inputs.specific_version }}"
|
||||
|
||||
# Fetch latest release
|
||||
FORGE_URL="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
||||
echo "Fetching latest release..."
|
||||
LATEST=$(curl -s "${FORGE_URL}/releases/latest" | jq -r '.tag_name // empty' || true)
|
||||
|
||||
if [ -z "$LATEST" ]; then
|
||||
LATEST="v0.0.0"
|
||||
echo "No previous releases found, using base version: $LATEST"
|
||||
else
|
||||
echo "Latest release: $LATEST"
|
||||
fi
|
||||
|
||||
# Parse current version components (strip 'v' prefix)
|
||||
CURRENT="${LATEST#v}"
|
||||
MAJOR=$(echo "$CURRENT" | cut -d. -f1)
|
||||
MINOR=$(echo "$CURRENT" | cut -d. -f2)
|
||||
PATCH=$(echo "$CURRENT" | cut -d. -f3)
|
||||
|
||||
case "$VERSION_TYPE" in
|
||||
BUMP_MAJOR)
|
||||
VERSION="v$((MAJOR + 1)).0.0"
|
||||
echo "Bumping major: $LATEST -> $VERSION"
|
||||
;;
|
||||
BUMP_MINOR)
|
||||
VERSION="v${MAJOR}.$((MINOR + 1)).0"
|
||||
echo "Bumping minor: $LATEST -> $VERSION"
|
||||
;;
|
||||
BUMP_PATCH)
|
||||
VERSION="v${MAJOR}.${MINOR}.$((PATCH + 1))"
|
||||
echo "Bumping patch: $LATEST -> $VERSION"
|
||||
;;
|
||||
SPECIFIC_VERSION)
|
||||
if [ -z "$SPECIFIC_VERSION" ]; then
|
||||
echo "Error: specific_version is required when version_type is SPECIFIC_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! "$SPECIFIC_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Error: Version must be in format vX.Y.Z (e.g., v1.0.0)"
|
||||
exit 1
|
||||
fi
|
||||
VERSION="$SPECIFIC_VERSION"
|
||||
echo "Using specific version: $VERSION"
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unknown version_type: $VERSION_TYPE"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check if this version already exists
|
||||
if curl -sf "${FORGE_URL}/releases/tags/$VERSION" > /dev/null 2>&1; then
|
||||
echo "Error: Release $VERSION already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "Building release: $VERSION"
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build changelog
|
||||
id: changelog
|
||||
- name: Run repository checks
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
prek run --all-files
|
||||
|
||||
FRAGMENTS=$(find docs/changelog.d -name "*.md" -not -name ".gitkeep" 2>/dev/null | wc -l)
|
||||
|
||||
if [ "$FRAGMENTS" -gt 0 ]; then
|
||||
echo "Found $FRAGMENTS changelog fragments, building changelog..."
|
||||
uvx towncrier build --version "$VERSION" --yes
|
||||
echo "changelog_updated=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Extract the changelog section for this release
|
||||
RELEASE_NOTES=$(awk -v ver="$VERSION" '
|
||||
/^## \[/ {
|
||||
if (found) exit
|
||||
if (index($0, "[" ver "]")) found=1
|
||||
}
|
||||
found {print}
|
||||
' CHANGELOG.md | tail -n +2)
|
||||
|
||||
echo "$RELEASE_NOTES" > /tmp/release_notes.md
|
||||
echo "Release notes extracted for $VERSION"
|
||||
- name: Run project-specific build hook
|
||||
run: |
|
||||
if [ -x .forgejo/scripts/build ]; then
|
||||
echo "Running project-specific build hook..."
|
||||
./.forgejo/scripts/build
|
||||
else
|
||||
echo "No changelog fragments found, skipping towncrier"
|
||||
echo "changelog_updated=false" >> "$GITHUB_OUTPUT"
|
||||
echo "" > /tmp/release_notes.md
|
||||
echo "No .forgejo/scripts/build hook found; template validation complete."
|
||||
fi
|
||||
|
||||
- name: Build docs
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
TARBALL="docs-${VERSION}.tar.gz"
|
||||
echo "Building docs via Dagger..."
|
||||
dagger call build-docs --src=. --version="$VERSION" \
|
||||
export --path="./$TARBALL"
|
||||
echo "Build complete!"
|
||||
ls -lh "$TARBALL"
|
||||
|
||||
- name: Create release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
TARBALL="docs-${VERSION}.tar.gz"
|
||||
CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}"
|
||||
|
||||
FORGE_URL="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
||||
|
||||
echo "Creating release $VERSION..."
|
||||
|
||||
{
|
||||
echo "Release $VERSION"
|
||||
echo ""
|
||||
|
||||
if [ "$CHANGELOG_UPDATED" = "true" ] && [ -s /tmp/release_notes.md ]; then
|
||||
echo "## What's Changed"
|
||||
echo ""
|
||||
cat /tmp/release_notes.md
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "## Documentation"
|
||||
echo ""
|
||||
echo "Download \`$TARBALL\` for the documentation site build."
|
||||
} > /tmp/release_body.txt
|
||||
|
||||
RELEASE_DATA=$(jq -n \
|
||||
--arg tag "$VERSION" \
|
||||
--arg name "Release $VERSION" \
|
||||
--rawfile body /tmp/release_body.txt \
|
||||
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')
|
||||
|
||||
RELEASE_RESPONSE=$(curl -s \
|
||||
-X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-d "$RELEASE_DATA" \
|
||||
"${FORGE_URL}/releases")
|
||||
|
||||
echo "API Response: $RELEASE_RESPONSE"
|
||||
|
||||
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | jq -r '.id')
|
||||
|
||||
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then
|
||||
echo "Error: Failed to create release"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Created release ID: $RELEASE_ID"
|
||||
|
||||
# Upload the asset
|
||||
echo "Uploading $TARBALL..."
|
||||
curl -s \
|
||||
-X POST \
|
||||
-H "Content-Type: application/gzip" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
--data-binary "@$TARBALL" \
|
||||
"${FORGE_URL}/releases/$RELEASE_ID/assets?name=$TARBALL"
|
||||
|
||||
echo ""
|
||||
echo "Release created successfully!"
|
||||
|
||||
- name: Commit changelog changes
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}"
|
||||
|
||||
if [ "$CHANGELOG_UPDATED" != "true" ]; then
|
||||
echo "No changelog changes to commit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git config user.name "Forgejo Actions"
|
||||
git config user.email "actions@forge.eblu.me"
|
||||
|
||||
git add CHANGELOG.md docs/changelog.d/
|
||||
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes to commit"
|
||||
else
|
||||
git commit -m "Update changelog for $VERSION [skip ci]"
|
||||
git push origin HEAD:main
|
||||
echo "Changelog changes committed and pushed"
|
||||
fi
|
||||
|
||||
- name: Summary
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
echo "================================================"
|
||||
echo "Release: $VERSION"
|
||||
echo "================================================"
|
||||
|
|
|
|||
277
.forgejo/workflows/release.yaml
Normal file
277
.forgejo/workflows/release.yaml
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
# Release Workflow
|
||||
#
|
||||
# Creates a versioned Forgejo release for template-based repositories.
|
||||
# By default this includes:
|
||||
# - Documentation site bundle (Quartz static build via Dagger)
|
||||
# - Changelog section built from towncrier fragments, when present
|
||||
#
|
||||
# Projects can optionally attach additional release artifacts by providing
|
||||
# an executable hook at `.forgejo/scripts/release`. That hook should place
|
||||
# any extra files under `release-assets/` for upload to the release.
|
||||
#
|
||||
# Usage:
|
||||
# 1. Go to Actions > Release > Run workflow
|
||||
# 2. Select version bump type (patch/minor/major) or choose specific version
|
||||
# 3. The workflow creates a release with the docs bundle and optional extras
|
||||
|
||||
name: Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version_type:
|
||||
description: "Version bump type"
|
||||
required: true
|
||||
default: "BUMP_PATCH"
|
||||
type: choice
|
||||
options:
|
||||
- BUMP_PATCH
|
||||
- BUMP_MINOR
|
||||
- BUMP_MAJOR
|
||||
- SPECIFIC_VERSION
|
||||
specific_version:
|
||||
description: "Specific version (only used when version_type is SPECIFIC_VERSION, e.g., v1.2.0)"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: k8s
|
||||
steps:
|
||||
- name: Resolve version
|
||||
id: version
|
||||
run: |
|
||||
VERSION_TYPE="${{ inputs.version_type }}"
|
||||
SPECIFIC_VERSION="${{ inputs.specific_version }}"
|
||||
|
||||
FORGE_URL="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
||||
echo "Fetching latest release..."
|
||||
LATEST=$(curl -s "${FORGE_URL}/releases/latest" | jq -r '.tag_name // empty' || true)
|
||||
|
||||
if [ -z "$LATEST" ]; then
|
||||
LATEST="v0.0.0"
|
||||
echo "No previous releases found, using base version: $LATEST"
|
||||
else
|
||||
echo "Latest release: $LATEST"
|
||||
fi
|
||||
|
||||
CURRENT="${LATEST#v}"
|
||||
MAJOR=$(echo "$CURRENT" | cut -d. -f1)
|
||||
MINOR=$(echo "$CURRENT" | cut -d. -f2)
|
||||
PATCH=$(echo "$CURRENT" | cut -d. -f3)
|
||||
|
||||
case "$VERSION_TYPE" in
|
||||
BUMP_MAJOR)
|
||||
VERSION="v$((MAJOR + 1)).0.0"
|
||||
echo "Bumping major: $LATEST -> $VERSION"
|
||||
;;
|
||||
BUMP_MINOR)
|
||||
VERSION="v${MAJOR}.$((MINOR + 1)).0"
|
||||
echo "Bumping minor: $LATEST -> $VERSION"
|
||||
;;
|
||||
BUMP_PATCH)
|
||||
VERSION="v${MAJOR}.${MINOR}.$((PATCH + 1))"
|
||||
echo "Bumping patch: $LATEST -> $VERSION"
|
||||
;;
|
||||
SPECIFIC_VERSION)
|
||||
if [ -z "$SPECIFIC_VERSION" ]; then
|
||||
echo "Error: specific_version is required when version_type is SPECIFIC_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! "$SPECIFIC_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Error: Version must be in format vX.Y.Z (e.g., v1.0.0)"
|
||||
exit 1
|
||||
fi
|
||||
VERSION="$SPECIFIC_VERSION"
|
||||
echo "Using specific version: $VERSION"
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unknown version_type: $VERSION_TYPE"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if curl -sf "${FORGE_URL}/releases/tags/$VERSION" > /dev/null 2>&1; then
|
||||
echo "Error: Release $VERSION already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "Building release: $VERSION"
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build changelog
|
||||
id: changelog
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
|
||||
FRAGMENTS=$(find docs/changelog.d -name "*.md" -not -name ".gitkeep" 2>/dev/null | wc -l)
|
||||
|
||||
if [ "$FRAGMENTS" -gt 0 ]; then
|
||||
echo "Found $FRAGMENTS changelog fragments, building changelog..."
|
||||
uvx towncrier build --version "$VERSION" --yes
|
||||
echo "changelog_updated=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
RELEASE_NOTES=$(awk -v ver="$VERSION" '
|
||||
/^## \[/ {
|
||||
if (found) exit
|
||||
if (index($0, "[" ver "]")) found=1
|
||||
}
|
||||
found {print}
|
||||
' CHANGELOG.md | tail -n +2)
|
||||
|
||||
echo "$RELEASE_NOTES" > /tmp/release_notes.md
|
||||
echo "Release notes extracted for $VERSION"
|
||||
else
|
||||
echo "No changelog fragments found, skipping towncrier"
|
||||
echo "changelog_updated=false" >> "$GITHUB_OUTPUT"
|
||||
echo "" > /tmp/release_notes.md
|
||||
fi
|
||||
|
||||
- name: Build docs
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
TARBALL="docs-${VERSION}.tar.gz"
|
||||
echo "Building docs via Dagger..."
|
||||
dagger call build-docs --src=. --version="$VERSION" \
|
||||
export --path="./$TARBALL"
|
||||
echo "Build complete!"
|
||||
ls -lh "$TARBALL"
|
||||
|
||||
- name: Build project-specific release artifacts
|
||||
run: |
|
||||
rm -rf release-assets
|
||||
mkdir -p release-assets
|
||||
|
||||
if [ -x .forgejo/scripts/release ]; then
|
||||
echo "Running project-specific release hook..."
|
||||
./.forgejo/scripts/release "${{ steps.version.outputs.version }}"
|
||||
else
|
||||
echo "No .forgejo/scripts/release hook found; docs-only release."
|
||||
fi
|
||||
|
||||
echo "Release asset inventory:"
|
||||
find release-assets -maxdepth 1 -type f -print | sort || true
|
||||
|
||||
- name: Create release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
TARBALL="docs-${VERSION}.tar.gz"
|
||||
CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}"
|
||||
FORGE_URL="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
||||
|
||||
echo "Creating release $VERSION..."
|
||||
|
||||
{
|
||||
echo "Release $VERSION"
|
||||
echo ""
|
||||
|
||||
if [ "$CHANGELOG_UPDATED" = "true" ] && [ -s /tmp/release_notes.md ]; then
|
||||
echo "## What's Changed"
|
||||
echo ""
|
||||
cat /tmp/release_notes.md
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "## Assets"
|
||||
echo ""
|
||||
echo "- \`$TARBALL\` contains the static docs site."
|
||||
|
||||
EXTRA_ASSET_COUNT=$(find release-assets -maxdepth 1 -type f | wc -l | tr -d ' ')
|
||||
if [ "$EXTRA_ASSET_COUNT" -gt 0 ]; then
|
||||
echo "- Additional project-specific artifacts are attached to this release."
|
||||
fi
|
||||
} > /tmp/release_body.txt
|
||||
|
||||
RELEASE_DATA=$(jq -n \
|
||||
--arg tag "$VERSION" \
|
||||
--arg name "Release $VERSION" \
|
||||
--rawfile body /tmp/release_body.txt \
|
||||
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')
|
||||
|
||||
RELEASE_RESPONSE=$(curl -s \
|
||||
-X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-d "$RELEASE_DATA" \
|
||||
"${FORGE_URL}/releases")
|
||||
|
||||
echo "API Response: $RELEASE_RESPONSE"
|
||||
|
||||
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | jq -r '.id')
|
||||
|
||||
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then
|
||||
echo "Error: Failed to create release"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Created release ID: $RELEASE_ID"
|
||||
|
||||
echo "Uploading $TARBALL..."
|
||||
curl -s \
|
||||
-X POST \
|
||||
-H "Content-Type: application/gzip" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
--data-binary "@$TARBALL" \
|
||||
"${FORGE_URL}/releases/$RELEASE_ID/assets?name=$TARBALL"
|
||||
|
||||
for artifact in release-assets/*; do
|
||||
if [ ! -f "$artifact" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
FILENAME=$(basename "$artifact")
|
||||
echo "Uploading $FILENAME..."
|
||||
curl -s \
|
||||
-X POST \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
--data-binary "@$artifact" \
|
||||
"${FORGE_URL}/releases/$RELEASE_ID/assets?name=$FILENAME"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Release created successfully!"
|
||||
|
||||
- name: Commit changelog changes
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}"
|
||||
|
||||
if [ "$CHANGELOG_UPDATED" != "true" ]; then
|
||||
echo "No changelog changes to commit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git config user.name "Forgejo Actions"
|
||||
git config user.email "actions@forge.eblu.me"
|
||||
|
||||
git add CHANGELOG.md docs/changelog.d/
|
||||
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes to commit"
|
||||
else
|
||||
git commit -m "Update changelog for $VERSION [skip ci]"
|
||||
git push origin HEAD:main
|
||||
echo "Changelog changes committed and pushed"
|
||||
fi
|
||||
|
||||
- name: Summary
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
EXTRA_ASSET_COUNT=$(find release-assets -maxdepth 1 -type f | wc -l | tr -d ' ')
|
||||
|
||||
echo "================================================"
|
||||
echo "Release: $VERSION"
|
||||
echo "================================================"
|
||||
echo "Docs bundle: docs-${VERSION}.tar.gz"
|
||||
echo "Extra project assets: $EXTRA_ASSET_COUNT"
|
||||
1
docs/changelog.d/+forgejo-workflow-templates.infra.md
Normal file
1
docs/changelog.d/+forgejo-workflow-templates.infra.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Split the template's Forgejo workflows into a generic CI `build` workflow and a docs-first `release` workflow, with optional hooks for project-specific validation and release artifacts.
|
||||
Loading…
Add table
Add a link
Reference in a new issue