Repository: goreleaser/nfpm
Pull request #667 (2023-06-02 04:45:17)

feat: expand environment variables in deb fields values
This is convenient in CI, one real world example usage in tests and docs.

(FWIW, `CI_REPOSITORY_URL` is a predefined env var at least in GitLab CI.)

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/goreleaser/nfpm/pull/667?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) Report
> Merging [#667](https://app.codecov.io/gh/goreleaser/nfpm/pull/667?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (093e1d1) into [main](https://app.codecov.io/gh/goreleaser/nfpm/commit/14ce368f139f7b973e44bd952a446daa2498c6dc?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (14ce368) will **increase** coverage by `0.04%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##             main     #667      +/-   ##
==========================================
+ Coverage   75.77%   75.81%   +0.04%     
==========================================
  Files          14       14              
  Lines        2951     2956       +5     
==========================================
+ Hits         2236     2241       +5     
  Misses        506      506              
  Partials      209      209              
```


| [Impacted Files](https://app.codecov.io/gh/goreleaser/nfpm/pull/667?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) | Coverage Δ | |
|---|---|---|
| [nfpm.go](https://app.codecov.io/gh/goreleaser/nfpm/pull/667?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-bmZwbS5nbw==) | `84.93% <100.00%> (+0.32%)` | :arrow_up: |


scop: CI fail fix in https://github.com/goreleaser/nfpm/pull/669

Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 0582883..2b61b62 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -26,6 +26,8 @@ linters-settings:
         yaml: snake
         json: snake
   depguard:
-     list-type: 'denylist'
-     packages-with-error-message:
-       - 'github.com/pkg/errors': 'use stdlib instead'
+    rules:
+      main:
+        deny:
+          - pkg: 'github.com/pkg/errors'
+            desc: 'use stdlib instead'
diff --git a/internal/cmd/docs.go b/internal/cmd/docs.go
index 64cd516..57eb640 100644
--- a/internal/cmd/docs.go
+++ b/internal/cmd/docs.go
@@ -20,6 +20,7 @@ func newDocsCmd() *docsCmd {
 		DisableFlagsInUseLine: true,
 		Hidden:                true,
 		Args:                  cobra.NoArgs,
+		ValidArgsFunction:     cobra.NoFileCompletions,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			root.cmd.Root().DisableAutoGenTag = true
 			return doc.GenMarkdownTreeCustom(root.cmd.Root(), "www/docs/cmd", func(_ string) string {
diff --git a/internal/cmd/init.go b/internal/cmd/init.go
index a5a0c4e..9df97e3 100644
--- a/internal/cmd/init.go
+++ b/internal/cmd/init.go
@@ -15,12 +15,13 @@ type initCmd struct {
 func newInitCmd() *initCmd {
 	root := &initCmd{}
 	cmd := &cobra.Command{
-		Use:           "init",
-		Aliases:       []string{"i"},
-		Short:         "Creates a sample nfpm.yaml configuration file",
-		SilenceUsage:  true,
-		SilenceErrors: true,
-		Args:          cobra.NoArgs,
+		Use:               "init",
+		Aliases:           []string{"i"},
+		Short:             "Creates a sample nfpm.yaml configuration file",
+		SilenceUsage:      true,
+		SilenceErrors:     true,
+		Args:              cobra.NoArgs,
+		ValidArgsFunction: cobra.NoFileCompletions,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if err := os.WriteFile(root.config, []byte(example), 0o666); err != nil {
 				return fmt.Errorf("failed to create example file: %w", err)
@@ -30,6 +31,9 @@ func newInitCmd() *initCmd {
 	}
 
 	cmd.Flags().StringVarP(&root.config, "config", "f", "nfpm.yaml", "path to the to-be-created config file")
+	if err := cmd.MarkFlagFilename("config", "yaml", "yml"); err != nil {
+		panic(err)
+	}
 
 	root.cmd = cmd
 	return root
diff --git a/internal/cmd/man.go b/internal/cmd/man.go
index 09768f1..8b21bf5 100644
--- a/internal/cmd/man.go
+++ b/internal/cmd/man.go
@@ -22,6 +22,7 @@ func newManCmd() *manCmd {
 		DisableFlagsInUseLine: true,
 		Hidden:                true,
 		Args:                  cobra.NoArgs,
+		ValidArgsFunction:     cobra.NoFileCompletions,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			manPage, err := mcobra.NewManPage(1, root.cmd.Root())
 			if err != nil {
diff --git a/internal/cmd/package.go b/internal/cmd/package.go
index 334dfe9..68b8daa 100644
--- a/internal/cmd/package.go
+++ b/internal/cmd/package.go
@@ -21,20 +21,30 @@ type packageCmd struct {
 func newPackageCmd() *packageCmd {
 	root := &packageCmd{}
 	cmd := &cobra.Command{
-		Use:           "package",
-		Aliases:       []string{"pkg", "p"},
-		Short:         "Creates a package based on the given config file and flags",
-		SilenceUsage:  true,
-		SilenceErrors: true,
-		Args:          cobra.NoArgs,
+		Use:               "package",
+		Aliases:           []string{"pkg", "p"},
+		Short:             "Creates a package based on the given config file and flags",
+		SilenceUsage:      true,
+		SilenceErrors:     true,
+		Args:              cobra.NoArgs,
+		ValidArgsFunction: cobra.NoFileCompletions,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			return doPackage(root.config, root.target, root.packager)
 		},
 	}
 
 	cmd.Flags().StringVarP(&root.config, "config", "f", "nfpm.yaml", "config file to be used")
+	if err := cmd.MarkFlagFilename("config", "yaml", "yml"); err != nil {
+		panic(err)
+	}
 	cmd.Flags().StringVarP(&root.target, "target", "t", "", "where to save the generated package (filename, folder or empty for current folder)")
+	if err := cmd.MarkFlagFilename("target"); err != nil {
+		panic(err)
+	}
 	cmd.Flags().StringVarP(&root.packager, "packager", "p", "", "which packager implementation to use [apk|deb|rpm|archlinux]")
+	if err := cmd.RegisterFlagCompletionFunc("packager", cobra.FixedCompletions([]string{"apk", "deb", "rpm", "archlinux"}, cobra.ShellCompDirectiveNoFileComp)); err != nil {
+		panic(err)
+	}
 
 	root.cmd = cmd
 	return root
diff --git a/internal/cmd/root.go b/internal/cmd/root.go
index f8f9978..5e91eec 100644
--- a/internal/cmd/root.go
+++ b/internal/cmd/root.go
@@ -33,13 +33,14 @@ func newRootCmd(version string, exit func(int)) *rootCmd {
 		exit: exit,
 	}
 	cmd := &cobra.Command{
-		Use:           "nfpm",
-		Short:         "Packages apps on RPM, Deb and APK formats based on a YAML configuration file",
-		Long:          `nFPM is a simple, 0-dependencies, deb, rpm and apk packager.`,
-		Version:       version,
-		SilenceUsage:  true,
-		SilenceErrors: true,
-		Args:          cobra.NoArgs,
+		Use:               "nfpm",
+		Short:             "Packages apps on RPM, Deb and APK formats based on a YAML configuration file",
+		Long:              `nFPM is a simple, 0-dependencies, deb, rpm and apk packager.`,
+		Version:           version,
+		SilenceUsage:      true,
+		SilenceErrors:     true,
+		Args:              cobra.NoArgs,
+		ValidArgsFunction: cobra.NoFileCompletions,
 	}
 
 	cmd.AddCommand(
diff --git a/internal/cmd/schema.go b/internal/cmd/schema.go
index fa77a4a..731275f 100644
--- a/internal/cmd/schema.go
+++ b/internal/cmd/schema.go
@@ -19,12 +19,13 @@ type schemaCmd struct {
 func newSchemaCmd() *schemaCmd {
 	root := &schemaCmd{}
 	cmd := &cobra.Command{
-		Use:           "jsonschema",
-		Aliases:       []string{"schema"},
-		Short:         "Outputs nFPM's JSON schema",
-		SilenceUsage:  true,
-		SilenceErrors: true,
-		Args:          cobra.NoArgs,
+		Use:               "jsonschema",
+		Aliases:           []string{"schema"},
+		Short:             "Outputs nFPM's JSON schema",
+		SilenceUsage:      true,
+		SilenceErrors:     true,
+		Args:              cobra.NoArgs,
+		ValidArgsFunction: cobra.NoFileCompletions,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			schema := jsonschema.Reflect(&nfpm.Config{})
 			schema.Description = "nFPM configuration definition file"
@@ -47,6 +48,9 @@ func newSchemaCmd() *schemaCmd {
 	}
 
 	cmd.Flags().StringVarP(&root.output, "output", "o", "-", "where to save the json schema")
+	if err := cmd.MarkFlagFilename("output", "json"); err != nil {
+		panic(err)
+	}
 
 	root.cmd = cmd
 	return root
diff --git a/nfpm.go b/nfpm.go
index 372164b..da20ba2 100644
--- a/nfpm.go
+++ b/nfpm.go
@@ -229,6 +229,11 @@ func (c *Config) expandEnvVars() {
 
 	// RPM specific
 	c.Info.RPM.Packager = os.Expand(c.RPM.Packager, c.envMappingFunc)
+
+	// Deb specific
+	for k, v := range c.Info.Deb.Fields {
+		c.Info.Deb.Fields[k] = os.Expand(v, c.envMappingFunc)
+	}
 }
 
 // Info contains information about a single package.
diff --git a/www/docs/configuration.md b/www/docs/configuration.md
index a359735..f942b20 100644
--- a/www/docs/configuration.md
+++ b/www/docs/configuration.md
@@ -399,6 +399,7 @@ deb:
     key_id: bc8acdd415bd80b3
 
   # Additional fields for the control file. Empty fields are ignored.
+  # This will expand any env vars you set in the field values, e.g. Vcs-Git: ${CI_REPOSITORY_URL}
   fields:
     Bugs: https://github.com/goreleaser/nfpm/issues
 


Test patch:
diff --git a/nfpm_test.go b/nfpm_test.go
index aa5274f..b3c8b5d 100644
--- a/nfpm_test.go
+++ b/nfpm_test.go
@@ -366,6 +366,7 @@ func TestOptionsFromEnvironment(t *testing.T) {
 		vendor          = "GoReleaser"
 		packager        = "nope"
 		maintainerEmail = "nope@example.com"
+		vcsURL          = "https://github.com/goreleaser/nfpm.git"
 	)
 
 	t.Run("platform", func(t *testing.T) {
@@ -486,6 +487,18 @@ overrides:
 		require.Len(t, info.Overrides["rpm"].Depends, 1)
 		require.Equal(t, "package = 1.0.0", info.Overrides["rpm"].Depends[0])
 	})
+
+	t.Run("deb fields", func(t *testing.T) {
+		t.Setenv("CI_REPOSITORY_URL", vcsURL)
+		info, err := nfpm.Parse(strings.NewReader(`
+name: foo
+deb:
+  fields:
+    Vcs-Git: ${CI_REPOSITORY_URL}
+`))
+		require.NoError(t, err)
+		require.Equal(t, vcsURL, info.Deb.Fields["Vcs-Git"])
+	})
 }
 
 func TestOverrides(t *testing.T) {