diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 00d0679bd0fa..7371468d0389 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -285,6 +285,8 @@ jobs: - name: Run linters uses: FerretDB/github-actions/linters@main + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} fuzz-short: name: Fuzz short diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c94a278f1ee..c7cbc3e0a691 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -78,6 +78,45 @@ you can reset the environment with `task env-reset`. To build a production release binaries, run `task build-production`. The results will be saved `tmp/bin`. +### Setting a GITHUB_TOKEN + +Some of our development tools require access to public information on GitHub +at a rate higher than allowed for unauthenticated requests. +Those tools will report a problem in this case. +It could be solved by creating a new classic or fine-graned personal access token +[there](https://github.com/settings/tokens). +No scopes are needed for classic tokens, not even `public_repo`. +For fine-graned tokens, only read-only access to public repositories is needed without any additional permissions. +After generating a token, set the `GITHUB_TOKEN` environment variable: + +```sh +export GITHUB_TOKEN=ghp_XXX +``` + +or + +```sh +export GITHUB_TOKEN=github_pat_XXX +``` + +## Reporting a bug + +We appreciate reporting a bug to us. +To help us accurately identify the cause, we encourage you to include a pull request with test script. +Please write the test script in [build/legacy-mongo-shell/test.js](build/legacy-mongo-shell/test.js). +You can find an overview of the available assertions [here](build/legacy-mongo-shell/README.md). +Use these assertions to validate your test's assumptions and invariants. +You can also find an example of how to prepare a test script in +[build/legacy-mongo-shell/test.example.js](build/legacy-mongo-shell/test.example.js). + +With `task` installed (see above), you may test your script using following steps: + +1. Start the development environment with `task env-up`. +2. Start FerretDB with `task run`. +3. Run the test script with `task testjs`. + +Please create a pull request and include the link of the pull request in the bug issue. + ## Contributing code ### Commands for contributing code @@ -334,26 +373,6 @@ Before submitting a pull request, please make sure that: If you have interest in becoming or are a long-term contributor, please read [PROCESS.md](.github/PROCESS.md) for more details. -## Reporting a bug - -We appreciate reporting a bug to us. -To help us accurately identify the cause, we encourage -you to include a pull request with test script. -Please write the test script in -[build/legacy-mongo-shell/test.js](build/legacy-mongo-shell/test.js). -You can find an overview of the available assertions [here](build/legacy-mongo-shell/README.md). -Use these assertions to validate your test's assumptions and invariants. -You can also find an example of how to prepare a test script in -[build/legacy-mongo-shell/test.example.js](build/legacy-mongo-shell/test.example.js). - -Test your script using following steps: - -1. Start the development environment with `task env-up`. -2. Start FerretDB with `task run`. -3. Run the test script with `task testjs`. - -Please create a pull request and include the link of the pull request in the bug issue. - ## Contributing documentation ### Commands for contributing documentation diff --git a/tools/checkcomments/checkcomments.go b/tools/checkcomments/checkcomments.go index f5a60dc98fa5..da26c7bc38d1 100644 --- a/tools/checkcomments/checkcomments.go +++ b/tools/checkcomments/checkcomments.go @@ -16,9 +16,16 @@ package main import ( + "context" + "errors" + "log" + "os" "regexp" + "strconv" "strings" + "github.com/FerretDB/gh" + "github.com/google/go-github/v56/github" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/singlechecker" ) @@ -38,20 +45,71 @@ func main() { // run analyses TODO comments. func run(pass *analysis.Pass) (any, error) { + token := os.Getenv("GITHUB_TOKEN") + + client, err := gh.NewRESTClient(token, nil) + if err != nil { + log.Fatal(err) + } + + issues := make(map[int]bool) + for _, f := range pass.Files { for _, cg := range f.Comments { for _, c := range cg.List { + line := c.Text + // the space between `//` and `TODO` is always added by `task fmt` - if strings.HasPrefix(c.Text, "// TODO") { - // skip comments without URLs for now - // TODO https://github.com/FerretDB/FerretDB/issues/2733 - if !strings.Contains(c.Text, "https://") { - continue - } + if !strings.HasPrefix(line, "// TODO") { + continue + } + + if f.Name.Name == "testdata" { + line, _, _ = strings.Cut(line, ` // want "`) + } + + // skip comments without URLs for now + // TODO https://github.com/FerretDB/FerretDB/issues/2733 + if !strings.Contains(line, "https://") { + continue + } - if !todoRE.MatchString(c.Text) { - pass.Reportf(c.Pos(), "invalid TODO comment") + match := todoRE.FindStringSubmatch(line) + + if match == nil { + pass.Reportf(c.Pos(), "invalid TODO: incorrect format") + continue + } + + n, err := strconv.Atoi(match[1]) + if err != nil { + log.Fatal(err) + } + + open, ok := issues[n] + if !ok { + issue, _, err := client.Issues.Get(context.TODO(), "FerretDB", "FerretDB", n) + if err != nil { + if errors.As(err, new(*github.RateLimitError)) && token == "" { + log.Printf( + "%[1]T %[1]s\n%[2]s %[3]s", + err, + "Please set a GITHUB_TOKEN as described at", + "https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md#setting-a-github_token", + ) + + return nil, nil + } + + log.Fatalf("%[1]T %[1]s", err) } + + open = issue.GetState() == "open" + issues[n] = open + } + + if !open { + pass.Reportf(c.Pos(), "invalid TODO: linked issue is closed") } } } diff --git a/tools/checkcomments/testdata/testdata.go b/tools/checkcomments/testdata/testdata.go index 11745d6de2dc..e4af60dc5d3f 100644 --- a/tools/checkcomments/testdata/testdata.go +++ b/tools/checkcomments/testdata/testdata.go @@ -16,13 +16,21 @@ package testdata func testCorrect() { - // TODO https://github.com/FerretDB/FerretDB/issues/2733 + // TODO https://github.com/FerretDB/FerretDB/issues/3413 } func testCorrectForNow() { // TODO no URL } -func testIncorrect() { - // TODO: https://github.com/FerretDB/FerretDB/issues/2733 // want "invalid TODO comment" +func testIncorrectFormat() { + // TODO: https://github.com/FerretDB/FerretDB/issues/3413 // want "invalid TODO: incorrect format" +} + +func testIncorrectClosed() { + // TODO https://github.com/FerretDB/FerretDB/issues/1 // want "invalid TODO: linked issue is closed" +} + +func testIncorrectFormatClosed() { + // TODO: https://github.com/FerretDB/FerretDB/issues/1 // want "invalid TODO: incorrect format" } diff --git a/tools/cleantool/cleantool.go b/tools/cleantool/cleantool.go index 7242c8b14e8b..0c79031d1142 100644 --- a/tools/cleantool/cleantool.go +++ b/tools/cleantool/cleantool.go @@ -22,7 +22,7 @@ import ( "strings" "time" - "github.com/google/go-github/v41/github" + "github.com/google/go-github/v56/github" "golang.org/x/oauth2" ) diff --git a/tools/go.mod b/tools/go.mod index 354763a86c7e..53cb1ed7050e 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -8,8 +8,9 @@ replace github.com/goreleaser/nfpm/v2 => github.com/AlekSi/nfpm/v2 v2.33.2-0.202 require ( github.com/BurntSushi/go-sumtype v0.0.0-20221020234012-480526a59796 + github.com/FerretDB/gh v0.0.0-20231017052058-110a65393a76 github.com/go-task/task/v3 v3.31.0 - github.com/google/go-github/v41 v41.0.0 + github.com/google/go-github/v56 v56.0.0 github.com/goreleaser/nfpm/v2 v2.33.1 github.com/quasilyte/go-consistent v0.6.0 github.com/stretchr/testify v1.8.4 diff --git a/tools/go.sum b/tools/go.sum index 08afcc823c4d..4a935fd89b43 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -8,6 +8,8 @@ github.com/BurntSushi/go-sumtype v0.0.0-20221020234012-480526a59796 h1:LkyKOzdmN github.com/BurntSushi/go-sumtype v0.0.0-20221020234012-480526a59796/go.mod h1:V4gPjiBeLsr++PoZh39o+6fZ++EbypxSUmMplhmBNRY= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/FerretDB/gh v0.0.0-20231017052058-110a65393a76 h1:Zc+NaElj5N+2sJ+QonY1HD3aX6pwGX41klDZXhbCmkM= +github.com/FerretDB/gh v0.0.0-20231017052058-110a65393a76/go.mod h1:IZaVgs+IhUzLBYd2lfJjS5U2OnwuuvvLvypP1zHftSY= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= @@ -99,7 +101,6 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -107,11 +108,10 @@ github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RA github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= -github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= +github.com/google/go-github/v56 v56.0.0 h1:TysL7dMa/r7wsQi44BjqlwaHvwlFlqkK8CtBWCX3gb4= +github.com/google/go-github/v56 v56.0.0/go.mod h1:D8cdcX98YWJvi7TLo7zM4/h8ZTx6u6fwGEkCdisopo0= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-replayers/httpreplay v1.0.0 h1:8SmT8fUYM4nueF+UnXIX8LJxNTb1vpPuknXz+yTWzL4= @@ -268,7 +268,6 @@ gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -293,7 +292,6 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/perf v0.0.0-20231006134539-cd219cffda85 h1:TTE4QVbOEiTwey734kAI878uRc0RyeTaJ87R8N/fMvw=