- stamp add: create .stamp/*.md changeset files (interactive + --no-interactive) - stamp status: show pending stamps and projected next versions (plain + --json) - stamp version: consume stamps, bump semver, update CHANGELOGs, commit - stamp publish: create git tags, GitHub/Gitea releases, upload artifacts - stamp comment: post/update idempotent PR comments via GitHub/Gitea API - Supports monorepos via stamp.toml [[projects]] blocks - Changeset files support YAML (---) and TOML (+++) frontmatter - Semver + pre-release support (alpha, beta, rc) - Examples and workflow documentation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
139 lines
3.5 KiB
Go
139 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/urfave/cli/v3"
|
|
|
|
"github.com/thokra/stamp/internal/changeset"
|
|
"github.com/thokra/stamp/internal/changelog"
|
|
"github.com/thokra/stamp/internal/config"
|
|
"github.com/thokra/stamp/internal/git"
|
|
"github.com/thokra/stamp/internal/semver"
|
|
)
|
|
|
|
func versionCmd() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "version",
|
|
Usage: "consume stamps, bump versions, and update changelogs",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "snapshot",
|
|
Usage: "pre-release identifier (e.g. alpha, beta, rc) for snapshot releases",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "no-commit",
|
|
Usage: "skip the git commit after versioning",
|
|
},
|
|
},
|
|
Action: func(ctx context.Context, cmd *cli.Command) error {
|
|
repoRoot, err := findRepoRoot(".")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cfg, err := config.Load(repoRoot)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
stampDir := filepath.Join(repoRoot, cfg.ChangesetDir())
|
|
|
|
changesets, err := changeset.ReadAll(stampDir)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
if len(changesets) == 0 {
|
|
fmt.Println("No pending stamps found.")
|
|
return nil
|
|
}
|
|
|
|
preID := cmd.String("snapshot")
|
|
projectBumps := semver.ProjectBumps(changesets)
|
|
now := time.Now()
|
|
|
|
var changedFiles []string
|
|
var bumped []string
|
|
|
|
for i := range cfg.Projects {
|
|
project := &cfg.Projects[i]
|
|
bumps := projectBumps[project.Name]
|
|
if len(bumps) == 0 {
|
|
continue
|
|
}
|
|
|
|
highest := semver.HighestBump(bumps)
|
|
if preID != "" {
|
|
highest = changeset.BumpPreRelease
|
|
}
|
|
|
|
nextVer, err := semver.Bump(project.Version, highest, preID)
|
|
if err != nil {
|
|
return fmt.Errorf("bumping %s: %w", project.Name, err)
|
|
}
|
|
|
|
// Build changelog body from all matching changesets.
|
|
var body string
|
|
for _, cs := range changesets {
|
|
if _, ok := cs.Bumps[project.Name]; ok {
|
|
if cs.Description != "" {
|
|
body += "- " + cs.Description + "\n"
|
|
}
|
|
}
|
|
}
|
|
|
|
clPath := project.ChangelogPath(repoRoot)
|
|
if err := changelog.Append(clPath, changelog.Entry{
|
|
Version: nextVer,
|
|
Date: now,
|
|
Description: body,
|
|
}); err != nil {
|
|
return fmt.Errorf("updating changelog for %s: %w", project.Name, err)
|
|
}
|
|
changedFiles = append(changedFiles, clPath)
|
|
|
|
fmt.Printf(" %s: %s → %s\n", project.Name, project.Version, nextVer)
|
|
project.Version = nextVer
|
|
bumped = append(bumped, project.Name)
|
|
}
|
|
|
|
if len(bumped) == 0 {
|
|
fmt.Println("No projects were bumped.")
|
|
return nil
|
|
}
|
|
|
|
// Update stamp.toml with new versions.
|
|
cfgPath := filepath.Join(repoRoot, config.ConfigFileName)
|
|
if err := config.Save(repoRoot, cfg); err != nil {
|
|
return fmt.Errorf("saving stamp.toml: %w", err)
|
|
}
|
|
changedFiles = append(changedFiles, cfgPath)
|
|
|
|
// Delete consumed stamp files.
|
|
if err := changeset.DeleteAll(stampDir); err != nil {
|
|
return fmt.Errorf("deleting stamp files: %w", err)
|
|
}
|
|
changedFiles = append(changedFiles, stampDir)
|
|
|
|
if cmd.Bool("no-commit") {
|
|
fmt.Println("\nVersioning complete (no commit).")
|
|
return nil
|
|
}
|
|
|
|
// Stage and commit.
|
|
if err := git.Add(repoRoot, changedFiles...); err != nil {
|
|
return fmt.Errorf("staging files: %w", err)
|
|
}
|
|
|
|
commitMsg := fmt.Sprintf("chore: version packages\n\nBumped: %v", bumped)
|
|
if err := git.Commit(repoRoot, commitMsg); err != nil {
|
|
return fmt.Errorf("committing: %w", err)
|
|
}
|
|
fmt.Println("\n✓ Committed version bump.")
|
|
return nil
|
|
},
|
|
}
|
|
}
|