Skip to content

Commit 0ead74b

Browse files
committed
Support flag to clear outputs from config
This change set adds a new command line flag called `--clear-config-outputs`. When setting this flag all configured outputs from the config file will be cleared and only the ones from the command line respected or if none, fallback to the default happens. This is useful for applications like the golangci-lint LSP that invoke golangci-lint and want to ensure that only the JSON output is enabled without respecting the users config.
1 parent 6441d5c commit 0ead74b

File tree

6 files changed

+521
-2
lines changed

6 files changed

+521
-2
lines changed

docs/data/cli_help.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"defaultEnabledLinters": "Enabled by default linters:\nerrcheck: Errcheck is a program for checking for unchecked errors in Go code. These unchecked errors can be critical bugs in some cases.\ngovet: Vet examines Go source code and reports suspicious constructs. It is roughly the same as 'go vet' and uses its passes. [auto-fix]\nineffassign: Detects when assignments to existing variables are not used. [fast]\nstaticcheck: It's the set of rules from staticcheck. [auto-fix]\nunused: Checks Go code for unused constants, variables, functions and types.",
33
"rootOutput": "Smart, fast linters runner.\n\nUsage:\n golangci-lint [flags]\n golangci-lint [command]\n\nAvailable Commands:\n cache Cache control and information.\n completion Generate the autocompletion script for the specified shell\n config Configuration file information and verification.\n custom Build a version of golangci-lint with custom linters.\n fmt Format Go source files.\n formatters List current formatters configuration.\n help Display extra help\n linters List current linters configuration.\n migrate Migrate configuration file from v1 to v2.\n run Lint the code.\n version Display the golangci-lint version.\n\nFlags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n --version Print version\n\nUse \"golangci-lint [command] --help\" for more information about a command.\n",
4-
"runOutput": "Lint the code.\n\nUsage:\n golangci-lint run [flags]\n\nFlags:\n -c, --config PATH Read config from file path PATH\n --no-config Don't read config file\n --default string Default set of linters to enable (default \"standard\")\n -D, --disable strings Disable specific linter\n -E, --enable strings Enable specific linter\n --enable-only strings Override linters configuration section to only run the specific linter(s)\n --fast-only Filter enabled linters to run only fast linters\n -j, --concurrency int Number of CPUs to use (Default: Automatically set to match Linux container CPU quota and fall back to the number of logical CPUs in the machine)\n --modules-download-mode string Modules download mode. If not empty, passed as -mod=\u003cmode\u003e to go tools\n --issues-exit-code int Exit code when issues were found (default 1)\n --build-tags strings Build tags\n --timeout duration Timeout for total work. Disabled by default\n --tests Analyze tests (*_test.go) (default true)\n --allow-parallel-runners Allow multiple parallel golangci-lint instances running.\n If false (default) - golangci-lint acquires file lock on start.\n --allow-serial-runners Allow multiple golangci-lint instances running, but serialize them around a lock.\n If false (default) - golangci-lint exits with an error if it fails to acquire file lock on start.\n --path-prefix string Path prefix to add to output\n --path-mode string Path mode to use (empty, or 'abs')\n --show-stats Show statistics per linter (default true)\n --output.text.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.text.print-linter-name Print linter name in the end of issue text. (default true)\n --output.text.print-issued-lines Print lines of code with issue. (default true)\n --output.text.colors Use colors. (default true)\n --output.json.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.tab.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.tab.print-linter-name Print linter name in the end of issue text. (default true)\n --output.tab.colors Use colors. (default true)\n --output.html.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.checkstyle.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.code-climate.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.junit-xml.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.junit-xml.extended Support extra JUnit XML fields.\n --output.teamcity.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.sarif.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --max-issues-per-linter int Maximum issues count per one linter. Set to 0 to disable (default 50)\n --max-same-issues int Maximum count of issues with the same text. Set to 0 to disable (default 3)\n --uniq-by-line Make issues output unique by line (default true)\n -n, --new Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed.\n It's a super-useful option for integration of golangci-lint into existing large codebase.\n It's not practical to fix all existing issues at the moment of integration: much better to not allow issues in new code.\n For CI setups, prefer --new-from-rev=HEAD~, as --new can skip linting the current patch if any scripts generate unstaged files before golangci-lint runs.\n --new-from-rev REV Show only new issues created after git revision REV\n --new-from-patch PATH Show only new issues created in git patch with file path PATH\n --new-from-merge-base string Show only new issues created after the best common ancestor (merge-base against HEAD)\n --whole-files Show issues in any part of update files (requires new-from-rev or new-from-patch)\n --fix Apply the fixes detected by the linters and formatters (if it's supported by the linter)\n --cpu-profile-path string Path to CPU profile output file\n --mem-profile-path string Path to memory profile output file\n --trace-path string Path to trace output file\n\nGlobal Flags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n",
4+
"runOutput": "Lint the code.\n\nUsage:\n golangci-lint run [flags]\n\nFlags:\n -c, --config PATH Read config from file path PATH\n --no-config Don't read config file\n --default string Default set of linters to enable (default \"standard\")\n -D, --disable strings Disable specific linter\n -E, --enable strings Enable specific linter\n --enable-only strings Override linters configuration section to only run the specific linter(s)\n --fast-only Filter enabled linters to run only fast linters\n -j, --concurrency int Number of CPUs to use (Default: Automatically set to match Linux container CPU quota and fall back to the number of logical CPUs in the machine)\n --modules-download-mode string Modules download mode. If not empty, passed as -mod=\u003cmode\u003e to go tools\n --issues-exit-code int Exit code when issues were found (default 1)\n --build-tags strings Build tags\n --timeout duration Timeout for total work. Disabled by default\n --tests Analyze tests (*_test.go) (default true)\n --allow-parallel-runners Allow multiple parallel golangci-lint instances running.\n If false (default) - golangci-lint acquires file lock on start.\n --allow-serial-runners Allow multiple golangci-lint instances running, but serialize them around a lock.\n If false (default) - golangci-lint exits with an error if it fails to acquire file lock on start.\n --path-prefix string Path prefix to add to output\n --path-mode string Path mode to use (empty, or 'abs')\n --show-stats Show statistics per linter (default true)\n --clear-config-outputs Clear all output formats from the configuration file. If no output formats are specified on the command line, the default text format will be used.\n --output.text.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.text.print-linter-name Print linter name in the end of issue text. (default true)\n --output.text.print-issued-lines Print lines of code with issue. (default true)\n --output.text.colors Use colors. (default true)\n --output.json.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.tab.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.tab.print-linter-name Print linter name in the end of issue text. (default true)\n --output.tab.colors Use colors. (default true)\n --output.html.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.checkstyle.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.code-climate.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.junit-xml.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.junit-xml.extended Support extra JUnit XML fields.\n --output.teamcity.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --output.sarif.path stdout Output path can be either stdout, `stderr` or path to the file to write to.\n --max-issues-per-linter int Maximum issues count per one linter. Set to 0 to disable (default 50)\n --max-same-issues int Maximum count of issues with the same text. Set to 0 to disable (default 3)\n --uniq-by-line Make issues output unique by line (default true)\n -n, --new Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed.\n It's a super-useful option for integration of golangci-lint into existing large codebase.\n It's not practical to fix all existing issues at the moment of integration: much better to not allow issues in new code.\n For CI setups, prefer --new-from-rev=HEAD~, as --new can skip linting the current patch if any scripts generate unstaged files before golangci-lint runs.\n --new-from-rev REV Show only new issues created after git revision REV\n --new-from-patch PATH Show only new issues created in git patch with file path PATH\n --new-from-merge-base string Show only new issues created after the best common ancestor (merge-base against HEAD)\n --whole-files Show issues in any part of update files (requires new-from-rev or new-from-patch)\n --fix Apply the fixes detected by the linters and formatters (if it's supported by the linter)\n --cpu-profile-path string Path to CPU profile output file\n --mem-profile-path string Path to memory profile output file\n --trace-path string Path to trace output file\n\nGlobal Flags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n",
55
"lintersOutput": "List current linters configuration.\n\nUsage:\n golangci-lint linters [flags]\n\nFlags:\n -c, --config PATH Read config from file path PATH\n --no-config Don't read config file\n --default string Default set of linters to enable (default \"standard\")\n -D, --disable strings Disable specific linter\n -E, --enable strings Enable specific linter\n --enable-only strings Override linters configuration section to only run the specific linter(s)\n --fast-only Filter enabled linters to run only fast linters\n --json Display as JSON\n\nGlobal Flags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n",
66
"fmtOutput": "Format Go source files.\n\nUsage:\n golangci-lint fmt [flags]\n\nFlags:\n -c, --config PATH Read config from file path PATH\n --no-config Don't read config file\n -E, --enable strings Enable specific formatter\n -d, --diff Display diffs instead of rewriting files\n --diff-colored Display diffs instead of rewriting files (with colors)\n --stdin Use standard input for piping source files\n\nGlobal Flags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n",
77
"formattersOutput": "List current formatters configuration.\n\nUsage:\n golangci-lint formatters [flags]\n\nFlags:\n -c, --config PATH Read config from file path PATH\n --no-config Don't read config file\n -E, --enable strings Enable specific formatter\n --json Display as JSON\n\nGlobal Flags:\n --color string Use color when printing; can be 'always', 'auto', or 'never' (default \"auto\")\n -h, --help Help for a command\n -v, --verbose Verbose output\n",

pkg/commands/flagsets.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ func setupOutputFlagSet(v *viper.Viper, fs *pflag.FlagSet) {
6666
color.GreenString("Path mode to use (empty, or 'abs')"))
6767
internal.AddFlagAndBind(v, fs, fs.Bool, "show-stats", "output.show-stats", true, color.GreenString("Show statistics per linter"))
6868

69+
const clearConfigOutputsDesc = "Clear all output formats from the configuration file. " +
70+
"If no output formats are specified on the command line, the default text format will be used."
71+
fs.Bool("clear-config-outputs", false, color.GreenString(clearConfigOutputsDesc)) // Flags only, no config file binding
72+
6973
setupOutputFormatsFlagSet(v, fs)
7074
}
7175

pkg/config/loader.go

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func newLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderO
6464
}
6565
}
6666

67-
func (l *Loader) Load(opts LoadOptions) error {
67+
func (l *Loader) Load(opts LoadOptions) error { //nolint:gocyclo // it's not too complex
6868
err := l.BaseLoader.Load()
6969
if err != nil {
7070
return err
@@ -119,6 +119,11 @@ func (l *Loader) Load(opts LoadOptions) error {
119119
return err
120120
}
121121

122+
err = l.handleClearConfigOutputs()
123+
if err != nil {
124+
return err
125+
}
126+
122127
if opts.Validation {
123128
err = l.cfg.Validate()
124129
if err != nil {
@@ -226,6 +231,98 @@ func (l *Loader) handleEnableOnlyOption() error {
226231
return nil
227232
}
228233

234+
func (l *Loader) handleClearConfigOutputs() error { //nolint:gocyclo // just having to check all the flags, it's fine.
235+
if l.fs == nil {
236+
return nil
237+
}
238+
239+
// Check if the flag is defined (it's only defined for the run command)
240+
flag := l.fs.Lookup("clear-config-outputs")
241+
if flag == nil {
242+
return nil
243+
}
244+
245+
clearConfigOutputs, err := l.fs.GetBool("clear-config-outputs")
246+
if err != nil {
247+
return err
248+
}
249+
250+
if !clearConfigOutputs {
251+
return nil
252+
}
253+
254+
// Save CLI-provided output format settings by checking which flags were explicitly set
255+
cliFormats := Formats{}
256+
257+
// Text format
258+
if l.fs.Changed("output.text.path") {
259+
cliFormats.Text.Path, _ = l.fs.GetString("output.text.path")
260+
}
261+
if l.fs.Changed("output.text.print-linter-name") {
262+
cliFormats.Text.PrintLinterName, _ = l.fs.GetBool("output.text.print-linter-name")
263+
}
264+
if l.fs.Changed("output.text.print-issued-lines") {
265+
cliFormats.Text.PrintIssuedLine, _ = l.fs.GetBool("output.text.print-issued-lines")
266+
}
267+
if l.fs.Changed("output.text.colors") {
268+
cliFormats.Text.Colors, _ = l.fs.GetBool("output.text.colors")
269+
}
270+
271+
// JSON format
272+
if l.fs.Changed("output.json.path") {
273+
cliFormats.JSON.Path, _ = l.fs.GetString("output.json.path")
274+
}
275+
276+
// Tab format
277+
if l.fs.Changed("output.tab.path") {
278+
cliFormats.Tab.Path, _ = l.fs.GetString("output.tab.path")
279+
}
280+
if l.fs.Changed("output.tab.print-linter-name") {
281+
cliFormats.Tab.PrintLinterName, _ = l.fs.GetBool("output.tab.print-linter-name")
282+
}
283+
if l.fs.Changed("output.tab.colors") {
284+
cliFormats.Tab.Colors, _ = l.fs.GetBool("output.tab.colors")
285+
}
286+
287+
// HTML format
288+
if l.fs.Changed("output.html.path") {
289+
cliFormats.HTML.Path, _ = l.fs.GetString("output.html.path")
290+
}
291+
292+
// Checkstyle format
293+
if l.fs.Changed("output.checkstyle.path") {
294+
cliFormats.Checkstyle.Path, _ = l.fs.GetString("output.checkstyle.path")
295+
}
296+
297+
// Code Climate format
298+
if l.fs.Changed("output.code-climate.path") {
299+
cliFormats.CodeClimate.Path, _ = l.fs.GetString("output.code-climate.path")
300+
}
301+
302+
// JUnit XML format
303+
if l.fs.Changed("output.junit-xml.path") {
304+
cliFormats.JUnitXML.Path, _ = l.fs.GetString("output.junit-xml.path")
305+
}
306+
if l.fs.Changed("output.junit-xml.extended") {
307+
cliFormats.JUnitXML.Extended, _ = l.fs.GetBool("output.junit-xml.extended")
308+
}
309+
310+
// TeamCity format
311+
if l.fs.Changed("output.teamcity.path") {
312+
cliFormats.TeamCity.Path, _ = l.fs.GetString("output.teamcity.path")
313+
}
314+
315+
// SARIF format
316+
if l.fs.Changed("output.sarif.path") {
317+
cliFormats.Sarif.Path, _ = l.fs.GetString("output.sarif.path")
318+
}
319+
320+
// Replace the config's output formats with only the CLI-provided ones
321+
l.cfg.Output.Formats = cliFormats
322+
323+
return nil
324+
}
325+
229326
func (l *Loader) handleFormatters() {
230327
l.handleFormatterOverrides()
231328
l.handleFormatterExclusions()

0 commit comments

Comments
 (0)