diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..8392d15 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake \ No newline at end of file diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 3440109..daf84d9 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -8,10 +8,21 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v2 - - name: Setup Go - uses: actions/setup-go@v3 - - name: Generate Coverage Report - run: go test -coverprofile coverage.txt -covermode atomic ./... - - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v3 + uses: actions/checkout@v4 + - name: Install Nix + uses: cachix/install-nix-action@v22 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + run: nix develop -c go test -coverprofile coverage.txt -covermode atomic ./... + - name: Upload Unit Test Coverage to Codecov + uses: codecov/codecov-action@v4 + with: + flags: unit + - name: Generate Coverage Report for Integration Tests + working-directory: test/ + run: nix develop -c bash codecov.sh -coverprofile + - name: Upload Integration Test Coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: ./test/prepare_coverage.txt,./test/integration_coverage.txt + flags: integration diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml index dc7648a..b107290 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/goreleaser.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Fetch All Tags @@ -22,12 +22,12 @@ jobs: - name: Set-Up Go uses: actions/setup-go@v2 with: - go-version: 1.19 - - name: Install Dependencies - run: go install golang.org/x/tools/cmd/stringer@latest - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v4 + go-version: '>=1.21.0' + - name: Install Nix + uses: cachix/install-nix-action@v22 with: - args: release --rm-dist + github_access_token: ${{ secrets.GITHUB_TOKEN }} + - name: Run GoReleaser + run: nix develop -c goreleaser release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1d1909f..de8aab6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,8 +8,8 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Lint Project - uses: reviewdog/action-golangci-lint@v1 + uses: reviewdog/action-golangci-lint@v2 with: reporter: github-pr-review diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 59b289c..da94c59 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,5 @@ name: Test + on: [push, pull_request] jobs: @@ -7,8 +8,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v2 - - name: Setup Go - uses: actions/setup-go@v3 - - name: Run Tests - run: go test -race ./... + uses: actions/checkout@v4 + - name: Install Nix + uses: cachix/install-nix-action@v22 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + - name: Run Unit Tests + run: nix develop -c go test -race ./... diff --git a/.golangci.yml b/.golangci.yml index 2f13530..5620009 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,13 +1,19 @@ linters: disable-all: true enable: + - asasalint + - asciicheck + - bidichk - bodyclose - - deadcode + - dupword - durationcheck - errcheck + - errname - errorlint + - execinquery + - exhaustive - exportloopref - - forbidigo + - gocheckcompilerdirectives - gocritic - godot - gofumpt @@ -16,22 +22,25 @@ linters: - gosimple - govet - ineffassign - - lll + - loggercheck - misspell - nakedret + - nilerr + - nolintlint + - nosprintfhostport - prealloc - predeclared + - reassign - revive - - rowserrcheck - staticcheck - - structcheck - - thelper + - tenv - tparallel - typecheck - unconvert - unparam - unused - - varcheck + - usestdlibvars + - wastedassign - whitespace linters-settings: @@ -39,24 +48,24 @@ linters-settings: exclude: - ^\s*.+:.+$ - ^\s*(?:=+|/+|-+|\++) + - ^\s*\w+$ + - ^\s*[a-z0-9] + unparam: + check-exported: true + gocritic: + disabled-checks: + - singleCaseSwitch + dupword: + ignore: + - XXX + + errcheck: + exclude-functions: + - github.com/mavolin/corgi/file/fileutil.Walk issues: exclude-rules: - # prevent errors on type assertions with field access - - linters: - - errorlint - source: \w\.\(\*?\w+\)\.\w+ - - linters: - - lll - source: //(?:nolint|go|goland) - # io.EOF and sql.ErrNoRows should, according to the doc, never be wrapped - - linters: - - errorlint - source: "\\w+\\s*==\\s*(io.EOF|sql.ErrNoRows)" - - path: (?:_test|test_util)\.go$ - linters: - - bodyclose - - errcheck - - errorlint - - gosec - - unparam + - path: ^test/ + linters: [unused] + - path: ^de/pensioninsurancenumber/area_code.go$ + linters: [revive] \ No newline at end of file diff --git a/de/postalcode/postalcode.go b/de/postalcode/postalcode.go index 101a331..69023cf 100644 --- a/de/postalcode/postalcode.go +++ b/de/postalcode/postalcode.go @@ -10,7 +10,7 @@ import ( var ErrSyntax = errors.New("postal code: must be 5-digit number") -// PostalCode represents a German postal code code (Postleitzahl). +// PostalCode represents a German postal code (Postleitzahl). // // It is a 5-digit string. type PostalCode string diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..6612c77 --- /dev/null +++ b/flake.lock @@ -0,0 +1,60 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1719506693, + "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-unstable", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "utils": "utils" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..86b7f7e --- /dev/null +++ b/flake.nix @@ -0,0 +1,27 @@ +{ + inputs = { + nixpkgs.url = "nixpkgs/nixos-unstable"; + utils.url = "github:numtide/flake-utils"; + }; + + outputs = { + self, + nixpkgs, + utils, + }: + utils.lib.eachDefaultSystem ( + system: let + pkgs = import nixpkgs { + inherit system; + }; + in { + formatter = pkgs.alejandra; + + devShells.default = pkgs.mkShell { + packages = with pkgs; [go golangci-lint goreleaser]; + + hardeningDisable = ["fortify"]; + }; + } + ); +} diff --git a/iban/national_checksum.go b/iban/national_checksum.go index b6a0b06..9c4863d 100644 --- a/iban/national_checksum.go +++ b/iban/national_checksum.go @@ -118,7 +118,7 @@ var checksumFuncs = map[iso3166.Alpha2Code]func(IBAN) bool{ }, // https://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country // https://www.ecbs.org/Download/Tr201v3.9.pdf (page 105) - // ECBS calls the concatentation of the bank code and account no. the + // ECBS calls the concatenation of the bank code and account no. the // "account number", which is a bit confusing. // Otherwise, the same as wiki. iso3166.NO: func(iban IBAN) bool { @@ -188,7 +188,7 @@ var checksumFuncs = map[iso3166.Alpha2Code]func(IBAN) bool{ // https://en.wikipedia.org/wiki/International_Bank_Account_Number#National_check_digits // https://www.ecbs.org/Download/Tr201v3.9.pdf (page 34) -// wiki has complement wrong, otherwise as above +// Wiki has complement wrong, otherwise as above. func czech(iban IBAN) bool { r := weighted(iban.BranchCode, 11, 10, 5, 8, 4, 2, 1) if r != 0 { @@ -196,11 +196,7 @@ func czech(iban IBAN) bool { } r = weighted(iban.AccountNumber, 11, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1) - if r != 0 { - return false - } - - return true + return r == 0 } // https://en.wikipedia.org/wiki/International_Bank_Account_Number#National_check_digits @@ -229,17 +225,16 @@ func franceTransliterate(s string) string { return string(bs) } -var ( - // https://www.ecbs.org/Download/Tr201v3.9.pdf (page 77) - // Officially called odd mapping, but since they consider the first digit - // to be odd, and 0 is even, I'm swapping the names. - italyEvenMapping = [...]int{ - 1, 0, 5, 7, 9, 13, 15, 17, 19, 21, - 2, 4, 18, 20, 11, 3, 6, 8, 12, 14, - 16, 10, 22, 25, 24, 23, - } - // odd mapping is just ascending numbers -) +// https://www.ecbs.org/Download/Tr201v3.9.pdf (page 77) +// Officially called odd mapping, but since they consider the first digit +// to be odd, and 0 is even, I'm swapping the names. +var italyEvenMapping = [...]int{ + 1, 0, 5, 7, 9, 13, 15, 17, 19, 21, + 2, 4, 18, 20, 11, 3, 6, 8, 12, 14, + 16, 10, 22, 25, 24, 23, +} + +// Odd mapping is just ascending numbers. func italy(iban IBAN) bool { if len(iban.NationalChecksum) != 1 { @@ -318,10 +313,10 @@ func weighted(s string, mod int, weights ...int) int { return sum % mod } -func weightedRTL(s string, mod int, weigths ...int) int { +func weightedRTL(s string, mod int, weights ...int) int { var sum int for i, r := 0, len(s)-1; r >= 0; i, r = i+1, r-1 { - sum += (digit(rune(s[r])) * weigths[i%len(weigths)]) % mod + sum += (digit(rune(s[r])) * weights[i%len(weights)]) % mod } return sum % mod } diff --git a/iban/parse.go b/iban/parse.go index 924218e..e523ec4 100644 --- a/iban/parse.go +++ b/iban/parse.go @@ -70,7 +70,7 @@ func Parse(s string) (IBAN, error) { iban.BBAN = s[4:] - bbanRegexp, _ := bbanRegexps[iban.CountryCode] + bbanRegexp := bbanRegexps[iban.CountryCode] if bbanRegexp != nil { matches := bbanRegexp.FindStringSubmatch(iban.BBAN) if matches == nil { diff --git a/tools/codegen/bban_regexp/main.go b/tools/codegen/bban_regexp/main.go index e46f025..dcd75b9 100644 --- a/tools/codegen/bban_regexp/main.go +++ b/tools/codegen/bban_regexp/main.go @@ -22,6 +22,9 @@ func main() { func run() error { // table needs to marked with id="IBAN_formats_by_country_table" in, err := os.Open("in.html") + if err != nil { + return err + } defer in.Close() n, err := html.Parse(in) @@ -125,7 +128,7 @@ func extractRawRulesFromTable(tbody *html.Node) (map[iso3166.Alpha2Code][2]strin bbanEl := checkDigitsEl.NextSibling for bbanEl != nil { - switch bbanEl.Type { + switch bbanEl.Type { //nolint:exhaustive case html.TextNode: formatBuilder.WriteString(bbanEl.Data) case html.ElementNode: @@ -142,7 +145,7 @@ func extractRawRulesFromTable(tbody *html.Node) (map[iso3166.Alpha2Code][2]strin format := strings.ReplaceAll(formatBuilder.String(), " ", "") format = strings.ReplaceAll(format, "\n", "") - rawRules[countryCode] = [2]string{charClasses, formatBuilder.String()} + rawRules[countryCode] = [2]string{charClasses, format} tr = nextElement(tr.NextSibling) } @@ -183,7 +186,7 @@ func nextElement(n *html.Node) *html.Node { func genRules(rawRules map[iso3166.Alpha2Code][2]string) (map[iso3166.Alpha2Code]string, error) { // map[iso3166.Alpha2Code]rawRegexp - var rules = make(map[iso3166.Alpha2Code]string, len(rawRules)) + rules := make(map[iso3166.Alpha2Code]string, len(rawRules)) for country, rule := range rawRules { rawLengths := strings.Split(rule[0], ",") diff --git a/tools/codegen/iso3166-1/iso3166.go b/tools/codegen/iso3166-1/iso3166.go index 7b673be..66d7c08 100644 --- a/tools/codegen/iso3166-1/iso3166.go +++ b/tools/codegen/iso3166-1/iso3166.go @@ -31,6 +31,9 @@ func main() { func run() error { in, err := os.Open("in.html") + if err != nil { + return err + } defer in.Close() n, err := html.Parse(in) @@ -54,9 +57,7 @@ func run() error { // we found our table - if n.FirstChild == nil || n.FirstChild != n.LastChild /* len(ChildNodes) != 1 */ || - n.FirstChild.DataAtom != atom.Tbody { - + if n.FirstChild == nil || n.FirstChild != n.LastChild /* len(ChildNodes) != 1 */ || n.FirstChild.DataAtom != atom.Tbody { panic("expected country code table to contain a single node, named tbody") } @@ -134,7 +135,7 @@ func extractCountryCodesFromTable(tbody *html.Node) ([]iso3166.Alpha2Code, error // two cases, either td contains the name, or an anchor containing the name - switch td.FirstChild.Type { + switch td.FirstChild.Type { //nolint:exhaustive case html.TextNode: code.Code = td.FirstChild.Data case html.ElementNode: