diff --git a/cmd/ninja/cmd/plugin.go b/cmd/ninja/cmd/plugin.go index 2665d05..305fb43 100644 --- a/cmd/ninja/cmd/plugin.go +++ b/cmd/ninja/cmd/plugin.go @@ -299,28 +299,10 @@ func newPluginPublishCmd() *cobra.Command { return err } - // Run the tracked-yet-gitignored warning BEFORE the dirty check so - // the developer sees it even on the aborted-publish path; the spec - // 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) + if err := emitPublishWarnings(".", allowDirty, os.Stderr); err != nil { + return err } - // `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(".") if err != nil { return fmt.Errorf("build archive: %w", err) @@ -676,6 +658,38 @@ func untrackedFilesWarning(repoDir string, w io.Writer) { fmt.Fprintln(w, " (run `git add ` 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. // `git archive` doesn't recurse into them so they ship as empty directories; // detection is via .gitmodules so it fires even for uninitialised submodules.