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:
|
# Usage:
|
||||||
# 1. Go to Actions > Build BlumeOps > Run workflow
|
# 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
|
# 3. The workflow creates a release with attached artifacts
|
||||||
#
|
#
|
||||||
# Documentation asset URL:
|
# Documentation asset URL:
|
||||||
|
|
@ -18,8 +18,18 @@ name: Build BlumeOps
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version_type:
|
||||||
description: 'Version (e.g., v1.2.0) or empty to auto-increment patch (v_._.+1)'
|
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
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
type: string
|
type: string
|
||||||
|
|
@ -31,30 +41,57 @@ jobs:
|
||||||
- name: Resolve version
|
- name: Resolve version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
INPUT_VERSION="${{ inputs.version }}"
|
VERSION_TYPE="${{ inputs.version_type }}"
|
||||||
|
SPECIFIC_VERSION="${{ inputs.specific_version }}"
|
||||||
|
|
||||||
if [ -n "$INPUT_VERSION" ]; then
|
# Fetch latest release
|
||||||
# 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"
|
|
||||||
else
|
|
||||||
# Auto-increment patch version from latest release
|
|
||||||
echo "Fetching 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)
|
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
|
if [ -z "$LATEST" ]; then
|
||||||
VERSION="v1.0.0"
|
LATEST="v0.0.0"
|
||||||
echo "No previous releases found, starting at: $VERSION"
|
echo "No previous releases found, using base version: $LATEST"
|
||||||
else
|
else
|
||||||
# Parse vX.Y.Z and increment patch
|
echo "Latest release: $LATEST"
|
||||||
VERSION=$(echo "$LATEST" | awk -F. '{print $1"."$2"."$3+1}')
|
|
||||||
echo "Auto-incremented from $LATEST to: $VERSION"
|
|
||||||
fi
|
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
|
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
|
# 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
|
if curl -sf "https://forge.ops.eblu.me/api/v1/repos/eblume/blumeops/releases/tags/$VERSION" > /dev/null 2>&1; then
|
||||||
|
|
@ -73,6 +110,7 @@ jobs:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Build changelog
|
- name: Build changelog
|
||||||
|
id: changelog
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
|
||||||
|
|
@ -83,11 +121,25 @@ jobs:
|
||||||
echo "Found $FRAGMENTS changelog fragments, building changelog..."
|
echo "Found $FRAGMENTS changelog fragments, building changelog..."
|
||||||
uvx towncrier build --version "$VERSION" --yes
|
uvx towncrier build --version "$VERSION" --yes
|
||||||
echo "changelog_updated=true" >> "$GITHUB_OUTPUT"
|
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
|
else
|
||||||
echo "No changelog fragments found, skipping towncrier"
|
echo "No changelog fragments found, skipping towncrier"
|
||||||
echo "changelog_updated=false" >> "$GITHUB_OUTPUT"
|
echo "changelog_updated=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "" > /tmp/release_notes.md
|
||||||
fi
|
fi
|
||||||
id: changelog
|
|
||||||
|
|
||||||
- name: Build docs
|
- name: Build docs
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -110,6 +162,9 @@ jobs:
|
||||||
rm -rf content
|
rm -rf content
|
||||||
cp -r "$GITHUB_WORKSPACE/docs" 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
|
# Build
|
||||||
echo "Building static site..."
|
echo "Building static site..."
|
||||||
npx quartz build
|
npx quartz build
|
||||||
|
|
@ -128,20 +183,37 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
TARBALL="docs-${VERSION}.tar.gz"
|
TARBALL="docs-${VERSION}.tar.gz"
|
||||||
|
CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}"
|
||||||
|
|
||||||
echo "Creating release $VERSION..."
|
echo "Creating release $VERSION..."
|
||||||
|
|
||||||
# Use Forgejo API to create release (requires authentication)
|
# Build release body with changelog if available
|
||||||
RELEASE_DATA=$(cat <<EOF
|
|
||||||
{
|
{
|
||||||
"tag_name": "$VERSION",
|
echo "BlumeOps release $VERSION"
|
||||||
"name": "BlumeOps $VERSION",
|
echo ""
|
||||||
"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,
|
if [ "$CHANGELOG_UPDATED" = "true" ] && [ -s /tmp/release_notes.md ]; then
|
||||||
"prerelease": false
|
echo "## What's Changed"
|
||||||
}
|
echo ""
|
||||||
EOF
|
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 \
|
RELEASE_RESPONSE=$(curl -s \
|
||||||
-X POST \
|
-X POST \
|
||||||
|
|
@ -203,7 +275,7 @@ jobs:
|
||||||
|
|
||||||
# Stage changelog changes if updated
|
# Stage changelog changes if updated
|
||||||
if [ "$CHANGELOG_UPDATED" = "true" ]; then
|
if [ "$CHANGELOG_UPDATED" = "true" ]; then
|
||||||
git add docs/CHANGELOG.md docs/changelog.d/
|
git add CHANGELOG.md docs/changelog.d/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if there are changes to commit
|
# Check if there are changes to commit
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
---
|
||||||
|
title: changelog
|
||||||
|
tags:
|
||||||
|
- meta
|
||||||
|
---
|
||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
All notable changes to BlumeOps are documented in this file.
|
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:
|
After merging documentation changes to main:
|
||||||
|
|
||||||
1. Go to **Actions** > **Build BlumeOps** > **Run workflow**
|
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
|
3. The workflow builds, releases, and deploys automatically
|
||||||
|
|
||||||
Direct link: https://forge.ops.eblu.me/eblume/blumeops/actions?workflow=build-blumeops.yaml
|
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
|
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:**
|
**Fragment types:**
|
||||||
| Type | Directory | Description |
|
| Type | Directory | Description |
|
||||||
|
|
|
||||||
|
|
@ -12,3 +12,4 @@ Welcome to the BlumeOps documentation.
|
||||||
- [[reference/index | Reference]] - Technical specifications and service details
|
- [[reference/index | Reference]] - Technical specifications and service details
|
||||||
- [[how-to/index | How-to]] - Task-oriented instructions for common operations
|
- [[how-to/index | How-to]] - Task-oriented instructions for common operations
|
||||||
- [[explanation/index | Explanation]] - Understanding the "why" behind BlumeOps
|
- [[explanation/index | Explanation]] - Understanding the "why" behind BlumeOps
|
||||||
|
- [[CHANGELOG]] - Release history and changes
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,14 @@ def main() -> int:
|
||||||
else:
|
else:
|
||||||
ambiguous_filenames.add(filename)
|
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
|
# Collect all broken and ambiguous links
|
||||||
broken_links: list[tuple[str, int, str]] = []
|
broken_links: list[tuple[str, int, str]] = []
|
||||||
ambiguous_links: list[tuple[str, int, str, list[str]]] = []
|
ambiguous_links: list[tuple[str, int, str, list[str]]] = []
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
[tool.towncrier]
|
[tool.towncrier]
|
||||||
directory = "docs/changelog.d"
|
directory = "docs/changelog.d"
|
||||||
filename = "docs/CHANGELOG.md"
|
filename = "CHANGELOG.md"
|
||||||
package = ""
|
package = ""
|
||||||
title_format = "## [{version}] - {project_date}"
|
title_format = "## [{version}] - {project_date}"
|
||||||
issue_format = ""
|
issue_format = ""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue