9 Commits
Author SHA1 Message Date
meda 54a7b1e6d8 feat: preserve fixed upstream versions with fork suffixes
Gitbump CI / test (push) Successful in 46s
Gitbump CI / build (push) Successful in 28s
Gitbump CI / notify-failure (push) Skipped
2026-09-25 10:02:33 +02:00
meda d6cf715a4a chore(deps): update dependency go to 1.27
Gitbump CI / build (push) Successful in 29s
Gitbump CI / test (push) Successful in 1m56s
Gitbump CI / notify-failure (push) Skipped
2026-08-21 00:02:45 +00:00
meda d4ab1e690c Merge pull request 'chore(deps): update actions/setup-go action to v7 (master)' (#6) from renovate/master-major-renovate-all into master
Gitbump CI / build (push) Successful in 31s
Gitbump CI / notify-failure (push) Skipped
Gitbump CI / test (push) Successful in 1m19s
Reviewed-on: #6
2026-07-31 00:49:24 +02:00
meda 5637163ed0 chore(deps): update actions/setup-go action to v7 2026-07-17 00:02:26 +00:00
meda f7aeaaca5c chore(deps): update all deps to v7
Gitbump CI / test (push) Successful in 45s
Gitbump CI / build (push) Successful in 33s
Gitbump CI / notify-failure (push) Has been skipped
2026-06-19 00:03:17 +00:00
meda 1357993978 Merge pull request 'chore(deps): update actions/checkout action to v6' (#2) from renovate/actions-checkout-6.x into master
Reviewed-on: #2
2026-02-15 21:31:04 +01:00
meda 0b27479ce3 Merge pull request 'chore(deps): update actions/setup-go action to v6' (#3) from renovate/actions-setup-go-6.x into master
Gitbump CI / test (push) Successful in 51s
Gitbump CI / build (push) Successful in 8s
Gitbump CI / notify-failure (push) Has been skipped
Reviewed-on: #3
2026-02-15 21:30:29 +01:00
meda 1b8c6d789a chore(deps): update actions/setup-go action to v6 2026-02-15 20:28:55 +00:00
meda f575d0ea75 chore(deps): update actions/checkout action to v6 2026-02-15 20:28:52 +00:00
5 changed files with 207 additions and 29 deletions

No files matched your search

+6 -6
View File
@@ -8,14 +8,14 @@ jobs:
test:
runs-on: [ubuntu-latest, amd64]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7
with:
go-version: '1.26'
go-version: '1.27'
- name: Install just
run: |
@@ -34,15 +34,15 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0
persist-credentials: true
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7
with:
go-version: '1.26'
go-version: '1.27'
- name: Bump & Tag
run: go run main.go
+12 -2
View File
@@ -19,7 +19,16 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- uses: https://gitea.com/your-user/gitbump@master
- uses: https://lab.zlymeda.dynu.net/actions/gitbump@master
```
For a fixed base version with an incrementing fork suffix:
```yaml
- uses: https://lab.zlymeda.dynu.net/actions/gitbump@master
with:
bump: suffix
suffix: meda
```
### Inputs
@@ -27,7 +36,8 @@ jobs:
| Input | Description | Default |
|-------|-------------|---------|
| `dry-run` | Show what would be done without making changes | `false` |
| `bump` | Force specific bump type (`major`, `minor`, or `patch`) | |
| `bump` | Force specific bump type (`major`, `minor`, `patch`, or `suffix`) | |
| `suffix` | Suffix label used when creating the first suffix | |
| `prefix` | Version prefix | `v` |
| `no-push` | Create tag but don't push to remote | `false` |
| `major-patterns` | Comma-separated list for major version bumps | `bump major,breaking change` |
+4 -1
View File
@@ -6,7 +6,10 @@ inputs:
required: false
default: 'false'
bump:
description: 'Force specific bump type (major, minor, or patch)'
description: 'Force specific bump type (major, minor, patch, or suffix)'
required: false
suffix:
description: 'Suffix label used when creating the first suffix'
required: false
prefix:
description: 'Version prefix (default "v")'
+99 -20
View File
@@ -22,10 +22,20 @@ type Config struct {
dryRun bool
forcedBump string
versionPrefix string
suffixLabel string
patterns Patterns
noPush bool
}
type taggedVersion struct {
major int
minor int
patch int
suffixLabel string
suffixRevision int
hasSuffix bool
}
type Patterns struct {
major []string
minor []string
@@ -74,11 +84,11 @@ func main() {
return
}
major, minor, patch, err := parseVersion(tag, config.versionPrefix)
version, err := parseTaggedVersion(tag, config.versionPrefix)
if err != nil {
log.Fatalf("Error parsing version: %v", err)
}
fmt.Println("version:", major, minor, patch)
fmt.Println("version:", version.major, version.minor, version.patch)
bumpType := getBumpType(commits, config)
fmt.Println("bump type:", bumpType)
@@ -87,7 +97,18 @@ func main() {
return
}
newVersion := calculateNewVersion(major, minor, patch, bumpType, config.versionPrefix)
var newVersion string
if bumpType == "suffix" {
newVersion, err = calculateSuffixVersion(version, config.suffixLabel, config.versionPrefix)
} else {
if version.hasSuffix {
log.Fatalf("Cannot apply %s bump to suffixed version %s", bumpType, tag)
}
newVersion = calculateNewVersion(version.major, version.minor, version.patch, bumpType, config.versionPrefix)
}
if err != nil {
log.Fatalf("Error calculating version: %v", err)
}
fmt.Println("new version:", newVersion)
if config.dryRun {
@@ -109,8 +130,9 @@ func parseFlags() Config {
flag.BoolVar(&config.printVersion, "version", false, "Just print version")
flag.BoolVar(&config.dryRun, "dry-run", getEnvBool("DRY_RUN", false), "Show what would be done without making changes")
flag.StringVar(&config.forcedBump, "bump", os.Getenv("BUMP"), "Force specific bump type (major, minor, or patch)")
flag.StringVar(&config.forcedBump, "bump", getEnv("BUMP", ""), "Force specific bump type (major, minor, patch, or suffix)")
flag.StringVar(&config.versionPrefix, "prefix", getEnv("PREFIX", "v"), "Version prefix (default 'v')")
flag.StringVar(&config.suffixLabel, "suffix", getEnv("SUFFIX", ""), "Suffix label used when creating the first suffix")
flag.BoolVar(&config.noPush, "no-push", getEnvBool("NO_PUSH", false), "Create tag but don't push to remote")
majorPatterns := flag.String("major-patterns", getEnv("MAJOR_PATTERNS", "bump major,breaking change"), "Comma-separated list will be joined with '|' for major version bumps")
@@ -127,20 +149,20 @@ func parseFlags() Config {
chore: strings.Split(*chorePatterns, ","),
}
if config.forcedBump != "" && !contains([]string{"major", "minor", "patch"}, config.forcedBump) {
log.Fatalf("Invalid bump type: %s. Must be one of: major, minor, patch", config.forcedBump)
if config.forcedBump != "" && !contains([]string{"major", "minor", "patch", "suffix"}, config.forcedBump) {
log.Fatalf("Invalid bump type: %s. Must be one of: major, minor, patch, suffix", config.forcedBump)
}
return config
}
func getEnv(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok {
if value, ok := os.LookupEnv(key); ok && value != "" {
return value
}
// Check for Gitea/GitHub Actions input prefix
inputKey := "INPUT_" + strings.ReplaceAll(strings.ToUpper(key), "-", "_")
if value, ok := os.LookupEnv(inputKey); ok {
if value, ok := os.LookupEnv(inputKey); ok && value != "" {
return value
}
return fallback
@@ -214,29 +236,60 @@ func getCommitsSinceTag(tag string) ([]string, error) {
}
func parseVersion(tag, prefix string) (int, int, int, error) {
tag = strings.TrimPrefix(tag, prefix)
version, err := parseTaggedVersion(tag, prefix)
if err != nil {
return 0, 0, 0, err
}
if version.hasSuffix {
return 0, 0, 0, fmt.Errorf("version has a suffix: %s", tag)
}
return version.major, version.minor, version.patch, nil
}
parts := strings.Split(tag, ".")
func parseTaggedVersion(tag, prefix string) (taggedVersion, error) {
rawVersion := strings.TrimPrefix(tag, prefix)
baseVersion := rawVersion
suffix := ""
if separator := strings.IndexByte(rawVersion, '-'); separator >= 0 {
baseVersion = rawVersion[:separator]
suffix = rawVersion[separator+1:]
}
parts := strings.Split(baseVersion, ".")
if len(parts) != 3 {
return 0, 0, 0, fmt.Errorf("invalid version format: %s", tag)
return taggedVersion{}, fmt.Errorf("invalid version format: %s", rawVersion)
}
major, err := strconv.Atoi(parts[0])
if err != nil {
return 0, 0, 0, err
if err != nil || major < 0 {
return taggedVersion{}, fmt.Errorf("invalid major version: %s", parts[0])
}
minor, err := strconv.Atoi(parts[1])
if err != nil {
return 0, 0, 0, err
if err != nil || minor < 0 {
return taggedVersion{}, fmt.Errorf("invalid minor version: %s", parts[1])
}
patch, err := strconv.Atoi(parts[2])
if err != nil {
return 0, 0, 0, err
if err != nil || patch < 0 {
return taggedVersion{}, fmt.Errorf("invalid patch version: %s", parts[2])
}
return major, minor, patch, nil
version := taggedVersion{major: major, minor: minor, patch: patch}
if suffix == "" {
return version, nil
}
suffixParts := strings.Split(suffix, ".")
if len(suffixParts) != 2 || suffixParts[0] == "" {
return taggedVersion{}, fmt.Errorf("invalid version suffix: %s", suffix)
}
revision, err := strconv.Atoi(suffixParts[1])
if err != nil || revision < 1 {
return taggedVersion{}, fmt.Errorf("invalid version suffix revision: %s", suffix)
}
version.suffixLabel = suffixParts[0]
version.suffixRevision = revision
version.hasSuffix = true
return version, nil
}
func getBumpType(commits []string, config Config) string {
@@ -289,6 +342,32 @@ func calculateNewVersion(major, minor, patch int, bumpType, prefix string) strin
return fmt.Sprintf("%s%d.%d.%d", prefix, major, minor, patch)
}
func calculateSuffixVersion(version taggedVersion, suffixLabel, prefix string) (string, error) {
if version.hasSuffix {
if suffixLabel != "" && suffixLabel != version.suffixLabel {
return "", fmt.Errorf("suffix label %q does not match %q", suffixLabel, version.suffixLabel)
}
version.suffixRevision++
return formatTaggedVersion(version, prefix), nil
}
if suffixLabel == "" {
return "", fmt.Errorf("suffix label is required for a base version")
}
version.suffixLabel = suffixLabel
version.suffixRevision = 1
version.hasSuffix = true
return formatTaggedVersion(version, prefix), nil
}
func formatTaggedVersion(version taggedVersion, prefix string) string {
base := fmt.Sprintf("%s%d.%d.%d", prefix, version.major, version.minor, version.patch)
if version.hasSuffix {
return fmt.Sprintf("%s-%s.%d", base, version.suffixLabel, version.suffixRevision)
}
return base
}
func createAndPushTag(version string, noPush bool) error {
if out, err := git("tag " + version); err != nil {
return fmt.Errorf("error creating tag: %v; stdout: %v", err, out)
+86
View File
@@ -12,3 +12,89 @@ func TestParseVersion(t *testing.T) {
t.Fatal("version does not match")
}
}
func TestParseTaggedVersion(t *testing.T) {
version, err := parseTaggedVersion("v0.10.50-meda.2", "v")
if err != nil {
t.Fatal(err)
}
if version.major != 0 || version.minor != 10 || version.patch != 50 {
t.Fatalf("base version does not match: %+v", version)
}
if !version.hasSuffix || version.suffixLabel != "meda" || version.suffixRevision != 2 {
t.Fatalf("suffix does not match: %+v", version)
}
}
func TestParseVersionRejectsSuffix(t *testing.T) {
if _, _, _, err := parseVersion("v0.10.50-meda.2", "v"); err == nil {
t.Fatal("expected suffixed version to be rejected")
}
}
func TestGetEnvActionInput(t *testing.T) {
t.Setenv("BUMP", "")
t.Setenv("SUFFIX", "")
t.Setenv("INPUT_BUMP", "suffix")
t.Setenv("INPUT_SUFFIX", "meda")
if value := getEnv("BUMP", ""); value != "suffix" {
t.Fatalf("expected suffix bump, got %s", value)
}
if value := getEnv("SUFFIX", ""); value != "meda" {
t.Fatalf("expected meda suffix, got %s", value)
}
}
func TestCalculateSuffixVersion(t *testing.T) {
tests := []struct {
name string
version taggedVersion
suffix string
expected string
expectsErr bool
}{
{
name: "first suffix",
version: taggedVersion{major: 0, minor: 10, patch: 50},
suffix: "meda",
expected: "v0.10.50-meda.1",
},
{
name: "increment suffix",
version: taggedVersion{major: 0, minor: 10, patch: 50, suffixLabel: "meda", suffixRevision: 1, hasSuffix: true},
suffix: "meda",
expected: "v0.10.50-meda.2",
},
{
name: "missing label",
version: taggedVersion{major: 0, minor: 10, patch: 50},
expectsErr: true,
},
{
name: "label mismatch",
version: taggedVersion{major: 0, minor: 10, patch: 50, suffixLabel: "meda", suffixRevision: 1, hasSuffix: true},
suffix: "other",
expectsErr: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual, err := calculateSuffixVersion(test.version, test.suffix, "v")
if test.expectsErr {
if err == nil {
t.Fatal("expected an error")
}
return
}
if err != nil {
t.Fatal(err)
}
if actual != test.expected {
t.Fatalf("expected %s, got %s", test.expected, actual)
}
})
}
}