Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions .github/workflows/auto-version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,35 @@ jobs:
if: steps.check_v2_only.outputs.v2_only != 'true'
id: version_bump
run: |
# Get commit messages since last tag
# Get commit messages since last tag, scoped to root-module
# files only. This prevents v2-only commits (which may contain
# feat!/refactor! subjects) from accidentally triggering a root
# major version bump.
LATEST_TAG="${{ steps.get_tag.outputs.latest_tag }}"
COMMITS=$(git log --pretty=format:"%s" ${LATEST_TAG}..HEAD)
COMMITS=$(git log --pretty=format:"%s" ${LATEST_TAG}..HEAD -- . ":(exclude)v2/")

echo "Commits since $LATEST_TAG:"
echo "Root-module commits since $LATEST_TAG:"
echo "$COMMITS"

if [ -z "$COMMITS" ]; then
echo "No root-module commits since $LATEST_TAG — skipping version bump"
echo "major_bump=false" >> $GITHUB_OUTPUT
echo "minor_bump=false" >> $GITHUB_OUTPUT
echo "patch_bump=false" >> $GITHUB_OUTPUT
echo "no_commits=true" >> $GITHUB_OUTPUT
exit 0
fi

# Determine version bump based on conventional commits
MAJOR_BUMP=false
MINOR_BUMP=false
PATCH_BUMP=false

# Check for breaking changes
if echo "$COMMITS" | grep -qiE "(breaking|!|BREAKING)"; then
# Check for breaking changes using the conventional-commit `!`
# indicator (e.g. "feat(scope)!: ..." or "BREAKING CHANGE: ...").
# The bare `!` match is intentionally scoped to the conventional-
# commit prefix, not any `!` anywhere in the message body.
if echo "$COMMITS" | grep -qiE '^[a-z]+(\(.+\))?!:' || echo "$COMMITS" | grep -qiE "^BREAKING[ -]CHANGE"; then
MAJOR_BUMP=true
echo "Major version bump detected (breaking changes)"
# Check for new features
Expand All @@ -102,6 +117,7 @@ jobs:
PATCH_BUMP=true
echo "Default patch version bump"
fi
echo "no_commits=false" >> $GITHUB_OUTPUT

echo "major_bump=$MAJOR_BUMP" >> $GITHUB_OUTPUT
echo "minor_bump=$MINOR_BUMP" >> $GITHUB_OUTPUT
Expand Down Expand Up @@ -134,42 +150,42 @@ jobs:
echo "New version: $NEW_VERSION"

- name: Generate release notes
if: steps.check_v2_only.outputs.v2_only != 'true' && steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag
if: steps.check_v2_only.outputs.v2_only != 'true' && steps.version_bump.outputs.no_commits != 'true' && steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag
id: release_notes
run: |
LATEST_TAG="${{ steps.get_tag.outputs.latest_tag }}"
{
echo "body<<EOF"
echo "## What's Changed"
echo ""
# Group commits by conventional-commit type
# Group commits by conventional-commit type, scoped to root
echo "### Breaking Changes"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD | grep -iE "^[a-z]+(\(.+\))?!:" || echo "_None_"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD -- . ":(exclude)v2/" | grep -iE "^[a-z]+(\(.+\))?!:" || echo "_None_"
echo ""
echo "### Features"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD | grep -iE "^feat" || echo "_None_"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD -- . ":(exclude)v2/" | grep -iE "^feat" || echo "_None_"
echo ""
echo "### Bug Fixes"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD | grep -iE "^fix" || echo "_None_"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD -- . ":(exclude)v2/" | grep -iE "^fix" || echo "_None_"
echo ""
echo "### Documentation"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD | grep -iE "^docs" || echo "_None_"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD -- . ":(exclude)v2/" | grep -iE "^docs" || echo "_None_"
echo ""
echo "### Refactors"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD | grep -iE "^refactor" || echo "_None_"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD -- . ":(exclude)v2/" | grep -iE "^refactor" || echo "_None_"
echo ""
echo "### Style / Chores"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD | grep -iE "^style|^chore|^ci" || echo "_None_"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD -- . ":(exclude)v2/" | grep -iE "^style|^chore|^ci" || echo "_None_"
echo ""
echo "### Other"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD | grep -viE "^(feat|fix|docs|refactor|style|chore|ci|merge|break)" || echo "_None_"
git log --pretty=format:"- %s (%h)" ${LATEST_TAG}..HEAD -- . ":(exclude)v2/" | grep -viE "^(feat|fix|docs|refactor|style|chore|ci|merge|break)" || echo "_None_"
echo ""
echo "**Full Changelog**: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/${LATEST_TAG}...${{ steps.new_version.outputs.new_version }}"
echo "EOF"
} >> "$GITHUB_OUTPUT"

- name: Create and push tag
if: steps.check_v2_only.outputs.v2_only != 'true' && steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag
if: steps.check_v2_only.outputs.v2_only != 'true' && steps.version_bump.outputs.no_commits != 'true' && steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag
run: |
NEW_VERSION="${{ steps.new_version.outputs.new_version }}"

Expand All @@ -182,7 +198,7 @@ jobs:
echo "Created and pushed tag: $NEW_VERSION"

- name: Create Release
if: steps.check_v2_only.outputs.v2_only != 'true' && steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag
if: steps.check_v2_only.outputs.v2_only != 'true' && steps.version_bump.outputs.no_commits != 'true' && steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.new_version.outputs.new_version }}
Expand All @@ -194,7 +210,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Update go.mod version
if: steps.check_v2_only.outputs.v2_only != 'true' && steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag
if: steps.check_v2_only.outputs.v2_only != 'true' && steps.version_bump.outputs.no_commits != 'true' && steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag
run: |
NEW_VERSION="${{ steps.new_version.outputs.new_version }}"

Expand All @@ -213,4 +229,4 @@ jobs:
echo "- **Previous version:** ${{ steps.get_tag.outputs.latest_tag }}" >> $GITHUB_STEP_SUMMARY
echo "- **New version:** ${{ steps.new_version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Bump type:** ${{ steps.version_bump.outputs.major_bump == 'true' && 'Major' || steps.version_bump.outputs.minor_bump == 'true' && 'Minor' || 'Patch' }}" >> $GITHUB_STEP_SUMMARY
echo "- **Tag created:** ${{ steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag && 'Yes' || 'No (no changes)' }}" >> $GITHUB_STEP_SUMMARY
echo "- **Tag created:** ${{ steps.version_bump.outputs.no_commits == 'true' && 'No (no root-module commits)' || steps.new_version.outputs.new_version != steps.get_tag.outputs.latest_tag && 'Yes' || 'No (no changes)' }}" >> $GITHUB_STEP_SUMMARY
55 changes: 55 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,58 @@ jobs:
- name: Build with vendor mode
working-directory: /tmp/consumer-test
run: go build -mod=vendor ./...

# Verifies that a downstream consumer can build against the root
# module using the real unsuffixed import path
# (github.com/hmmftg/requestCore) with Go 1.27, without v2 or the
# workspace. This guards the stable-v1 import-path contract.
root-consumer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: Force standalone root module
run: |
if [ -f go.work ]; then rm go.work; fi
if [ -f go.work.sum ]; then rm go.work.sum; fi
- name: Tidy root module
run: go mod tidy
- name: Create root-only consumer module
run: |
mkdir -p /tmp/root-consumer
cd /tmp/root-consumer
cat > go.mod <<'GOMOD'
module root-consumer

go 1.27.0

require github.com/hmmftg/requestCore v0.0.0
GOMOD
echo "replace github.com/hmmftg/requestCore => $GITHUB_WORKSPACE" >> go.mod
- name: Create consumer main.go
run: |
cd /tmp/root-consumer
cat > main.go <<'GOFILE'
package main

import (
_ "github.com/hmmftg/requestCore/webFramework"
_ "github.com/hmmftg/requestCore/handlers"
_ "github.com/hmmftg/requestCore/response"
_ "github.com/hmmftg/requestCore/libRequest"
)

func main() {}
GOFILE
- name: Tidy consumer
working-directory: /tmp/root-consumer
run: go mod tidy
- name: Build consumer
working-directory: /tmp/root-consumer
run: go build ./...
- name: Vet consumer
working-directory: /tmp/root-consumer
run: go vet ./...
Loading
Loading