refactor(cli): extract publish-time warnings into testable helpers

Pull the three inline warning blocks in newPluginPublishCmd —
gitignoredTrackedWarning, untrackedFilesWarning, submoduleWarning — into
package-private helpers that take a repo dir and an io.Writer. Output is
byte-identical to the previous inline code; this just makes them unit-
testable without driving the whole cobra command.
This commit is contained in:
Alex Dunmow 2026-06-03 09:12:56 +08:00
parent 421f5ee0cb
commit fda01e81b5

View File

@ -4,6 +4,7 @@ import (
"bufio"
"context"
"fmt"
"io"
"os"
"os/exec"
"regexp"
@ -301,14 +302,7 @@ func newPluginPublishCmd() *cobra.Command {
// 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.
out, _ := exec.Command("git", "ls-files", "--cached", "--ignored", "--exclude-standard").Output()
if names := strings.TrimSpace(string(out)); names != "" {
fmt.Fprintln(os.Stderr, "warning: these tracked files match .gitignore and will still be shipped:")
for _, n := range strings.Split(names, "\n") {
fmt.Fprintln(os.Stderr, " "+n)
}
fmt.Fprintln(os.Stderr, " (run `git rm --cached <file>` to drop)")
}
gitignoredTrackedWarning(".", os.Stderr)
if !allowDirty {
out, _ := exec.Command("git", "status", "--porcelain").Output()
@ -318,27 +312,14 @@ func newPluginPublishCmd() *cobra.Command {
} else {
// `git stash create` only captures tracked content, so untracked
// files would be silently dropped from the archive. Warn loudly.
out, _ := exec.Command("git", "ls-files", "--others", "--exclude-standard").Output()
if names := strings.TrimSpace(string(out)); names != "" {
fmt.Fprintln(os.Stderr, "warning: --allow-dirty: these untracked files will NOT be in the archive:")
for _, n := range strings.Split(names, "\n") {
fmt.Fprintln(os.Stderr, " "+n)
}
fmt.Fprintln(os.Stderr, " (run `git add <file>` if they should be shipped)")
}
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.
if paths := submodulePaths("."); len(paths) > 0 {
fmt.Fprintln(os.Stderr, "warning: this repo has submodules; git archive will ship them as empty directories:")
for _, p := range paths {
fmt.Fprintln(os.Stderr, " "+p)
}
fmt.Fprintln(os.Stderr, " (vendor the contents or pack them separately if the plugin depends on them)")
}
submoduleWarning(".", os.Stderr)
archiveBytes, err := archive.BuildSourceArchive(".")
if err != nil {
@ -658,6 +639,58 @@ func writeMod(path string, m *core.ModFile) error {
return os.WriteFile(path, []byte(b.String()), 0o644)
}
// gitignoredTrackedWarning writes a warning to w if any tracked files
// in repoDir match the active .gitignore — those files still ship in the
// archive, which is almost always not what the author wants.
func gitignoredTrackedWarning(repoDir string, w io.Writer) {
cmd := exec.Command("git", "ls-files", "--cached", "--ignored", "--exclude-standard")
cmd.Dir = repoDir
out, _ := cmd.Output()
names := strings.TrimSpace(string(out))
if names == "" {
return
}
fmt.Fprintln(w, "warning: these tracked files match .gitignore and will still be shipped:")
for _, n := range strings.Split(names, "\n") {
fmt.Fprintln(w, " "+n)
}
fmt.Fprintln(w, " (run `git rm --cached <file>` to drop)")
}
// untrackedFilesWarning writes a warning to w listing untracked files in
// repoDir. Used on the --allow-dirty publish path because `git stash create`
// only captures tracked content, so untracked files silently vanish from the
// archive.
func untrackedFilesWarning(repoDir string, w io.Writer) {
cmd := exec.Command("git", "ls-files", "--others", "--exclude-standard")
cmd.Dir = repoDir
out, _ := cmd.Output()
names := strings.TrimSpace(string(out))
if names == "" {
return
}
fmt.Fprintln(w, "warning: --allow-dirty: these untracked files will NOT be in the archive:")
for _, n := range strings.Split(names, "\n") {
fmt.Fprintln(w, " "+n)
}
fmt.Fprintln(w, " (run `git add <file>` if they should be shipped)")
}
// 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.
func submoduleWarning(repoDir string, w io.Writer) {
paths := submodulePaths(repoDir)
if len(paths) == 0 {
return
}
fmt.Fprintln(w, "warning: this repo has submodules; git archive will ship them as empty directories:")
for _, p := range paths {
fmt.Fprintln(w, " "+p)
}
fmt.Fprintln(w, " (vendor the contents or pack them separately if the plugin depends on them)")
}
// autoCommitPluginMod stages and commits plugin.mod if it differs from
// what's already at HEAD. No-op when there's nothing to commit.
func autoCommitPluginMod() error {