Improve build workflow with version bump selection and changelog in releases (#104)
## Summary - Add `version_type` choice input with options: BUMP_PATCH (default), BUMP_MINOR, BUMP_MAJOR, SPECIFIC_VERSION - Add optional `specific_version` input for explicit version selection - Include changelog content in Forgejo release body under "What's Changed" section - Move CHANGELOG.md to repository root (still copied into docs during Quartz build) - Add CHANGELOG link to docs index page - Update doc-links script to recognize build-time docs from repo root ## Changes **Workflow inputs:** - Previously: single optional `version` string input - Now: `version_type` choice dropdown (defaults to BUMP_PATCH) + optional `specific_version` for explicit versions **Release body:** - Previously: just asset download instructions - Now: includes "What's Changed" section with changelog entries for this release **CHANGELOG.md location:** - Previously: `docs/CHANGELOG.md` - Now: `CHANGELOG.md` (repo root), copied into docs content during build ## Deployment and Testing - [ ] Run build workflow with BUMP_PATCH (default) - [ ] Run build workflow with BUMP_MINOR - [ ] Verify changelog appears in release body - [ ] Verify docs site includes CHANGELOG page Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/104
This commit is contained in:
parent
e720b524d3
commit
efdd569285
9 changed files with 129 additions and 39 deletions
|
|
@ -7,7 +7,7 @@
|
|||
#
|
||||
# Usage:
|
||||
# 1. Go to Actions > Build BlumeOps > Run workflow
|
||||
# 2. Enter a version tag (e.g., v1.2.0) or leave empty to auto-increment patch
|
||||
# 2. Select version bump type (patch/minor/major) or choose specific version
|
||||
# 3. The workflow creates a release with attached artifacts
|
||||
#
|
||||
# Documentation asset URL:
|
||||
|
|
@ -18,8 +18,18 @@ name: Build BlumeOps
|
|||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version (e.g., v1.2.0) or empty to auto-increment patch (v_._.+1)'
|
||||
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
|
||||
|
|
@ -31,31 +41,58 @@ jobs:
|
|||
- name: Resolve version
|
||||
id: version
|
||||
run: |
|
||||
INPUT_VERSION="${{ inputs.version }}"
|
||||
VERSION_TYPE="${{ inputs.version_type }}"
|
||||
SPECIFIC_VERSION="${{ inputs.specific_version }}"
|
||||
|
||||
if [ -n "$INPUT_VERSION" ]; then
|
||||
# User provided a version - validate it
|
||||
if [[ ! "$INPUT_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="$INPUT_VERSION"
|
||||
echo "Using provided version: $VERSION"
|
||||
# Fetch latest release
|
||||
echo "Fetching latest release..."
|
||||
LATEST=$(curl -s "https://forge.ops.eblu.me/api/v1/repos/eblume/blumeops/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
|
||||
# Auto-increment patch version from latest release
|
||||
echo "Fetching latest release..."
|
||||
LATEST=$(curl -s "https://forge.ops.eblu.me/api/v1/repos/eblume/blumeops/releases/latest" | jq -r '.tag_name // empty' || true)
|
||||
|
||||
if [ -z "$LATEST" ]; then
|
||||
VERSION="v1.0.0"
|
||||
echo "No previous releases found, starting at: $VERSION"
|
||||
else
|
||||
# Parse vX.Y.Z and increment patch
|
||||
VERSION=$(echo "$LATEST" | awk -F. '{print $1"."$2"."$3+1}')
|
||||
echo "Auto-incremented from $LATEST to: $VERSION"
|
||||
fi
|
||||
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
|
||||
# Validate format
|
||||
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 "https://forge.ops.eblu.me/api/v1/repos/eblume/blumeops/releases/tags/$VERSION" > /dev/null 2>&1; then
|
||||
echo "Error: Release $VERSION already exists"
|
||||
|
|
@ -73,6 +110,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: Build changelog
|
||||
id: changelog
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
|
||||
|
|
@ -83,11 +121,25 @@ jobs:
|
|||
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 to include in release body
|
||||
# The section starts with "## [$VERSION]" and ends before the next "## [" or EOF
|
||||
RELEASE_NOTES=$(awk -v ver="$VERSION" '
|
||||
/^## \[/ {
|
||||
if (found) exit
|
||||
if (index($0, "[" ver "]")) found=1
|
||||
}
|
||||
found {print}
|
||||
' CHANGELOG.md | tail -n +2)
|
||||
|
||||
# Save release notes to a file for later use (handles multiline content)
|
||||
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
|
||||
id: changelog
|
||||
|
||||
- name: Build docs
|
||||
run: |
|
||||
|
|
@ -110,6 +162,9 @@ jobs:
|
|||
rm -rf content
|
||||
cp -r "$GITHUB_WORKSPACE/docs" content
|
||||
|
||||
# Copy CHANGELOG.md from repo root into content so it's accessible in docs
|
||||
cp "$GITHUB_WORKSPACE/CHANGELOG.md" content/
|
||||
|
||||
# Build
|
||||
echo "Building static site..."
|
||||
npx quartz build
|
||||
|
|
@ -128,20 +183,37 @@ jobs:
|
|||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
TARBALL="docs-${VERSION}.tar.gz"
|
||||
CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}"
|
||||
|
||||
echo "Creating release $VERSION..."
|
||||
|
||||
# Use Forgejo API to create release (requires authentication)
|
||||
RELEASE_DATA=$(cat <<EOF
|
||||
# Build release body with changelog if available
|
||||
{
|
||||
"tag_name": "$VERSION",
|
||||
"name": "BlumeOps $VERSION",
|
||||
"body": "BlumeOps release $VERSION\n\n## Documentation\n\nDownload \`$TARBALL\` and configure the quartz container with:\n\n\`\`\`\nDOCS_RELEASE_URL=https://forge.ops.eblu.me/eblume/blumeops/releases/download/$VERSION/$TARBALL\n\`\`\`",
|
||||
"draft": false,
|
||||
"prerelease": false
|
||||
}
|
||||
EOF
|
||||
)
|
||||
echo "BlumeOps 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\` and configure the quartz container with:"
|
||||
echo ""
|
||||
echo "\`\`\`"
|
||||
echo "DOCS_RELEASE_URL=https://forge.ops.eblu.me/eblume/blumeops/releases/download/$VERSION/$TARBALL"
|
||||
echo "\`\`\`"
|
||||
} > /tmp/release_body.txt
|
||||
|
||||
# Use jq to properly escape the body for JSON
|
||||
RELEASE_DATA=$(jq -n \
|
||||
--arg tag "$VERSION" \
|
||||
--arg name "BlumeOps $VERSION" \
|
||||
--rawfile body /tmp/release_body.txt \
|
||||
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')
|
||||
|
||||
RELEASE_RESPONSE=$(curl -s \
|
||||
-X POST \
|
||||
|
|
@ -203,7 +275,7 @@ jobs:
|
|||
|
||||
# Stage changelog changes if updated
|
||||
if [ "$CHANGELOG_UPDATED" = "true" ]; then
|
||||
git add docs/CHANGELOG.md docs/changelog.d/
|
||||
git add CHANGELOG.md docs/changelog.d/
|
||||
fi
|
||||
|
||||
# Check if there are changes to commit
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
---
|
||||
title: changelog
|
||||
tags:
|
||||
- meta
|
||||
---
|
||||
|
||||
# Changelog
|
||||
|
||||
All notable changes to BlumeOps are documented in this file.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Build workflow now supports version bump selection (major/minor/patch) and includes changelog in release body
|
||||
|
|
@ -0,0 +1 @@
|
|||
Move CHANGELOG.md to repository root (still included in docs build)
|
||||
|
|
@ -0,0 +1 @@
|
|||
doc-links script now recognizes build-time docs from repo root (e.g., CHANGELOG.md)
|
||||
|
|
@ -15,7 +15,7 @@ How to publish documentation changes to https://docs.ops.eblu.me.
|
|||
After merging documentation changes to main:
|
||||
|
||||
1. Go to **Actions** > **Build BlumeOps** > **Run workflow**
|
||||
2. Enter a version (e.g., `v1.2.0`) or leave empty to auto-increment
|
||||
2. Select version bump type (patch/minor/major) or enter a specific version
|
||||
3. The workflow builds, releases, and deploys automatically
|
||||
|
||||
Direct link: https://forge.ops.eblu.me/eblume/blumeops/actions?workflow=build-blumeops.yaml
|
||||
|
|
@ -47,7 +47,7 @@ echo "Add new feature X" > docs/changelog.d/my-feature.feature.md
|
|||
echo "Fix bug Y" > docs/changelog.d/+fix-bug.bugfix.md
|
||||
```
|
||||
|
||||
Fragments are automatically collected into `docs/CHANGELOG.md` during release.
|
||||
Fragments are automatically collected into `CHANGELOG.md` (at repo root) during release.
|
||||
|
||||
**Fragment types:**
|
||||
| Type | Directory | Description |
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@ Welcome to the BlumeOps documentation.
|
|||
- [[reference/index | Reference]] - Technical specifications and service details
|
||||
- [[how-to/index | How-to]] - Task-oriented instructions for common operations
|
||||
- [[explanation/index | Explanation]] - Understanding the "why" behind BlumeOps
|
||||
- [[CHANGELOG]] - Release history and changes
|
||||
|
|
|
|||
|
|
@ -82,6 +82,14 @@ def main() -> int:
|
|||
else:
|
||||
ambiguous_filenames.add(filename)
|
||||
|
||||
# Special case: files at repo root that are copied into docs during build
|
||||
# These are valid link targets even though they don't exist in docs/
|
||||
REPO_ROOT = DOCS_DIR.parent
|
||||
BUILD_TIME_DOCS = ["CHANGELOG.md"]
|
||||
for filename in BUILD_TIME_DOCS:
|
||||
if (REPO_ROOT / filename).exists():
|
||||
valid_targets.add(Path(filename).stem)
|
||||
|
||||
# Collect all broken and ambiguous links
|
||||
broken_links: list[tuple[str, int, str]] = []
|
||||
ambiguous_links: list[tuple[str, int, str, list[str]]] = []
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
[tool.towncrier]
|
||||
directory = "docs/changelog.d"
|
||||
filename = "docs/CHANGELOG.md"
|
||||
filename = "CHANGELOG.md"
|
||||
package = ""
|
||||
title_format = "## [{version}] - {project_date}"
|
||||
issue_format = ""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue