Skip to content

CI/CD Versioning Migration Guide

This document provides a complete guide for migrating from git-based versioning to per-service semantic versioning with Changesets.

The current CI/CD pipeline rebuilds all Docker images on every push, regardless of which services actually changed. Images are tagged with git-based versions (e.g., staging-a1b2c3d) that don’t convey semantic meaning about changes.

Implement per-service semantic versioning using Changesets:

  • Each app gets independent semantic versions (1.2.3 format)
  • Only services with changes get new versions and Docker builds
  • Developers document changes via changeset files
  • Automated changelog generation
  • Enforced change documentation via pre-commit hooks
.changeset/
├── config.json # Changesets configuration
└── README.md # Changesets documentation
.github/
├── workflows/
│ ├── version-aware-build.yml # New CI/CD pipeline
│ └── release.yml # Automated release workflow
└── workflows-backup/
└── ci-cd-pipeline-legacy.yml # Backup of old pipeline (disabled)
.husky/
└── pre-commit # Git hook to enforce changesets
docs/
├── DEVELOPER_WORKFLOW.md # Developer guide
└── ci-cd-versioning-migration.md # This file
apps/pdf-api/
└── package.json # New - enables Changesets tracking
apps/pdf-worker/
└── package.json # New - enables Changesets tracking
package.json # Added Changesets, Husky, lint-staged
apps/webapp/package.json # Changed name to @erp-unlocked/webapp
apps/crm/package.json # Changed name to @erp-unlocked/crm
apps/marketing/package.json # Changed name to @erp-unlocked/marketing
{
"devDependencies": {
"@changesets/cli": "^2.27.1",
"@changesets/changelog-github": "^0.5.0",
"husky": "^9.0.0",
"lint-staged": "^15.0.0"
}
}
{
"scripts": {
"changeset": "changeset",
"changeset:version": "changeset version",
"changeset:status": "changeset status",
"changeset:pre-check": "changeset status --check",
"version:check": "changeset status",
"version:preview": "changeset status --verbose",
"version:apply": "changeset version",
"release:prepare": "pnpm version:apply && pnpm install",
"release:publish": "pnpm build && changeset publish",
"prepare": "husky install"
}
}
  • Install and configure Changesets
  • Create .changeset/config.json
  • Update app package.json files with new names
  • Create package.json for Python services (pdf-api, pdf-worker)
  • Install Husky and lint-staged
  • Create pre-commit hook for changeset enforcement
  • Create version-aware CI/CD workflow
  • Create automated release workflow
  • Create developer documentation
  • Backup existing CI/CD pipeline
  • Test changeset workflow on feature branch
  • Test version-aware build on staging
  • Verify Docker image tagging works correctly
  • Test deployment to staging environment
  • Update team documentation
  • Train team on new workflow
  • Deploy to production

Day 1-2: Setup

  • Install dependencies
  • Configure Changesets
  • Update package configurations
  • Create documentation

Day 3-4: Testing

  • Create test branch
  • Make sample changes
  • Generate changesets
  • Verify changeset status output

Day 5: Review

  • Team review of changes
  • Documentation review
  • Pre-commit hook testing

Day 1-2: Branch Testing

  • Merge changes to staging branch
  • Verify version-aware build runs
  • Check Docker image tags
  • Verify only changed services build

Day 3-4: Deployment Testing

  • Test staging deployments
  • Verify webhook calls work
  • Check service versions in deployment
  • Test rollback procedures

Day 5: Validation

  • Full end-to-end test
  • Documentation updates
  • Team training session

Day 1-2: Preparation

  • Create production changeset
  • Generate version bump PR
  • Review and approve PR

Day 3: Production Deploy

  • Merge to main
  • Monitor automated release
  • Verify production deployments
  • Check Docker image versions

Day 4-5: Stabilization

  • Monitor for issues
  • Address any problems
  • Update documentation based on learnings
  • Delete old CI/CD pipeline
  • Archive legacy documentation
  • Update README files
  • Collect team feedback

Test the changeset workflow locally before pushing:

Terminal window
# Create a feature branch
git checkout -b test/changeset-workflow
# Make a small change to webapp
echo "// test change" >> apps/webapp/src/pages/index.astro
# Create changeset
pnpm changeset
# Select: @erp-unlocked/webapp
# Type: patch
# Summary: Test changeset workflow
# Try to commit without changeset (should fail)
git add apps/webapp/src/pages/index.astro
git commit -m "test: change"
# Expected: Pre-commit hook should block
# Commit with changeset (should succeed)
git add .changeset/*.md
git commit -m "test: verify changeset workflow"
# Expected: Commit succeeds
# Check changeset status
pnpm version:check
# Expected: Shows webapp with patch version bump
# Push and create PR
git push origin test/changeset-workflow

After creating a PR to staging:

Terminal window
# Monitor GitHub Actions
# Expected outcomes:
# - detect-versions job runs successfully
# - webapp-changed = true, webapp-version = pr-{sha}
# - build-and-push job builds only webapp
# - Other services not built

After merging to staging:

Terminal window
# Monitor GitHub Actions
# Expected outcomes:
# - Changeset status shows pending releases
# - Docker images built with PR version
# - Staging webhook called for changed services
# - Services deployed to staging environment

Test the full release cycle:

Terminal window
# Merge to main
# Expected outcomes:
# - release.yml workflow creates "Version Packages" PR
# - PR updates package.json versions
# - PR generates CHANGELOG.md entries
# - Changesets consumed and removed
# Merge Version Packages PR
# Expected outcomes:
# - version-aware-build.yml triggers
# - Docker images tagged with semantic versions (1.2.3)
# - Production webhooks called
# - Services deployed to production

If issues arise during migration, follow this rollback procedure:

  1. Restore old CI/CD pipeline

    Terminal window
    mv .github/workflows-backup/ci-cd-pipeline-legacy.yml .github/workflows/ci-cd-pipeline.yml
    mv .github/workflows/version-aware-build.yml .github/workflows-backup/version-aware-build-disabled.yml
    git add .github/
    git commit -m "rollback: restore legacy CI/CD pipeline"
    git push
  2. Disable pre-commit hook

    Terminal window
    mv .husky/pre-commit .husky/pre-commit.disabled
    git add .husky/
    git commit -m "rollback: disable changeset pre-commit hook"
    git push
  3. Notify team

    • Send Slack message about rollback
    • Document issues encountered
    • Plan remediation
Terminal window
# Create rollback branch
git checkout -b rollback/changesets-migration
# Revert all changeset-related changes
git revert <migration-commit-range>
# Or reset to pre-migration commit
git reset --hard <pre-migration-commit>
# Force push (only if necessary and approved)
git push origin rollback/changesets-migration --force
# Create emergency PR
# Merge after approval

After rollback:

  • CI/CD pipeline building all services
  • Docker tags using git-based versions
  • Deployments working correctly
  • No breaking changes for developers
  1. Update README.md

    • Add section on changesets workflow
    • Link to DEVELOPER_WORKFLOW.md
    • Update contribution guidelines
  2. Update CONTRIBUTING.md (create if doesn’t exist)

    • Add changeset requirements
    • Explain version types
    • Provide examples
  3. Update PR Template (create if doesn’t exist)

    ## Changes
    - [ ] I have created a changeset describing my changes
    - [ ] I have selected the appropriate version type (patch/minor/major)
    ## Changeset Summary
    <!-- Paste your changeset summary here -->
  1. Training Session (1 hour)

    • Overview of changesets
    • Live demo of workflow
    • Q&A session
  2. Training Materials

    • Record training session
    • Create video walkthrough
    • Update onboarding docs
  3. Support Channel

    • Create #changesets-help Slack channel
    • Designate changeset champions
    • Document FAQs
  1. Set up monitoring

    • Track CI/CD run times (should decrease)
    • Monitor Docker build frequency per service
    • Track changeset compliance rate
  2. Create alerts

    • Alert if builds fail
    • Alert if changesets missing in merged PRs
    • Alert if releases fail
  1. Weekly Review (First Month)

    • Review changeset quality
    • Identify pain points
    • Update documentation
  2. Monthly Metrics

    • CI/CD time savings
    • Number of deployments per service
    • Changeset compliance rate
    • Team satisfaction
  • ❌ All 5 services rebuilt on every change
  • ❌ Docker tags: staging-a1b2c3d, main-b4c5d6e
  • ❌ Manual changelog management
  • ❌ No version enforcement
  • ❌ ~15 minute CI/CD runs
  • ✅ Only changed services rebuilt
  • ✅ Docker tags: 1.2.3, 2.0.1, latest
  • ✅ Automatic changelog generation
  • ✅ Enforced change documentation
  • ✅ ~5-10 minute CI/CD runs (for single service)
  • ✅ Clear release history per service
  • ✅ Semantic versioning for all images

Mitigation:

  • Keep legacy pipeline as backup
  • Test thoroughly on staging
  • Document rollback procedures
  • Have team available during migration

Mitigation:

  • Comprehensive documentation
  • Training sessions
  • Support channel
  • Gradual rollout

Mitigation:

  • Test on feature branches first
  • Monitor closely during rollout
  • Quick rollback plan ready
  • Team on standby

Mitigation:

  • Test version detection thoroughly
  • Verify image tags before deploying
  • Keep legacy tags initially
  • Document version mapping

Track these metrics to measure migration success:

  1. CI/CD Efficiency

    • Average build time per push
    • Number of services built per push
    • Cost savings (compute time)
  2. Developer Experience

    • Time to create changeset (< 2 minutes)
    • Changeset compliance rate (target: 100%)
    • Pre-commit hook bypass rate (< 5%)
    • Developer satisfaction score
  3. Release Quality

    • Changelog completeness
    • Version bump accuracy
    • Number of version-related incidents
    • Deployment success rate
  4. Operational

    • Number of unnecessary builds eliminated
    • Deployment frequency per service
    • Rollback frequency
    • Time to resolve issues

Q: Do I need a changeset for every commit?

Section titled “Q: Do I need a changeset for every commit?”

A: No, only for commits that change code in apps/ or packages/. Config changes, documentation updates, and CI changes typically don’t need changesets.

A: Yes, using git commit --no-verify, but this should be rare. Most code changes should have a changeset.

Q: What if multiple people create changesets?

Section titled “Q: What if multiple people create changesets?”

A: That’s fine! Each changeset is a separate file. They’ll all be processed during the next release.

Q: How do I know what version type to use?

Section titled “Q: How do I know what version type to use?”

A: Follow semantic versioning:

  • patch: Bug fixes, no new features
  • minor: New features, backward compatible
  • major: Breaking changes

A: They remain in the registry. You can clean up old images manually or set up retention policies in GHCR.

Q: Can I change a version type after creating a changeset?

Section titled “Q: Can I change a version type after creating a changeset?”

A: Yes, just edit the .changeset/*.md file and change patch, minor, or major.

Q: What if I forget to create a changeset?

Section titled “Q: What if I forget to create a changeset?”

A: The pre-commit hook will remind you. If you’ve already pushed, create a changeset in a follow-up commit.

For questions or issues:

  1. Check Developer Workflow Guide
  2. Search existing issues
  3. Ask in #changesets-help (Slack)
  4. Create an issue in the repository

Last Updated: 2025-10-11
Migration Status: ✅ Implementation Complete - Ready for Testing
Maintainers: Development Team