docs: use information from the previous release to create pages (#4457)
This commit is contained in:
parent
5cb16561d5
commit
85e1dee09a
12
.github/workflows/post-release.yml
vendored
12
.github/workflows/post-release.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: "Publish release documentation"
|
||||
name: "Post release"
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
@ -44,7 +44,7 @@ jobs:
|
||||
delete-branch: true
|
||||
|
||||
update-assets:
|
||||
name: "Update GitHub Action assets"
|
||||
name: "Update assets"
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GOLANGCI_LINT_TOKEN }}
|
||||
@ -62,12 +62,18 @@ jobs:
|
||||
- name: Update GitHub action config
|
||||
run: make assets/github-action-config.json
|
||||
|
||||
- name: Update reference files
|
||||
run: cp .golangci.next.reference.yml .golangci.reference.yml
|
||||
|
||||
- name: Update information
|
||||
run: make website_dump_info
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
base: master
|
||||
token: ${{ secrets.GOLANGCI_LINT_TOKEN }}
|
||||
branch-suffix: timestamp
|
||||
title: "docs: update GitHub Action assets"
|
||||
title: "docs: update assets"
|
||||
team-reviewers: golangci/team
|
||||
delete-branch: true
|
||||
|
2904
.golangci.next.reference.yml
Normal file
2904
.golangci.next.reference.yml
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,8 +6,7 @@
|
||||
|
||||
# Options for analysis running.
|
||||
run:
|
||||
# Number of operating system threads (`GOMAXPROCS`) that can execute golangci-lint simultaneously.
|
||||
# If it is explicitly set to 0 (i.e. not the default) then golangci-lint will automatically set the value to match Linux container CPU quota.
|
||||
# Number of CPUs to use when running golangci-lint.
|
||||
# Default: the number of logical CPUs in the machine
|
||||
concurrency: 4
|
||||
|
||||
@ -81,6 +80,10 @@ run:
|
||||
# Default: use Go version from the go.mod file, fallback on the env var `GOVERSION`, fallback on 1.17
|
||||
go: '1.19'
|
||||
|
||||
# Show statistics per linter.
|
||||
# Default: false
|
||||
show-stats: true
|
||||
|
||||
|
||||
# output configuration options
|
||||
output:
|
||||
@ -110,32 +113,10 @@ output:
|
||||
# Default: ""
|
||||
path-prefix: ""
|
||||
|
||||
# Sort results by the order defined in `sort-order`.
|
||||
# Sort results by: filepath, line and column.
|
||||
# Default: false
|
||||
sort-results: true
|
||||
|
||||
# Order to use when sorting results.
|
||||
# Require `sort-results` to `true`.
|
||||
# Possible values: `file`, `linter`, and `severity`.
|
||||
#
|
||||
# If the severity values are inside the following list, they are ordered in this order:
|
||||
# 1. error
|
||||
# 2. warning
|
||||
# 3. high
|
||||
# 4. medium
|
||||
# 5. low
|
||||
# Either they are sorted alphabetically.
|
||||
#
|
||||
# Default: ["file"]
|
||||
sort-order:
|
||||
- linter
|
||||
- severity
|
||||
- file # filepath, line, and column.
|
||||
|
||||
# Show statistics per linter.
|
||||
# Default: false
|
||||
show-stats: true
|
||||
|
||||
|
||||
# All available settings of specific linters.
|
||||
linters-settings:
|
||||
@ -168,11 +149,6 @@ linters-settings:
|
||||
first-strong-isolate: false
|
||||
pop-directional-isolate: false
|
||||
|
||||
copyloopvar:
|
||||
# If true, ignore aliasing of loop variables.
|
||||
# Default: false
|
||||
ignore-alias: true
|
||||
|
||||
cyclop:
|
||||
# The maximal code complexity to report.
|
||||
# Default: 10
|
||||
@ -388,6 +364,16 @@ linters-settings:
|
||||
# Default: false
|
||||
default-case-required: true
|
||||
|
||||
exhaustivestruct:
|
||||
# Struct Patterns is list of expressions to match struct packages and names.
|
||||
# The struct packages have the form `example.com/package.ExampleStruct`.
|
||||
# The matching patterns can use matching syntax from https://pkg.go.dev/path#Match.
|
||||
# If this list is empty, all structs are tested.
|
||||
# Default: []
|
||||
struct-patterns:
|
||||
- '*.Test'
|
||||
- 'example.com/package.ExampleStruct'
|
||||
|
||||
exhaustruct:
|
||||
# List of regular expressions to match struct packages and their names.
|
||||
# Regular expressions must match complete canonical struct package/name/structname.
|
||||
@ -555,9 +541,6 @@ linters-settings:
|
||||
- ruleguard
|
||||
- truncateCmp
|
||||
|
||||
# Enable all checks.
|
||||
# Default: false
|
||||
enable-all: true
|
||||
# Which checks should be disabled; can't be combined with 'enabled-checks'.
|
||||
# Default: []
|
||||
disabled-checks:
|
||||
@ -780,6 +763,11 @@ linters-settings:
|
||||
# Default: ""
|
||||
local-prefixes: github.com/org/project
|
||||
|
||||
golint:
|
||||
# Minimal confidence for issues.
|
||||
# Default: 0.8
|
||||
min-confidence: 0.7
|
||||
|
||||
gomnd:
|
||||
# List of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description.
|
||||
# Default: ["argument", "case", "condition", "operation", "return", "assign"]
|
||||
@ -1119,7 +1107,7 @@ linters-settings:
|
||||
# stdmethods, stringintconv, structtag, testinggoroutine, tests, timeformat, unmarshal, unreachable, unsafeptr,
|
||||
# unusedresult
|
||||
# ).
|
||||
# Run `GL_DEBUG=govet golangci-lint run --enable=govet` to see default, all available analyzers, and enabled analyzers.
|
||||
# Run `go tool vet help` to see all analyzers.
|
||||
# Default: []
|
||||
enable:
|
||||
- appends
|
||||
@ -1171,7 +1159,7 @@ linters-settings:
|
||||
# atomicalign, deepequalerrors, fieldalignment, findcall, nilness, reflectvaluecompare, shadow, sortslice,
|
||||
# timeformat, unusedwrite
|
||||
# ).
|
||||
# Run `GL_DEBUG=govet golangci-lint run --enable=govet` to see default, all available analyzers, and enabled analyzers.
|
||||
# Run `go tool vet help` to see all analyzers.
|
||||
# Default: []
|
||||
disable:
|
||||
- appends
|
||||
@ -1244,6 +1232,15 @@ linters-settings:
|
||||
# Default: false
|
||||
var-require-grouping: true
|
||||
|
||||
ifshort:
|
||||
# Maximum length of variable declaration measured in number of lines, after which linter won't suggest using short syntax.
|
||||
# Has higher priority than max-decl-chars.
|
||||
# Default: 1
|
||||
max-decl-lines: 2
|
||||
# Maximum length of variable declaration measured in number of characters, after which linter won't suggest using short syntax.
|
||||
# Default: 30
|
||||
max-decl-chars: 40
|
||||
|
||||
importas:
|
||||
# Do not allow unaliased imports of aliased packages.
|
||||
# Default: false
|
||||
@ -1347,25 +1344,19 @@ linters-settings:
|
||||
# Default: false
|
||||
always: true
|
||||
|
||||
maligned:
|
||||
# Print struct with more effective memory layout or not.
|
||||
# Default: false
|
||||
suggest-new: true
|
||||
|
||||
misspell:
|
||||
# Correct spellings using locale preferences for US or UK.
|
||||
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
|
||||
# Default is to use a neutral variety of English.
|
||||
locale: US
|
||||
# Typos to ignore.
|
||||
# Should be in lower case.
|
||||
# Default: []
|
||||
ignore-words:
|
||||
- someword
|
||||
# Extra word corrections.
|
||||
# `typo` and `correction` should only contain letters.
|
||||
# The words are case-insensitive.
|
||||
# Default: []
|
||||
extra-words:
|
||||
- typo: "iff"
|
||||
correction: "if"
|
||||
- typo: "cancelation"
|
||||
correction: "cancellation"
|
||||
# Mode of the analysis:
|
||||
# - default: checks all the file content.
|
||||
# - restricted: checks only comments.
|
||||
@ -1450,9 +1441,6 @@ linters-settings:
|
||||
# Optimizes `fmt.Sprintf` with only one argument.
|
||||
# Default: true
|
||||
sprintf1: false
|
||||
# Optimizes into strings concatenation.
|
||||
# Default: true
|
||||
strconcat: false
|
||||
|
||||
prealloc:
|
||||
# IMPORTANT: we don't recommend using this linter before doing performance profiling.
|
||||
@ -1549,7 +1537,6 @@ linters-settings:
|
||||
- name: add-constant
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- maxLitCount: "3"
|
||||
allowStrs: '""'
|
||||
@ -1559,50 +1546,41 @@ linters-settings:
|
||||
- name: argument-limit
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments: [ 4 ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#atomic
|
||||
- name: atomic
|
||||
severity: warning
|
||||
exclude: [""]
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#banned-characters
|
||||
- name: banned-characters
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments: [ "Ω","Σ","σ", "7" ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bare-return
|
||||
- name: bare-return
|
||||
severity: warning
|
||||
exclude: [""]
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#blank-imports
|
||||
- name: blank-imports
|
||||
severity: warning
|
||||
exclude: [""]
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bool-literal-in-expr
|
||||
- name: bool-literal-in-expr
|
||||
severity: warning
|
||||
exclude: [""]
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#call-to-gc
|
||||
- name: call-to-gc
|
||||
severity: warning
|
||||
exclude: [""]
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cognitive-complexity
|
||||
- name: cognitive-complexity
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments: [ 7 ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#comment-spacings
|
||||
- name: comment-spacings
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- mypragma
|
||||
- otherpragma
|
||||
@ -1610,125 +1588,103 @@ linters-settings:
|
||||
- name: confusing-naming
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#confusing-results
|
||||
- name: confusing-results
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#constant-logical-expr
|
||||
- name: constant-logical-expr
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-as-argument
|
||||
- name: context-as-argument
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- allowTypesBefore: "*testing.T,*github.com/user/repo/testing.Harness"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-keys-type
|
||||
- name: context-keys-type
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cyclomatic
|
||||
- name: cyclomatic
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments: [ 3 ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#datarace
|
||||
- name: datarace
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#deep-exit
|
||||
- name: deep-exit
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#defer
|
||||
- name: defer
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- [ "call-chain", "loop" ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#dot-imports
|
||||
- name: dot-imports
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#duplicated-imports
|
||||
- name: duplicated-imports
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#early-return
|
||||
- name: early-return
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "preserveScope"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-block
|
||||
- name: empty-block
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-lines
|
||||
- name: empty-lines
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#enforce-map-style
|
||||
- name: enforce-map-style
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "make"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#enforce-repeated-arg-type-style
|
||||
- name: enforce-repeated-arg-type-style
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "short"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#enforce-slice-style
|
||||
- name: enforce-slice-style
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "make"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-naming
|
||||
- name: error-naming
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-return
|
||||
- name: error-return
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-strings
|
||||
- name: error-strings
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#errorf
|
||||
- name: errorf
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#exported
|
||||
- name: exported
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "preserveScope"
|
||||
- "checkPrivateReceivers"
|
||||
@ -1737,65 +1693,54 @@ linters-settings:
|
||||
- name: file-header
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- This is the text that must appear at the top of source files.
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#flag-parameter
|
||||
- name: flag-parameter
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#function-result-limit
|
||||
- name: function-result-limit
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments: [ 2 ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#function-length
|
||||
- name: function-length
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments: [ 10, 0 ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#get-return
|
||||
- name: get-return
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#identical-branches
|
||||
- name: identical-branches
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#if-return
|
||||
- name: if-return
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#increment-decrement
|
||||
- name: increment-decrement
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#indent-error-flow
|
||||
- name: indent-error-flow
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "preserveScope"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-alias-naming
|
||||
- name: import-alias-naming
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "^[a-z][a-z0-9]{0,}$"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#imports-blocklist
|
||||
- name: imports-blocklist
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "crypto/md5"
|
||||
- "crypto/sha1"
|
||||
@ -1803,90 +1748,73 @@ linters-settings:
|
||||
- name: import-shadowing
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#line-length-limit
|
||||
- name: line-length-limit
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments: [ 80 ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#max-control-nesting
|
||||
- name: max-control-nesting
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments: [ 3 ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#max-public-structs
|
||||
- name: max-public-structs
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments: [ 3 ]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#modifies-parameter
|
||||
- name: modifies-parameter
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#modifies-value-receiver
|
||||
- name: modifies-value-receiver
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#nested-structs
|
||||
- name: nested-structs
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#optimize-operands-order
|
||||
- name: optimize-operands-order
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#package-comments
|
||||
- name: package-comments
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range
|
||||
- name: range
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-in-closure
|
||||
- name: range-val-in-closure
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-address
|
||||
- name: range-val-address
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#receiver-naming
|
||||
- name: receiver-naming
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#redundant-import-alias
|
||||
- name: redundant-import-alias
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#redefines-builtin-id
|
||||
- name: redefines-builtin-id
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-of-int
|
||||
- name: string-of-int
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-format
|
||||
- name: string-format
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- - 'core.WriteError[1].Message'
|
||||
- '/^([^A-Z]|$)/'
|
||||
@ -1904,29 +1832,24 @@ linters-settings:
|
||||
- "bson,outline,gnu"
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#superfluous-else
|
||||
- name: superfluous-else
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "preserveScope"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-equal
|
||||
- name: time-equal
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-naming
|
||||
- name: time-naming
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-naming
|
||||
- name: var-naming
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- [ "ID" ] # AllowList
|
||||
- [ "VM" ] # DenyList
|
||||
@ -1935,27 +1858,22 @@ linters-settings:
|
||||
- name: var-declaration
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unconditional-recursion
|
||||
- name: unconditional-recursion
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-naming
|
||||
- name: unexported-naming
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-return
|
||||
- name: unexported-return
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unhandled-error
|
||||
- name: unhandled-error
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- "fmt.Printf"
|
||||
- "myFunction"
|
||||
@ -1963,36 +1881,30 @@ linters-settings:
|
||||
- name: unnecessary-stmt
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unreachable-code
|
||||
- name: unreachable-code
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter
|
||||
- name: unused-parameter
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- allowRegex: "^_"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-receiver
|
||||
- name: unused-receiver
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- allowRegex: "^_"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#useless-break
|
||||
- name: useless-break
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#waitgroup-by-value
|
||||
- name: waitgroup-by-value
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
|
||||
rowserrcheck:
|
||||
# database/sql is always checked
|
||||
@ -2186,10 +2098,6 @@ linters-settings:
|
||||
- suite-thelper
|
||||
- useless-assert
|
||||
|
||||
bool-compare:
|
||||
# To ignore user defined types (over builtin bool).
|
||||
# Default: false
|
||||
ignore-custom-types: true
|
||||
expected-actual:
|
||||
# Regexp for expected variable name.
|
||||
# Default: (^(exp(ected)?|want(ed)?)([A-Z]\w*)?$)|(^(\w*[a-z])?(Exp(ected)?|Want(ed)?)$)
|
||||
@ -2293,14 +2201,6 @@ linters-settings:
|
||||
# Default: false
|
||||
syslog-priority: true
|
||||
|
||||
unconvert:
|
||||
# Remove conversions that force intermediate rounding.
|
||||
# Default: false
|
||||
fast-math: true
|
||||
# Be more conservative (experimental).
|
||||
# Default: false
|
||||
safe: true
|
||||
|
||||
unparam:
|
||||
# Inspect exported functions.
|
||||
#
|
||||
@ -2335,6 +2235,11 @@ linters-settings:
|
||||
# Default: true
|
||||
generated-is-used: false
|
||||
|
||||
varcheck:
|
||||
# Check usage of exported fields and variables.
|
||||
# Default: false
|
||||
exported-fields: true
|
||||
|
||||
varnamelen:
|
||||
# The longest distance, in source lines, that is being considered a "small scope".
|
||||
# Variables used in at most this many lines will be ignored.
|
||||
@ -2480,10 +2385,6 @@ linters-settings:
|
||||
custom:
|
||||
# Each custom linter should have a unique name.
|
||||
example:
|
||||
# The plugin type.
|
||||
# It can be `goplugin` or `module`.
|
||||
# Default: goplugin
|
||||
type: module
|
||||
# The path to the plugin *.so. Can be absolute or local.
|
||||
# Required for each custom linter.
|
||||
path: /path/to/example.so
|
||||
@ -2493,11 +2394,6 @@ linters-settings:
|
||||
# Intended to point to the repo location of the linter.
|
||||
# Optional.
|
||||
original-url: github.com/golangci/example-linter
|
||||
# Plugins settings/configuration.
|
||||
# Only work with plugin based on `linterdb.PluginConstructor`.
|
||||
# Optional.
|
||||
settings:
|
||||
foo: bar
|
||||
|
||||
|
||||
linters:
|
||||
@ -2513,8 +2409,8 @@ linters:
|
||||
- bodyclose
|
||||
- containedctx
|
||||
- contextcheck
|
||||
- copyloopvar
|
||||
- cyclop
|
||||
- deadcode
|
||||
- decorder
|
||||
- depguard
|
||||
- dogsled
|
||||
@ -2527,6 +2423,7 @@ linters:
|
||||
- errorlint
|
||||
- execinquery
|
||||
- exhaustive
|
||||
- exhaustivestruct
|
||||
- exhaustruct
|
||||
- exportloopref
|
||||
- forbidigo
|
||||
@ -2549,6 +2446,7 @@ linters:
|
||||
- gofumpt
|
||||
- goheader
|
||||
- goimports
|
||||
- golint
|
||||
- gomnd
|
||||
- gomoddirectives
|
||||
- gomodguard
|
||||
@ -2558,16 +2456,18 @@ linters:
|
||||
- gosmopolitan
|
||||
- govet
|
||||
- grouper
|
||||
- ifshort
|
||||
- importas
|
||||
- inamedparam
|
||||
- ineffassign
|
||||
- interfacebloat
|
||||
- intrange
|
||||
- interfacer
|
||||
- ireturn
|
||||
- lll
|
||||
- loggercheck
|
||||
- maintidx
|
||||
- makezero
|
||||
- maligned
|
||||
- mirror
|
||||
- misspell
|
||||
- musttag
|
||||
@ -2579,6 +2479,7 @@ linters:
|
||||
- noctx
|
||||
- nolintlint
|
||||
- nonamedreturns
|
||||
- nosnakecase
|
||||
- nosprintfhostport
|
||||
- paralleltest
|
||||
- perfsprint
|
||||
@ -2589,10 +2490,12 @@ linters:
|
||||
- reassign
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- scopelint
|
||||
- sloglint
|
||||
- spancheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- stylecheck
|
||||
- tagalign
|
||||
- tagliatelle
|
||||
@ -2607,6 +2510,7 @@ linters:
|
||||
- unparam
|
||||
- unused
|
||||
- usestdlibvars
|
||||
- varcheck
|
||||
- varnamelen
|
||||
- wastedassign
|
||||
- whitespace
|
||||
@ -2626,8 +2530,8 @@ linters:
|
||||
- bodyclose
|
||||
- containedctx
|
||||
- contextcheck
|
||||
- copyloopvar
|
||||
- cyclop
|
||||
- deadcode
|
||||
- decorder
|
||||
- depguard
|
||||
- dogsled
|
||||
@ -2640,6 +2544,7 @@ linters:
|
||||
- errorlint
|
||||
- execinquery
|
||||
- exhaustive
|
||||
- exhaustivestruct
|
||||
- exhaustruct
|
||||
- exportloopref
|
||||
- forbidigo
|
||||
@ -2662,6 +2567,7 @@ linters:
|
||||
- gofumpt
|
||||
- goheader
|
||||
- goimports
|
||||
- golint
|
||||
- gomnd
|
||||
- gomoddirectives
|
||||
- gomodguard
|
||||
@ -2671,16 +2577,18 @@ linters:
|
||||
- gosmopolitan
|
||||
- govet
|
||||
- grouper
|
||||
- ifshort
|
||||
- importas
|
||||
- inamedparam
|
||||
- ineffassign
|
||||
- interfacebloat
|
||||
- intrange
|
||||
- interfacer
|
||||
- ireturn
|
||||
- lll
|
||||
- loggercheck
|
||||
- maintidx
|
||||
- makezero
|
||||
- maligned
|
||||
- mirror
|
||||
- misspell
|
||||
- musttag
|
||||
@ -2692,6 +2600,7 @@ linters:
|
||||
- noctx
|
||||
- nolintlint
|
||||
- nonamedreturns
|
||||
- nosnakecase
|
||||
- nosprintfhostport
|
||||
- paralleltest
|
||||
- perfsprint
|
||||
@ -2702,10 +2611,12 @@ linters:
|
||||
- reassign
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- scopelint
|
||||
- sloglint
|
||||
- spancheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- stylecheck
|
||||
- tagalign
|
||||
- tagliatelle
|
||||
@ -2720,22 +2631,13 @@ linters:
|
||||
- unparam
|
||||
- unused
|
||||
- usestdlibvars
|
||||
- varcheck
|
||||
- varnamelen
|
||||
- wastedassign
|
||||
- whitespace
|
||||
- wrapcheck
|
||||
- wsl
|
||||
- zerologlint
|
||||
- deadcode # Deprecated
|
||||
- exhaustivestruct # Deprecated
|
||||
- golint # Deprecated
|
||||
- ifshort # Deprecated
|
||||
- interfacer # Deprecated
|
||||
- maligned # Deprecated
|
||||
- nosnakecase # Deprecated
|
||||
- scopelint # Deprecated
|
||||
- structcheck # Deprecated
|
||||
- varcheck # Deprecated
|
||||
|
||||
# Enable presets.
|
||||
# https://golangci-lint.run/usage/linters
|
||||
@ -2880,8 +2782,6 @@ severity:
|
||||
# - GitHub: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
|
||||
# - TeamCity: https://www.jetbrains.com/help/teamcity/service-messages.html#Inspection+Instance
|
||||
#
|
||||
# `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...)
|
||||
#
|
||||
# Default: ""
|
||||
default-severity: error
|
||||
|
||||
@ -2892,9 +2792,6 @@ severity:
|
||||
# When a list of severity rules are provided, severity information will be added to lint issues.
|
||||
# Severity rules have the same filtering capability as exclude rules
|
||||
# except you are allowed to specify one matcher per severity rule.
|
||||
#
|
||||
# `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...)
|
||||
#
|
||||
# Only affects out formats that support setting severity information.
|
||||
#
|
||||
# Default: []
|
||||
|
10
Makefile
10
Makefile
@ -88,9 +88,13 @@ go.mod: FORCE
|
||||
go mod verify
|
||||
go.sum: go.mod
|
||||
|
||||
expand_website_templates:
|
||||
go run ./scripts/expand_website_templates/main.go
|
||||
.PHONY: expand_website_templates
|
||||
website_expand_templates:
|
||||
go run ./scripts/website/expand_templates/
|
||||
.PHONY: website_expand_templates
|
||||
|
||||
website_dump_info:
|
||||
go run ./scripts/website/dump_info/
|
||||
.PHONY: dump_info
|
||||
|
||||
update_contributors_list:
|
||||
cd .github/contributors && npm run all
|
||||
|
5
assets/cli-help.json
Normal file
5
assets/cli-help.json
Normal file
File diff suppressed because one or more lines are too long
92
assets/default-exclusions.json
Normal file
92
assets/default-exclusions.json
Normal file
@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"id": "EXC0001",
|
||||
"pattern": "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked",
|
||||
"linter": "errcheck",
|
||||
"why": "Almost all programs ignore errors on these functions and in most cases it's ok"
|
||||
},
|
||||
{
|
||||
"id": "EXC0002",
|
||||
"pattern": "(comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form)",
|
||||
"linter": "golint",
|
||||
"why": "Annoying issue about not having a comment. The rare codebase has such comments"
|
||||
},
|
||||
{
|
||||
"id": "EXC0003",
|
||||
"pattern": "func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this",
|
||||
"linter": "golint",
|
||||
"why": "False positive when tests are defined in package 'test'"
|
||||
},
|
||||
{
|
||||
"id": "EXC0004",
|
||||
"pattern": "(possible misuse of unsafe.Pointer|should have signature)",
|
||||
"linter": "govet",
|
||||
"why": "Common false positives"
|
||||
},
|
||||
{
|
||||
"id": "EXC0005",
|
||||
"pattern": "ineffective break statement. Did you mean to break out of the outer loop",
|
||||
"linter": "staticcheck",
|
||||
"why": "Developers tend to write in C-style with an explicit 'break' in a 'switch', so it's ok to ignore"
|
||||
},
|
||||
{
|
||||
"id": "EXC0006",
|
||||
"pattern": "Use of unsafe calls should be audited",
|
||||
"linter": "gosec",
|
||||
"why": "Too many false-positives on 'unsafe' usage"
|
||||
},
|
||||
{
|
||||
"id": "EXC0007",
|
||||
"pattern": "Subprocess launch(ed with variable|ing should be audited)",
|
||||
"linter": "gosec",
|
||||
"why": "Too many false-positives for parametrized shell calls"
|
||||
},
|
||||
{
|
||||
"id": "EXC0008",
|
||||
"pattern": "(G104)",
|
||||
"linter": "gosec",
|
||||
"why": "Duplicated errcheck checks"
|
||||
},
|
||||
{
|
||||
"id": "EXC0009",
|
||||
"pattern": "(Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)",
|
||||
"linter": "gosec",
|
||||
"why": "Too many issues in popular repos"
|
||||
},
|
||||
{
|
||||
"id": "EXC0010",
|
||||
"pattern": "Potential file inclusion via variable",
|
||||
"linter": "gosec",
|
||||
"why": "False positive is triggered by 'src, err := ioutil.ReadFile(filename)'"
|
||||
},
|
||||
{
|
||||
"id": "EXC0011",
|
||||
"pattern": "(comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form)",
|
||||
"linter": "stylecheck",
|
||||
"why": "Annoying issue about not having a comment. The rare codebase has such comments"
|
||||
},
|
||||
{
|
||||
"id": "EXC0012",
|
||||
"pattern": "exported (.+) should have comment( \\(or a comment on this block\\))? or be unexported",
|
||||
"linter": "revive",
|
||||
"why": "Annoying issue about not having a comment. The rare codebase has such comments"
|
||||
},
|
||||
{
|
||||
"id": "EXC0013",
|
||||
"pattern": "package comment should be of the form \"(.+)...",
|
||||
"linter": "revive",
|
||||
"why": "Annoying issue about not having a comment. The rare codebase has such comments"
|
||||
},
|
||||
{
|
||||
"id": "EXC0014",
|
||||
"pattern": "comment on exported (.+) should be of the form \"(.+)...\"",
|
||||
"linter": "revive",
|
||||
"why": "Annoying issue about not having a comment. The rare codebase has such comments"
|
||||
},
|
||||
{
|
||||
"id": "EXC0015",
|
||||
"pattern": "should have a package comment",
|
||||
"linter": "revive",
|
||||
"why": "Annoying issue about not having a comment. The rare codebase has such comments"
|
||||
}
|
||||
]
|
1600
assets/linters-info.json
Normal file
1600
assets/linters-info.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -51,7 +51,7 @@
|
||||
"gatsby-plugin-netlify": "^5.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "make -C .. expand_website_templates && gatsby build",
|
||||
"build": "make -C .. website_expand_templates && gatsby build",
|
||||
"start": "gatsby develop",
|
||||
"serve": "gatsby serve",
|
||||
"clean": "gatsby clean"
|
||||
|
@ -30,8 +30,8 @@ allowing to use `React` components.
|
||||
## Templating
|
||||
|
||||
We use templates like `{.SomeField}` inside our `mdx` files.
|
||||
There templates are expanded by running `make expand_website_templates` in the root of the repository.
|
||||
It runs script `scripts/expand_website_templates/main.go` that rewrites `mdx` files with replaced templates.
|
||||
There templates are expanded by running `make website_expand_templates` in the root of the repository.
|
||||
It runs script `scripts/website/expand_templates/` that rewrites `mdx` files with replaced templates.
|
||||
|
||||
## Hosting
|
||||
|
||||
@ -59,5 +59,5 @@ Also, there is no need to refresh a webpage: hot reload updates changed content
|
||||
To do it run:
|
||||
|
||||
```sh
|
||||
go run ./scripts/expand_website_templates/main.go
|
||||
go run ./scripts/website/expand_templates/
|
||||
```
|
||||
|
@ -1,572 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/golangci/golangci-lint/internal/renameio"
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||
)
|
||||
|
||||
const listItemPrefix = "list-item-"
|
||||
|
||||
func main() {
|
||||
replacements, err := buildTemplateContext()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to build template context: %s", err)
|
||||
}
|
||||
|
||||
if err := rewriteDocs(replacements); err != nil {
|
||||
log.Fatalf("Failed to rewrite docs: %s", err)
|
||||
}
|
||||
|
||||
log.Print("Successfully expanded templates")
|
||||
}
|
||||
|
||||
func rewriteDocs(replacements map[string]string) error {
|
||||
madeReplacements := map[string]bool{}
|
||||
err := filepath.Walk(filepath.Join("docs", "src", "docs"),
|
||||
func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
return processDoc(path, replacements, madeReplacements)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to walk dir: %w", err)
|
||||
}
|
||||
|
||||
if len(madeReplacements) != len(replacements) {
|
||||
for key := range replacements {
|
||||
if !madeReplacements[key] {
|
||||
log.Printf("Replacement %q wasn't performed", key)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%d replacements weren't performed", len(replacements)-len(madeReplacements))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func processDoc(path string, replacements map[string]string, madeReplacements map[string]bool) error {
|
||||
contentBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read %s: %w", path, err)
|
||||
}
|
||||
|
||||
content := string(contentBytes)
|
||||
hasReplacements := false
|
||||
for key, replacement := range replacements {
|
||||
nextContent := content
|
||||
nextContent = strings.ReplaceAll(nextContent, fmt.Sprintf("{.%s}", key), replacement)
|
||||
|
||||
// Yaml formatter in mdx code section makes extra spaces, need to match them too.
|
||||
nextContent = strings.ReplaceAll(nextContent, fmt.Sprintf("{ .%s }", key), replacement)
|
||||
|
||||
if nextContent != content {
|
||||
hasReplacements = true
|
||||
madeReplacements[key] = true
|
||||
content = nextContent
|
||||
}
|
||||
}
|
||||
if !hasReplacements {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("Expanded template in %s, saving it", path)
|
||||
if err = renameio.WriteFile(path, []byte(content), os.ModePerm); err != nil {
|
||||
return fmt.Errorf("failed to write changes to file %s: %w", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type latestRelease struct {
|
||||
TagName string `json:"tag_name"`
|
||||
}
|
||||
|
||||
func getLatestVersion() (string, error) {
|
||||
req, err := http.NewRequest( //nolint:noctx
|
||||
http.MethodGet,
|
||||
"https://api.github.com/repos/golangci/golangci-lint/releases/latest",
|
||||
http.NoBody,
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to prepare a http request: %w", err)
|
||||
}
|
||||
req.Header.Add("Accept", "application/vnd.github.v3+json")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get http response for the latest tag: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read a body for the latest tag: %w", err)
|
||||
}
|
||||
release := latestRelease{}
|
||||
err = json.Unmarshal(body, &release)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal the body for the latest tag: %w", err)
|
||||
}
|
||||
return release.TagName, nil
|
||||
}
|
||||
|
||||
func buildTemplateContext() (map[string]string, error) {
|
||||
golangciYamlExample, err := os.ReadFile(".golangci.reference.yml")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read .golangci.reference.yml: %w", err)
|
||||
}
|
||||
|
||||
snippets, err := extractExampleSnippets(golangciYamlExample)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read .golangci.reference.yml: %w", err)
|
||||
}
|
||||
|
||||
if err = exec.Command("make", "build").Run(); err != nil {
|
||||
return nil, fmt.Errorf("can't run go install: %w", err)
|
||||
}
|
||||
|
||||
lintersOut, err := exec.Command("./golangci-lint", "help", "linters").Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't run linters cmd: %w", err)
|
||||
}
|
||||
|
||||
lintersOutParts := bytes.Split(lintersOut, []byte("\n\n"))
|
||||
|
||||
helpCmd := exec.Command("./golangci-lint", "run", "-h")
|
||||
helpCmd.Env = append(helpCmd.Env, os.Environ()...)
|
||||
helpCmd.Env = append(helpCmd.Env, "HELP_RUN=1") // make default concurrency stable: don't depend on machine CPU number
|
||||
help, err := helpCmd.Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't run help cmd: %w", err)
|
||||
}
|
||||
|
||||
helpLines := bytes.Split(help, []byte("\n"))
|
||||
shortHelp := bytes.Join(helpLines[2:], []byte("\n"))
|
||||
changeLog, err := os.ReadFile("CHANGELOG.md")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
latestVersion, err := getLatestVersion()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get the latest version: %w", err)
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
"LintersExample": snippets.LintersSettings,
|
||||
"ConfigurationExample": snippets.ConfigurationFile,
|
||||
"LintersCommandOutputEnabledOnly": string(lintersOutParts[0]),
|
||||
"LintersCommandOutputDisabledOnly": string(lintersOutParts[1]),
|
||||
"EnabledByDefaultLinters": getLintersListMarkdown(true),
|
||||
"DisabledByDefaultLinters": getLintersListMarkdown(false),
|
||||
"DefaultExclusions": getDefaultExclusions(),
|
||||
"ThanksList": getThanksList(),
|
||||
"RunHelpText": string(shortHelp),
|
||||
"ChangeLog": string(changeLog),
|
||||
"LatestVersion": latestVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getDefaultExclusions() string {
|
||||
bufferString := bytes.NewBufferString("")
|
||||
|
||||
for _, pattern := range config.DefaultExcludePatterns {
|
||||
_, _ = fmt.Fprintln(bufferString)
|
||||
_, _ = fmt.Fprintf(bufferString, "### %s\n", pattern.ID)
|
||||
_, _ = fmt.Fprintln(bufferString)
|
||||
_, _ = fmt.Fprintf(bufferString, "- linter: `%s`\n", pattern.Linter)
|
||||
_, _ = fmt.Fprintf(bufferString, "- pattern: `%s`\n", strings.ReplaceAll(pattern.Pattern, "`", "`"))
|
||||
_, _ = fmt.Fprintf(bufferString, "- why: %s\n", pattern.Why)
|
||||
}
|
||||
|
||||
return bufferString.String()
|
||||
}
|
||||
|
||||
func getLintersListMarkdown(enabled bool) string {
|
||||
dbManager, _ := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
|
||||
lcs := dbManager.GetAllSupportedLinterConfigs()
|
||||
|
||||
var neededLcs []*linter.Config
|
||||
for _, lc := range lcs {
|
||||
if lc.Internal {
|
||||
continue
|
||||
}
|
||||
|
||||
if lc.EnabledByDefault == enabled {
|
||||
neededLcs = append(neededLcs, lc)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(neededLcs, func(i, j int) bool {
|
||||
return neededLcs[i].Name() < neededLcs[j].Name()
|
||||
})
|
||||
|
||||
lines := []string{
|
||||
"|Name|Description|Presets|AutoFix|Since|",
|
||||
"|---|---|---|---|---|---|",
|
||||
}
|
||||
|
||||
for _, lc := range neededLcs {
|
||||
line := fmt.Sprintf("|%s|%s|%s|%v|%s|",
|
||||
getName(lc),
|
||||
getDesc(lc),
|
||||
strings.Join(lc.InPresets, ", "),
|
||||
check(lc.CanAutoFix, "Auto fix supported"),
|
||||
lc.Since,
|
||||
)
|
||||
lines = append(lines, line)
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func getName(lc *linter.Config) string {
|
||||
name := lc.Name()
|
||||
|
||||
if lc.OriginalURL != "" {
|
||||
name = fmt.Sprintf("[%s](%s)", name, lc.OriginalURL)
|
||||
}
|
||||
|
||||
if hasSettings(lc.Name()) {
|
||||
name = fmt.Sprintf("%s [%s](#%s)", name, spanWithID(listItemPrefix+lc.Name(), "Configuration", "⚙️"), lc.Name())
|
||||
}
|
||||
|
||||
if !lc.IsDeprecated() {
|
||||
return name
|
||||
}
|
||||
|
||||
title := "deprecated"
|
||||
if lc.Deprecation.Replacement != "" {
|
||||
title += fmt.Sprintf(" since %s", lc.Deprecation.Since)
|
||||
}
|
||||
|
||||
return name + " " + span(title, "⚠")
|
||||
}
|
||||
|
||||
func getDesc(lc *linter.Config) string {
|
||||
desc := lc.Linter.Desc()
|
||||
if lc.IsDeprecated() {
|
||||
desc = lc.Deprecation.Message
|
||||
if lc.Deprecation.Replacement != "" {
|
||||
desc += fmt.Sprintf(" Replaced by %s.", lc.Deprecation.Replacement)
|
||||
}
|
||||
}
|
||||
|
||||
return formatDesc(desc)
|
||||
}
|
||||
|
||||
func formatDesc(desc string) string {
|
||||
runes := []rune(desc)
|
||||
|
||||
r, _ := utf8.DecodeRuneInString(desc)
|
||||
runes[0] = unicode.ToUpper(r)
|
||||
|
||||
if runes[len(runes)-1] != '.' {
|
||||
runes = append(runes, '.')
|
||||
}
|
||||
|
||||
return strings.ReplaceAll(string(runes), "\n", "<br/>")
|
||||
}
|
||||
|
||||
func check(b bool, title string) string {
|
||||
if b {
|
||||
return span(title, "✔")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func hasSettings(name string) bool {
|
||||
tp := reflect.TypeOf(config.LintersSettings{})
|
||||
|
||||
for i := 0; i < tp.NumField(); i++ {
|
||||
if strings.EqualFold(name, tp.Field(i).Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func span(title, icon string) string {
|
||||
return fmt.Sprintf(`<span title=%q>%s</span>`, title, icon)
|
||||
}
|
||||
|
||||
func spanWithID(id, title, icon string) string {
|
||||
return fmt.Sprintf(`<span id=%q title=%q>%s</span>`, id, title, icon)
|
||||
}
|
||||
|
||||
type authorDetails struct {
|
||||
Linters []string
|
||||
Profile string
|
||||
Avatar string
|
||||
}
|
||||
|
||||
func getThanksList() string {
|
||||
addedAuthors := map[string]*authorDetails{}
|
||||
dbManager, _ := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
|
||||
for _, lc := range dbManager.GetAllSupportedLinterConfigs() {
|
||||
if lc.Internal {
|
||||
continue
|
||||
}
|
||||
|
||||
if lc.OriginalURL == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
linterURL := lc.OriginalURL
|
||||
if lc.Name() == "staticcheck" {
|
||||
linterURL = "https://github.com/dominikh/go-tools"
|
||||
}
|
||||
|
||||
if author := extractAuthor(linterURL, "https://github.com/"); author != "" && author != "golangci" {
|
||||
if _, ok := addedAuthors[author]; ok {
|
||||
addedAuthors[author].Linters = append(addedAuthors[author].Linters, lc.Name())
|
||||
} else {
|
||||
addedAuthors[author] = &authorDetails{
|
||||
Linters: []string{lc.Name()},
|
||||
Profile: fmt.Sprintf("[%[1]s](https://github.com/sponsors/%[1]s)", author),
|
||||
Avatar: fmt.Sprintf(`<img src="https://github.com/%[1]s.png" alt="%[1]s" style="max-width: 100%%;" width="20px;" />`, author),
|
||||
}
|
||||
}
|
||||
} else if author := extractAuthor(linterURL, "https://gitlab.com/"); author != "" {
|
||||
if _, ok := addedAuthors[author]; ok {
|
||||
addedAuthors[author].Linters = append(addedAuthors[author].Linters, lc.Name())
|
||||
} else {
|
||||
addedAuthors[author] = &authorDetails{
|
||||
Linters: []string{lc.Name()},
|
||||
Profile: fmt.Sprintf("[%[1]s](https://gitlab.com/%[1]s)", author),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
authors := maps.Keys(addedAuthors)
|
||||
sort.Slice(authors, func(i, j int) bool {
|
||||
return strings.ToLower(authors[i]) < strings.ToLower(authors[j])
|
||||
})
|
||||
|
||||
lines := []string{
|
||||
"|Author|Linter(s)|",
|
||||
"|---|---|",
|
||||
}
|
||||
|
||||
for _, author := range authors {
|
||||
lines = append(lines, fmt.Sprintf("|%s %s|%s|",
|
||||
addedAuthors[author].Avatar, addedAuthors[author].Profile, strings.Join(addedAuthors[author].Linters, ", ")))
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func extractAuthor(originalURL, prefix string) string {
|
||||
if !strings.HasPrefix(originalURL, prefix) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.SplitN(strings.TrimPrefix(originalURL, prefix), "/", 2)[0]
|
||||
}
|
||||
|
||||
type SettingSnippets struct {
|
||||
ConfigurationFile string
|
||||
LintersSettings string
|
||||
}
|
||||
|
||||
func extractExampleSnippets(example []byte) (*SettingSnippets, error) {
|
||||
var data yaml.Node
|
||||
err := yaml.Unmarshal(example, &data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
root := data.Content[0]
|
||||
|
||||
globalNode := &yaml.Node{
|
||||
Kind: root.Kind,
|
||||
Style: root.Style,
|
||||
Tag: root.Tag,
|
||||
Value: root.Value,
|
||||
Anchor: root.Anchor,
|
||||
Alias: root.Alias,
|
||||
HeadComment: root.HeadComment,
|
||||
LineComment: root.LineComment,
|
||||
FootComment: root.FootComment,
|
||||
Line: root.Line,
|
||||
Column: root.Column,
|
||||
}
|
||||
|
||||
snippets := SettingSnippets{}
|
||||
|
||||
builder := strings.Builder{}
|
||||
|
||||
for j, node := range root.Content {
|
||||
switch node.Value {
|
||||
case "run", "output", "linters", "linters-settings", "issues", "severity":
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
nextNode := root.Content[j+1]
|
||||
|
||||
newNode := &yaml.Node{
|
||||
Kind: nextNode.Kind,
|
||||
Content: []*yaml.Node{
|
||||
{
|
||||
HeadComment: fmt.Sprintf("See the dedicated %q documentation section.", node.Value),
|
||||
Kind: node.Kind,
|
||||
Style: node.Style,
|
||||
Tag: node.Tag,
|
||||
Value: "option",
|
||||
},
|
||||
{
|
||||
Kind: node.Kind,
|
||||
Style: node.Style,
|
||||
Tag: node.Tag,
|
||||
Value: "value",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
globalNode.Content = append(globalNode.Content, node, newNode)
|
||||
|
||||
if node.Value == "linters-settings" {
|
||||
snippets.LintersSettings, err = getLintersSettingSections(node, nextNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _ = builder.WriteString(
|
||||
fmt.Sprintf(
|
||||
"### `%s` configuration\n\nSee the dedicated [linters-settings](/usage/linters) documentation section.\n\n",
|
||||
node.Value,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
nodeSection := &yaml.Node{
|
||||
Kind: root.Kind,
|
||||
Style: root.Style,
|
||||
Tag: root.Tag,
|
||||
Value: root.Value,
|
||||
Content: []*yaml.Node{node, nextNode},
|
||||
}
|
||||
|
||||
snippet, errSnip := marshallSnippet(nodeSection)
|
||||
if errSnip != nil {
|
||||
return nil, errSnip
|
||||
}
|
||||
|
||||
_, _ = builder.WriteString(fmt.Sprintf("### `%s` configuration\n\n%s", node.Value, snippet))
|
||||
}
|
||||
|
||||
overview, err := marshallSnippet(globalNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
snippets.ConfigurationFile = overview + builder.String()
|
||||
|
||||
return &snippets, nil
|
||||
}
|
||||
|
||||
func getLintersSettingSections(node, nextNode *yaml.Node) (string, error) {
|
||||
dbManager, _ := lintersdb.NewManager(nil, nil, lintersdb.NewLinterBuilder())
|
||||
lcs := dbManager.GetAllSupportedLinterConfigs()
|
||||
|
||||
var lintersDesc = make(map[string]string)
|
||||
for _, lc := range lcs {
|
||||
if lc.Internal {
|
||||
continue
|
||||
}
|
||||
|
||||
// it's important to use lc.Name() nor name because name can be alias
|
||||
lintersDesc[lc.Name()] = getDesc(lc)
|
||||
}
|
||||
|
||||
builder := &strings.Builder{}
|
||||
|
||||
for i := 0; i < len(nextNode.Content); i += 2 {
|
||||
r := &yaml.Node{
|
||||
Kind: nextNode.Kind,
|
||||
Style: nextNode.Style,
|
||||
Tag: nextNode.Tag,
|
||||
Value: node.Value,
|
||||
Content: []*yaml.Node{
|
||||
{
|
||||
Kind: node.Kind,
|
||||
Value: node.Value,
|
||||
},
|
||||
{
|
||||
Kind: nextNode.Kind,
|
||||
Content: []*yaml.Node{nextNode.Content[i], nextNode.Content[i+1]},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(builder, "### %s\n\n", nextNode.Content[i].Value)
|
||||
_, _ = fmt.Fprintf(builder, "%s\n\n", lintersDesc[nextNode.Content[i].Value])
|
||||
_, _ = fmt.Fprintln(builder, "```yaml")
|
||||
|
||||
encoder := yaml.NewEncoder(builder)
|
||||
encoder.SetIndent(2)
|
||||
|
||||
err := encoder.Encode(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(builder, "```")
|
||||
_, _ = fmt.Fprintln(builder)
|
||||
_, _ = fmt.Fprintf(builder, "[%s](#%s)\n\n", span("Back to the top", "🔼"), listItemPrefix+nextNode.Content[i].Value)
|
||||
_, _ = fmt.Fprintln(builder)
|
||||
}
|
||||
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
func marshallSnippet(node *yaml.Node) (string, error) {
|
||||
builder := &strings.Builder{}
|
||||
|
||||
if node.Value != "" {
|
||||
_, _ = fmt.Fprintf(builder, "### %s\n\n", node.Value)
|
||||
}
|
||||
_, _ = fmt.Fprintln(builder, "```yaml")
|
||||
|
||||
encoder := yaml.NewEncoder(builder)
|
||||
encoder.SetIndent(2)
|
||||
|
||||
err := encoder.Encode(node)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(builder, "```")
|
||||
_, _ = fmt.Fprintln(builder)
|
||||
|
||||
return builder.String(), nil
|
||||
}
|
133
scripts/website/dump_info/main.go
Normal file
133
scripts/website/dump_info/main.go
Normal file
@ -0,0 +1,133 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||
"github.com/golangci/golangci-lint/scripts/website/types"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := saveLinters()
|
||||
if err != nil {
|
||||
log.Fatalf("Save linters: %v", err)
|
||||
}
|
||||
|
||||
err = saveDefaultExclusions()
|
||||
if err != nil {
|
||||
log.Fatalf("Save default exclusions: %v", err)
|
||||
}
|
||||
|
||||
err = saveCLIHelp(filepath.Join("assets", "cli-help.json"))
|
||||
if err != nil {
|
||||
log.Fatalf("Save CLI help: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func saveLinters() error {
|
||||
linters, _ := lintersdb.NewLinterBuilder().Build(config.NewDefault())
|
||||
|
||||
var wraps []types.LinterWrapper
|
||||
for _, l := range linters {
|
||||
wrapper := types.LinterWrapper{
|
||||
Name: l.Linter.Name(),
|
||||
Desc: l.Linter.Desc(),
|
||||
EnabledByDefault: l.EnabledByDefault,
|
||||
LoadMode: l.LoadMode,
|
||||
InPresets: l.InPresets,
|
||||
AlternativeNames: l.AlternativeNames,
|
||||
OriginalURL: l.OriginalURL,
|
||||
Internal: l.Internal,
|
||||
CanAutoFix: l.CanAutoFix,
|
||||
IsSlow: l.IsSlow,
|
||||
DoesChangeTypes: l.DoesChangeTypes,
|
||||
Since: l.Since,
|
||||
}
|
||||
|
||||
if l.Deprecation != nil {
|
||||
wrapper.Deprecation = &types.Deprecation{
|
||||
Since: l.Deprecation.Since,
|
||||
Message: l.Deprecation.Message,
|
||||
Replacement: l.Deprecation.Replacement,
|
||||
}
|
||||
}
|
||||
|
||||
wraps = append(wraps, wrapper)
|
||||
}
|
||||
|
||||
return saveToJSONFile(filepath.Join("assets", "linters-info.json"), wraps)
|
||||
}
|
||||
|
||||
func saveDefaultExclusions() error {
|
||||
var excludePatterns []types.ExcludePattern
|
||||
|
||||
for _, pattern := range config.DefaultExcludePatterns {
|
||||
excludePatterns = append(excludePatterns, types.ExcludePattern{
|
||||
ID: pattern.ID,
|
||||
Pattern: pattern.Pattern,
|
||||
Linter: pattern.Linter,
|
||||
Why: pattern.Why,
|
||||
})
|
||||
}
|
||||
|
||||
return saveToJSONFile(filepath.Join("assets", "default-exclusions.json"), excludePatterns)
|
||||
}
|
||||
|
||||
func saveCLIHelp(dst string) error {
|
||||
err := exec.Command("make", "build").Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't run make build: %w", err)
|
||||
}
|
||||
|
||||
lintersOut, err := exec.Command("./golangci-lint", "help", "linters").Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't run linters cmd: %w", err)
|
||||
}
|
||||
|
||||
lintersOutParts := bytes.Split(lintersOut, []byte("\n\n"))
|
||||
|
||||
helpCmd := exec.Command("./golangci-lint", "run", "-h")
|
||||
helpCmd.Env = append(helpCmd.Env, os.Environ()...)
|
||||
helpCmd.Env = append(helpCmd.Env, "HELP_RUN=1") // make default concurrency stable: don't depend on machine CPU number
|
||||
help, err := helpCmd.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't run help cmd: %w", err)
|
||||
}
|
||||
|
||||
helpLines := bytes.Split(help, []byte("\n"))
|
||||
shortHelp := bytes.Join(helpLines[2:], []byte("\n"))
|
||||
|
||||
data := types.CLIHelp{
|
||||
Enable: string(lintersOutParts[0]),
|
||||
Disable: string(lintersOutParts[1]),
|
||||
Help: string(shortHelp),
|
||||
}
|
||||
|
||||
return saveToJSONFile(dst, data)
|
||||
}
|
||||
|
||||
func saveToJSONFile(dst string, data any) error {
|
||||
file, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open file (%s): %w", dst, err)
|
||||
}
|
||||
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
encoder := json.NewEncoder(file)
|
||||
encoder.SetIndent("", " ")
|
||||
|
||||
err = encoder.Encode(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode JSON (%s): %w", dst, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
48
scripts/website/expand_templates/exclusions.go
Normal file
48
scripts/website/expand_templates/exclusions.go
Normal file
@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/golangci/golangci-lint/scripts/website/types"
|
||||
)
|
||||
|
||||
const exclusionTmpl = `{{ $tick := "` + "`" + `" }}
|
||||
### {{ .ID }}
|
||||
|
||||
- linter: {{ $tick }}{{ .Linter }}{{ $tick }}
|
||||
- pattern: {{ $tick }}{{ .Pattern }}{{ $tick }}
|
||||
- why: {{ .Why }}
|
||||
`
|
||||
|
||||
func getDefaultExclusions() (string, error) {
|
||||
defaultExcludePatterns, err := readJSONFile[[]types.ExcludePattern](filepath.Join("assets", "default-exclusions.json"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bufferString := bytes.NewBufferString("")
|
||||
|
||||
tmpl, err := template.New("exclusions").Parse(exclusionTmpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, pattern := range defaultExcludePatterns {
|
||||
data := map[string]any{
|
||||
"ID": pattern.ID,
|
||||
"Linter": pattern.Linter,
|
||||
"Pattern": strings.ReplaceAll(pattern.Pattern, "`", "`"),
|
||||
"Why": pattern.Why,
|
||||
}
|
||||
|
||||
err := tmpl.Execute(bufferString, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return bufferString.String(), nil
|
||||
}
|
315
scripts/website/expand_templates/linters.go
Normal file
315
scripts/website/expand_templates/linters.go
Normal file
@ -0,0 +1,315 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/scripts/website/types"
|
||||
)
|
||||
|
||||
const listItemPrefix = "list-item-"
|
||||
|
||||
func getLintersListMarkdown(enabled bool) string {
|
||||
linters, err := readJSONFile[[]*types.LinterWrapper](filepath.Join("assets", "linters-info.json"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var neededLcs []*types.LinterWrapper
|
||||
for _, lc := range linters {
|
||||
if lc.Internal {
|
||||
continue
|
||||
}
|
||||
|
||||
if lc.EnabledByDefault == enabled {
|
||||
neededLcs = append(neededLcs, lc)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(neededLcs, func(i, j int) bool {
|
||||
return neededLcs[i].Name < neededLcs[j].Name
|
||||
})
|
||||
|
||||
lines := []string{
|
||||
"|Name|Description|Presets|AutoFix|Since|",
|
||||
"|---|---|---|---|---|---|",
|
||||
}
|
||||
|
||||
for _, lc := range neededLcs {
|
||||
line := fmt.Sprintf("|%s|%s|%s|%v|%s|",
|
||||
getName(lc),
|
||||
getDesc(lc),
|
||||
strings.Join(lc.InPresets, ", "),
|
||||
check(lc.CanAutoFix, "Auto fix supported"),
|
||||
lc.Since,
|
||||
)
|
||||
lines = append(lines, line)
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func getName(lc *types.LinterWrapper) string {
|
||||
name := lc.Name
|
||||
|
||||
if lc.OriginalURL != "" {
|
||||
name = fmt.Sprintf("[%s](%s)", name, lc.OriginalURL)
|
||||
}
|
||||
|
||||
if hasSettings(lc.Name) {
|
||||
name = fmt.Sprintf("%s [%s](#%s)", name, spanWithID(listItemPrefix+lc.Name, "Configuration", "⚙️"), lc.Name)
|
||||
}
|
||||
|
||||
if lc.Deprecation == nil {
|
||||
return name
|
||||
}
|
||||
|
||||
title := "deprecated"
|
||||
if lc.Deprecation.Replacement != "" {
|
||||
title += fmt.Sprintf(" since %s", lc.Deprecation.Since)
|
||||
}
|
||||
|
||||
return name + " " + span(title, "⚠")
|
||||
}
|
||||
|
||||
func check(b bool, title string) string {
|
||||
if b {
|
||||
return span(title, "✔")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getDesc(lc *types.LinterWrapper) string {
|
||||
desc := lc.Desc
|
||||
if lc.Deprecation != nil {
|
||||
desc = lc.Deprecation.Message
|
||||
if lc.Deprecation.Replacement != "" {
|
||||
desc += fmt.Sprintf(" Replaced by %s.", lc.Deprecation.Replacement)
|
||||
}
|
||||
}
|
||||
|
||||
return formatDesc(desc)
|
||||
}
|
||||
|
||||
func formatDesc(desc string) string {
|
||||
runes := []rune(desc)
|
||||
|
||||
r, _ := utf8.DecodeRuneInString(desc)
|
||||
runes[0] = unicode.ToUpper(r)
|
||||
|
||||
if runes[len(runes)-1] != '.' {
|
||||
runes = append(runes, '.')
|
||||
}
|
||||
|
||||
return strings.ReplaceAll(string(runes), "\n", "<br/>")
|
||||
}
|
||||
|
||||
func hasSettings(name string) bool {
|
||||
tp := reflect.TypeOf(config.LintersSettings{})
|
||||
|
||||
for i := 0; i < tp.NumField(); i++ {
|
||||
if strings.EqualFold(name, tp.Field(i).Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func span(title, icon string) string {
|
||||
return fmt.Sprintf(`<span title=%q>%s</span>`, title, icon)
|
||||
}
|
||||
|
||||
func spanWithID(id, title, icon string) string {
|
||||
return fmt.Sprintf(`<span id=%q title=%q>%s</span>`, id, title, icon)
|
||||
}
|
||||
|
||||
type SettingSnippets struct {
|
||||
ConfigurationFile string
|
||||
LintersSettings string
|
||||
}
|
||||
|
||||
func extractExampleSnippets(example []byte) (*SettingSnippets, error) {
|
||||
var data yaml.Node
|
||||
err := yaml.Unmarshal(example, &data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
root := data.Content[0]
|
||||
|
||||
globalNode := &yaml.Node{
|
||||
Kind: root.Kind,
|
||||
Style: root.Style,
|
||||
Tag: root.Tag,
|
||||
Value: root.Value,
|
||||
Anchor: root.Anchor,
|
||||
Alias: root.Alias,
|
||||
HeadComment: root.HeadComment,
|
||||
LineComment: root.LineComment,
|
||||
FootComment: root.FootComment,
|
||||
Line: root.Line,
|
||||
Column: root.Column,
|
||||
}
|
||||
|
||||
snippets := SettingSnippets{}
|
||||
|
||||
builder := strings.Builder{}
|
||||
|
||||
for j, node := range root.Content {
|
||||
switch node.Value {
|
||||
case "run", "output", "linters", "linters-settings", "issues", "severity":
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
nextNode := root.Content[j+1]
|
||||
|
||||
newNode := &yaml.Node{
|
||||
Kind: nextNode.Kind,
|
||||
Content: []*yaml.Node{
|
||||
{
|
||||
HeadComment: fmt.Sprintf("See the dedicated %q documentation section.", node.Value),
|
||||
Kind: node.Kind,
|
||||
Style: node.Style,
|
||||
Tag: node.Tag,
|
||||
Value: "option",
|
||||
},
|
||||
{
|
||||
Kind: node.Kind,
|
||||
Style: node.Style,
|
||||
Tag: node.Tag,
|
||||
Value: "value",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
globalNode.Content = append(globalNode.Content, node, newNode)
|
||||
|
||||
if node.Value == "linters-settings" {
|
||||
snippets.LintersSettings, err = getLintersSettingSections(node, nextNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _ = builder.WriteString(
|
||||
fmt.Sprintf(
|
||||
"### `%s` configuration\n\nSee the dedicated [linters-settings](/usage/linters) documentation section.\n\n",
|
||||
node.Value,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
nodeSection := &yaml.Node{
|
||||
Kind: root.Kind,
|
||||
Style: root.Style,
|
||||
Tag: root.Tag,
|
||||
Value: root.Value,
|
||||
Content: []*yaml.Node{node, nextNode},
|
||||
}
|
||||
|
||||
snippet, errSnip := marshallSnippet(nodeSection)
|
||||
if errSnip != nil {
|
||||
return nil, errSnip
|
||||
}
|
||||
|
||||
_, _ = builder.WriteString(fmt.Sprintf("### `%s` configuration\n\n%s", node.Value, snippet))
|
||||
}
|
||||
|
||||
overview, err := marshallSnippet(globalNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
snippets.ConfigurationFile = overview + builder.String()
|
||||
|
||||
return &snippets, nil
|
||||
}
|
||||
|
||||
func getLintersSettingSections(node, nextNode *yaml.Node) (string, error) {
|
||||
linters, err := readJSONFile[[]*types.LinterWrapper](filepath.Join("assets", "linters-info.json"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var lintersDesc = make(map[string]string)
|
||||
for _, lc := range linters {
|
||||
if lc.Internal {
|
||||
continue
|
||||
}
|
||||
|
||||
// it's important to use lc.Name() nor name because name can be alias
|
||||
lintersDesc[lc.Name] = getDesc(lc)
|
||||
}
|
||||
|
||||
builder := &strings.Builder{}
|
||||
|
||||
for i := 0; i < len(nextNode.Content); i += 2 {
|
||||
r := &yaml.Node{
|
||||
Kind: nextNode.Kind,
|
||||
Style: nextNode.Style,
|
||||
Tag: nextNode.Tag,
|
||||
Value: node.Value,
|
||||
Content: []*yaml.Node{
|
||||
{
|
||||
Kind: node.Kind,
|
||||
Value: node.Value,
|
||||
},
|
||||
{
|
||||
Kind: nextNode.Kind,
|
||||
Content: []*yaml.Node{nextNode.Content[i], nextNode.Content[i+1]},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(builder, "### %s\n\n", nextNode.Content[i].Value)
|
||||
_, _ = fmt.Fprintf(builder, "%s\n\n", lintersDesc[nextNode.Content[i].Value])
|
||||
_, _ = fmt.Fprintln(builder, "```yaml")
|
||||
|
||||
encoder := yaml.NewEncoder(builder)
|
||||
encoder.SetIndent(2)
|
||||
|
||||
err := encoder.Encode(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(builder, "```")
|
||||
_, _ = fmt.Fprintln(builder)
|
||||
_, _ = fmt.Fprintf(builder, "[%s](#%s)\n\n", span("Back to the top", "🔼"), listItemPrefix+nextNode.Content[i].Value)
|
||||
_, _ = fmt.Fprintln(builder)
|
||||
}
|
||||
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
func marshallSnippet(node *yaml.Node) (string, error) {
|
||||
builder := &strings.Builder{}
|
||||
|
||||
if node.Value != "" {
|
||||
_, _ = fmt.Fprintf(builder, "### %s\n\n", node.Value)
|
||||
}
|
||||
_, _ = fmt.Fprintln(builder, "```yaml")
|
||||
|
||||
encoder := yaml.NewEncoder(builder)
|
||||
encoder.SetIndent(2)
|
||||
|
||||
err := encoder.Encode(node)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(builder, "```")
|
||||
_, _ = fmt.Fprintln(builder)
|
||||
|
||||
return builder.String(), nil
|
||||
}
|
182
scripts/website/expand_templates/main.go
Normal file
182
scripts/website/expand_templates/main.go
Normal file
@ -0,0 +1,182 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/golangci/golangci-lint/internal/renameio"
|
||||
"github.com/golangci/golangci-lint/scripts/website/types"
|
||||
)
|
||||
|
||||
func main() {
|
||||
replacements, err := buildTemplateContext()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to build template context: %s", err)
|
||||
}
|
||||
|
||||
if err := rewriteDocs(replacements); err != nil {
|
||||
log.Fatalf("Failed to rewrite docs: %s", err)
|
||||
}
|
||||
|
||||
log.Print("Successfully expanded templates")
|
||||
}
|
||||
|
||||
func rewriteDocs(replacements map[string]string) error {
|
||||
madeReplacements := map[string]bool{}
|
||||
err := filepath.Walk(filepath.Join("docs", "src", "docs"),
|
||||
func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
return processDoc(path, replacements, madeReplacements)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to walk dir: %w", err)
|
||||
}
|
||||
|
||||
if len(madeReplacements) != len(replacements) {
|
||||
for key := range replacements {
|
||||
if !madeReplacements[key] {
|
||||
log.Printf("Replacement %q wasn't performed", key)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%d replacements weren't performed", len(replacements)-len(madeReplacements))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func processDoc(path string, replacements map[string]string, madeReplacements map[string]bool) error {
|
||||
contentBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read %s: %w", path, err)
|
||||
}
|
||||
|
||||
content := string(contentBytes)
|
||||
hasReplacements := false
|
||||
for key, replacement := range replacements {
|
||||
nextContent := content
|
||||
nextContent = strings.ReplaceAll(nextContent, fmt.Sprintf("{.%s}", key), replacement)
|
||||
|
||||
// Yaml formatter in mdx code section makes extra spaces, need to match them too.
|
||||
nextContent = strings.ReplaceAll(nextContent, fmt.Sprintf("{ .%s }", key), replacement)
|
||||
|
||||
if nextContent != content {
|
||||
hasReplacements = true
|
||||
madeReplacements[key] = true
|
||||
content = nextContent
|
||||
}
|
||||
}
|
||||
if !hasReplacements {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("Expanded template in %s, saving it", path)
|
||||
if err = renameio.WriteFile(path, []byte(content), os.ModePerm); err != nil {
|
||||
return fmt.Errorf("failed to write changes to file %s: %w", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type latestRelease struct {
|
||||
TagName string `json:"tag_name"`
|
||||
}
|
||||
|
||||
func getLatestVersion() (string, error) {
|
||||
req, err := http.NewRequest( //nolint:noctx
|
||||
http.MethodGet,
|
||||
"https://api.github.com/repos/golangci/golangci-lint/releases/latest",
|
||||
http.NoBody,
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to prepare a http request: %w", err)
|
||||
}
|
||||
req.Header.Add("Accept", "application/vnd.github.v3+json")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get http response for the latest tag: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read a body for the latest tag: %w", err)
|
||||
}
|
||||
release := latestRelease{}
|
||||
err = json.Unmarshal(body, &release)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal the body for the latest tag: %w", err)
|
||||
}
|
||||
return release.TagName, nil
|
||||
}
|
||||
|
||||
func buildTemplateContext() (map[string]string, error) {
|
||||
golangciYamlExample, err := os.ReadFile(".golangci.reference.yml")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read .golangci.reference.yml: %w", err)
|
||||
}
|
||||
|
||||
snippets, err := extractExampleSnippets(golangciYamlExample)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read .golangci.reference.yml: %w", err)
|
||||
}
|
||||
|
||||
helps, err := readJSONFile[types.CLIHelp](filepath.Join("assets", "cli-help.json"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
changeLog, err := os.ReadFile("CHANGELOG.md")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
latestVersion, err := getLatestVersion()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get the latest version: %w", err)
|
||||
}
|
||||
|
||||
exclusions, err := getDefaultExclusions()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("default exclusions: %w", err)
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
"LintersExample": snippets.LintersSettings,
|
||||
"ConfigurationExample": snippets.ConfigurationFile,
|
||||
"LintersCommandOutputEnabledOnly": helps.Enable,
|
||||
"LintersCommandOutputDisabledOnly": helps.Disable,
|
||||
"EnabledByDefaultLinters": getLintersListMarkdown(true),
|
||||
"DisabledByDefaultLinters": getLintersListMarkdown(false),
|
||||
"DefaultExclusions": exclusions,
|
||||
"ThanksList": getThanksList(),
|
||||
"RunHelpText": helps.Help,
|
||||
"ChangeLog": string(changeLog),
|
||||
"LatestVersion": latestVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func readJSONFile[T any](src string) (T, error) {
|
||||
file, err := os.Open(src)
|
||||
if err != nil {
|
||||
var zero T
|
||||
return zero, err
|
||||
}
|
||||
|
||||
var result T
|
||||
err = json.NewDecoder(file).Decode(&result)
|
||||
if err != nil {
|
||||
var zero T
|
||||
return zero, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
87
scripts/website/expand_templates/thanks.go
Normal file
87
scripts/website/expand_templates/thanks.go
Normal file
@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/lintersdb"
|
||||
)
|
||||
|
||||
type authorDetails struct {
|
||||
Linters []string
|
||||
Profile string
|
||||
Avatar string
|
||||
}
|
||||
|
||||
func getThanksList() string {
|
||||
addedAuthors := map[string]*authorDetails{}
|
||||
|
||||
linters, _ := lintersdb.NewLinterBuilder().Build(config.NewDefault())
|
||||
|
||||
for _, lc := range linters {
|
||||
if lc.Internal {
|
||||
continue
|
||||
}
|
||||
|
||||
if lc.OriginalURL == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
linterURL := lc.OriginalURL
|
||||
if lc.Name() == "staticcheck" {
|
||||
linterURL = "https://github.com/dominikh/go-tools"
|
||||
}
|
||||
|
||||
if author := extractAuthor(linterURL, "https://github.com/"); author != "" && author != "golangci" {
|
||||
if _, ok := addedAuthors[author]; ok {
|
||||
addedAuthors[author].Linters = append(addedAuthors[author].Linters, lc.Name())
|
||||
} else {
|
||||
addedAuthors[author] = &authorDetails{
|
||||
Linters: []string{lc.Name()},
|
||||
Profile: fmt.Sprintf("[%[1]s](https://github.com/sponsors/%[1]s)", author),
|
||||
Avatar: fmt.Sprintf(`<img src="https://github.com/%[1]s.png" alt="%[1]s" style="max-width: 100%%;" width="20px;" />`, author),
|
||||
}
|
||||
}
|
||||
} else if author := extractAuthor(linterURL, "https://gitlab.com/"); author != "" {
|
||||
if _, ok := addedAuthors[author]; ok {
|
||||
addedAuthors[author].Linters = append(addedAuthors[author].Linters, lc.Name())
|
||||
} else {
|
||||
addedAuthors[author] = &authorDetails{
|
||||
Linters: []string{lc.Name()},
|
||||
Profile: fmt.Sprintf("[%[1]s](https://gitlab.com/%[1]s)", author),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
authors := maps.Keys(addedAuthors)
|
||||
sort.Slice(authors, func(i, j int) bool {
|
||||
return strings.ToLower(authors[i]) < strings.ToLower(authors[j])
|
||||
})
|
||||
|
||||
lines := []string{
|
||||
"|Author|Linter(s)|",
|
||||
"|---|---|",
|
||||
}
|
||||
|
||||
for _, author := range authors {
|
||||
lines = append(lines, fmt.Sprintf("|%s %s|%s|",
|
||||
addedAuthors[author].Avatar, addedAuthors[author].Profile, strings.Join(addedAuthors[author].Linters, ", ")))
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func extractAuthor(originalURL, prefix string) string {
|
||||
if !strings.HasPrefix(originalURL, prefix) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.SplitN(strings.TrimPrefix(originalURL, prefix), "/", 2)[0]
|
||||
}
|
48
scripts/website/types/types.go
Normal file
48
scripts/website/types/types.go
Normal file
@ -0,0 +1,48 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
type CLIHelp struct {
|
||||
Enable string `json:"enable"`
|
||||
Disable string `json:"disable"`
|
||||
Help string `json:"help"`
|
||||
}
|
||||
|
||||
type ExcludePattern struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
Linter string `json:"linter,omitempty"`
|
||||
Why string `json:"why,omitempty"`
|
||||
}
|
||||
|
||||
type Deprecation struct {
|
||||
Since string `json:"since,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Replacement string `json:"replacement,omitempty"`
|
||||
}
|
||||
|
||||
// LinterWrapper same fields but with struct tags.
|
||||
// The field Name and Desc are added to have the information about the linter.
|
||||
// The field Linter is removed (not serializable).
|
||||
type LinterWrapper struct {
|
||||
Name string `json:"name"` // From linter.
|
||||
Desc string `json:"desc"` // From linter.
|
||||
|
||||
EnabledByDefault bool `json:"enabledByDefault,omitempty"`
|
||||
|
||||
LoadMode packages.LoadMode `json:"loadMode,omitempty"`
|
||||
|
||||
InPresets []string `json:"inPresets,omitempty"`
|
||||
AlternativeNames []string `json:"alternativeNames,omitempty"`
|
||||
|
||||
OriginalURL string `json:"originalURL,omitempty"`
|
||||
Internal bool `json:"internal"`
|
||||
CanAutoFix bool `json:"canAutoFix,omitempty"`
|
||||
IsSlow bool `json:"isSlow"`
|
||||
DoesChangeTypes bool `json:"doesChangeTypes,omitempty"`
|
||||
|
||||
Since string `json:"since,omitempty"`
|
||||
Deprecation *Deprecation `json:"deprecation,omitempty"`
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user