Skip to content

feat: implement comprehensive GitHub workflow and project management … #1

feat: implement comprehensive GitHub workflow and project management …

feat: implement comprehensive GitHub workflow and project management … #1

Workflow file for this run

name: Changelog Management
on:
push:
branches: [main]
pull_request:
branches: [main]
types: [closed]
jobs:
update-changelog:
runs-on: ubuntu-latest
if: github.event_name == 'push' || (github.event.pull_request.merged == true)
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20.x"
- name: Generate changelog
id: changelog
run: |
# Get the latest tag
latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$latest_tag" ]; then
echo "No previous tags found, generating full changelog"
commit_range="HEAD"
else
echo "Latest tag: $latest_tag"
commit_range="$latest_tag..HEAD"
fi
# Generate changelog content
echo "# Changelog" > CHANGELOG_NEW.md
echo "" >> CHANGELOG_NEW.md
echo "All notable changes to this project will be documented in this file." >> CHANGELOG_NEW.md
echo "" >> CHANGELOG_NEW.md
echo "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)," >> CHANGELOG_NEW.md
echo "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)." >> CHANGELOG_NEW.md
echo "" >> CHANGELOG_NEW.md
# Get current version from package.json
current_version=$(node -p "require('./package.json').version")
echo "## [Unreleased]" >> CHANGELOG_NEW.md
echo "" >> CHANGELOG_NEW.md
# Parse commits since last tag
features=""
fixes=""
docs=""
chores=""
breaking=""
while IFS= read -r commit; do
if [[ $commit == feat* ]]; then
features="$features\n- ${commit#feat*: }"
elif [[ $commit == fix* ]]; then
fixes="$fixes\n- ${commit#fix*: }"
elif [[ $commit == docs* ]]; then
docs="$docs\n- ${commit#docs*: }"
elif [[ $commit == *BREAKING* ]] || [[ $commit == *breaking* ]]; then
breaking="$breaking\n- $commit"
else
chores="$chores\n- $commit"
fi
done < <(git log --format="%s" $commit_range)
# Add sections to changelog
if [ -n "$breaking" ]; then
echo "### ⚠️ BREAKING CHANGES" >> CHANGELOG_NEW.md
echo -e "$breaking" >> CHANGELOG_NEW.md
echo "" >> CHANGELOG_NEW.md
fi
if [ -n "$features" ]; then
echo "### ✨ Features" >> CHANGELOG_NEW.md
echo -e "$features" >> CHANGELOG_NEW.md
echo "" >> CHANGELOG_NEW.md
fi
if [ -n "$fixes" ]; then
echo "### 🐛 Bug Fixes" >> CHANGELOG_NEW.md
echo -e "$fixes" >> CHANGELOG_NEW.md
echo "" >> CHANGELOG_NEW.md
fi
if [ -n "$docs" ]; then
echo "### 📚 Documentation" >> CHANGELOG_NEW.md
echo -e "$docs" >> CHANGELOG_NEW.md
echo "" >> CHANGELOG_NEW.md
fi
if [ -n "$chores" ]; then
echo "### 🔧 Maintenance" >> CHANGELOG_NEW.md
echo -e "$chores" >> CHANGELOG_NEW.md
echo "" >> CHANGELOG_NEW.md
fi
# Append existing changelog if it exists
if [ -f CHANGELOG.md ]; then
# Skip the header from existing changelog
tail -n +8 CHANGELOG.md >> CHANGELOG_NEW.md
fi
mv CHANGELOG_NEW.md CHANGELOG.md
echo "changelog_updated=true" >> $GITHUB_OUTPUT
- name: Commit changelog
if: steps.changelog.outputs.changelog_updated == 'true'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add CHANGELOG.md
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "docs: update changelog [skip ci]"
git push
fi
prepare-release:
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: update-changelog
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20.x"
- name: Check if release is needed
id: release_check
run: |
# Get current version
current_version=$(node -p "require('./package.json').version")
# Get latest tag
latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
latest_version=${latest_tag#v}
echo "Current version: $current_version"
echo "Latest tag version: $latest_version"
if [ "$current_version" != "$latest_version" ]; then
echo "Version bump detected: $latest_version -> $current_version"
echo "needs_release=true" >> $GITHUB_OUTPUT
echo "new_version=$current_version" >> $GITHUB_OUTPUT
else
echo "No version bump detected"
echo "needs_release=false" >> $GITHUB_OUTPUT
fi
- name: Create release PR
if: steps.release_check.outputs.needs_release == 'true'
uses: actions/github-script@v7
with:
script: |
const version = '${{ steps.release_check.outputs.new_version }}';
// Check if release PR already exists
const existingPRs = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
head: `release/v${version}`,
state: 'open'
});
if (existingPRs.data.length > 0) {
console.log('Release PR already exists');
return;
}
// Create release branch
const mainBranch = await github.rest.repos.getBranch({
owner: context.repo.owner,
repo: context.repo.repo,
branch: 'main'
});
await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/heads/release/v${version}`,
sha: mainBranch.data.commit.sha
});
// Create PR
const pr = await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Release v${version}`,
head: `release/v${version}`,
base: 'main',
body: `## Release v${version}
This PR prepares the release for version ${version}.
### Pre-release Checklist
- [ ] All tests pass
- [ ] Documentation is up to date
- [ ] Changelog is accurate
- [ ] Version number is correct
- [ ] Templates are tested
- [ ] Security audit passes
### Release Notes
See CHANGELOG.md for detailed changes.
**This PR will trigger the release workflow when merged.**`,
draft: false
});
// Add labels
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.data.number,
labels: ['release', 'automated']
});
console.log(`Created release PR #${pr.data.number}`);
validate-release:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true && startsWith(github.head_ref, 'release/')
steps:
- name: Extract version from branch
id: version
run: |
branch_name="${{ github.head_ref }}"
version=${branch_name#release/v}
echo "version=$version" >> $GITHUB_OUTPUT
- name: Create and push tag
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git tag -a "v${{ steps.version.outputs.version }}" -m "Release v${{ steps.version.outputs.version }}"
git push origin "v${{ steps.version.outputs.version }}"
- name: Trigger release workflow
uses: actions/github-script@v7
with:
script: |
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'release.yml',
ref: 'main'
});