Getting closer to having a fully structured release process. Much t… #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release Management | ||
| on: | ||
| push: | ||
| branches: [ release ] | ||
| pull_request: | ||
| branches: [ release ] | ||
| env: | ||
| BUILD_TYPE: Release | ||
| jobs: | ||
| # ============================================================================= | ||
| # Release Creation (on merge to release branch) | ||
| # ============================================================================= | ||
| create-release: | ||
| runs-on: ubuntu-latest | ||
| if: github.event_name == 'push' && github.ref == 'refs/heads/release' | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Get current version | ||
| id: version | ||
| run: | | ||
| chmod +x scripts/version_manager.sh | ||
| VERSION=$(./scripts/version_manager.sh get) | ||
| echo "current_version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "Current version: $VERSION" | ||
| - name: Check if release already exists | ||
| id: check_release | ||
| run: | | ||
| if gh release view "v${{ steps.version.outputs.current_version }}" &> /dev/null; then | ||
| echo "release_exists=true" >> $GITHUB_OUTPUT | ||
| echo "Release v${{ steps.version.outputs.current_version }} already exists" | ||
| else | ||
| echo "release_exists=false" >> $GITHUB_OUTPUT | ||
| echo "Release v${{ steps.version.outputs.current_version }} does not exist" | ||
| fi | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Update version in project files | ||
| if: steps.check_release.outputs.release_exists == 'false' | ||
| run: | | ||
| echo "Updating project files with version ${{ steps.version.outputs.current_version }}" | ||
| ./scripts/version_manager.sh update-files | ||
| - name: Build release artifacts | ||
| if: steps.check_release.outputs.release_exists == 'false' | ||
| run: | | ||
| # Configure and build release | ||
| cmake -B build \ | ||
| -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ | ||
| -DCMAKE_C_COMPILER=clang \ | ||
| -DPTK_BUILD_TESTS=ON \ | ||
| -DPTK_ENABLE_STATIC_ANALYSIS=ON | ||
| cmake --build build --config ${{env.BUILD_TYPE}} --parallel | ||
| # Create source tarball | ||
| tar -czf protocol_toolkit-${{ steps.version.outputs.current_version }}.tar.gz \ | ||
| --exclude='.git*' \ | ||
| --exclude='build' \ | ||
| --exclude='*.tar.gz' \ | ||
| --exclude='*.zip' \ | ||
| . | ||
| # Create build artifacts | ||
| mkdir -p artifacts | ||
| cp build/lib/libprotocol_toolkit.a artifacts/ || true | ||
| cp build/bin/test_harness artifacts/ || true | ||
| # Create artifact tarball | ||
| tar -czf protocol_toolkit-${{ steps.version.outputs.current_version }}-artifacts.tar.gz \ | ||
| -C artifacts . | ||
| - name: Generate release notes | ||
| if: steps.check_release.outputs.release_exists == 'false' | ||
| id: release_notes | ||
| run: | | ||
| # Get commits since last release | ||
| LAST_RELEASE=$(gh release list --limit 1 --json tagName --jq '.[0].tagName' || echo "") | ||
| if [ -n "$LAST_RELEASE" ]; then | ||
| COMMITS=$(git log --oneline "${LAST_RELEASE}..HEAD" --no-merges) || COMMITS="" | ||
| else | ||
| COMMITS=$(git log --oneline --no-merges -10) || COMMITS="" | ||
| fi | ||
| # Create release notes | ||
| cat > release_notes.md << EOF | ||
| # Protocol Toolkit v${{ steps.version.outputs.current_version }} | ||
| ## 🚀 What's New | ||
| This release includes all changes that have been tested and validated through our comprehensive CI/CD pipeline. | ||
| ## 📋 Changes | ||
| EOF | ||
| if [ -n "$COMMITS" ]; then | ||
| echo "### Commits in this release:" >> release_notes.md | ||
| echo "" >> release_notes.md | ||
| echo "$COMMITS" | while read line; do | ||
| echo "- $line" >> release_notes.md | ||
| done | ||
| else | ||
| echo "- Initial release" >> release_notes.md | ||
| fi | ||
| cat >> release_notes.md << EOF | ||
| ## ✅ Testing | ||
| This release has been thoroughly tested with: | ||
| - **Architecture Support**: x86_64, x86, ARM64, ARMv6, ARMv7 Hard Float | ||
| - **Platform Support**: Ubuntu (20.04, 22.04), Windows, macOS | ||
| - **Sanitizer Testing**: AddressSanitizer, MemorySanitizer, UndefinedBehaviorSanitizer, ThreadSanitizer | ||
| - **Memory Analysis**: Valgrind with leak detection and origin tracking | ||
| - **Static Analysis**: Clang Static Analyzer, Cppcheck | ||
| - **API Coverage**: 100% of 157 functions across 10 modules | ||
| ## 📦 Downloads | ||
| - **Source Code**: Available as source tarball and ZIP | ||
| - **Build Artifacts**: Pre-built libraries and test harness | ||
| ## 🔧 Installation | ||
| ### From Source | ||
| \`\`\`bash | ||
| tar -xzf protocol_toolkit-${{ steps.version.outputs.current_version }}.tar.gz | ||
| cd protocol_toolkit-${{ steps.version.outputs.current_version }} | ||
| mkdir build && cd build | ||
| cmake -DCMAKE_BUILD_TYPE=Release .. | ||
| make -j\$(nproc) | ||
| \`\`\` | ||
| ### Using CMake | ||
| \`\`\`cmake | ||
| find_package(PTK ${{ steps.version.outputs.current_version }} REQUIRED) | ||
| target_link_libraries(your_target PTK::protocol_toolkit) | ||
| \`\`\` | ||
| ## 🐛 Known Issues | ||
| None at this time. Please report any issues on our GitHub repository. | ||
| --- | ||
| **Full Changelog**: https://github.com/\${{github.repository}}/compare/\${LAST_RELEASE}...v${{ steps.version.outputs.current_version }} | ||
| EOF | ||
| echo "Release notes generated" | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Create GitHub release | ||
| if: steps.check_release.outputs.release_exists == 'false' | ||
| run: | | ||
| gh release create "v${{ steps.version.outputs.current_version }}" \ | ||
| --title "Protocol Toolkit v${{ steps.version.outputs.current_version }}" \ | ||
| --notes-file release_notes.md \ | ||
| --target release \ | ||
| protocol_toolkit-${{ steps.version.outputs.current_version }}.tar.gz \ | ||
| protocol_toolkit-${{ steps.version.outputs.current_version }}-artifacts.tar.gz | ||
| echo "✅ Created release v${{ steps.version.outputs.current_version }}" | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Increment patch version | ||
| if: steps.check_release.outputs.release_exists == 'false' | ||
| run: | | ||
| # Increment patch version for next development cycle | ||
| NEW_VERSION=$(./scripts/version_manager.sh increment-patch) | ||
| echo "Incremented version to $NEW_VERSION for next development cycle" | ||
| # Update project files with new version | ||
| ./scripts/version_manager.sh update-files | ||
| # Commit version update | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git add VERSION src/include/ptk_version.h CMakeLists.txt | ||
| git commit -m "Bump version to $NEW_VERSION after release | ||
| 🤖 Generated with [Claude Code](https://claude.ai/code) | ||
| Co-Authored-By: Claude <noreply@anthropic.com>" | ||
| git push origin release | ||
| echo "✅ Version bumped to $NEW_VERSION" | ||
| - name: Create development branch PR | ||
| if: steps.check_release.outputs.release_exists == 'false' | ||
| run: | | ||
| # Check if dev branch exists | ||
| if ! git ls-remote --exit-code --heads origin dev; then | ||
| echo "Dev branch doesn't exist, skipping PR creation" | ||
| exit 0 | ||
| fi | ||
| # Check if there's already a PR from release to dev for version sync | ||
| PR_EXISTS=$(gh pr list --base dev --head release --state open --json number --jq length) | ||
| if [ "$PR_EXISTS" -eq 0 ]; then | ||
| # Create PR to sync version update back to dev | ||
| gh pr create \ | ||
| --base dev \ | ||
| --head release \ | ||
| --title "Sync version update to dev branch" \ | ||
| --body "$(cat <<EOF | ||
| # Version Sync: Post-Release Update | ||
| This PR syncs the version update from the release branch back to the dev branch. | ||
| **Changes:** | ||
| - Updated VERSION file to next development version | ||
| - Updated project files with new version | ||
| - Updated version header file | ||
| This ensures the dev branch stays in sync with the latest version information. | ||
| **Note:** This PR should be merged after the release is created. | ||
| 🤖 Generated with [Claude Code](https://claude.ai/code) | ||
| EOF | ||
| )" \ | ||
| --label "version-sync" \ | ||
| --label "auto-generated" | ||
| echo "✅ Created version sync PR to dev branch" | ||
| else | ||
| echo "ℹ️ Version sync PR already exists" | ||
| fi | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| # ============================================================================= | ||
| # Release Validation (on PR to release branch) | ||
| # ============================================================================= | ||
| validate-release: | ||
| runs-on: ubuntu-latest | ||
| if: github.event_name == 'pull_request' && github.base_ref == 'release' | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - name: Get current version | ||
| id: version | ||
| run: | | ||
| chmod +x scripts/version_manager.sh | ||
| VERSION=$(./scripts/version_manager.sh get) | ||
| echo "current_version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "Current version: $VERSION" | ||
| - name: Validate version format | ||
| run: | | ||
| ./scripts/version_manager.sh validate ${{ steps.version.outputs.current_version }} | ||
| echo "✅ Version format is valid" | ||
| - name: Check if release exists | ||
| run: | | ||
| if gh release view "v${{ steps.version.outputs.current_version }}" &> /dev/null; then | ||
| echo "❌ Release v${{ steps.version.outputs.current_version }} already exists!" | ||
| echo "Please increment the version before creating a release." | ||
| exit 1 | ||
| else | ||
| echo "✅ Release v${{ steps.version.outputs.current_version }} does not exist yet" | ||
| fi | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Validate version consistency | ||
| run: | | ||
| # Check if version is consistent across project files | ||
| ./scripts/version_manager.sh update-files | ||
| # Check if there are any changes (there shouldn't be) | ||
| if git diff --exit-code > /dev/null; then | ||
| echo "✅ Version is consistent across all project files" | ||
| else | ||
| echo "❌ Version inconsistency detected!" | ||
| echo "The following files have inconsistent versions:" | ||
| git diff --name-only | ||
| echo "" | ||
| echo "Please run './scripts/version_manager.sh update-files' to fix this." | ||
| exit 1 | ||
| fi | ||
| - name: Build and test release candidate | ||
| run: | | ||
| # Quick build and test to ensure release candidate is valid | ||
| cmake -B build \ | ||
| -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ | ||
| -DCMAKE_C_COMPILER=clang \ | ||
| -DPTK_BUILD_TESTS=ON | ||
| cmake --build build --config ${{env.BUILD_TYPE}} --parallel | ||
| # Run quick test | ||
| cd build | ||
| ./bin/test_harness | ||
| echo "✅ Release candidate builds and tests successfully" | ||
| - name: Add validation comment | ||
| run: | | ||
| gh pr comment --body "## 🔍 Release Validation Results | ||
| ✅ **Version Format**: Valid (${{ steps.version.outputs.current_version }}) | ||
| ✅ **Release Uniqueness**: No existing release found | ||
| ✅ **Version Consistency**: All project files are consistent | ||
| ✅ **Build Test**: Release candidate builds successfully | ||
| ✅ **Basic Tests**: All tests pass | ||
| **Ready for Release**: This PR is ready to be merged to create release v${{ steps.version.outputs.current_version }} | ||
| **Next Steps**: | ||
| 1. Manual review and approval | ||
| 2. Manual merge (do not use auto-merge) | ||
| 3. Automatic release creation will be triggered | ||
| 4. Version will be auto-incremented for next development cycle | ||
| --- | ||
| 🤖 Generated with [Claude Code](https://claude.ai/code)" \ | ||
| ${{ github.event.pull_request.number }} | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||