mirror of
https://github.com/therootcompany/golib.git
synced 2026-03-02 23:57:59 +00:00
fix(monorel): guard .goreleaser.yaml overwrite in release; loosen compat check
release subcommand:
- Replace yamlLooksCorrect with yamlIsCompatible: file is considered OK if
{{ .ProjectName }} is absent AND at least one binary's VERSION string is
present. Extra hand-edited binaries (like fixtures) no longer trigger a
rewrite.
- Before overwriting an existing file, prompt the user [Y/n]. --yes does
not skip this prompt; --force does. If stdin is not a terminal and
--force is not set, the command errors rather than silently clobbering.
init subcommand: unchanged — still uses the strict yamlLooksCorrect check
(all binaries must be present, ldflags must include main.version).
This commit is contained in:
parent
c14bc239f5
commit
1289f3e5b6
@ -112,11 +112,12 @@ func usage() {
|
||||
|
||||
func runRelease(args []string) {
|
||||
fs := flag.NewFlagSet("monorel release", flag.ExitOnError)
|
||||
var recursive, all, dryRun, yes, draft, prerelease bool
|
||||
var recursive, all, dryRun, yes, force, draft, prerelease bool
|
||||
fs.BoolVar(&recursive, "recursive", false, "find all main packages recursively under each path")
|
||||
fs.BoolVar(&all, "A", false, "include dot/underscore-prefixed directories; warn rather than error on failures")
|
||||
fs.BoolVar(&dryRun, "dry-run", false, "show each step without running it")
|
||||
fs.BoolVar(&yes, "yes", false, "run all steps without prompting")
|
||||
fs.BoolVar(&force, "force", false, "overwrite .goreleaser.yaml without prompting even if it has been modified")
|
||||
fs.BoolVar(&draft, "draft", false, "keep the GitHub release in draft state after uploading (default: publish)")
|
||||
fs.BoolVar(&prerelease, "prerelease", false, "keep the GitHub release marked as pre-release even for clean tags (default: promote clean tags to stable)")
|
||||
fs.Usage = func() {
|
||||
@ -161,7 +162,7 @@ func runRelease(args []string) {
|
||||
printGroupHeader(cwd, group)
|
||||
relPath, _ := filepath.Rel(cwd, group.root)
|
||||
relPath = filepath.ToSlash(relPath)
|
||||
processModule(group, relPath, dryRun, yes, draft, prerelease)
|
||||
processModule(group, relPath, dryRun, yes, force, draft, prerelease)
|
||||
}
|
||||
}
|
||||
|
||||
@ -952,7 +953,7 @@ func printGroupHeader(cwd string, group *moduleGroup) {
|
||||
// for one module group. relPath is the path from the caller's CWD to the
|
||||
// module root; it is used in the script for all paths so that the script can
|
||||
// be run from the directory where monorel was invoked.
|
||||
func processModule(group *moduleGroup, relPath string, dryRun, yes, draft, prerelease bool) {
|
||||
func processModule(group *moduleGroup, relPath string, dryRun, yes, force, draft, prerelease bool) {
|
||||
modRoot := group.root
|
||||
bins := group.bins
|
||||
|
||||
@ -971,18 +972,18 @@ func processModule(group *moduleGroup, relPath string, dryRun, yes, draft, prere
|
||||
rawURL := mustRunIn(modRoot, "git", "remote", "get-url", "origin")
|
||||
repoPath := normalizeGitURL(rawURL)
|
||||
|
||||
// 1. Write .goreleaser.yaml (always regenerate).
|
||||
// Track whether this is a first-time creation: auto-commit and auto-tag
|
||||
// only apply when the file is new. If it already exists, just update it
|
||||
// on disk and leave committing to the user.
|
||||
// 1. Write .goreleaser.yaml when necessary.
|
||||
// For release, the file is considered compatible if it has no stock
|
||||
// {{ .ProjectName }} template and at least one binary uses the VERSION env
|
||||
// var — local edits that add extra binaries etc. are preserved.
|
||||
// Auto-commit and auto-tag only apply when the file is brand new.
|
||||
yamlContent := goreleaserYAML(projectName, bins)
|
||||
yamlPath := filepath.Join(modRoot, ".goreleaser.yaml")
|
||||
existing, readErr := os.ReadFile(yamlPath)
|
||||
isNewFile := readErr != nil
|
||||
isChanged := isNewFile || !yamlLooksCorrect(string(existing), bins)
|
||||
isChanged := isNewFile || !yamlIsCompatible(string(existing), bins)
|
||||
if !isNewFile && isChanged {
|
||||
// Warn if a stock {{ .ProjectName }} template is in use (one of the
|
||||
// reasons yamlLooksCorrect may have returned false).
|
||||
// Warn if a stock {{ .ProjectName }} template is in use.
|
||||
hasProjectName := strings.Contains(string(existing), "{{ .ProjectName }}") ||
|
||||
strings.Contains(string(existing), "{{.ProjectName}}")
|
||||
gitInfo, gitErr := os.Stat(filepath.Join(modRoot, ".git"))
|
||||
@ -991,6 +992,23 @@ func processModule(group *moduleGroup, relPath string, dryRun, yes, draft, prere
|
||||
fmt.Fprintf(os.Stderr, "warning: %s: contains {{ .ProjectName }} but module is a monorepo subdirectory;\n", yamlPath)
|
||||
fmt.Fprintf(os.Stderr, " replacing stock goreleaser config with monorel-generated config.\n")
|
||||
}
|
||||
// Prompt before overwriting a modified file. --yes does not apply;
|
||||
// use --force to skip the prompt. If stdin is not a terminal and
|
||||
// --force is not set, refuse rather than silently clobber.
|
||||
if !force {
|
||||
fi, statErr := os.Stdin.Stat()
|
||||
isTTY := statErr == nil && fi.Mode()&os.ModeCharDevice != 0
|
||||
if !isTTY {
|
||||
fatalf("%s needs updating but stdin is not a terminal; use --force to overwrite", cwdRelPath(yamlPath))
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s needs updating; overwrite? [Y/n] ", cwdRelPath(yamlPath))
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
line, _ := reader.ReadString('\n')
|
||||
if resp := strings.ToLower(strings.TrimSpace(line)); resp == "n" || resp == "no" {
|
||||
fmt.Fprintf(os.Stderr, "skipped %s\n", cwdRelPath(yamlPath))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if isChanged {
|
||||
if err := os.WriteFile(yamlPath, []byte(yamlContent), 0o644); err != nil {
|
||||
@ -1273,6 +1291,24 @@ func goreleaserYAML(projectName string, bins []binary) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// yamlIsCompatible is the looser check used by the release subcommand.
|
||||
// It returns true when the file has no stock {{ .ProjectName }} template and
|
||||
// at least one binary already uses the VERSION env var in its archive name.
|
||||
// This preserves hand-edited files that add extra binaries or tweak settings,
|
||||
// where yamlLooksCorrect would demand every declared binary be present.
|
||||
func yamlIsCompatible(content string, bins []binary) bool {
|
||||
if strings.Contains(content, "{{ .ProjectName }}") ||
|
||||
strings.Contains(content, "{{.ProjectName}}") {
|
||||
return false
|
||||
}
|
||||
for _, bin := range bins {
|
||||
if strings.Contains(content, bin.name+"_{{ .Env.VERSION }}_") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// yamlLooksCorrect returns true when content appears to be a valid monorel-
|
||||
// generated (or compatible) .goreleaser.yaml for the given binaries:
|
||||
//
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user