From 0e495ef2f508ad57b90f01a6b86c2a4c4374cdc3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 17:59:20 +0000 Subject: [PATCH 1/3] Initial plan From 7715bc013ba2d0bee5f5316f8b80e7ddf261fd2b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 18:01:42 +0000 Subject: [PATCH 2/3] Add automated release notes generation workflow Co-authored-by: elenafuengar <83642100+elenafuengar@users.noreply.github.com> --- .github/workflows/update_release_notes.yml | 199 +++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 .github/workflows/update_release_notes.yml diff --git a/.github/workflows/update_release_notes.yml b/.github/workflows/update_release_notes.yml new file mode 100644 index 0000000..281e420 --- /dev/null +++ b/.github/workflows/update_release_notes.yml @@ -0,0 +1,199 @@ +name: Update Release Notes + +on: + push: + branches: + - main + pull_request: + branches: + - main + types: [opened, synchronize, reopened] + +jobs: + update-release-notes: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for proper changelog generation + ref: ${{ github.head_ref || github.ref_name }} + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Generate release notes + run: | + # Get the version from setup.py + VERSION=$(python setup.py --version 2>/dev/null || echo "dev") + + # Determine the commit range + if [ "${{ github.event_name }}" = "pull_request" ]; then + BASE_REF="${{ github.event.pull_request.base.sha }}" + HEAD_REF="${{ github.event.pull_request.head.sha }}" + COMMIT_RANGE="${BASE_REF}..${HEAD_REF}" + else + # For push events, use the last 20 commits + COMMIT_RANGE="HEAD~20..HEAD" + fi + + # Create a temporary file for the new release notes + cat > /tmp/new_release_section.md << 'EOF' + # v${VERSION} + + This release includes updates from recent commits. + + --- + + ## ๐Ÿš€ New Features + + EOF + + # Process commits and categorize them + echo "Processing commits in range: ${COMMIT_RANGE}" + + # Extract feature commits + git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^feature:" --grep="^feat:" -i > /tmp/features.txt || true + if [ -s /tmp/features.txt ]; then + cat /tmp/features.txt >> /tmp/new_release_section.md + else + echo "* No new features in this update" >> /tmp/new_release_section.md + fi + + echo "" >> /tmp/new_release_section.md + echo "---" >> /tmp/new_release_section.md + echo "" >> /tmp/new_release_section.md + echo "## ๐Ÿ’— Other Tag Highlights" >> /tmp/new_release_section.md + echo "" >> /tmp/new_release_section.md + echo "* ๐Ÿ” **Tests**" >> /tmp/new_release_section.md + + # Extract test commits + git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^test:" -i > /tmp/tests.txt || true + if [ -s /tmp/tests.txt ]; then + cat /tmp/tests.txt >> /tmp/new_release_section.md + else + echo " * No test updates" >> /tmp/new_release_section.md + fi + + echo "" >> /tmp/new_release_section.md + echo "* ๐Ÿ“š **Documentation**" >> /tmp/new_release_section.md + + # Extract doc commits + git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^docs:" -i > /tmp/docs.txt || true + if [ -s /tmp/docs.txt ]; then + cat /tmp/docs.txt >> /tmp/new_release_section.md + else + echo " * No documentation updates" >> /tmp/new_release_section.md + fi + + echo "" >> /tmp/new_release_section.md + echo "---" >> /tmp/new_release_section.md + echo "" >> /tmp/new_release_section.md + echo "## ๐Ÿ› **Bugfixes**" >> /tmp/new_release_section.md + echo "" >> /tmp/new_release_section.md + + # Extract bugfix commits + git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^fix:" --grep="^bugfix:" -i > /tmp/fixes.txt || true + if [ -s /tmp/fixes.txt ]; then + cat /tmp/fixes.txt >> /tmp/new_release_section.md + else + echo "* No bugfixes in this update" >> /tmp/new_release_section.md + fi + + echo "" >> /tmp/new_release_section.md + echo "---" >> /tmp/new_release_section.md + echo "" >> /tmp/new_release_section.md + echo "## ๐Ÿ“ **Full changelog**" >> /tmp/new_release_section.md + echo "" >> /tmp/new_release_section.md + + # Count commits by category + TOTAL_COMMITS=$(git log ${COMMIT_RANGE} --oneline | wc -l) + FEAT_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^feature:" --grep="^feat:" -i | wc -l || echo 0) + TEST_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^test:" -i | wc -l || echo 0) + DOCS_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^docs:" -i | wc -l || echo 0) + FIX_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^fix:" --grep="^bugfix:" -i | wc -l || echo 0) + STYLE_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^style:" -i | wc -l || echo 0) + + if [ ${TOTAL_COMMITS} -gt 0 ]; then + FEAT_PCT=$(awk "BEGIN {printf \"%.1f\", (${FEAT_COUNT}/${TOTAL_COMMITS})*100}") + TEST_PCT=$(awk "BEGIN {printf \"%.1f\", (${TEST_COUNT}/${TOTAL_COMMITS})*100}") + DOCS_PCT=$(awk "BEGIN {printf \"%.1f\", (${DOCS_COUNT}/${TOTAL_COMMITS})*100}") + FIX_PCT=$(awk "BEGIN {printf \"%.1f\", (${FIX_COUNT}/${TOTAL_COMMITS})*100}") + STYLE_PCT=$(awk "BEGIN {printf \"%.1f\", (${STYLE_COUNT}/${TOTAL_COMMITS})*100}") + OTHER_COUNT=$((TOTAL_COMMITS - FEAT_COUNT - TEST_COUNT - DOCS_COUNT - FIX_COUNT - STYLE_COUNT)) + OTHER_PCT=$(awk "BEGIN {printf \"%.1f\", (${OTHER_COUNT}/${TOTAL_COMMITS})*100}") + else + FEAT_PCT=0 + TEST_PCT=0 + DOCS_PCT=0 + FIX_PCT=0 + STYLE_PCT=0 + OTHER_PCT=0 + fi + + cat >> /tmp/new_release_section.md << EOF + | **${TOTAL_COMMITS} commits** | ๐Ÿ“š Docs | ๐Ÿงช Tests | ๐Ÿ› Fixes | ๐ŸŽจ Style | โœจ Features | Other | + |-----------------|---------|----------|-----------|------------|--------------|-------| + | % of Commits | ${DOCS_PCT}% | ${TEST_PCT}% | ${FIX_PCT}% | ${STYLE_PCT}% | ${FEAT_PCT}% | ${OTHER_PCT}% | + + EOF + + echo "" >> /tmp/new_release_section.md + echo '`git log --date=short --pretty=format:"* %ad %s (%aN)"`' >> /tmp/new_release_section.md + echo "" >> /tmp/new_release_section.md + echo "" >> /tmp/new_release_section.md + + # Add all commits + git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" >> /tmp/new_release_section.md + + echo "" >> /tmp/new_release_section.md + echo "" >> /tmp/new_release_section.md + + # Prepend the new section to the existing release.md + if [ -f release.md ]; then + cat /tmp/new_release_section.md > /tmp/updated_release.md + echo "---" >> /tmp/updated_release.md + echo "" >> /tmp/updated_release.md + cat release.md >> /tmp/updated_release.md + mv /tmp/updated_release.md release.md + else + mv /tmp/new_release_section.md release.md + fi + + # Replace ${VERSION} placeholder + sed -i "s/\${VERSION}/${VERSION}/g" release.md + + - name: Check for changes + id: check_changes + run: | + if git diff --quiet release.md; then + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "No changes to release.md" + else + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "Changes detected in release.md" + fi + + - name: Commit and push changes + if: steps.check_changes.outputs.has_changes == 'true' && github.event_name == 'push' + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add release.md + git commit -m "chore: auto-update release.md [skip ci]" + git push + + - name: Commit changes to PR + if: steps.check_changes.outputs.has_changes == 'true' && github.event_name == 'pull_request' + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add release.md + git commit -m "chore: auto-update release.md for PR #${{ github.event.pull_request.number }}" + git push origin HEAD:${{ github.head_ref }} From e4587b07f84527605861037f722187ce96a2a17b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 18:05:18 +0000 Subject: [PATCH 3/3] Improve release notes workflow with unreleased section and documentation Co-authored-by: elenafuengar <83642100+elenafuengar@users.noreply.github.com> --- .../workflows/README_update_release_notes.md | 85 +++++++++ .github/workflows/update_release_notes.yml | 166 +++++++++++------- 2 files changed, 188 insertions(+), 63 deletions(-) create mode 100644 .github/workflows/README_update_release_notes.md diff --git a/.github/workflows/README_update_release_notes.md b/.github/workflows/README_update_release_notes.md new file mode 100644 index 0000000..2497177 --- /dev/null +++ b/.github/workflows/README_update_release_notes.md @@ -0,0 +1,85 @@ +# Automated Release Notes Workflow + +This document explains how the automated release notes generation workflow works. + +## Overview + +The `update_release_notes.yml` workflow automatically updates the `release.md` file whenever: +- Commits are pushed to the `main` branch +- Pull requests are opened, synchronized, or reopened targeting the `main` branch + +## How It Works + +### Commit Range Detection + +- **For Pull Requests**: Analyzes commits between the PR base and head +- **For Push Events**: Analyzes commits since the last tag, or last 50 commits if no tags exist + +### Categorization + +The workflow categorizes commits based on conventional commit prefixes: + +- **๐Ÿš€ Features**: Commits starting with `feature:` or `feat:` +- **๐Ÿงช Tests**: Commits starting with `test:` +- **๐Ÿ“š Documentation**: Commits starting with `docs:` +- **โš™๏ธ Build & Compatibility**: Commits starting with `build:` or `ci:` +- **๐Ÿ› Bugfixes**: Commits starting with `fix:` or `bugfix:` +- **๐ŸŽจ Style**: Commits starting with `style:` + +### Release Notes Structure + +The workflow generates an "Unreleased" section at the top of `release.md` with: + +1. **New Features**: List of feature commits +2. **Other Tag Highlights**: Organized by category (Tests, Docs, Build) +3. **Bugfixes**: List of bugfix commits +4. **Full Changelog**: Statistics table showing commit distribution and complete commit list + +### Workflow Behavior + +1. **On Push to Main**: The workflow commits and pushes the updated `release.md` directly to the main branch +2. **On Pull Request**: The workflow commits the updated `release.md` to the PR branch + +The commit message includes `[skip ci]` for push events to prevent triggering the workflow recursively. + +## Using Conventional Commit Messages + +To take full advantage of automatic categorization, use conventional commit prefixes: + +```bash +# Examples +git commit -m "feat: add new GPU acceleration support" +git commit -m "fix: resolve memory leak in solver" +git commit -m "docs: update installation guide" +git commit -m "test: add unit tests for geometry module" +git commit -m "style: format code with black" +git commit -m "build: update numpy dependency" +``` + +## Manual Release Process + +When you're ready to publish a new release: + +1. Review the "Unreleased" section in `release.md` +2. Manually edit it to: + - Change "# Unreleased" to "# v{version}" + - Add a descriptive summary of the release + - Organize and expand the automatically generated content + - Add any additional sections (e.g., "New Contributors") +3. Commit the changes +4. Tag the release using `release.sh` or manually + +The next time the workflow runs, it will create a new "Unreleased" section above your versioned release. + +## Disabling the Workflow + +If you need to temporarily disable automatic release notes: + +1. Rename the workflow file or move it to a different directory +2. Or add a condition to skip the workflow in certain cases + +## Troubleshooting + +- **No changes detected**: The workflow only commits if there are actual changes to `release.md` +- **Permission errors**: Ensure the workflow has `contents: write` permission +- **Commit range issues**: For repositories with shallow clones, increase fetch-depth in checkout action diff --git a/.github/workflows/update_release_notes.yml b/.github/workflows/update_release_notes.yml index 281e420..4f72d5f 100644 --- a/.github/workflows/update_release_notes.yml +++ b/.github/workflows/update_release_notes.yml @@ -39,15 +39,31 @@ jobs: HEAD_REF="${{ github.event.pull_request.head.sha }}" COMMIT_RANGE="${BASE_REF}..${HEAD_REF}" else - # For push events, use the last 20 commits - COMMIT_RANGE="HEAD~20..HEAD" + # For push events, get the last tag and use commits since then + LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + if [ -n "$LAST_TAG" ]; then + COMMIT_RANGE="${LAST_TAG}..HEAD" + else + # If no tags, use last 50 commits + COMMIT_RANGE="HEAD~50..HEAD" 2>/dev/null || COMMIT_RANGE="HEAD" + fi fi - # Create a temporary file for the new release notes - cat > /tmp/new_release_section.md << 'EOF' - # v${VERSION} + echo "Processing commits in range: ${COMMIT_RANGE}" + + # Count total commits in range + TOTAL_COMMITS=$(git log ${COMMIT_RANGE} --oneline 2>/dev/null | wc -l || echo 0) + + if [ ${TOTAL_COMMITS} -eq 0 ]; then + echo "No new commits to process" + exit 0 + fi + + # Create a temporary file for the unreleased section + cat > /tmp/unreleased_section.md << 'EOF' + # Unreleased - This release includes updates from recent commits. + This section contains updates that will be included in the next release. --- @@ -55,70 +71,77 @@ jobs: EOF - # Process commits and categorize them - echo "Processing commits in range: ${COMMIT_RANGE}" - # Extract feature commits - git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^feature:" --grep="^feat:" -i > /tmp/features.txt || true + git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^feature:" --grep="^feat:" -i 2>/dev/null > /tmp/features.txt || true if [ -s /tmp/features.txt ]; then - cat /tmp/features.txt >> /tmp/new_release_section.md + cat /tmp/features.txt >> /tmp/unreleased_section.md else - echo "* No new features in this update" >> /tmp/new_release_section.md + echo "* No new features yet" >> /tmp/unreleased_section.md fi - echo "" >> /tmp/new_release_section.md - echo "---" >> /tmp/new_release_section.md - echo "" >> /tmp/new_release_section.md - echo "## ๐Ÿ’— Other Tag Highlights" >> /tmp/new_release_section.md - echo "" >> /tmp/new_release_section.md - echo "* ๐Ÿ” **Tests**" >> /tmp/new_release_section.md + echo "" >> /tmp/unreleased_section.md + echo "---" >> /tmp/unreleased_section.md + echo "" >> /tmp/unreleased_section.md + echo "## ๐Ÿ’— Other Tag Highlights" >> /tmp/unreleased_section.md + echo "" >> /tmp/unreleased_section.md + echo "* ๐Ÿ” **Tests**" >> /tmp/unreleased_section.md # Extract test commits - git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^test:" -i > /tmp/tests.txt || true + git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^test:" -i 2>/dev/null > /tmp/tests.txt || true if [ -s /tmp/tests.txt ]; then - cat /tmp/tests.txt >> /tmp/new_release_section.md + cat /tmp/tests.txt >> /tmp/unreleased_section.md else - echo " * No test updates" >> /tmp/new_release_section.md + echo " * No test updates" >> /tmp/unreleased_section.md fi - echo "" >> /tmp/new_release_section.md - echo "* ๐Ÿ“š **Documentation**" >> /tmp/new_release_section.md + echo "" >> /tmp/unreleased_section.md + echo "* ๐Ÿ“š **Documentation**" >> /tmp/unreleased_section.md # Extract doc commits - git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^docs:" -i > /tmp/docs.txt || true + git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^docs:" -i 2>/dev/null > /tmp/docs.txt || true if [ -s /tmp/docs.txt ]; then - cat /tmp/docs.txt >> /tmp/new_release_section.md + cat /tmp/docs.txt >> /tmp/unreleased_section.md + else + echo " * No documentation updates" >> /tmp/unreleased_section.md + fi + + echo "" >> /tmp/unreleased_section.md + echo "* โš™๏ธ **Build & Compatibility**" >> /tmp/unreleased_section.md + + # Extract build commits + git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^build:" --grep="^ci:" -i 2>/dev/null > /tmp/build.txt || true + if [ -s /tmp/build.txt ]; then + cat /tmp/build.txt >> /tmp/unreleased_section.md else - echo " * No documentation updates" >> /tmp/new_release_section.md + echo " * No build updates" >> /tmp/unreleased_section.md fi - echo "" >> /tmp/new_release_section.md - echo "---" >> /tmp/new_release_section.md - echo "" >> /tmp/new_release_section.md - echo "## ๐Ÿ› **Bugfixes**" >> /tmp/new_release_section.md - echo "" >> /tmp/new_release_section.md + echo "" >> /tmp/unreleased_section.md + echo "---" >> /tmp/unreleased_section.md + echo "" >> /tmp/unreleased_section.md + echo "## ๐Ÿ› **Bugfixes**" >> /tmp/unreleased_section.md + echo "" >> /tmp/unreleased_section.md # Extract bugfix commits - git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^fix:" --grep="^bugfix:" -i > /tmp/fixes.txt || true + git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^fix:" --grep="^bugfix:" -i 2>/dev/null > /tmp/fixes.txt || true if [ -s /tmp/fixes.txt ]; then - cat /tmp/fixes.txt >> /tmp/new_release_section.md + cat /tmp/fixes.txt >> /tmp/unreleased_section.md else - echo "* No bugfixes in this update" >> /tmp/new_release_section.md + echo "* No bugfixes yet" >> /tmp/unreleased_section.md fi - echo "" >> /tmp/new_release_section.md - echo "---" >> /tmp/new_release_section.md - echo "" >> /tmp/new_release_section.md - echo "## ๐Ÿ“ **Full changelog**" >> /tmp/new_release_section.md - echo "" >> /tmp/new_release_section.md + echo "" >> /tmp/unreleased_section.md + echo "---" >> /tmp/unreleased_section.md + echo "" >> /tmp/unreleased_section.md + echo "## ๐Ÿ“ **Full changelog**" >> /tmp/unreleased_section.md + echo "" >> /tmp/unreleased_section.md # Count commits by category - TOTAL_COMMITS=$(git log ${COMMIT_RANGE} --oneline | wc -l) - FEAT_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^feature:" --grep="^feat:" -i | wc -l || echo 0) - TEST_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^test:" -i | wc -l || echo 0) - DOCS_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^docs:" -i | wc -l || echo 0) - FIX_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^fix:" --grep="^bugfix:" -i | wc -l || echo 0) - STYLE_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^style:" -i | wc -l || echo 0) + FEAT_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^feature:" --grep="^feat:" -i 2>/dev/null | wc -l || echo 0) + TEST_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^test:" -i 2>/dev/null | wc -l || echo 0) + DOCS_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^docs:" -i 2>/dev/null | wc -l || echo 0) + FIX_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^fix:" --grep="^bugfix:" -i 2>/dev/null | wc -l || echo 0) + STYLE_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^style:" -i 2>/dev/null | wc -l || echo 0) if [ ${TOTAL_COMMITS} -gt 0 ]; then FEAT_PCT=$(awk "BEGIN {printf \"%.1f\", (${FEAT_COUNT}/${TOTAL_COMMITS})*100}") @@ -137,37 +160,54 @@ jobs: OTHER_PCT=0 fi - cat >> /tmp/new_release_section.md << EOF + cat >> /tmp/unreleased_section.md << EOF | **${TOTAL_COMMITS} commits** | ๐Ÿ“š Docs | ๐Ÿงช Tests | ๐Ÿ› Fixes | ๐ŸŽจ Style | โœจ Features | Other | |-----------------|---------|----------|-----------|------------|--------------|-------| | % of Commits | ${DOCS_PCT}% | ${TEST_PCT}% | ${FIX_PCT}% | ${STYLE_PCT}% | ${FEAT_PCT}% | ${OTHER_PCT}% | EOF - echo "" >> /tmp/new_release_section.md - echo '`git log --date=short --pretty=format:"* %ad %s (%aN)"`' >> /tmp/new_release_section.md - echo "" >> /tmp/new_release_section.md - echo "" >> /tmp/new_release_section.md + echo "" >> /tmp/unreleased_section.md + echo '`git log --date=short --pretty=format:"* %ad %s (%aN)"`' >> /tmp/unreleased_section.md + echo "" >> /tmp/unreleased_section.md + echo "" >> /tmp/unreleased_section.md # Add all commits - git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" >> /tmp/new_release_section.md + git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" 2>/dev/null >> /tmp/unreleased_section.md || true - echo "" >> /tmp/new_release_section.md - echo "" >> /tmp/new_release_section.md + echo "" >> /tmp/unreleased_section.md + echo "" >> /tmp/unreleased_section.md - # Prepend the new section to the existing release.md + # Update release.md if [ -f release.md ]; then - cat /tmp/new_release_section.md > /tmp/updated_release.md - echo "---" >> /tmp/updated_release.md - echo "" >> /tmp/updated_release.md - cat release.md >> /tmp/updated_release.md - mv /tmp/updated_release.md release.md + # Check if there's already an Unreleased section and remove it + if grep -q "^# Unreleased" release.md; then + # Find the line number of the first released version (starts with # v) + FIRST_VERSION_LINE=$(grep -n "^# v[0-9]" release.md | head -1 | cut -d: -f1) + if [ -n "$FIRST_VERSION_LINE" ]; then + # Keep everything from the first version onwards + tail -n +${FIRST_VERSION_LINE} release.md > /tmp/existing_releases.md + # Prepend new unreleased section + cat /tmp/unreleased_section.md > release.md + echo "---" >> release.md + echo "" >> release.md + cat /tmp/existing_releases.md >> release.md + else + # No versioned releases found, just replace with unreleased + mv /tmp/unreleased_section.md release.md + fi + else + # No unreleased section exists, prepend to existing content + cat /tmp/unreleased_section.md > /tmp/updated_release.md + echo "---" >> /tmp/updated_release.md + echo "" >> /tmp/updated_release.md + cat release.md >> /tmp/updated_release.md + mv /tmp/updated_release.md release.md + fi else - mv /tmp/new_release_section.md release.md + # No release.md exists, create it + mv /tmp/unreleased_section.md release.md fi - - # Replace ${VERSION} placeholder - sed -i "s/\${VERSION}/${VERSION}/g" release.md - name: Check for changes id: check_changes