refactor(cli): extract publish-time warnings into emitPublishWarnings

Pulls the three warning calls and the dirty-tree check out of the
publish RunE closure into a single helper so a refactor that drops one
warning can be caught by a fixture-based test.
This commit is contained in:
Alex Dunmow 2026-06-03 10:14:50 +08:00
parent ea744888ae
commit 824d55a1fa

View File

@ -299,27 +299,9 @@ func newPluginPublishCmd() *cobra.Command {
return err return err
} }
// Run the tracked-yet-gitignored warning BEFORE the dirty check so if err := emitPublishWarnings(".", allowDirty, os.Stderr); err != nil {
// the developer sees it even on the aborted-publish path; the spec return err
// asks for this warning to be unconditional.
gitignoredTrackedWarning(".", os.Stderr)
if !allowDirty {
out, _ := exec.Command("git", "status", "--porcelain").Output()
if len(strings.TrimSpace(string(out))) > 0 {
return fmt.Errorf("working tree dirty; commit or pass --allow-dirty")
} }
} else {
// `git stash create` only captures tracked content, so untracked
// files would be silently dropped from the archive. Warn loudly.
untrackedFilesWarning(".", os.Stderr)
}
// `git archive` does not recurse into submodules, so any submodule
// paths will appear as empty directories in the tarball. Detect via
// .gitmodules so this works even for submodules that haven't been
// initialised yet.
submoduleWarning(".", os.Stderr)
archiveBytes, err := archive.BuildSourceArchive(".") archiveBytes, err := archive.BuildSourceArchive(".")
if err != nil { if err != nil {
@ -676,6 +658,38 @@ func untrackedFilesWarning(repoDir string, w io.Writer) {
fmt.Fprintln(w, " (run `git add <file>` if they should be shipped)") fmt.Fprintln(w, " (run `git add <file>` if they should be shipped)")
} }
// emitPublishWarnings runs the publish-time warning helpers in the order the
// CLI expects:
//
// 1. gitignoredTrackedWarning is unconditional so the developer sees it even
// when the publish is about to abort.
// 2. If allowDirty is false the working tree must be clean — a dirty tree
// returns an error and the remaining warnings (which are only useful on
// the proceeding-publish path) are skipped.
// 3. If allowDirty is true the untracked-files warning fires so the user
// knows those files won't be in the archive.
// 4. submoduleWarning is unconditional on the proceeding path because
// `git archive` does not recurse into submodules.
func emitPublishWarnings(repoDir string, allowDirty bool, w io.Writer) error {
gitignoredTrackedWarning(repoDir, w)
if !allowDirty {
cmd := exec.Command("git", "status", "--porcelain")
cmd.Dir = repoDir
out, _ := cmd.Output()
if len(strings.TrimSpace(string(out))) > 0 {
return fmt.Errorf("working tree dirty; commit or pass --allow-dirty")
}
} else {
// `git stash create` only captures tracked content, so untracked
// files would be silently dropped from the archive. Warn loudly.
untrackedFilesWarning(repoDir, w)
}
submoduleWarning(repoDir, w)
return nil
}
// submoduleWarning writes a warning to w if repoDir contains submodules. // submoduleWarning writes a warning to w if repoDir contains submodules.
// `git archive` doesn't recurse into them so they ship as empty directories; // `git archive` doesn't recurse into them so they ship as empty directories;
// detection is via .gitmodules so it fires even for uninitialised submodules. // detection is via .gitmodules so it fires even for uninitialised submodules.