diff --git a/tools/go.mod b/tools/go.mod index 1660b4cbf..7257b66fe 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -12,11 +12,9 @@ require ( github.com/creachadair/command v0.1.13 github.com/creachadair/flax v0.0.0-20240525192034-44db93b3a8ad github.com/creachadair/mds v0.15.2 - github.com/google/go-github/v63 v63.0.0 + github.com/creachadair/taskgroup v0.9.0 + github.com/google/go-github/v67 v67.0.0 github.com/natefinch/atomic v1.0.1 ) -require ( - github.com/creachadair/taskgroup v0.9.0 // indirect - github.com/google/go-querystring v1.1.0 // indirect -) +require github.com/google/go-querystring v1.1.0 // indirect diff --git a/tools/go.sum b/tools/go.sum index 09822230a..31fffa06b 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -6,11 +6,13 @@ github.com/creachadair/mds v0.15.2 h1:es1qGKgRGSaztpvrSQcZ0B9I6NsHYJ1Sa9naD/3OfC github.com/creachadair/mds v0.15.2/go.mod h1:4vrFYUzTXMJpMBU+OA292I6IUxKWCCfZkgXg+/kBZMo= github.com/creachadair/taskgroup v0.9.0 h1:kzXSea5C7R5DtnKFBOTEW3hvmCkiVnRkODMVDMgSS6k= github.com/creachadair/taskgroup v0.9.0/go.mod h1:+1hJc8zL1rQkxcMVqEYJ0UPGtwl6Iz1+fd4zcOLtt+A= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v63 v63.0.0 h1:13xwK/wk9alSokujB9lJkuzdmQuVn2QCPeck76wR3nE= -github.com/google/go-github/v63 v63.0.0/go.mod h1:IqbcrgUmIcEaioWrGYei/09o+ge5vhffGOcxrO0AfmA= +github.com/google/go-github/v67 v67.0.0 h1:g11NDAmfaBaCO8qYdI9fsmbaRipHNWRIU/2YGvlh4rg= +github.com/google/go-github/v67 v67.0.0/go.mod h1:zH3K7BxjFndr9QSeFibx4lTKkYS3K9nDanoI1NjaOtY= 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/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= diff --git a/tools/internal/github/pr.go b/tools/internal/github/pr.go index 69e683d89..ad16706f5 100644 --- a/tools/internal/github/pr.go +++ b/tools/internal/github/pr.go @@ -9,7 +9,7 @@ import ( "os" "time" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v67/github" ) // Client is a GitHub API client that performs PSL-specific @@ -185,3 +185,11 @@ func (c *Repo) PSLForHash(ctx context.Context, hash string) ([]byte, error) { } return []byte(ret), nil } + +func (c *Repo) LabelPullRequest(ctx context.Context, prNum int, labels []string) error { + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + _, _, err := c.apiClient().Issues.ReplaceLabelsForIssue(ctx, c.owner(), c.repo(), prNum, labels) + return err +} diff --git a/tools/psltool/errors.go b/tools/psltool/errors.go new file mode 100644 index 000000000..01d5693b9 --- /dev/null +++ b/tools/psltool/errors.go @@ -0,0 +1,100 @@ +package main + +import ( + "errors" + "reflect" + + "github.com/publicsuffix/list/tools/internal/parser" +) + +const ( + invalidTag = "❌invalid" + dnsFailTag = "❌FAIL - DNS VALIDATION" + sortFailTag = "❌FAIL - FIX SORTING ⏬" +) + +var errToLabel = map[error]string{ + // all parser errors, sort in alphabetical order + //parser.ErrCommentPreventsSectionSort{}: "", + parser.ErrConflictingSuffixAndException{}: invalidTag, + //parser.ErrCommentPreventsSuffixSort{}: "", + parser.ErrDuplicateSection{}: invalidTag, + parser.ErrDuplicateSuffix{}: invalidTag, + parser.ErrInvalidEncoding{}: invalidTag, + parser.ErrInvalidSuffix{}: invalidTag, + parser.ErrInvalidUnicode{}: invalidTag, + parser.ErrMissingEntityEmail{}: invalidTag, + parser.ErrMissingEntityName{}: invalidTag, + parser.ErrMissingSection{}: invalidTag, + parser.ErrMissingTXTRecord{}: dnsFailTag, + parser.ErrMismatchedSection{}: invalidTag, + parser.ErrNestedSection{}: invalidTag, + parser.ErrSectionInSuffixBlock{}: invalidTag, + parser.ErrTXTCheckFailure{}: dnsFailTag, + parser.ErrTXTRecordMismatch{}: dnsFailTag, + parser.ErrUnclosedSection{}: invalidTag, + parser.ErrUnknownSection{}: invalidTag, + parser.ErrUnknownSectionMarker{}: invalidTag, + parser.ErrUnknownSectionMarker{}: invalidTag, + parser.ErrUnclosedSection{}: invalidTag, + + // all other errors + ErrReformat: sortFailTag, +} + +var ( + ErrReformat = errors.New("file needs reformatting, run 'psltool fmt' to fix") +) + +func errorsToLabels(errs []error) []string { + labels := make([]string, 0, len(errs)) + + var ( + sortSuccess = true + dnsSuccess = true + ) + setLabel := func(label string) { + switch label { + case sortFailTag: + sortSuccess = false + case dnsFailTag: + dnsSuccess = false + } + labels = append(labels, label) + } + + for _, err := range errs { + if label, ok := errToLabel[err]; ok { + setLabel(label) + continue + } + for tpl, label := range errToLabel { + if isType(err, tpl) { + setLabel(label) + break + } + } + } + + if sortSuccess { + labels = append(labels, "✔️Sorting Validated") + } + if dnsSuccess { + labels = append(labels, "✔️DNS _psl Validated") + } + + return labels +} + +func isType(err error, tpl error) bool { + if errors.Is(err, tpl) { + return true + } + if reflect.TypeOf(err) == reflect.TypeOf(tpl) { + return true + } + if wraped, ok := err.(interface{ Unwrap() error }); ok { + return isType(wraped.Unwrap(), tpl) + } + return false +} diff --git a/tools/psltool/psltool.go b/tools/psltool/psltool.go index 5bcecbd55..b859e3c0b 100644 --- a/tools/psltool/psltool.go +++ b/tools/psltool/psltool.go @@ -258,7 +258,15 @@ func runCheckPR(env *command.Env, prStr string) error { clean := after.MarshalPSL() if !bytes.Equal(withPR, clean) { - errs = append(errs, errors.New("file needs reformatting, run 'psltool fmt' to fix")) + errs = append(errs, ErrReformat) + } + + // Label the PR base on our errors + if len(errs) > 0 { + labels := errorsToLabels(errs) + if err := client.LabelPullRequest(env.Context(), pr, labels); err != nil { + return fmt.Errorf("failed to set labels on PR: %w", err) + } } // Print the blocks marked changed, so a human can check that