# Nova Release Pipeline — GitHub Actions (production) # # Runs on push to main. Computes the next semver tag from the latest tag + # commit history, creates the tag, updates floating MAJOR.MINOR and MAJOR tags, # and creates a GitHub release with auto-generated notes. # # Semver policy: # - Regular phase commit -> bump PATCH (v1.6.0 -> v1.6.1) # - Milestone completion ("docs(milestone): complete") -> bump MINOR (v1.6.1 -> v1.7.0) # - Major bumps are manual (not implemented here). name: nova-release on: push: branches: [main] jobs: release: name: Compute semver + update tags runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # need full history for tag computation - uses: actions/setup-python@v5 with: python-version: "3.12" - name: Compute next version id: version run: | # Get the latest tag LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") echo "Latest tag: $LATEST_TAG" # Parse the version MAJOR=$(echo "$LATEST_TAG" | sed -n 's/v\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/p') MINOR=$(echo "$LATEST_TAG" | sed -n 's/v\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/p') PATCH=$(echo "$LATEST_TAG" | sed -n 's/v\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/p') # Check if this is a milestone completion (look for "docs(milestone): complete" in the latest commits) if git log --format='%s' -5 | grep -q 'docs(milestone): complete'; then # Milestone completion -> bump minor MINOR=$((MINOR + 1)) PATCH=0 else # Regular phase -> bump patch PATCH=$((PATCH + 1)) fi NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}" MAJOR_MINOR_TAG="v${MAJOR}.${MINOR}" MAJOR_TAG="v${MAJOR}" echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT echo "major_minor_tag=$MAJOR_MINOR_TAG" >> $GITHUB_OUTPUT echo "major_tag=$MAJOR_TAG" >> $GITHUB_OUTPUT echo "Next version: $NEW_TAG" - name: Create version tag run: | git tag ${{ steps.version.outputs.new_tag }} git push origin ${{ steps.version.outputs.new_tag }} - name: Update floating MAJOR.MINOR tag run: | git tag -f ${{ steps.version.outputs.major_minor_tag }} ${{ steps.version.outputs.new_tag }} git push origin ${{ steps.version.outputs.major_minor_tag }} --force - name: Update floating MAJOR tag run: | git tag -f ${{ steps.version.outputs.major_tag }} ${{ steps.version.outputs.new_tag }} git push origin ${{ steps.version.outputs.major_tag }} --force - name: Create GitHub release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Generate release body from commit history since last tag PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") if [ -n "$PREV_TAG" ]; then BODY=$(git log --format='- %s' "$PREV_TAG"..HEAD) else BODY=$(git log --format='- %s' HEAD) fi gh release create ${{ steps.version.outputs.new_tag }} \ --title "Nova ${{ steps.version.outputs.new_tag }}" \ --notes "$BODY" \ --generate-notes || true