diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 2e051e1..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -dist/** -diff linguist-generated=true \ No newline at end of file diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml deleted file mode 100644 index 8b0bebd..0000000 --- a/.github/workflows/build-test.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: Build & Test - -on: - pull_request: - paths-ignore: - - '**.md' - push: - branches: - - main - - releases/* - paths-ignore: - - '**.md' - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: '1.16.5' - - run: go build -o gh-release . - - run: go test ./... diff --git a/.github/workflows/gh-release.yaml b/.github/workflows/gh-release.yaml deleted file mode 100644 index 2be09b3..0000000 --- a/.github/workflows/gh-release.yaml +++ /dev/null @@ -1,24 +0,0 @@ -name: GitHub Release - -on: - push: - branches: - - main - paths: - - 'RELEASE' - pull_request: - types: [opened, synchronize] - branches: - - main - paths: - - 'RELEASE' - -jobs: - gh-release: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - uses: ./ - with: - release_file: 'RELEASE' - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile index 4193610..a90103a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1 @@ -FROM golang:1.16.5-alpine3.14 - -RUN apk update && apk add git - -COPY . /app - -RUN cd /app && \ - go build -o /gh-release . && \ - chmod +x /gh-release - -ENTRYPOINT ["/gh-release"] +FROM gcr.io/pipecd/actions-gh-release:2.3.4 diff --git a/Makefile b/Makefile deleted file mode 100644 index 68750ab..0000000 --- a/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -.PHONY: build -build: - go build -o gh-release . - -.PHONY: test -test: - go test ./... - -.PHONY: dep -dep: - go mod tidy diff --git a/README.md b/README.md index 3cd8701..97935da 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - uses: pipe-cd/actions-gh-release@v2.2.0 + - uses: pipe-cd/actions-gh-release@v2.3.4 with: release_file: '**/RELEASE' token: ${{ secrets.GITHUB_TOKEN }} diff --git a/RELEASE b/RELEASE deleted file mode 100644 index d8c1b90..0000000 --- a/RELEASE +++ /dev/null @@ -1,21 +0,0 @@ -tag: v1.1.0 - -commitExclude: - prefixes: - - "Merge pull request #" - -commitCategories: - - title: "Breaking Changes" - contains: - - change-category/breaking-change - - title: "New Features" - contains: - - change-category/new-feature - - title: "Notable Changes" - contains: - - change-category/notable-change - - title: "Internal Changes" - -releaseNoteGenerator: - showCommitter: true - useReleaseNoteBlock: true diff --git a/comment.go b/comment.go deleted file mode 100644 index cc1a1f0..0000000 --- a/comment.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "fmt" - "strings" -) - -const ( - successBadgeURL = ` -[![RELEASE](https://img.shields.io/static/v1?label=GitHub&message=RELEASE&color=success&style=flat)](https://github.com/pipe-cd/actions-gh-release) - -` -) - -func makeCommentBody(proposals []ReleaseProposal, exists []ReleaseProposal) string { - var b strings.Builder - b.WriteString(successBadgeURL) - - if len(proposals) == 0 { - if len(exists) == 0 { - fmt.Fprintf(&b, "No GitHub releases will be created one this pull request got merged. Because this pull request did not modified any RELEASE files.\n") - return b.String() - } - - fmt.Fprintf(&b, "No GitHub releases will be created one this pull request got merged. Because the following tags were already created before.\n") - for _, p := range exists { - fmt.Fprintf(&b, "- %s\n", p.Tag) - } - return b.String() - } - - b.WriteString(fmt.Sprintf("The following %d GitHub releases will be created once this pull request got merged.\n", len(proposals))) - for _, p := range proposals { - fmt.Fprintf(&b, "\n") - fmt.Fprintf(&b, p.ReleaseNote) - fmt.Fprintf(&b, "\n") - } - - if len(exists) > 0 { - fmt.Fprintf(&b, "The following %d releases will be skipped because they were already created before.\n", len(exists)) - for _, p := range exists { - fmt.Fprintf(&b, "- %s\n", p.Tag) - } - } - - return b.String() -} diff --git a/comment_test.go b/comment_test.go deleted file mode 100644 index 1c96504..0000000 --- a/comment_test.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestMakeCommentBody(t *testing.T) { - testcases := []struct { - name string - proposals []ReleaseProposal - exists []ReleaseProposal - expected string - }{ - { - name: "no release", - expected: "testdata/no-release-comment.txt", - }, - { - name: "one release", - proposals: []ReleaseProposal{ - ReleaseProposal{ - ReleaseNote: "Release note for tag 1", - }, - }, - expected: "testdata/one-release-comment.txt", - }, - { - name: "multiple releases", - proposals: []ReleaseProposal{ - ReleaseProposal{ - ReleaseNote: "Release note for tag 1", - }, - ReleaseProposal{ - ReleaseNote: "Release note for tag 2", - }, - }, - expected: "testdata/multi-release-comment.txt", - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - got := makeCommentBody(tc.proposals, tc.exists) - expected, err := testdata.ReadFile(tc.expected) - require.NoError(t, err) - - assert.Equal(t, string(expected), got) - }) - } -} diff --git a/filematcher.go b/filematcher.go deleted file mode 100644 index 28fb13f..0000000 --- a/filematcher.go +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Copyright 2013-2018 Docker, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "errors" - "os" - "path/filepath" - "regexp" - "strings" - "text/scanner" -) - -type RegexpProvider func(string) (*regexp.Regexp, error) - -// PatternMatcher allows checking paths against a list of patterns. -type PatternMatcher struct { - patterns []*Pattern - exclusions []*Pattern - regexpProvider RegexpProvider -} - -// An Option configures a PatternMatcher. -type Option func(*PatternMatcher) - -// WithRegexpProvider sets a custom regexp provider. -func WithRegexpProvider(p RegexpProvider) Option { - return func(pm *PatternMatcher) { - pm.regexpProvider = p - } -} - -// NewPatternMatcher creates a new matcher object for specific patterns that can -// be used later to match against patterns against paths. -func NewPatternMatcher(patterns []string, opts ...Option) (*PatternMatcher, error) { - pm := &PatternMatcher{ - regexpProvider: regexp.Compile, - } - for _, opt := range opts { - opt(pm) - } - for _, p := range patterns { - // Eliminate leading and trailing whitespace. - p = strings.TrimSpace(p) - if p == "" { - continue - } - p = filepath.Clean(p) - negative := false - if p[0] == '!' { - if len(p) == 1 { - return nil, errors.New("illegal exclusion pattern: \"!\"") - } - p = p[1:] - negative = true - } - // Do some syntax checking on the pattern. - // filepath's Match() has some really weird rules that are inconsistent - // so instead of trying to dup their logic, just call Match() for its - // error state and if there is an error in the pattern return it. - // If this becomes an issue we can remove this since its really only - // needed in the error (syntax) case - which isn't really critical. - if _, err := filepath.Match(p, "."); err != nil { - return nil, err - } - newp := &Pattern{ - cleanedPattern: p, - dirs: strings.Split(p, string(os.PathSeparator)), - } - regexp, err := pm.regexpProvider(newp.regexpString()) - if err != nil { - return nil, filepath.ErrBadPattern - } - newp.regexp = regexp - if negative { - pm.exclusions = append(pm.exclusions, newp) - } else { - pm.patterns = append(pm.patterns, newp) - } - } - return pm, nil -} - -// Matches matches path against all the patterns. Matches is not safe to be -// called concurrently. -func (pm *PatternMatcher) Matches(file string) bool { - matched := matches(file, pm.exclusions) - if matched { - return false - } - return matches(file, pm.patterns) -} - -func (pm *PatternMatcher) MatchesAny(files []string) bool { - for _, file := range files { - if pm.Matches(file) { - return true - } - } - return false -} - -func matches(file string, patterns []*Pattern) bool { - file = filepath.FromSlash(file) - parentPath := filepath.Dir(file) - parentPathDirs := strings.Split(parentPath, string(os.PathSeparator)) - - for _, pattern := range patterns { - matched := pattern.regexp.MatchString(file) - if !matched && parentPath != "." { - // Check to see if the pattern matches one of our parent dirs. - if len(pattern.dirs) <= len(parentPathDirs) { - matched = pattern.regexp.MatchString(strings.Join(parentPathDirs[:len(pattern.dirs)], string(os.PathSeparator))) - } - } - if matched { - return true - } - } - return false -} - -// Exclusions returns array of negative patterns. -func (pm *PatternMatcher) Exclusions() []*Pattern { - return pm.exclusions -} - -// Patterns returns array of active patterns. -func (pm *PatternMatcher) Patterns() []*Pattern { - return pm.patterns -} - -// Pattern defines a single regexp used to filter file paths. -type Pattern struct { - cleanedPattern string - dirs []string - regexp *regexp.Regexp -} - -func (p *Pattern) String() string { - return p.cleanedPattern -} - -func (p *Pattern) regexpString() string { - regStr := "^" - pattern := p.cleanedPattern - // Go through the pattern and convert it to a regexp. - // We use a scanner so we can support utf-8 chars. - var scan scanner.Scanner - scan.Init(strings.NewReader(pattern)) - - sl := string(os.PathSeparator) - escSL := sl - if sl == `\` { - escSL += `\` - } - - for scan.Peek() != scanner.EOF { - ch := scan.Next() - - if ch == '*' { - if scan.Peek() == '*' { - // Is some flavor of "**". - scan.Next() - - // Treat **/ as ** so eat the "/". - if string(scan.Peek()) == sl { - scan.Next() - } - - if scan.Peek() == scanner.EOF { - // Is "**EOF" - to align with .gitignore just accept all. - regStr += ".*" - } else { - // Is "**". - // Note that this allows for any # of /'s (even 0) because - // the .* will eat everything, even /'s. - regStr += "(.*" + escSL + ")?" - } - } else { - // Is "*" so map it to anything but "/". - regStr += "[^" + escSL + "]*" - } - } else if ch == '?' { - // "?" is any char except "/". - regStr += "[^" + escSL + "]" - } else if ch == '.' || ch == '$' { - // Escape some regexp special chars that have no meaning - // in golang's filepath.Match. - regStr += `\` + string(ch) - } else if ch == '\\' { - // Escape next char. Note that a trailing \ in the pattern - // will be left alone (but need to escape it). - if sl == `\` { - // On windows map "\" to "\\", meaning an escaped backslash, - // and then just continue because filepath.Match on - // Windows doesn't allow escaping at all. - regStr += escSL - continue - } - if scan.Peek() != scanner.EOF { - regStr += `\` + string(scan.Next()) - } else { - regStr += `\` - } - } else { - regStr += string(ch) - } - } - regStr += "$" - return regStr -} - -// Matches returns true if file matches any of the patterns -// and isn't excluded by any of the subsequent patterns. -func Matches(file string, patterns []string, opts ...Option) (bool, error) { - pm, err := NewPatternMatcher(patterns, opts...) - if err != nil { - return false, err - } - file = filepath.Clean(file) - - if file == "." { - // Don't let them exclude everything, kind of silly. - return false, nil - } - - return pm.Matches(file), nil -} diff --git a/git.go b/git.go deleted file mode 100644 index 25491bb..0000000 --- a/git.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "bytes" - "context" - "fmt" - "os/exec" - "strconv" - "strings" -) - -const ( - separator = "__GIT_LOG_SEPARATOR__" - delimiter = "__GIT_LOG_DELIMITER__" - fieldNum = 9 - commitLogFormat = separator + - "%an" + delimiter + // author name - "%cn" + delimiter + // committer name - "%at" + delimiter + // author date (UNIX timestamp) - "%H" + delimiter + // commit hash - "%h" + delimiter + // abbreviated commit hash - "%P" + delimiter + // parent hashes - "%p" + delimiter + // abbreviated parent hashes - "%s" + delimiter + // subject - "%b" // body -) - -type Commit struct { - Author string `json:"author,omitempty"` - Committer string `json:"committer,omitempty"` - CreatedAt int `json:"createdAt,omitempty"` - Hash string `json:"hash,omitempty"` - AbbreviatedHash string `json:"abbreviatedHash,omitempty"` - ParentHashes []string `json:"parentHashes,omitempty"` - AbbreviatedParentHashes []string `json:"abbreviatedParentHashes,omitempty"` - Subject string `json:"subject,omitempty"` - Body string `json:"body,omitempty"` -} - -func (c Commit) IsMerge() bool { - return len(c.ParentHashes) == 2 -} - -func (c Commit) PullRequestNumber() (int, bool) { - if !c.IsMerge() { - return 0, false - } - - subs := defaultMergeCommitRegex.FindStringSubmatch(c.Subject) - if len(subs) != 2 { - return 0, false - } - - prNumber, err := strconv.Atoi(subs[1]) - if err != nil { - return 0, false - } - - return prNumber, true -} - -func parseCommits(log string) ([]Commit, error) { - lines := strings.Split(log, separator) - if len(lines) < 1 { - return nil, fmt.Errorf("invalid log") - } - commits := make([]Commit, 0, len(lines)) - for _, line := range lines[1:] { - commit, err := parseCommit(line) - if err != nil { - return nil, err - } - commits = append(commits, commit) - } - return commits, nil -} - -func parseCommit(log string) (Commit, error) { - fields := strings.Split(log, delimiter) - if len(fields) != fieldNum { - return Commit{}, fmt.Errorf("invalid log: log line should contain %d fields but got %d", fieldNum, len(fields)) - } - createdAt, err := strconv.Atoi(fields[2]) - if err != nil { - return Commit{}, err - } - return Commit{ - Author: fields[0], - Committer: fields[1], - CreatedAt: createdAt, - Hash: fields[3], - AbbreviatedHash: fields[4], - ParentHashes: strings.Split(fields[5], " "), - AbbreviatedParentHashes: strings.Split(fields[6], " "), - Subject: fields[7], - Body: strings.TrimSpace(fields[8]), - }, nil -} - -// listCommits returns a list of commits between the given revision range. -func listCommits(ctx context.Context, gitExecPath, repoDir string, revisionRange string) ([]Commit, error) { - args := []string{ - "log", - "--no-decorate", - fmt.Sprintf("--pretty=format:%s", commitLogFormat), - } - if revisionRange != "" { - args = append(args, revisionRange) - } - - cmd := exec.CommandContext(ctx, gitExecPath, args...) - cmd.Dir = repoDir - out, err := cmd.CombinedOutput() - if err != nil { - return nil, fmt.Errorf("err: %w, out: %s", err, string(out)) - } - - return parseCommits(string(out)) -} - -// changedFiles returns a list of files those were touched between two commits. -func changedFiles(ctx context.Context, gitExecPath, repoDir, from, to string) ([]string, error) { - cmd := exec.CommandContext(ctx, gitExecPath, "diff", "--name-only", from, to) - cmd.Dir = repoDir - out, err := cmd.CombinedOutput() - - if err != nil { - return nil, fmt.Errorf("err: %w, out: %s", err, string(out)) - } - - var ( - lines = strings.Split(string(out), "\n") - files = make([]string, 0, len(lines)) - ) - // We need to remove all empty lines since the result may include them. - for _, f := range lines { - if f != "" { - files = append(files, f) - } - } - return files, nil -} - -// readFileAtCommit reads the content of a specific file at the given commit. -func readFileAtCommit(ctx context.Context, gitExecPath, repoDir, filePath, commit string) ([]byte, error) { - args := []string{ - "show", - fmt.Sprintf("%s:%s", commit, filePath), - } - - cmd := exec.CommandContext(ctx, gitExecPath, args...) - cmd.Dir = repoDir - out, err := cmd.CombinedOutput() - if err != nil { - return nil, fmt.Errorf("err: %w, out: %s", err, string(out)) - } - - return bytes.TrimSpace(out), nil -} diff --git a/git_test.go b/git_test.go deleted file mode 100644 index c1d8528..0000000 --- a/git_test.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "sort" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestParseCommit(t *testing.T) { - log, err := testdata.ReadFile("testdata/log.txt") - require.NoError(t, err) - require.NotNil(t, log) - - expected := []Commit{ - { - Author: "nghialv", - Committer: "kapetanios-robot", - CreatedAt: 1565752022, - Hash: "74e20ede0242fdc7fd75b5be56e8d7fa72060707", - AbbreviatedHash: "74e20ed", - ParentHashes: []string{"ea8674c36467fc4d5a2e7900fa47e6c0d7b40948"}, - AbbreviatedParentHashes: []string{"ea8674c"}, - Subject: "wip", - }, - { - Author: "Le Van Nghia", - Committer: "kapetanios-robot", - CreatedAt: 1565749682, - Hash: "c9a7596e7e92ea5e3f03eeb951f632acb02b88a3", - AbbreviatedHash: "c9a7596", - ParentHashes: []string{"74e20ede0242fdc7fd75b5be56e8d7fa72060707"}, - AbbreviatedParentHashes: []string{"74e20ed"}, - Subject: `Add implementation of inplug service (#648)`, - Body: `**What this PR does / why we need it**: - -**Which issue(s) this PR fixes**: - -Fixes # - -**Does this PR introduce a user-facing change?**: - -` + "```" + `release-note -NONE -` + "```" + ` - -This PR was merged by Kapetanios.`, - }, - { - Author: "nghialv", - Committer: "kapetanios-robot", - CreatedAt: 2565752022, - Hash: "24e20ede0242fdc7fd75b5be56e8d7fa72060707", - AbbreviatedHash: "24e20ed", - ParentHashes: []string{"74e20ede0242fdc7fd75b5be56e8d7fa72060707", "c9a7596e7e92ea5e3f03eeb951f632acb02b88a3"}, - AbbreviatedParentHashes: []string{"74e20ed", "c9a7596"}, - Subject: `Added commands to "kapectl" for creating, updating project secret (#475)`, - }, - } - commits, err := parseCommits(string(log)) - require.NoError(t, err) - sort.Slice(expected, func(i, j int) bool { - return expected[i].Hash > expected[j].Hash - }) - sort.Slice(commits, func(i, j int) bool { - return commits[i].Hash > commits[j].Hash - }) - assert.Equal(t, expected, commits) -} diff --git a/github.go b/github.go deleted file mode 100644 index 27ee777..0000000 --- a/github.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "fmt" - "io/ioutil" - "net/http" - "os" - "regexp" - - "github.com/google/go-github/v39/github" - "golang.org/x/oauth2" -) - -var ( - defaultMergeCommitRegex = regexp.MustCompile(`Merge pull request #([0-9]+) from .+`) -) - -type ( - PullRequestState string - PullRequestSort string - PullRequestDirection string -) - -const ( - // PullRequestState - PullRequestStateOpen PullRequestState = "open" - PullRequestStateClosed PullRequestState = "closed" - PullRequestStateAll PullRequestState = "all" - - // PullRequestSort - PullRequestSortCreated PullRequestSort = "created" - PullRequestSortUpdated PullRequestSort = "updated" - PullRequestSortPopularity PullRequestSort = "popularity" - PullRequestSortLongRunning PullRequestSort = "long-running" - - // PullRequestDirection - PullRequestDirectionAsc PullRequestDirection = "asc" - PullRequestDirectionDesc PullRequestDirection = "desc" -) - -type githubEvent struct { - Name string - - Owner string - Repo string - - HeadCommit string - BaseCommit string - - PRNumber int - IsComment bool - CommentURL string -} - -const ( - eventPush = "push" - eventPullRequest = "pull_request" - eventIssueComment = "issue_comment" -) - -type githubClient struct { - restClient *github.Client -} - -type githubClientConfig struct { - Token string -} - -func (p PullRequestState) String() string { - return string(p) -} - -func (p PullRequestSort) String() string { - return string(p) -} - -func (p PullRequestDirection) String() string { - return string(p) -} - -func newGitHubClient(ctx context.Context, cfg *githubClientConfig) *githubClient { - var httpClient *http.Client - if cfg.Token != "" { - t := &oauth2.Token{AccessToken: cfg.Token} - ts := oauth2.StaticTokenSource(t) - httpClient = oauth2.NewClient(ctx, ts) - } - - return &githubClient{ - restClient: github.NewClient(httpClient), - } -} - -// parsePullRequestEvent uses the given environment variables -// to parse and build githubEvent struct. -func (g *githubClient) parseGitHubEvent(ctx context.Context) (*githubEvent, error) { - var parseEvents = map[string]struct{}{ - eventPush: {}, - eventPullRequest: {}, - eventIssueComment: {}, - } - - eventName := os.Getenv("GITHUB_EVENT_NAME") - if _, ok := parseEvents[eventName]; !ok { - return &githubEvent{ - Name: eventName, - }, nil - } - - eventPath := os.Getenv("GITHUB_EVENT_PATH") - payload, err := ioutil.ReadFile(eventPath) - if err != nil { - return nil, fmt.Errorf("failed to read event payload: %v", err) - } - - event, err := github.ParseWebHook(eventName, payload) - if err != nil { - return nil, fmt.Errorf("failed to parse event payload: %v", err) - } - - switch e := event.(type) { - case *github.PushEvent: - return &githubEvent{ - Name: eventPush, - Owner: e.Repo.Owner.GetLogin(), - Repo: e.Repo.GetName(), - HeadCommit: e.GetAfter(), - BaseCommit: e.GetBefore(), - }, nil - - case *github.PullRequestEvent: - return &githubEvent{ - Name: eventPullRequest, - Owner: e.Repo.Owner.GetLogin(), - Repo: e.Repo.GetName(), - HeadCommit: e.PullRequest.Head.GetSHA(), - BaseCommit: e.PullRequest.Base.GetSHA(), - PRNumber: e.GetNumber(), - }, nil - - case *github.IssueCommentEvent: - var ( - owner = e.Repo.Owner.GetLogin() - repo = e.Repo.GetName() - prNum = e.Issue.GetNumber() - ) - - pr, _, err := g.restClient.PullRequests.Get(ctx, owner, repo, prNum) - if err != nil { - return nil, err - } - - return &githubEvent{ - Name: eventIssueComment, - Owner: owner, - Repo: repo, - HeadCommit: pr.Head.GetSHA(), - BaseCommit: pr.Base.GetSHA(), - PRNumber: prNum, - IsComment: true, - CommentURL: e.Comment.GetHTMLURL(), - }, nil - - default: - return nil, fmt.Errorf("got an unexpected event type, got: %t", e) - } -} - -func (g *githubClient) sendComment(ctx context.Context, owner, repo string, prNum int, body string) (*github.IssueComment, error) { - c, _, err := g.restClient.Issues.CreateComment(ctx, owner, repo, prNum, &github.IssueComment{ - Body: &body, - }) - return c, err -} - -func (g *githubClient) createRelease(ctx context.Context, owner, repo string, p ReleaseProposal) (*github.RepositoryRelease, error) { - release, _, err := g.restClient.Repositories.CreateRelease(ctx, owner, repo, &github.RepositoryRelease{ - TagName: &p.Tag, - Name: &p.Title, - TargetCommitish: &p.TargetCommitish, - Body: &p.ReleaseNote, - Prerelease: &p.Prerelease, - }) - return release, err -} - -func (g *githubClient) existRelease(ctx context.Context, owner, repo, tag string) (bool, error) { - _, resp, err := g.restClient.Repositories.GetReleaseByTag(ctx, owner, repo, tag) - if err != nil { - if resp != nil && resp.StatusCode == http.StatusNotFound { - return false, nil - } - return false, err - } - return resp.StatusCode == http.StatusOK, nil -} - -func (g *githubClient) getPullRequest(ctx context.Context, owner, repo string, number int) (*github.PullRequest, error) { - pr, _, err := g.restClient.PullRequests.Get(ctx, owner, repo, number) - return pr, err -} - -type ListPullRequestOptions struct { - State PullRequestState - Sort PullRequestSort - Direction PullRequestDirection - Limit int -} - -func (g *githubClient) listPullRequests(ctx context.Context, owner, repo string, opt *ListPullRequestOptions) ([]*github.PullRequest, error) { - const perPage = 100 - listOpts := github.ListOptions{PerPage: perPage} - opts := &github.PullRequestListOptions{ - State: opt.State.String(), - Sort: opt.Sort.String(), - Direction: opt.Direction.String(), - ListOptions: listOpts, - } - ret := make([]*github.PullRequest, 0, opt.Limit) - count := opt.Limit / perPage - for i := 0; i <= count; i++ { - prs, resp, err := g.restClient.PullRequests.List(ctx, owner, repo, opts) - if err != nil { - return nil, err - } - for _, pr := range prs { - if len(ret) == opt.Limit { - break - } - ret = append(ret, pr) - } - if resp.NextPage == 0 || len(ret) == opt.Limit { - break - } - opts.Page = resp.NextPage - } - return ret, nil -} diff --git a/go.mod b/go.mod deleted file mode 100644 index e58af60..0000000 --- a/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/pipe-cd/actions-gh-release - -go 1.16 - -require ( - github.com/creasty/defaults v1.5.2 - github.com/google/go-github/v39 v39.2.0 - github.com/stretchr/testify v1.4.0 - golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 - sigs.k8s.io/yaml v1.3.0 -) diff --git a/go.sum b/go.sum deleted file mode 100644 index 8e992e9..0000000 --- a/go.sum +++ /dev/null @@ -1,388 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/creasty/defaults v1.5.2 h1:/VfB6uxpyp6h0fr7SPp7n8WJBoV8jfxQXPCnkVSjyls= -github.com/creasty/defaults v1.5.2/go.mod h1:FPZ+Y0WNrbqOVw+c6av63eyHUAl6pMHZwqLPvXUZGfY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -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.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ= -github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= -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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 h1:B333XXssMuKQeBwiNODx4TupZy7bf4sxFZnN2ZOcvUE= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/main.go b/main.go deleted file mode 100644 index 6ec7211..0000000 --- a/main.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "encoding/json" - "fmt" - "log" - "os" - "os/signal" - "strings" - "syscall" - - "github.com/google/go-github/v39/github" -) - -const ( - gitExecPath = "git" - defaultReleaseFile = "RELEASE" -) - -func main() { - log.Println("Start running actions-gh-release") - - ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) - defer stop() - - args, err := parseArgs(os.Args) - if err != nil { - log.Fatalf("Failed to parse arguments: %v\n", err) - } - log.Println("Successfully parsed arguments") - - workspace := os.Getenv("GITHUB_WORKSPACE") - if workspace == "" { - log.Fatal("GITHUB_WORKSPACE was not defined") - } - - cfg := &githubClientConfig{Token: args.Token} - ghClient := newGitHubClient(ctx, cfg) - - event, err := ghClient.parseGitHubEvent(ctx) - if err != nil { - log.Fatalf("Failed to parse GitHub event: %v\n", err) - } - log.Printf("Successfully parsed GitHub event %s\n\tbase-commit %s\n\thead-commit %s\n", - event.Name, - event.BaseCommit, - event.HeadCommit, - ) - - // Find all changed RELEASE files. - changedFiles, err := changedFiles(ctx, gitExecPath, workspace, event.BaseCommit, event.HeadCommit) - if err != nil { - log.Fatalf("Failed to list changed files: %v\n", err) - } - - changedReleaseFiles := make([]string, 0, 0) - matcher, err := NewPatternMatcher([]string{args.ReleaseFile}) - if err != nil { - log.Fatalf("Failed to create pattern matcher for release file: %v\n", err) - } - for _, f := range changedFiles { - if matcher.Matches(f) { - changedReleaseFiles = append(changedReleaseFiles, f) - } - } - - if len(changedReleaseFiles) == 0 { - log.Println("Nothing to do since there were no modified release files") - return - } - - proposals := make([]ReleaseProposal, 0, len(changedReleaseFiles)) - for _, f := range changedReleaseFiles { - p, err := buildReleaseProposal(ctx, ghClient, f, gitExecPath, workspace, event) - if err != nil { - log.Fatalf("Failed to build release for %s: %v\n", f, err) - } - proposals = append(proposals, *p) - } - - // Filter all existing releases. - var ( - newProposals = make([]ReleaseProposal, 0, len(proposals)) - existingProposals = make([]ReleaseProposal, 0) - ) - for _, p := range proposals { - if p.Tag != "" { - exist, err := ghClient.existRelease(ctx, event.Owner, event.Repo, p.Tag) - if err != nil { - log.Fatalf("Failed to check the existence of release for %s: %v\n", p.Tag, err) - } - if exist { - existingProposals = append(existingProposals, p) - continue - } - } - newProposals = append(newProposals, p) - } - - notify := func() (*github.IssueComment, error) { - body := makeCommentBody(newProposals, existingProposals) - return ghClient.sendComment(ctx, event.Owner, event.Repo, event.PRNumber, body) - } - - if len(existingProposals) != 0 { - if len(newProposals) == 0 { - log.Printf("All of %d detected releases were already created before so no new release will be created\n", len(proposals)) - notify() - return - } - log.Printf("%d releases from %d detected ones were already created before so only %d releases will be created\n", len(existingProposals), len(proposals), len(newProposals)) - } - - releasesJSON, err := json.Marshal(newProposals) - if err != nil { - log.Fatalf("Failed to marshal releases: %v\n", err) - } - fmt.Printf("::set-output name=releases::%s\n", string(releasesJSON)) - if args.OutputReleasesFilePath != "" { - if err := os.WriteFile(args.OutputReleasesFilePath, releasesJSON, 0644); err != nil { - log.Fatalf("Failed to write releases JSON to %s: %v\n", args.OutputReleasesFilePath, err) - } - log.Printf("Successfully wrote releases JSON to %s\n", args.OutputReleasesFilePath) - } - - // Create GitHub releases if the event was push. - if event.Name == eventPush { - log.Printf("Will create %d GitHub releases\n", len(newProposals)) - for _, p := range newProposals { - r, err := ghClient.createRelease(ctx, event.Owner, event.Repo, p) - if err != nil { - log.Fatalf("Failed to create release %s: %v\n", p.Tag, err) - } - log.Printf("Successfully created a new GitHub release %s\n%s\n", r.GetTagName(), r.GetHTMLURL()) - } - - log.Printf("Successfully created all %d GitHub releases\n", len(newProposals)) - return - } - - // Otherwise, just leave a comment to show the changelogs. - comment, err := notify() - if err != nil { - log.Fatalf("Failed to send comment: %v\n", err) - } - - log.Printf("Successfully commented actions-gh-release result on pull request\n%s\n", *comment.HTMLURL) -} - -type arguments struct { - ReleaseFile string - Token string - OutputReleasesFilePath string -} - -func parseArgs(args []string) (arguments, error) { - var out arguments - - for _, arg := range args { - ps := strings.SplitN(arg, "=", 2) - if len(ps) != 2 { - continue - } - switch ps[0] { - case "release-file": - out.ReleaseFile = ps[1] - case "token": - out.Token = ps[1] - case "output-releases-file-path": - out.OutputReleasesFilePath = ps[1] - } - } - - if out.ReleaseFile == "" { - out.ReleaseFile = defaultReleaseFile - } - if out.Token == "" { - return out, fmt.Errorf("token argument must be set") - } - return out, nil -} diff --git a/main_test.go b/main_test.go deleted file mode 100644 index b8c915a..0000000 --- a/main_test.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "embed" -) - -//go:embed testdata/* -var testdata embed.FS diff --git a/release.go b/release.go deleted file mode 100644 index c7bc198..0000000 --- a/release.go +++ /dev/null @@ -1,433 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "encoding/json" - "fmt" - "log" - "regexp" - "strings" - - "github.com/creasty/defaults" - "github.com/google/go-github/v39/github" - "sigs.k8s.io/yaml" -) - -var ( - releaseNoteBlockRegex = regexp.MustCompile(`(?s)(?:Release note\*\*:\s*(?:\s*)?` + "```(?:release-note)?|```release-note)(.+?)```") -) - -type ReleaseConfig struct { - Tag string `json:"tag,omitempty"` - Name string `json:"name,omitempty"` - Title string `json:"title,omitempty"` - TargetCommitish string `json:"targetCommitish,omitempty"` - ReleaseNote string `json:"releaseNote,omitempty"` - Prerelease bool `json:"prerelease,omitempty"` - - CommitInclude ReleaseCommitMatcherConfig `json:"commitInclude,omitempty"` - CommitExclude ReleaseCommitMatcherConfig `json:"commitExclude,omitempty"` - - CommitCategories []ReleaseCommitCategoryConfig `json:"commitCategories,omitempty"` - ReleaseNoteGenerator ReleaseNoteGeneratorConfig `json:"releaseNoteGenerator,omitempty"` -} - -type ReleaseCommitCategoryConfig struct { - Id string `json:"id,omitempty"` - Title string `json:"title,omitempty"` - ReleaseCommitMatcherConfig -} - -type ReleaseNoteGeneratorConfig struct { - ShowAbbrevHash bool `json:"showAbbrevHash,omitempty" default:"false"` - ShowCommitter bool `json:"showCommitter,omitempty" default:"true"` - UseReleaseNoteBlock bool `json:"useReleaseNoteBlock,omitempty" default:"false"` - UsePullRequestMetadata bool `json:"usePullRequestMetadata,omitempty" default:"false"` - CommitInclude ReleaseCommitMatcherConfig `json:"commitInclude,omitempty"` - CommitExclude ReleaseCommitMatcherConfig `json:"commitExclude,omitempty"` -} - -type ReleaseCommitMatcherConfig struct { - ParentOfMergeCommit bool `json:"parentOfMergeCommit,omitempty"` - Prefixes []string `json:"prefixes,omitempty"` - Contains []string `json:"contains,omitempty"` -} - -func (c ReleaseCommitMatcherConfig) Empty() bool { - return len(c.Prefixes)+len(c.Contains) == 0 -} - -func (c ReleaseCommitMatcherConfig) Match(commit Commit, mergeCommit *Commit) bool { - if c.ParentOfMergeCommit && mergeCommit != nil { - if c.Match(*mergeCommit, nil) { - return true - } - } - for _, s := range c.Prefixes { - if strings.HasPrefix(commit.Subject, s) { - return true - } - } - for _, s := range c.Contains { - if strings.Contains(commit.Body, s) { - return true - } - } - return false -} - -func (c *ReleaseConfig) Validate() error { - if c.Tag == "" { - return fmt.Errorf("tag must be specified") - } - return nil -} - -func parseReleaseConfig(data []byte) (*ReleaseConfig, error) { - js, err := yaml.YAMLToJSON(data) - if err != nil { - return nil, err - } - - c := &ReleaseConfig{} - if err := json.Unmarshal(js, c); err != nil { - return nil, err - } - - if err := defaults.Set(c); err != nil { - return nil, err - } - for i := range c.CommitCategories { - if c.CommitCategories[i].Id == "" { - c.CommitCategories[i].Id = fmt.Sprintf("_category_%d", i) - } - } - - if err := c.Validate(); err != nil { - return nil, err - } - return c, nil -} - -type ReleaseProposal struct { - Tag string `json:"tag,omitempty"` - Name string `json:"name,omitempty"` - Title string `json:"title,omitempty"` - TargetCommitish string `json:"targetCommitish,omitempty"` - ReleaseNote string `json:"releaseNote,omitempty"` - Prerelease bool `json:"prerelease,omitempty"` - - Owner string `json:"owner,omitempty"` - Repo string `json:"repo,omitempty"` - PreTag string `json:"preTag,omitempty"` - BaseCommit string `json:"baseCommit,omitempty"` - HeadCommit string `json:"headCommit,omitempty"` - Commits []ReleaseCommit `json:"commits,omitempty"` -} - -type ReleaseCommit struct { - Commit - ReleaseNote string `json:"releaseNote,omitempty"` - CategoryName string `json:"categoryName,omitempty"` - PullRequestNumber int `json:"pullRequestNumber,omitempty"` - PullRequestOwner string `json:"pullRequestOwner,omitempty"` -} - -func buildReleaseProposal(ctx context.Context, ghClient *githubClient, releaseFile string, gitExecPath, repoDir string, event *githubEvent) (*ReleaseProposal, error) { - configLoader := func(commit string) (*ReleaseConfig, error) { - data, err := readFileAtCommit(ctx, gitExecPath, repoDir, releaseFile, commit) - if err != nil { - return nil, err - } - return parseReleaseConfig(data) - } - - baseCfg, err := configLoader(event.BaseCommit) - if err != nil { - return nil, err - } - - headCfg, err := configLoader(event.HeadCommit) - if err != nil { - return nil, err - } - - // List all commits from the last release until now. - revisions := fmt.Sprintf("%s...%s", baseCfg.Tag, event.HeadCommit) - commits, err := listCommits(ctx, gitExecPath, repoDir, revisions) - if err != nil { - return nil, err - } - - releaseCommits, err := buildReleaseCommits(ctx, ghClient, commits, *headCfg, event) - if err != nil { - return nil, err - } - p := ReleaseProposal{ - Tag: headCfg.Tag, - Name: headCfg.Name, - Title: headCfg.Title, - TargetCommitish: headCfg.TargetCommitish, - ReleaseNote: headCfg.ReleaseNote, - Prerelease: headCfg.Prerelease, - Owner: event.Owner, - Repo: event.Repo, - PreTag: baseCfg.Tag, - BaseCommit: event.BaseCommit, - HeadCommit: event.HeadCommit, - Commits: releaseCommits, - } - - if p.Title == "" { - p.Title = fmt.Sprintf("Release %s", p.Tag) - } - if p.TargetCommitish == "" { - p.TargetCommitish = event.HeadCommit - } - if p.ReleaseNote == "" { - ln := renderReleaseNote(p, *headCfg) - p.ReleaseNote = string(ln) - } - - return &p, nil -} - -func buildReleaseCommits(ctx context.Context, ghClient *githubClient, commits []Commit, cfg ReleaseConfig, event *githubEvent) ([]ReleaseCommit, error) { - hashes := make(map[string]Commit, len(commits)) - for _, commit := range commits { - hashes[commit.Hash] = commit - } - - mergeCommits := make(map[string]*Commit, len(commits)) - for i := range commits { - commit := commits[i] - if !commit.IsMerge() { - continue - } - cursor, finish := commit.ParentHashes[1], commit.ParentHashes[0] - for { - parent, ok := hashes[cursor] - if !ok { - break - } - if parent.Hash == finish { - break - } - if len(parent.ParentHashes) != 1 { - break - } - mergeCommits[cursor] = &commit - cursor = parent.ParentHashes[0] - } - } - - gen, limit := cfg.ReleaseNoteGenerator, 1000 - prs := make(map[string]*github.PullRequest, limit) - if gen.UsePullRequestMetadata { - opts := &ListPullRequestOptions{ - State: PullRequestStateClosed, - Sort: PullRequestSortUpdated, - Direction: PullRequestDirectionDesc, - Limit: limit, - } - v, err := ghClient.listPullRequests(ctx, event.Owner, event.Repo, opts) - if err != nil { - return nil, err - } - for i := range v { - sha := v[i].GetMergeCommitSHA() - // if merge commit sha is empty, the test merge commit was not generated. - // this cause when PR is conflict and closed without resolved. - if sha == "" { - continue - } - prs[sha] = v[i] - } - } - - getPullRequest := func(commit Commit) (*github.PullRequest, error) { - if !commit.IsMerge() { - return nil, nil - } - if pr, ok := prs[commit.Hash]; ok { - return pr, nil - } - prNumber, ok := commit.PullRequestNumber() - if !ok { - return nil, nil - } - pr, err := ghClient.getPullRequest(ctx, event.Owner, event.Repo, prNumber) - if err != nil { - return nil, fmt.Errorf("failed to get pull request by number %d: %v", prNumber, err) - } - return pr, nil - } - - out := make([]ReleaseCommit, 0, len(commits)) - for _, commit := range commits { - - // Exclude was specified and matched. - if !cfg.CommitExclude.Empty() && cfg.CommitExclude.Match(commit, mergeCommits[commit.Hash]) { - continue - } - - // Include was specified and not matched. - if !cfg.CommitInclude.Empty() && !cfg.CommitInclude.Match(commit, mergeCommits[commit.Hash]) { - continue - } - - c := ReleaseCommit{ - Commit: commit, - ReleaseNote: extractReleaseNote(commit.Subject, commit.Body, gen.UseReleaseNoteBlock), - CategoryName: determineCommitCategory(commit, mergeCommits[commit.Hash], cfg.CommitCategories), - } - - if gen.UsePullRequestMetadata { - pr, err := getPullRequest(commit) - if err != nil { - // only error logging, ignore error - log.Printf("Failed to get pull request: %v\n", err) - } - if pr != nil { - c.PullRequestNumber = pr.GetNumber() - c.PullRequestOwner = pr.GetUser().GetLogin() - c.ReleaseNote = extractReleaseNote(pr.GetTitle(), pr.GetBody(), gen.UseReleaseNoteBlock) - } - } - - out = append(out, c) - } - return out, nil -} - -func extractReleaseNote(def, body string, useReleaseNoteBlock bool) string { - if !useReleaseNoteBlock { - return def - } - - subs := releaseNoteBlockRegex.FindStringSubmatch(body) - if len(subs) != 2 { - return def - } - if rn := strings.TrimSpace(subs[1]); rn != "" { - return rn - } - return def -} - -func determineCommitCategory(commit Commit, mergeCommit *Commit, categories []ReleaseCommitCategoryConfig) string { - for _, c := range categories { - if c.ReleaseCommitMatcherConfig.Empty() { - return c.Id - } - if c.ReleaseCommitMatcherConfig.Match(commit, mergeCommit) { - return c.Id - } - } - return "" -} - -func renderReleaseNote(p ReleaseProposal, cfg ReleaseConfig) []byte { - var b strings.Builder - b.WriteString(fmt.Sprintf("## Release %s with changes since %s\n\n", p.Tag, p.PreTag)) - - gen := cfg.ReleaseNoteGenerator - renderCommit := func(c ReleaseCommit) { - b.WriteString(fmt.Sprintf("* %s", c.ReleaseNote)) - if gen.UsePullRequestMetadata && c.PullRequestNumber != 0 { - b.WriteString(fmt.Sprintf(" ([#%d](https://github.com/%s/%s/pull/%d))", c.PullRequestNumber, p.Owner, p.Repo, c.PullRequestNumber)) - if !gen.UseReleaseNoteBlock && c.PullRequestOwner != "" { - b.WriteString(fmt.Sprintf(" - by @%s", c.PullRequestOwner)) - } - b.WriteString("\n") - return - } - if gen.ShowAbbrevHash { - b.WriteString(fmt.Sprintf(" [%s](https://github.com/%s/%s/commit/%s)", c.AbbreviatedHash, p.Owner, p.Repo, c.Hash)) - } - if gen.ShowCommitter { - b.WriteString(fmt.Sprintf(" - by %s", c.Committer)) - } - b.WriteString("\n") - } - - hashes := make(map[string]Commit, len(p.Commits)) - for _, commit := range p.Commits { - hashes[commit.Hash] = commit.Commit - } - - mergeCommits := make(map[string]*Commit, len(p.Commits)) - for i := range p.Commits { - commit := p.Commits[i] - if !commit.IsMerge() { - continue - } - cursor, finish := commit.ParentHashes[1], commit.ParentHashes[0] - for { - parent, ok := hashes[cursor] - if !ok { - break - } - if parent.Hash == finish { - break - } - if len(parent.ParentHashes) != 1 { - break - } - mergeCommits[cursor] = &commit.Commit - cursor = parent.ParentHashes[0] - } - } - - filteredCommits := make([]ReleaseCommit, 0, len(p.Commits)) - for _, c := range p.Commits { - // Exclude was specified and matched. - if !cfg.ReleaseNoteGenerator.CommitExclude.Empty() && cfg.ReleaseNoteGenerator.CommitExclude.Match(c.Commit, mergeCommits[c.Hash]) { - continue - } - // Include was specified and not matched. - if !cfg.ReleaseNoteGenerator.CommitInclude.Empty() && !cfg.ReleaseNoteGenerator.CommitInclude.Match(c.Commit, mergeCommits[c.Hash]) { - continue - } - filteredCommits = append(filteredCommits, c) - } - - for _, ctg := range cfg.CommitCategories { - commits := make([]ReleaseCommit, 0, 0) - for _, c := range filteredCommits { - if c.CategoryName == ctg.Id { - commits = append(commits, c) - } - } - if len(commits) == 0 { - continue - } - b.WriteString(fmt.Sprintf("### %s\n\n", ctg.Title)) - for _, c := range commits { - renderCommit(c) - } - b.WriteString("\n") - } - - for _, c := range filteredCommits { - if c.CategoryName == "" { - renderCommit(c) - } - } - - return []byte(b.String()) -} diff --git a/release_test.go b/release_test.go deleted file mode 100644 index d2d088e..0000000 --- a/release_test.go +++ /dev/null @@ -1,427 +0,0 @@ -// Copyright 2021 The PipeCD Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestParseReleaseConfig(t *testing.T) { - testcases := []struct { - name string - configFile string - expected *ReleaseConfig - expectedErr error - }{ - { - name: "empty config", - configFile: "testdata/empty-config.txt", - expectedErr: fmt.Errorf("tag must be specified"), - }, - { - name: "valid config", - configFile: "testdata/valid-config.txt", - expected: &ReleaseConfig{ - Tag: "v1.1.0", - Name: "hello", - CommitInclude: ReleaseCommitMatcherConfig{ - Contains: []string{ - "app/hello", - }, - }, - CommitExclude: ReleaseCommitMatcherConfig{ - Prefixes: []string{ - "Merge pull request #", - }, - }, - CommitCategories: []ReleaseCommitCategoryConfig{ - ReleaseCommitCategoryConfig{ - Id: "_category_0", - Title: "Breaking Changes", - ReleaseCommitMatcherConfig: ReleaseCommitMatcherConfig{ - Contains: []string{"change-category/breaking-change"}, - }, - }, - ReleaseCommitCategoryConfig{ - Id: "_category_1", - Title: "New Features", - ReleaseCommitMatcherConfig: ReleaseCommitMatcherConfig{ - Contains: []string{"change-category/new-feature"}, - }, - }, - ReleaseCommitCategoryConfig{ - Id: "_category_2", - Title: "Notable Changes", - ReleaseCommitMatcherConfig: ReleaseCommitMatcherConfig{ - Contains: []string{"change-category/notable-change"}, - }, - }, - ReleaseCommitCategoryConfig{ - Id: "_category_3", - Title: "Internal Changes", - ReleaseCommitMatcherConfig: ReleaseCommitMatcherConfig{}, - }, - }, - ReleaseNoteGenerator: ReleaseNoteGeneratorConfig{ - ShowCommitter: true, - UseReleaseNoteBlock: true, - }, - }, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - data, err := testdata.ReadFile(tc.configFile) - require.NoError(t, err) - - cfg, err := parseReleaseConfig(data) - assert.Equal(t, tc.expected, cfg) - assert.Equal(t, tc.expectedErr, err) - }) - } -} - -func TestBuildReleaseCommits(t *testing.T) { - ctx := context.Background() - config := ReleaseConfig{ - Tag: "v1.1.0", - Name: "hello", - CommitInclude: ReleaseCommitMatcherConfig{ - Contains: []string{ - "app/hello", - }, - }, - CommitExclude: ReleaseCommitMatcherConfig{ - Prefixes: []string{ - "Merge pull request #", - }, - }, - CommitCategories: []ReleaseCommitCategoryConfig{ - ReleaseCommitCategoryConfig{ - Id: "breaking-change", - Title: "Breaking Changes", - ReleaseCommitMatcherConfig: ReleaseCommitMatcherConfig{ - Contains: []string{"change-category/breaking-change"}, - }, - }, - ReleaseCommitCategoryConfig{ - Id: "new-feature", - Title: "New Features", - ReleaseCommitMatcherConfig: ReleaseCommitMatcherConfig{ - Contains: []string{"change-category/new-feature"}, - }, - }, - ReleaseCommitCategoryConfig{ - Id: "notable-change", - Title: "Notable Changes", - ReleaseCommitMatcherConfig: ReleaseCommitMatcherConfig{ - Contains: []string{"change-category/notable-change"}, - }, - }, - ReleaseCommitCategoryConfig{ - Id: "internal-change", - Title: "Internal Changes", - ReleaseCommitMatcherConfig: ReleaseCommitMatcherConfig{}, - }, - }, - ReleaseNoteGenerator: ReleaseNoteGeneratorConfig{ - ShowCommitter: true, - UseReleaseNoteBlock: true, - }, - } - - testcases := []struct { - name string - commits []Commit - config ReleaseConfig - expected []ReleaseCommit - wantErr bool - }{ - { - name: "empty", - expected: []ReleaseCommit{}, - wantErr: false, - }, - { - name: "ok", - commits: []Commit{ - Commit{ - Subject: "Commit 1 message", - Body: "commit 1\napp/hello\n- change-category/breaking-change", - }, - Commit{ - Subject: "Commit 2 message", - Body: "commit 2\napp/hello", - }, - Commit{ - Subject: "Commit 3 message", - Body: "commit 3\napp/hello\n- change-category/notable-change", - }, - Commit{ - Subject: "Commit 4 message", - Body: "commit 4\napp/hello\n```release-note\nCommit 4 release note\n```\n- change-category/notable-change\n", - }, - Commit{ - Subject: "Commit 5 message", - Body: "commit 5", - }, - }, - config: config, - expected: []ReleaseCommit{ - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 1 message", - Body: "commit 1\napp/hello\n- change-category/breaking-change", - }, - CategoryName: "breaking-change", - ReleaseNote: "Commit 1 message", - }, - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 2 message", - Body: "commit 2\napp/hello", - }, - CategoryName: "internal-change", - ReleaseNote: "Commit 2 message", - }, - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 3 message", - Body: "commit 3\napp/hello\n- change-category/notable-change", - }, - CategoryName: "notable-change", - ReleaseNote: "Commit 3 message", - }, - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 4 message", - Body: "commit 4\napp/hello\n```release-note\nCommit 4 release note\n```\n- change-category/notable-change\n", - }, - CategoryName: "notable-change", - ReleaseNote: "Commit 4 release note", - }, - }, - wantErr: false, - }, - { - name: "Add include condition: parent of merge commit", - commits: []Commit{ - { - Hash: "a", - ParentHashes: []string{"z"}, - Subject: "Commit 1 message", - Body: "commit 1", - }, - { - Hash: "b", - ParentHashes: []string{"a"}, - Subject: "Commit 2 message", - Body: "commit 2", - }, - { - Hash: "c", - ParentHashes: []string{"z", "b"}, - Subject: "Commit 3 message", - Body: "commit 3\napp/hello\n- change-category/notable-change", - }, - { - Hash: "d", - ParentHashes: []string{"c"}, - Subject: "Commit 4 message", - Body: "commit 4", - }, - { - Hash: "e", - ParentHashes: []string{"c", "d"}, - Subject: "Commit 5 message", - Body: "commit 5", - }, - }, - config: func(base ReleaseConfig) ReleaseConfig { - base.CommitInclude.ParentOfMergeCommit = true - return base - }(config), - expected: []ReleaseCommit{ - { - Commit: Commit{ - Hash: "a", - ParentHashes: []string{"z"}, - Subject: "Commit 1 message", - Body: "commit 1", - }, - CategoryName: "internal-change", - ReleaseNote: "Commit 1 message", - }, - { - Commit: Commit{ - Hash: "b", - ParentHashes: []string{"a"}, - Subject: "Commit 2 message", - Body: "commit 2", - }, - CategoryName: "internal-change", - ReleaseNote: "Commit 2 message", - }, - { - Commit: Commit{ - Hash: "c", - ParentHashes: []string{"z", "b"}, - Subject: "Commit 3 message", - Body: "commit 3\napp/hello\n- change-category/notable-change", - }, - CategoryName: "notable-change", - ReleaseNote: "Commit 3 message", - }, - }, - wantErr: false, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - got, err := buildReleaseCommits(ctx, nil, tc.commits, tc.config, nil) - assert.Equal(t, tc.wantErr, err != nil) - assert.Equal(t, tc.expected, got) - }) - } -} - -func TestRenderReleaseNote(t *testing.T) { - testcases := []struct { - name string - proposal ReleaseProposal - config ReleaseConfig - expected string - }{ - { - name: "no category", - proposal: ReleaseProposal{ - Tag: "v0.2.0", - PreTag: "v0.1.0", - Commits: []ReleaseCommit{ - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 1 message", - Body: "commit 1\n- change-category/breaking-change", - }, - ReleaseNote: "Commit 1 message", - }, - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 2 message", - Body: "commit 2", - }, - ReleaseNote: "Commit 2 message", - }, - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 3 message", - Body: "commit 3\n- change-category/notable-change", - }, - ReleaseNote: "Commit 3 message", - }, - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 4 message", - Body: "commit 4\n```release-note\nCommit 4 release note\n```\n- change-category/notable-change", - }, - ReleaseNote: "Commit 4 release note", - }, - }, - }, - config: ReleaseConfig{}, - expected: "testdata/no-category-release-note.txt", - }, - { - name: "has category", - proposal: ReleaseProposal{ - Tag: "v0.2.0", - PreTag: "v0.1.0", - Commits: []ReleaseCommit{ - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 1 message", - Body: "commit 1\n- change-category/breaking-change", - }, - CategoryName: "breaking-change", - ReleaseNote: "Commit 1 message", - }, - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 2 message", - Body: "commit 2", - }, - CategoryName: "internal-change", - ReleaseNote: "Commit 2 message", - }, - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 3 message", - Body: "commit 3\n- change-category/notable-change", - }, - CategoryName: "notable-change", - ReleaseNote: "Commit 3 message", - }, - ReleaseCommit{ - Commit: Commit{ - Subject: "Commit 4 message", - Body: "commit 4\n```release-note\nCommit 4 release note\n```\n- change-category/notable-change", - }, - CategoryName: "notable-change", - ReleaseNote: "Commit 4 release note", - }, - }, - }, - config: ReleaseConfig{ - CommitCategories: []ReleaseCommitCategoryConfig{ - ReleaseCommitCategoryConfig{ - Id: "breaking-change", - Title: "Breaking Changes", - }, - ReleaseCommitCategoryConfig{ - Id: "new-feature", - Title: "New Features", - }, - ReleaseCommitCategoryConfig{ - Id: "notable-change", - Title: "Notable Changes", - }, - ReleaseCommitCategoryConfig{ - Id: "internal-change", - Title: "Internal Changes", - }, - }, - }, - expected: "testdata/has-category-release-note.txt", - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - got := renderReleaseNote(tc.proposal, tc.config) - - expected, err := testdata.ReadFile(tc.expected) - require.NoError(t, err) - - assert.Equal(t, string(expected), string(got)) - }) - } -} diff --git a/testdata/empty-config.txt b/testdata/empty-config.txt deleted file mode 100644 index e69de29..0000000 diff --git a/testdata/has-category-release-note.txt b/testdata/has-category-release-note.txt deleted file mode 100644 index 3ee9a82..0000000 --- a/testdata/has-category-release-note.txt +++ /dev/null @@ -1,15 +0,0 @@ -## Release v0.2.0 with changes since v0.1.0 - -### Breaking Changes - -* Commit 1 message - -### Notable Changes - -* Commit 3 message -* Commit 4 release note - -### Internal Changes - -* Commit 2 message - diff --git a/testdata/log.txt b/testdata/log.txt deleted file mode 100644 index 575648b..0000000 --- a/testdata/log.txt +++ /dev/null @@ -1,17 +0,0 @@ -__GIT_LOG_SEPARATOR__nghialv__GIT_LOG_DELIMITER__kapetanios-robot__GIT_LOG_DELIMITER__1565752022__GIT_LOG_DELIMITER__74e20ede0242fdc7fd75b5be56e8d7fa72060707__GIT_LOG_DELIMITER__74e20ed__GIT_LOG_DELIMITER__ea8674c36467fc4d5a2e7900fa47e6c0d7b40948__GIT_LOG_DELIMITER__ea8674c__GIT_LOG_DELIMITER__wip__GIT_LOG_DELIMITER__ -__GIT_LOG_SEPARATOR__Le Van Nghia__GIT_LOG_DELIMITER__kapetanios-robot__GIT_LOG_DELIMITER__1565749682__GIT_LOG_DELIMITER__c9a7596e7e92ea5e3f03eeb951f632acb02b88a3__GIT_LOG_DELIMITER__c9a7596__GIT_LOG_DELIMITER__74e20ede0242fdc7fd75b5be56e8d7fa72060707__GIT_LOG_DELIMITER__74e20ed__GIT_LOG_DELIMITER__Add implementation of inplug service (#648)__GIT_LOG_DELIMITER__**What this PR does / why we need it**: - -**Which issue(s) this PR fixes**: - -Fixes # - -**Does this PR introduce a user-facing change?**: - -```release-note -NONE -``` - -This PR was merged by Kapetanios. -__GIT_LOG_SEPARATOR__nghialv__GIT_LOG_DELIMITER__kapetanios-robot__GIT_LOG_DELIMITER__2565752022__GIT_LOG_DELIMITER__24e20ede0242fdc7fd75b5be56e8d7fa72060707__GIT_LOG_DELIMITER__24e20ed__GIT_LOG_DELIMITER__74e20ede0242fdc7fd75b5be56e8d7fa72060707 c9a7596e7e92ea5e3f03eeb951f632acb02b88a3__GIT_LOG_DELIMITER__74e20ed c9a7596__GIT_LOG_DELIMITER__Added commands to "kapectl" for creating, updating project secret (#475)__GIT_LOG_DELIMITER__ diff --git a/testdata/multi-release-comment.txt b/testdata/multi-release-comment.txt deleted file mode 100644 index 183b2fb..0000000 --- a/testdata/multi-release-comment.txt +++ /dev/null @@ -1,8 +0,0 @@ - -[![RELEASE](https://img.shields.io/static/v1?label=GitHub&message=RELEASE&color=success&style=flat)](https://github.com/pipe-cd/actions-gh-release) - -The following 2 GitHub releases will be created once this pull request got merged. - -Release note for tag 1 - -Release note for tag 2 diff --git a/testdata/no-category-release-note.txt b/testdata/no-category-release-note.txt deleted file mode 100644 index 623a5f8..0000000 --- a/testdata/no-category-release-note.txt +++ /dev/null @@ -1,6 +0,0 @@ -## Release v0.2.0 with changes since v0.1.0 - -* Commit 1 message -* Commit 2 message -* Commit 3 message -* Commit 4 release note diff --git a/testdata/no-release-comment.txt b/testdata/no-release-comment.txt deleted file mode 100644 index c380f36..0000000 --- a/testdata/no-release-comment.txt +++ /dev/null @@ -1,4 +0,0 @@ - -[![RELEASE](https://img.shields.io/static/v1?label=GitHub&message=RELEASE&color=success&style=flat)](https://github.com/pipe-cd/actions-gh-release) - -No GitHub releases will be created one this pull request got merged. Because this pull request did not modified any RELEASE files. diff --git a/testdata/one-release-comment.txt b/testdata/one-release-comment.txt deleted file mode 100644 index 59cefd3..0000000 --- a/testdata/one-release-comment.txt +++ /dev/null @@ -1,6 +0,0 @@ - -[![RELEASE](https://img.shields.io/static/v1?label=GitHub&message=RELEASE&color=success&style=flat)](https://github.com/pipe-cd/actions-gh-release) - -The following 1 GitHub releases will be created once this pull request got merged. - -Release note for tag 1 diff --git a/testdata/valid-config.txt b/testdata/valid-config.txt deleted file mode 100644 index ea17c11..0000000 --- a/testdata/valid-config.txt +++ /dev/null @@ -1,25 +0,0 @@ -tag: v1.1.0 -name: hello - -commitInclude: - contains: - - app/hello -commitExclude: - prefixes: - - "Merge pull request #" - -commitCategories: - - title: "Breaking Changes" - contains: - - change-category/breaking-change - - title: "New Features" - contains: - - change-category/new-feature - - title: "Notable Changes" - contains: - - change-category/notable-change - - title: "Internal Changes" - -releaseNoteGenerator: - showCommitter: true - useReleaseNoteBlock: true