Repository: twpayne/chezmoi
Pull request #310 (2019-05-19 13:56:05)

Resolve all lint problems and enable more linters


Patch:
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 000000000..ef021d66b
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,19 @@
+linters:
+  enable-all: true
+  disable:
+    - gocyclo
+    - lll
+    - maligned
+
+issues:
+  exclude-rules:
+    - linters:
+        - gochecknoglobals
+        - gochecknoinits
+      path: cmd/
+    - linters:
+        - gochecknoglobals
+      path: internal/
+    - linters:
+        - scopelint
+      path: "_test\\.go"
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 0bfb735b3..ed1866c4e 100644
--- a/Makefile
+++ b/Makefile
@@ -48,9 +48,6 @@ lint:
 	go vet ./...
 	golangci-lint run
 
-.PHONY: pre-release-checks
-pre-release-checks: strict-lint
-
 .PHONY: release
 release:
 	goreleaser release \
@@ -99,10 +96,6 @@ test-release-snap:
 		--snapshot \
 		${GORELEASER_FLAGS}
 
-.PHONY: strict-lint
-strict-lint:
-	golangci-lint run --enable-all ./...
-
 .PHONY: test
 test:
 	go test -race ./...
diff --git a/cmd/config.go b/cmd/config.go
index b256724b3..562c7fed7 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -33,41 +33,42 @@ type sourceVCSConfig struct {
 
 // A Config represents a configuration.
 type Config struct {
-	configFile      string
-	err             error
-	SourceDir       string
-	DestDir         string
-	Umask           permValue
-	DryRun          bool
-	Verbose         bool
-	Color           string
-	GPGRecipient    string
-	SourceVCS       sourceVCSConfig
-	Merge           mergeConfig
-	Bitwarden       bitwardenCmdConfig
-	GenericSecret   genericSecretCmdConfig
-	KeePassXC       keePassXCCmdConfig
-	Lastpass        lastpassCmdConfig
-	Onepassword     onepasswordCmdConfig
-	Vault           vaultCmdConfig
-	Pass            passCmdConfig
-	Data            map[string]interface{}
-	colored         bool
-	persistentState chezmoi.PersistentState
-	templateFuncs   template.FuncMap
-	add             addCmdConfig
-	data            dataCmdConfig
-	dump            dumpCmdConfig
-	edit            editCmdConfig
-	init            initCmdConfig
-	_import         importCmdConfig
-	keyring         keyringCmdConfig
-	update          updateCmdConfig
-	upgrade         upgradeCmdConfig
-	stdin           io.Reader
-	stdout          io.Writer
-	stderr          io.Writer
-	bds             *xdg.BaseDirectorySpecification
+	configFile        string
+	err               error
+	SourceDir         string
+	DestDir           string
+	Umask             permValue
+	DryRun            bool
+	Verbose           bool
+	Color             string
+	GPGRecipient      string
+	SourceVCS         sourceVCSConfig
+	Merge             mergeConfig
+	Bitwarden         bitwardenCmdConfig
+	GenericSecret     genericSecretCmdConfig
+	KeePassXC         keePassXCCmdConfig
+	Lastpass          lastpassCmdConfig
+	Onepassword       onepasswordCmdConfig
+	Vault             vaultCmdConfig
+	Pass              passCmdConfig
+	Data              map[string]interface{}
+	colored           bool
+	persistentState   chezmoi.PersistentState
+	templateFuncs     template.FuncMap
+	add               addCmdConfig
+	data              dataCmdConfig
+	dump              dumpCmdConfig
+	edit              editCmdConfig
+	init              initCmdConfig
+	_import           importCmdConfig
+	keyring           keyringCmdConfig
+	update            updateCmdConfig
+	upgrade           upgradeCmdConfig
+	stdin             io.Reader
+	stdout            io.Writer
+	stderr            io.Writer
+	bds               *xdg.BaseDirectorySpecification
+	scriptStateBucket []byte
 }
 
 var (
@@ -133,13 +134,14 @@ func (c *Config) applyArgs(fs vfs.FS, args []string, mutator chezmoi.Mutator) er
 		return err
 	}
 	applyOptions := &chezmoi.ApplyOptions{
-		DestDir:         ts.DestDir,
-		DryRun:          c.DryRun,
-		Ignore:          ts.TargetIgnore.Match,
-		PersistentState: c.persistentState,
-		Stdout:          c.Stdout(),
-		Umask:           ts.Umask,
-		Verbose:         c.Verbose,
+		DestDir:           ts.DestDir,
+		DryRun:            c.DryRun,
+		Ignore:            ts.TargetIgnore.Match,
+		PersistentState:   c.persistentState,
+		ScriptStateBucket: c.scriptStateBucket,
+		Stdout:            c.Stdout(),
+		Umask:             ts.Umask,
+		Verbose:           c.Verbose,
 	}
 	if len(args) == 0 {
 		return ts.Apply(fs, mutator, applyOptions)
@@ -207,7 +209,7 @@ func (c *Config) execEditor(argv ...string) error {
 func (c *Config) getDefaultMutator(fs vfs.FS) chezmoi.Mutator {
 	var mutator chezmoi.Mutator
 	if c.DryRun {
-		mutator = chezmoi.NullMutator
+		mutator = chezmoi.NullMutator{}
 	} else {
 		mutator = chezmoi.NewFSMutator(fs)
 	}
@@ -227,7 +229,7 @@ func (c *Config) getEditor() string {
 	return "vi"
 }
 
-func (c *Config) getEntries(fs vfs.FS, ts *chezmoi.TargetState, args []string) ([]chezmoi.Entry, error) {
+func (c *Config) getEntries(fs vfs.Stater, ts *chezmoi.TargetState, args []string) ([]chezmoi.Entry, error) {
 	entries := []chezmoi.Entry{}
 	for _, arg := range args {
 		targetPath, err := filepath.Abs(arg)
diff --git a/cmd/diff.go b/cmd/diff.go
index 3f150a980..bae1e2535 100644
--- a/cmd/diff.go
+++ b/cmd/diff.go
@@ -20,6 +20,6 @@ func init() {
 }
 
 func (c *Config) runDiffCmd(fs vfs.FS, args []string) error {
-	mutator := chezmoi.NewLoggingMutator(c.Stdout(), chezmoi.NullMutator, c.colored)
+	mutator := chezmoi.NewLoggingMutator(c.Stdout(), chezmoi.NullMutator{}, c.colored)
 	return c.applyArgs(fs, args, mutator)
 }
diff --git a/cmd/edit.go b/cmd/edit.go
index 2b969f6b6..2f908c0f5 100644
--- a/cmd/edit.go
+++ b/cmd/edit.go
@@ -134,15 +134,16 @@ func (c *Config) runEditCmd(fs vfs.FS, args []string) error {
 	readOnlyFS := vfs.NewReadOnlyFS(fs)
 	applyMutator := c.getDefaultMutator(fs)
 	applyOptions := chezmoi.ApplyOptions{
-		DestDir: ts.DestDir,
-		DryRun:  c.DryRun,
-		Ignore:  ts.TargetIgnore.Match,
-		Stdout:  c.Stdout(),
-		Umask:   ts.Umask,
-		Verbose: c.Verbose,
+		DestDir:           ts.DestDir,
+		DryRun:            c.DryRun,
+		Ignore:            ts.TargetIgnore.Match,
+		ScriptStateBucket: c.scriptStateBucket,
+		Stdout:            c.Stdout(),
+		Umask:             ts.Umask,
+		Verbose:           c.Verbose,
 	}
 	for i, entry := range entries {
-		anyMutator := chezmoi.NewAnyMutator(chezmoi.NullMutator)
+		anyMutator := chezmoi.NewAnyMutator(chezmoi.NullMutator{})
 		var mutator chezmoi.Mutator = anyMutator
 		if c.edit.diff {
 			mutator = chezmoi.NewLoggingMutator(c.Stdout(), mutator, c.colored)
diff --git a/cmd/root.go b/cmd/root.go
index 91675e77f..63b08eaf1 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -24,7 +24,8 @@ var config = Config{
 	Merge: mergeConfig{
 		Command: "vimdiff",
 	},
-	templateFuncs: sprig.HermeticTxtFuncMap(),
+	templateFuncs:     sprig.HermeticTxtFuncMap(),
+	scriptStateBucket: []byte("script"),
 }
 
 // Version information.
@@ -112,6 +113,7 @@ func Execute() {
 	}
 }
 
+//nolint:interfacer
 func (c *Config) persistentPreRunRootE(fs vfs.FS, args []string) error {
 	switch c.Color {
 	case "on":
diff --git a/cmd/upgrade.go b/cmd/upgrade.go
index 34facd527..e3ebd6a39 100644
--- a/cmd/upgrade.go
+++ b/cmd/upgrade.go
@@ -195,6 +195,7 @@ func (c *Config) downloadURL(url string) ([]byte, error) {
 	if c.Verbose {
 		fmt.Fprintf(c.Stdout(), "curl -s -L %s\n", url)
 	}
+	//nolint:gosec
 	resp, err := http.Get(url)
 	if err != nil {
 		return nil, err
@@ -276,9 +277,9 @@ func (c *Config) upgradePackage(fs vfs.FS, mutator chezmoi.Mutator, rr *github.R
 		// Find the corresponding release asset.
 		var releaseAsset *github.ReleaseAsset
 		suffix := arch + "." + packageType
-		for _, ra := range rr.Assets {
+		for i, ra := range rr.Assets {
 			if strings.HasSuffix(ra.GetName(), suffix) {
-				releaseAsset = &ra
+				releaseAsset = &rr.Assets[i]
 				break
 			}
 		}
@@ -432,9 +433,9 @@ func getPackageType(fs vfs.FS) (string, error) {
 }
 
 func getReleaseAssetByName(rr *github.RepositoryRelease, name string) *github.ReleaseAsset {
-	for _, ra := range rr.Assets {
+	for i, ra := range rr.Assets {
 		if ra.GetName() == name {
-			return &ra
+			return &rr.Assets[i]
 		}
 	}
 	return nil
diff --git a/cmd/verify.go b/cmd/verify.go
index e2721659c..5ef726682 100644
--- a/cmd/verify.go
+++ b/cmd/verify.go
@@ -22,7 +22,7 @@ func init() {
 }
 
 func (c *Config) runVerifyCmd(fs vfs.FS, args []string) error {
-	mutator := chezmoi.NewAnyMutator(chezmoi.NullMutator)
+	mutator := chezmoi.NewAnyMutator(chezmoi.NullMutator{})
 	if err := c.applyArgs(fs, args, mutator); err != nil {
 		return err
 	}
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index 1cdda2357..5a12cbadf 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -21,15 +21,15 @@ tools. Install these extra tools with:
 
 Build chezmoi:
 
-    go build github.com/twpayne/chezmoi
+    go build .
 
 Run all tests:
 
-    go test github.com/twpayne/chezmoi/...
+    go test ./...
 
 Run chezmoi:
 
-    go run github.com/twpayne/chezmoi
+    go run .
 
 ## Contributing changes
 
@@ -72,13 +72,6 @@ that:
 
 Releases are managed with [goreleaser](https://goreleaser.com/).
 
-Before creating a release, please run:
-
-    make pre-release-checks
-
-This will run a variety of strict checks. Many can be ignored, but please
-manually check each of them before tagging a release.
-
 To create a new release, push a tag, eg:
 
     git tag -a v0.1.0 -m "First release"
diff --git a/lib/chezmoi/chezmoi.go b/lib/chezmoi/chezmoi.go
index b0d840e45..64c1a6fe4 100644
--- a/lib/chezmoi/chezmoi.go
+++ b/lib/chezmoi/chezmoi.go
@@ -41,13 +41,14 @@ type PersistentState interface {
 
 // An ApplyOptions is a big ball of mud for things that affect Entry.Apply.
 type ApplyOptions struct {
-	DestDir         string
-	DryRun          bool
-	Ignore          func(string) bool
-	PersistentState PersistentState
-	Stdout          io.Writer
-	Umask           os.FileMode
-	Verbose         bool
+	DestDir           string
+	DryRun            bool
+	Ignore            func(string) bool
+	PersistentState   PersistentState
+	ScriptStateBucket []byte
+	Stdout            io.Writer
+	Umask             os.FileMode
+	Verbose           bool
 }
 
 // An Entry is either a Dir, a File, or a Symlink.
diff --git a/lib/chezmoi/nullmutator.go b/lib/chezmoi/nullmutator.go
index 2b974a0a6..c79dfcf23 100644
--- a/lib/chezmoi/nullmutator.go
+++ b/lib/chezmoi/nullmutator.go
@@ -2,33 +2,31 @@ package chezmoi
 
 import "os"
 
-type nullMutator struct{}
-
 // NullMutator is an Mutator that does nothing.
-var NullMutator nullMutator
+type NullMutator struct{}
 
 // Chmod implements Mutator.Chmod.
-func (nullMutator) Chmod(string, os.FileMode) error {
+func (NullMutator) Chmod(string, os.FileMode) error {
 	return nil
 }
 
 // Mkdir implements Mutator.Mkdir.
-func (nullMutator) Mkdir(string, os.FileMode) error {
+func (NullMutator) Mkdir(string, os.FileMode) error {
 	return nil
 }
 
 // RemoveAll implements Mutator.RemoveAll.
-func (nullMutator) RemoveAll(string) error {
+func (NullMutator) RemoveAll(string) error {
 	return nil
 }
 
 // Rename implements Mutator.Rename.
-func (nullMutator) Rename(string, string) error {
+func (NullMutator) Rename(string, string) error {
 	return nil
 }
 
 // Stat implements Mutator.Stat.
-func (nullMutator) Stat(path string) (os.FileInfo, error) {
+func (NullMutator) Stat(path string) (os.FileInfo, error) {
 	return nil, &os.PathError{
 		Op:   "stat",
 		Path: path,
@@ -37,11 +35,11 @@ func (nullMutator) Stat(path string) (os.FileInfo, error) {
 }
 
 // WriteFile implements Mutator.WriteFile.
-func (nullMutator) WriteFile(string, []byte, os.FileMode, []byte) error {
+func (NullMutator) WriteFile(string, []byte, os.FileMode, []byte) error {
 	return nil
 }
 
 // WriteSymlink implements Mutator.WriteSymlink.
-func (nullMutator) WriteSymlink(string, string) error {
+func (NullMutator) WriteSymlink(string, string) error {
 	return nil
 }
diff --git a/lib/chezmoi/script.go b/lib/chezmoi/script.go
index 73dbc3e88..d95d0ced3 100644
--- a/lib/chezmoi/script.go
+++ b/lib/chezmoi/script.go
@@ -16,8 +16,6 @@ import (
 	vfs "github.com/twpayne/go-vfs"
 )
 
-var scriptStateBucket = []byte("script")
-
 // FIXME allow encrypted scripts
 // FIXME add pre- and post- attributes
 
@@ -104,7 +102,7 @@ func (s *Script) Apply(fs vfs.FS, mutator Mutator, applyOptions *ApplyOptions) e
 	if s.Once {
 		contentsKeyArr := sha256.Sum256(contents)
 		key = []byte(s.targetName + ":" + hex.EncodeToString(contentsKeyArr[:]))
-		scriptStateData, err := applyOptions.PersistentState.Get(scriptStateBucket, key)
+		scriptStateData, err := applyOptions.PersistentState.Get(applyOptions.ScriptStateBucket, key)
 		if err != nil {
 			return err
 		}
@@ -159,7 +157,7 @@ func (s *Script) Apply(fs vfs.FS, mutator Mutator, applyOptions *ApplyOptions) e
 		if err != nil {
 			return err
 		}
-		if err := applyOptions.PersistentState.Set(scriptStateBucket, key, scriptStateData); err != nil {
+		if err := applyOptions.PersistentState.Set(applyOptions.ScriptStateBucket, key, scriptStateData); err != nil {
 			return err
 		}
 	}
diff --git a/lib/chezmoi/targetstate.go b/lib/chezmoi/targetstate.go
index b6482cf7d..c2504c3a3 100644
--- a/lib/chezmoi/targetstate.go
+++ b/lib/chezmoi/targetstate.go
@@ -240,7 +240,7 @@ func (ts *TargetState) Evaluate() error {
 }
 
 // Get returns the state of the given target, or nil if no such target is found.
-func (ts *TargetState) Get(fs vfs.FS, target string) (Entry, error) {
+func (ts *TargetState) Get(fs vfs.Stater, target string) (Entry, error) {
 	contains, err := vfs.Contains(fs, target, ts.DestDir)
 	if err != nil {
 		return nil, err


Test patch:
diff --git a/cmd/apply_test.go b/cmd/apply_test.go
index 04ba9ad5d..1ff70d120 100644
--- a/cmd/apply_test.go
+++ b/cmd/apply_test.go
@@ -154,11 +154,12 @@ func TestApplyScript(t *testing.T) {
 			persistentState, err := chezmoi.NewBoltPersistentState(fs, "/home/user/.config/chezmoi/chezmoistate.boltdb")
 			require.NoError(t, err)
 			c := &Config{
-				SourceDir:       "/home/user/.local/share/chezmoi",
-				DestDir:         "/",
-				Umask:           022,
-				Data:            tc.data,
-				persistentState: persistentState,
+				SourceDir:         "/home/user/.local/share/chezmoi",
+				DestDir:           "/",
+				Umask:             022,
+				Data:              tc.data,
+				persistentState:   persistentState,
+				scriptStateBucket: []byte("script"),
 			}
 			assert.NoError(t, c.runApplyCmd(fs, nil))
 			evidencePath := filepath.Join(tempDir, tc.evidence)
@@ -196,7 +197,8 @@ func TestApplyRunOnce(t *testing.T) {
 		Data: map[string]interface{}{
 			"TempFile": tempFile,
 		},
-		persistentState: persistentState,
+		persistentState:   persistentState,
+		scriptStateBucket: []byte("script"),
 	}
 
 	require.NoError(t, c.runApplyCmd(fs, nil))
diff --git a/lib/chezmoi/targetstate_test.go b/lib/chezmoi/targetstate_test.go
index a52b7170e..15ea541d0 100644
--- a/lib/chezmoi/targetstate_test.go
+++ b/lib/chezmoi/targetstate_test.go
@@ -100,10 +100,11 @@ func TestEndToEnd(t *testing.T) {
 			ts := NewTargetState(tc.destDir, tc.umask, tc.sourceDir, tc.data, tc.templateFuncs, "")
 			assert.NoError(t, ts.Populate(fs))
 			applyOptions := &ApplyOptions{
-				DestDir: ts.DestDir,
-				Ignore:  ts.TargetIgnore.Match,
-				Stdout:  os.Stdout,
-				Umask:   022,
+				DestDir:           ts.DestDir,
+				Ignore:            ts.TargetIgnore.Match,
+				ScriptStateBucket: []byte("script"),
+				Stdout:            os.Stdout,
+				Umask:             022,
 			}
 			assert.NoError(t, ts.Apply(fs, NewLoggingMutator(os.Stderr, NewFSMutator(fs), false), applyOptions))
 			vfst.RunTests(t, fs, "", tc.tests)