Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checkdocs checks issues, separate GitHub code #4258

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9957373
init github package
kropidlowsky Apr 23, 2024
5645f42
remove checkcomments client (github)
kropidlowsky Apr 23, 2024
8fda8d8
WIP
kropidlowsky Apr 23, 2024
a2ae558
move checkcomments tests related to github + refactoring
kropidlowsky Apr 23, 2024
1e177ac
github issue unit tests
kropidlowsky Apr 23, 2024
28e70a6
add internal github pkg to checkdocs, checkcomments
kropidlowsky Apr 24, 2024
e04d02d
add TestVerifyIssues
kropidlowsky Apr 24, 2024
8062882
add `tmp/checkdocs` to docs-fmt
kropidlowsky Apr 24, 2024
e55db99
Merge branch 'main' into checkdocs-checks-issues
kropidlowsky Apr 24, 2024
e3c8451
Merge branch 'main' into checkdocs-checks-issues
AlekSi Apr 29, 2024
28d9be4
Merge branch 'main' into checkdocs-checks-issues
AlekSi May 1, 2024
ed4198e
Merge branch 'main' into checkdocs-checks-issues
AlekSi May 6, 2024
319c557
Update tools/checkcomments/checkcomments.go
kropidlowsky May 6, 2024
7187ddd
Merge branch 'main' into checkdocs-checks-issues
kropidlowsky May 7, 2024
fc32537
WIP
kropidlowsky May 7, 2024
3531a28
use githubcache in docs-fmt
kropidlowsky May 7, 2024
fd11bea
remove issueReference var
kropidlowsky May 7, 2024
5b58b05
wip
kropidlowsky May 9, 2024
2cc2ffc
wip
kropidlowsky May 9, 2024
c911f47
fmt
kropidlowsky May 9, 2024
68888ca
Merge branch 'main' into checkdocs-checks-issues
kropidlowsky May 9, 2024
29a6461
update unit test
kropidlowsky May 9, 2024
530292f
wip
kropidlowsky May 12, 2024
98166c5
lint
kropidlowsky May 12, 2024
7de6e86
Merge branch 'main' into checkdocs-checks-issues
kropidlowsky May 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Taskfile.yml
Expand Up @@ -882,6 +882,8 @@ tasks:
- docker compose run --rm textlint --fix --config build/.textlintrc "**/*.md" ".github/**/*.md"
- docker compose run --rm prettier --write --parser markdown --no-semi --single-quote --trailing-comma none "**/*.md"
- docker compose run --rm markdownlint "build/.markdownlint.yml" "**/*.md"
- bin/envtool{{exeExt}} shell rmdir tmp/githubcache
- bin/envtool{{exeExt}} shell mkdir tmp/githubcache
- bin/checkdocs

pngcrush:
Expand Down
14 changes: 8 additions & 6 deletions tools/checkcomments/checkcomments.go
Expand Up @@ -26,6 +26,8 @@ import (
"github.com/FerretDB/gh"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/singlechecker"

"github.com/FerretDB/FerretDB/tools/github"
)

// todoRE represents correct // TODO comment format.
Expand Down Expand Up @@ -53,10 +55,10 @@ func main() {

// run analyses TODO comments.
func run(pass *analysis.Pass) (any, error) {
var client *client
var client *github.Client

if !pass.Analyzer.Flags.Lookup("offline").Value.(flag.Getter).Get().(bool) {
p, err := cacheFilePath()
p, err := github.CacheFilePath()
if err != nil {
log.Panic(err)
}
Expand All @@ -71,7 +73,7 @@ func run(pass *analysis.Pass) (any, error) {
clientDebugF = log.New(log.Writer(), "client-debug: ", log.Flags()).Printf
}

if client, err = newClient(p, log.Printf, cacheDebugF, clientDebugF); err != nil {
if client, err = github.NewClient(p, log.Printf, cacheDebugF, clientDebugF); err != nil {
log.Panic(err)
}
}
Expand Down Expand Up @@ -119,11 +121,11 @@ func run(pass *analysis.Pass) (any, error) {
}

switch status {
case issueOpen:
case github.IssueOpen:
// nothing
case issueClosed:
case github.IssueClosed:
pass.Reportf(c.Pos(), "invalid TODO: linked issue %s is closed", url)
case issueNotFound:
case github.IssueNotFound:
pass.Reportf(c.Pos(), "invalid TODO: linked issue %s is not found", url)
default:
log.Panicf("unknown issue status: %s", status)
Expand Down
84 changes: 3 additions & 81 deletions tools/checkcomments/checkcomments_test.go
Expand Up @@ -15,102 +15,24 @@
package main

import (
"context"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/tools/go/analysis/analysistest"

"github.com/FerretDB/FerretDB/tools/github"
)

func TestCheckCommentIssue(t *testing.T) {
t.Parallel()

path, err := cacheFilePath()
path, err := github.CacheFilePath()
require.NoError(t, err)

err = os.MkdirAll(filepath.Dir(path), 0o777)
require.NoError(t, err)

analysistest.Run(t, analysistest.TestData(), analyzer)
}

func TestCacheFilePath(t *testing.T) {
t.Parallel()

wd, err := os.Getwd()
require.NoError(t, err)
expected := filepath.Join(wd, "..", "..", "tmp", "githubcache", "cache.json")

actual, err := cacheFilePath()
require.NoError(t, err)
assert.Equal(t, expected, actual)
}

func TestClient(t *testing.T) {
t.Parallel()

cacheFilePath := filepath.Join(t.TempDir(), "cache.json")
ctx := context.Background()

t.Run("CheckIssueStatus", func(t *testing.T) {
t.Parallel()

c, err := newClient(cacheFilePath, t.Logf, t.Logf, t.Logf)
require.NoError(t, err)

actual, err := c.checkIssueStatus(ctx, "FerretDB", 10)
require.NoError(t, err)
assert.Equal(t, issueOpen, actual)

actual, err = c.checkIssueStatus(ctx, "FerretDB", 1)
require.NoError(t, err)
assert.Equal(t, issueClosed, actual)

actual, err = c.checkIssueStatus(ctx, "FerretDB", 999999)
require.NoError(t, err)
assert.Equal(t, issueNotFound, actual)
})

t.Run("IssueStatus", func(t *testing.T) {
t.Parallel()

c, err := newClient(cacheFilePath, t.Logf, t.Logf, t.Logf)
require.NoError(t, err)

actual, err := c.IssueStatus(ctx, "https://github.com/FerretDB/FerretDB/issues/10", "FerretDB", 10)
require.NoError(t, err)
assert.Equal(t, issueOpen, actual)

actual, err = c.IssueStatus(ctx, "https://github.com/FerretDB/FerretDB/issues/1", "FerretDB", 1)
require.NoError(t, err)
assert.Equal(t, issueClosed, actual)

actual, err = c.IssueStatus(ctx, "https://github.com/FerretDB/FerretDB/issues/999999", "FerretDB", 999999)
require.NoError(t, err)
assert.Equal(t, issueNotFound, actual)

// The following tests should use cache and not the client,
// but it may be empty if tests above failed for some reason.

if t.Failed() {
return
}

c.c = nil

actual, err = c.IssueStatus(ctx, "https://github.com/FerretDB/FerretDB/issues/10", "FerretDB", 10)
require.NoError(t, err)
assert.Equal(t, issueOpen, actual)

actual, err = c.IssueStatus(ctx, "https://github.com/FerretDB/FerretDB/issues/1", "FerretDB", 1)
require.NoError(t, err)
assert.Equal(t, issueClosed, actual)

actual, err = c.IssueStatus(ctx, "https://github.com/FerretDB/FerretDB/issues/999999", "FerretDB", 999999)
require.NoError(t, err)
assert.Equal(t, issueNotFound, actual)
})
}
104 changes: 104 additions & 0 deletions tools/checkdocs/checkdocs.go
Expand Up @@ -18,21 +18,39 @@ package main
import (
"bufio"
"bytes"
"context"
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/FerretDB/gh"

"github.com/FerretDB/FerretDB/tools/github"
)

// issueRE represents correct {{STATUS}} | (issue)[{{URL}}] format in the markdown files containing tables.
var issueRE = regexp.MustCompile(`\[(i?)(Issue)]\((\Qhttps://github.com/FerretDB/\E([-\w]+)/issues/(\d+))\)`)

func main() {
files, err := filepath.Glob(filepath.Join("website", "blog", "*.md"))
if err != nil {
log.Fatal(err)
}

checkFiles(files, log.Printf, log.Fatalf)

tableFile, err := filepath.Abs(filepath.Join("website", "docs", "reference", "supported-commands.md"))
if err != nil {
log.Fatal(err)
}

if err = checkTableFile(tableFile, log.Printf, log.Fatalf); err != nil {
log.Fatal(err)
}
}

// checkFiles verifies that blog posts are correctly formatted,
Expand Down Expand Up @@ -220,3 +238,89 @@ func verifyTags(fm []byte) error {

return nil
}

// checkTableFile verifies that supported-commands.md is correctly formatted,
// using logf for progress reporting and fatalf for errors.
func checkTableFile(file string, logf, fatalf func(string, ...any)) error {
fileInBytes, err := os.ReadFile(file)
if err != nil {
return fmt.Errorf("couldn't read file %s: %s", file, err)
}

verifyIssues(fileInBytes, logf, fatalf)

return nil
}

// verifyIssues checks that listed issues statuses.
func verifyIssues(fm []byte, logf, fatalf func(string, ...any)) {
p, err := github.CacheFilePath()
if err != nil {
log.Panic(err)
}

clientDebugF := gh.NoopPrintf

client, err := github.NewClient(p, log.Printf, logf, clientDebugF)
if err != nil {
log.Panic(err)
}

s := bufio.NewScanner(bytes.NewReader(fm))
for s.Scan() {
line := s.Text()

match := issueRE.FindStringSubmatch(line)
if len(match) == 0 {
continue
}

expectedMatchLen := 6

if len(match) != expectedMatchLen {
logf("invalid [issue]({URL}) format: %s", line)
continue
}

url := match[3]
repo := match[4]

var num int

num, err = strconv.Atoi(match[5])
if err != nil {
fatalf(err.Error())
}

if num <= 0 {
logf("invalid [issue]({URL}) incorrect issue number")
continue
}

if client == nil {
continue
}

var status github.IssueStatus

status, err = client.IssueStatus(context.TODO(), url, repo, num)
if err != nil {
fatalf(err.Error())
}

switch status {
case github.IssueOpen:
// nothing
case github.IssueClosed:
logf("invalid [issue]({URL}) linked issue %s is closed", url)
case github.IssueNotFound:
logf("invalid [issue]({URL}) linked issue %s is not found", url)
default:
log.Panicf("unknown issue status: %s", status)
}
}

if err = s.Err(); err != nil {
fatalf("error reading input: %s", err)
}
}
24 changes: 24 additions & 0 deletions tools/checkdocs/checkdocs_test.go
Expand Up @@ -16,11 +16,15 @@ package main

import (
"bytes"
"os"
"path/filepath"
"testing"

"github.com/FerretDB/gh"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/FerretDB/FerretDB/tools/github"
)

func TestReal(t *testing.T) {
Expand Down Expand Up @@ -67,3 +71,23 @@ func TestVerifyTruncateString(t *testing.T) {
err := verifyTruncateString(fm)
assert.EqualError(t, err, "<!--truncate--> must be included to have \"Read more\" link on the homepage")
}

func TestVerifyIssues(t *testing.T) {
t.Parallel()

path, err := github.CacheFilePath()
require.NoError(t, err)

err = os.MkdirAll(filepath.Dir(path), 0o777)
require.NoError(t, err)

t.Run("Empty fm", func(t *testing.T) {
verifyIssues(nil, gh.NoopPrintf, gh.NoopPrintf)
})

t.Run("Sample row", func(t *testing.T) {
fm = []byte("| ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/4035) |")

verifyIssues(fm, gh.NoopPrintf, gh.NoopPrintf)
})
}