Skip to content

Release Process

This document describes the release process for the train-juniper gem.

Overview

The train-juniper project uses a semi-automated release process that follows the RuboCop model: - Version bumps and changelog generation happen locally - Changes are committed and tagged locally - GitHub Actions handles gem publication when tags are pushed

Release Workflow Options

When working with pull requests:

  1. Complete development on feature branch
  2. Create and merge PR to main
  3. Then follow release steps from main branch

Option B: Direct to Main (Legacy)

For hotfixes or when working directly on main branch.

Prerequisites

  1. Ensure you have git-cliff installed (for changelog generation):

    brew install git-cliff
    

  2. For PR workflow - After PR is merged, ensure you're on the main branch:

    git checkout main
    git pull origin main
    git status  # Should show no changes
    

  3. Ensure all tests pass:

    bundle exec rake test
    bundle exec rake lint
    bundle exec rake security
    

  4. Verify trusted publishing is configured on RubyGems.org:

  5. Go to https://rubygems.org/gems/train-juniper/trusted_publishers
  6. Should show: GitHub Repository: mitre/train-juniper, Workflow: release-tag.yml
  7. No API keys needed - uses OIDC authentication!

Release Steps

1. Choose Version Bump Type

Decide on the version bump based on Semantic Versioning: - Patch (0.5.0 → 0.5.1): Bug fixes, minor updates - Minor (0.5.0 → 0.6.0): New features, backward compatible - Major (0.5.0 → 1.0.0): Breaking changes

2. Prepare the Release

Execute the appropriate rake task to prepare the release:

# For patch release (bug fixes)
bundle exec rake release:patch

# For minor release (new features)
bundle exec rake release:minor

# For major release (breaking changes)
bundle exec rake release:major

This rake task will automatically: - ✅ Update lib/train-juniper/version.rb with the new version - ✅ Update Gemfile.lock with the new version - ✅ Generate/update CHANGELOG.md using git-cliff (groups commits by type) - ✅ Create release notes in docs/release-notes/v{version}.md - ✅ Commit all changes with message "Bump version to {version}" - ❌ Does NOT create a tag (Bundler will do this)

3. Review Changes

Before releasing, review what was changed:

# Review the commit
git show

# Check the updated CHANGELOG.md
cat CHANGELOG.md

# Check the release notes
cat docs/release-notes/v{version}.md

4. Push Changes

Push your commits to GitHub:

git push origin main

5. Create Tag and Publish

Use Bundler's standard release process:

bundle exec rake release

This will: - ✅ Create tag v{version} - ✅ Push the tag to GitHub - ⏭️ Trigger GitHub Actions to build and publish the gem

5. Automated Publication

Once the tag is pushed, GitHub Actions will automatically: 1. Run the full test suite 2. Run security audits 3. Run linting checks 4. Create a GitHub Release using the pre-generated release notes 5. Build the gem 6. Publish to RubyGems.org using trusted publishing (OIDC authentication)

Monitor the release workflow at: https://github.com/mitre/train-juniper/actions

Commit Message Convention

For better changelog generation, use Conventional Commits:

  • feat: New features
  • fix: Bug fixes
  • docs: Documentation changes
  • test: Test additions or fixes
  • refactor: Code refactoring
  • chore: Maintenance tasks
  • ci: CI/CD changes

Examples:

git commit -m "feat: add support for JunOS 23.x"
git commit -m "fix: handle SSH timeout gracefully"
git commit -m "docs: update installation instructions"

Manual Steps (if needed)

Regenerate Changelog

If you need to regenerate the changelog:

git-cliff --tag v{version} -o CHANGELOG.md

Create GitHub Release Manually

If the automated release fails, create manually:

  1. Go to https://github.com/mitre/train-juniper/releases/new
  2. Choose the tag you just pushed
  3. Copy content from docs/release-notes/v{version}.md
  4. Publish the release

Publish Gem Manually

If gem publication fails:

gem build train-juniper.gemspec
gem push train-juniper-{version}.gem

Troubleshooting

"Working directory is not clean"

  • Commit or stash your changes first
  • Run git status to see what's changed

"Must be on main branch"

  • Switch to main: git checkout main
  • Ensure it's up to date: git pull origin main

Changelog not generating properly

  • Ensure git-cliff is installed: brew install git-cliff
  • Check .cliff.toml configuration exists
  • Use conventional commit messages for better grouping

GitHub Actions failing

  • Check the Actions tab
  • Ensure trusted publishing is configured on RubyGems.org
  • Verify all tests pass locally first

PR-Based Release Workflow (Detailed)

When using pull requests, the workflow is:

Development Phase

  1. Create feature branch from main

    git checkout -b fix/issue-description
    

  2. Develop and test on feature branch

    bundle exec rake test
    bundle exec rake lint
    

  3. Push branch and create PR

    git push -u origin fix/issue-description
    gh pr create  # or use GitHub web UI
    

  4. Wait for PR checks to pass (CI/CD)

  5. Get PR reviewed and approved

Release Phase (After PR Merge)

  1. Switch to main and pull latest

    git checkout main
    git pull origin main
    

  2. Decide on version bump based on changes:

  3. Multiple PRs with features → minor bump
  4. Only bug fixes → patch bump
  5. Breaking changes → major bump

  6. Run release preparation

    bundle exec rake release:patch  # or :minor or :major
    

  7. Review and push

    git push origin main
    

  8. Create tag and publish

    bundle exec rake release
    

Key Differences from Direct Workflow

  • Never run rake release:* on feature branches
  • Version bump happens AFTER merge, not before
  • Changelog captures all PRs merged since last release
  • More traceable history through PR references

Version History

See CHANGELOG for the complete version history.