Files
stamp/internal/git/git.go
Thomas 77462f5e8a feat: initial stamp implementation
- 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>
2026-03-08 20:56:23 +01:00

85 lines
2.1 KiB
Go

package git
import (
"fmt"
"os/exec"
"strings"
)
// Run executes a git command in the given directory and returns combined output.
func Run(dir string, args ...string) (string, error) {
cmd := exec.Command("git", args...)
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("git %s: %w\n%s", strings.Join(args, " "), err, out)
}
return strings.TrimSpace(string(out)), nil
}
// RepoRoot returns the root of the git repository.
func RepoRoot(dir string) (string, error) {
return Run(dir, "rev-parse", "--show-toplevel")
}
// Add stages the given paths.
func Add(dir string, paths ...string) error {
args := append([]string{"add", "--"}, paths...)
_, err := Run(dir, args...)
return err
}
// Commit creates a commit with the given message.
func Commit(dir, message string) error {
_, err := Run(dir, "commit", "-m", message)
return err
}
// Tag creates an annotated tag.
func Tag(dir, name, message string) error {
_, err := Run(dir, "tag", "-a", name, "-m", message)
return err
}
// TagLightweight creates a lightweight tag.
func TagLightweight(dir, name string) error {
_, err := Run(dir, "tag", name)
return err
}
// Push pushes the current branch and all tags to origin.
func Push(dir string) error {
_, err := Run(dir, "push", "--follow-tags")
return err
}
// PushTag pushes a specific tag to origin.
func PushTag(dir, tag string) error {
_, err := Run(dir, "push", "origin", tag)
return err
}
// CurrentBranch returns the current branch name.
func CurrentBranch(dir string) (string, error) {
return Run(dir, "rev-parse", "--abbrev-ref", "HEAD")
}
// TagName returns the conventional tag name for a project version.
// For a single-project repo (projectName == "") it returns "v<version>".
// For monorepos it returns "<projectName>@v<version>".
func TagName(projectName, version string) string {
if projectName == "" {
return "v" + version
}
return projectName + "@v" + version
}
// TagExists returns true if the tag already exists locally.
func TagExists(dir, tag string) (bool, error) {
out, err := Run(dir, "tag", "-l", tag)
if err != nil {
return false, err
}
return strings.TrimSpace(out) == tag, nil
}