From 6ab34be69a604075b39cf3a05d694e2f1e76c332 Mon Sep 17 00:00:00 2001 From: "Giau. Tran Minh" Date: Tue, 17 Dec 2024 21:02:12 +0700 Subject: [PATCH 1/4] atlasaction: allow the SCM client control the comment format --- atlasaction/action.go | 24 ++--- atlasaction/action_test.go | 14 ++- atlasaction/bitbucket.go | 5 +- atlasaction/comments/schema-plan.tmpl | 2 +- atlasaction/gh_action.go | 97 +++++++++++-------- atlasaction/gitlab_ci.go | 93 +++++++++++------- atlasaction/testdata/gitlab/schema-plan.txtar | 2 +- 7 files changed, 140 insertions(+), 97 deletions(-) diff --git a/atlasaction/action.go b/atlasaction/action.go index f4d058e8..ee88357b 100644 --- a/atlasaction/action.go +++ b/atlasaction/action.go @@ -62,8 +62,10 @@ type ( } // SCMClient contains methods for interacting with SCM platforms (GitHub, Gitlab etc...). SCMClient interface { - // UpsertComment posts or updates a pull request comment. - UpsertComment(ctx context.Context, pr *PullRequest, id, comment string) error + // CommentLint comments on the pull request with the lint report. + CommentLint(context.Context, *TriggerContext, *atlasexec.SummaryReport) error + // CommentPlan comments on the pull request with the schema plan. + CommentPlan(context.Context, *TriggerContext, *atlasexec.SchemaPlan) error } // SCMSuggestions contains methods for interacting with SCM platforms (GitHub, Gitlab etc...) @@ -134,6 +136,7 @@ type ( // TriggerContext holds the context of the environment the action is running in. TriggerContext struct { + Act Action // Act is the action that is running. SCM SCM // SCM is the source control management system. Repo string // Repo is the repository name. e.g. "ariga/atlas-action". RepoURL string // RepoURL is full URL of the repository. e.g. "https://github.com/ariga/atlas-action". @@ -535,11 +538,7 @@ func (a *Actions) MigrateLint(ctx context.Context) error { case err != nil: return err default: - comment, err := RenderTemplate("migrate-lint.tmpl", &payload) - if err != nil { - return err - } - if err = c.UpsertComment(ctx, tc.PullRequest, dirName, comment); err != nil { + if err = c.CommentLint(ctx, tc, &payload); err != nil { a.Errorf("failed to comment on the pull request: %v", err) } if c, ok := c.(SCMSuggestions); ok { @@ -742,16 +741,7 @@ func (a *Actions) SchemaPlan(ctx context.Context) error { case err != nil: return err default: - // Report the schema plan to the user and add a comment to the PR. - comment, err := RenderTemplate("schema-plan.tmpl", map[string]any{ - "Plan": plan, - "EnvName": params.Env, - "RerunCommand": tc.RerunCmd, - }) - if err != nil { - return fmt.Errorf("failed to generate schema plan comment: %w", err) - } - err = c.UpsertComment(ctx, tc.PullRequest, plan.File.Name, comment) + err = c.CommentPlan(ctx, tc, plan) if err != nil { // Don't fail the action if the comment fails. // It may be due to the missing permissions. diff --git a/atlasaction/action_test.go b/atlasaction/action_test.go index aba0b3d1..a8fb6501 100644 --- a/atlasaction/action_test.go +++ b/atlasaction/action_test.go @@ -2500,7 +2500,19 @@ func (m *mockSCM) UpsertSuggestion(context.Context, *atlasaction.PullRequest, *a return nil } -func (m *mockSCM) UpsertComment(_ context.Context, _ *atlasaction.PullRequest, id string, _ string) error { +func (m *mockSCM) CommentLint(ctx context.Context, tc *atlasaction.TriggerContext, r *atlasexec.SummaryReport) error { + comment, err := atlasaction.RenderTemplate("migrate-lint.tmpl", r) + if err != nil { + return err + } + return m.comment(ctx, tc.PullRequest, tc.Act.GetInput("dir-name"), comment) +} + +func (m *mockSCM) CommentPlan(ctx context.Context, tc *atlasaction.TriggerContext, p *atlasexec.SchemaPlan) error { + return m.comment(ctx, tc.PullRequest, p.File.Name, "") +} + +func (m *mockSCM) comment(_ context.Context, _ *atlasaction.PullRequest, id string, _ string) error { var ( method = http.MethodPatch urlPath = "/repos/ariga/atlas-action/issues/comments/1" diff --git a/atlasaction/bitbucket.go b/atlasaction/bitbucket.go index ecbce214..1ca52e11 100644 --- a/atlasaction/bitbucket.go +++ b/atlasaction/bitbucket.go @@ -25,7 +25,7 @@ type bbPipe struct { } // NewBitBucketPipe returns a new Action for BitBucket. -func NewBitBucketPipe(getenv func(string) string, w io.Writer) Action { +func NewBitBucketPipe(getenv func(string) string, w io.Writer) *bbPipe { // Disable color output for testing, // but enable it for non-testing environments. color.NoColor = testing.Testing() @@ -33,13 +33,14 @@ func NewBitBucketPipe(getenv func(string) string, w io.Writer) Action { } // GetType implements Action. -func (a *bbPipe) GetType() atlasexec.TriggerType { +func (*bbPipe) GetType() atlasexec.TriggerType { return atlasexec.TriggerTypeBitbucket } // GetTriggerContext implements Action. func (a *bbPipe) GetTriggerContext(context.Context) (*TriggerContext, error) { tc := &TriggerContext{ + Act: a, Branch: a.getenv("BITBUCKET_BRANCH"), Commit: a.getenv("BITBUCKET_COMMIT"), Repo: a.getenv("BITBUCKET_REPO_FULL_NAME"), diff --git a/atlasaction/comments/schema-plan.tmpl b/atlasaction/comments/schema-plan.tmpl index 68069019..a9d72c44 100644 --- a/atlasaction/comments/schema-plan.tmpl +++ b/atlasaction/comments/schema-plan.tmpl @@ -24,7 +24,7 @@ the database with the desired state. Otherwise, Atlas will report a schema drift 3\. Push the updated plan to the registry using the following command: ```bash -atlas schema plan push --pending --env {{ .EnvName }} --file {{ .Plan.File.Name }}.plan.hcl +atlas schema plan push --pending --file {{ .Plan.File.Name }}.plan.hcl ``` {{- if .RerunCommand }} diff --git a/atlasaction/gh_action.go b/atlasaction/gh_action.go index 09a22867..a639e048 100644 --- a/atlasaction/gh_action.go +++ b/atlasaction/gh_action.go @@ -71,7 +71,6 @@ func (a *ghAction) SchemaApply(_ context.Context, r *atlasexec.SchemaApply) { func (a *ghAction) SchemaPlan(_ context.Context, r *atlasexec.SchemaPlan) { summary, err := RenderTemplate("schema-plan.tmpl", map[string]any{ "Plan": r, - "EnvName": a.GetInput("env"), "RerunCommand": fmt.Sprintf("gh run rerun %s", a.Getenv("GITHUB_RUN_ID")), }) if err != nil { @@ -82,7 +81,7 @@ func (a *ghAction) SchemaPlan(_ context.Context, r *atlasexec.SchemaPlan) { } // GetType implements the Action interface. -func (a *ghAction) GetType() atlasexec.TriggerType { +func (*ghAction) GetType() atlasexec.TriggerType { return atlasexec.TriggerTypeGithubAction } @@ -97,6 +96,7 @@ func (a *ghAction) GetTriggerContext(context.Context) (*TriggerContext, error) { return nil, err } tc := &TriggerContext{ + Act: a, SCM: SCM{Type: atlasexec.SCMTypeGithub, APIURL: ctx.APIURL}, Repo: ctx.Repository, Branch: ctx.HeadRef, @@ -176,8 +176,29 @@ type ( } ) -func (g *githubAPI) UpsertComment(ctx context.Context, pr *PullRequest, id, comment string) error { - comments, err := g.getIssueComments(ctx, pr) +// CommentLint implements SCMClient. +func (c *githubAPI) CommentLint(ctx context.Context, tc *TriggerContext, r *atlasexec.SummaryReport) error { + comment, err := RenderTemplate("migrate-lint.tmpl", r) + if err != nil { + return err + } + return c.comment(ctx, tc.PullRequest, tc.Act.GetInput("dir-name"), comment) +} + +// CommentPlan implements SCMClient. +func (c *githubAPI) CommentPlan(ctx context.Context, tc *TriggerContext, p *atlasexec.SchemaPlan) error { + // Report the schema plan to the user and add a comment to the PR. + comment, err := RenderTemplate("schema-plan.tmpl", map[string]any{ + "Plan": p, + }) + if err != nil { + return err + } + return c.comment(ctx, tc.PullRequest, p.File.Name, comment) +} + +func (c *githubAPI) comment(ctx context.Context, pr *PullRequest, id, comment string) error { + comments, err := c.getIssueComments(ctx, pr) if err != nil { return err } @@ -188,43 +209,43 @@ func (g *githubAPI) UpsertComment(ctx context.Context, pr *PullRequest, id, comm if found := slices.IndexFunc(comments, func(c githubIssueComment) bool { return strings.Contains(c.Body, marker) }); found != -1 { - return g.updateIssueComment(ctx, comments[found].ID, body) + return c.updateIssueComment(ctx, comments[found].ID, body) } - return g.createIssueComment(ctx, pr, body) + return c.createIssueComment(ctx, pr, body) } -func (g *githubAPI) getIssueComments(ctx context.Context, pr *PullRequest) ([]githubIssueComment, error) { - url := fmt.Sprintf("%v/repos/%v/issues/%v/comments", g.baseURL, g.repo, pr.Number) +func (c *githubAPI) getIssueComments(ctx context.Context, pr *PullRequest) ([]githubIssueComment, error) { + url := fmt.Sprintf("%v/repos/%v/issues/%v/comments", c.baseURL, c.repo, pr.Number) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { - return nil, fmt.Errorf("error querying github comments with %v/%v, %w", g.repo, pr.Number, err) + return nil, fmt.Errorf("error querying github comments with %v/%v, %w", c.repo, pr.Number, err) } defer res.Body.Close() buf, err := io.ReadAll(res.Body) if err != nil { - return nil, fmt.Errorf("error reading PR issue comments from %v/%v, %v", g.repo, pr.Number, err) + return nil, fmt.Errorf("error reading PR issue comments from %v/%v, %v", c.repo, pr.Number, err) } if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected status code %v when calling GitHub API", res.StatusCode) } var comments []githubIssueComment if err = json.Unmarshal(buf, &comments); err != nil { - return nil, fmt.Errorf("error parsing github comments with %v/%v from %v, %w", g.repo, pr.Number, string(buf), err) + return nil, fmt.Errorf("error parsing github comments with %v/%v from %v, %w", c.repo, pr.Number, string(buf), err) } return comments, nil } -func (g *githubAPI) createIssueComment(ctx context.Context, pr *PullRequest, content io.Reader) error { - url := fmt.Sprintf("%v/repos/%v/issues/%v/comments", g.baseURL, g.repo, pr.Number) +func (c *githubAPI) createIssueComment(ctx context.Context, pr *PullRequest, content io.Reader) error { + url := fmt.Sprintf("%v/repos/%v/issues/%v/comments", c.baseURL, c.repo, pr.Number) req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, content) if err != nil { return err } - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { return err } @@ -240,13 +261,13 @@ func (g *githubAPI) createIssueComment(ctx context.Context, pr *PullRequest, con } // updateIssueComment updates issue comment with the given id. -func (g *githubAPI) updateIssueComment(ctx context.Context, id int, content io.Reader) error { - url := fmt.Sprintf("%v/repos/%v/issues/comments/%v", g.baseURL, g.repo, id) +func (c *githubAPI) updateIssueComment(ctx context.Context, id int, content io.Reader) error { + url := fmt.Sprintf("%v/repos/%v/issues/comments/%v", c.baseURL, c.repo, id) req, err := http.NewRequestWithContext(ctx, http.MethodPatch, url, content) if err != nil { return err } - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { return err } @@ -262,11 +283,11 @@ func (g *githubAPI) updateIssueComment(ctx context.Context, id int, content io.R } // UpsertSuggestion creates or updates a suggestion review comment on trigger event pull request. -func (g *githubAPI) UpsertSuggestion(ctx context.Context, pr *PullRequest, s *Suggestion) error { +func (c *githubAPI) UpsertSuggestion(ctx context.Context, pr *PullRequest, s *Suggestion) error { marker := commentMarker(s.ID) body := fmt.Sprintf("%s\n%s", s.Comment, marker) // TODO: Listing the comments only once and updating the comment in the same call. - comments, err := g.listReviewComments(ctx, pr) + comments, err := c.listReviewComments(ctx, pr) if err != nil { return err } @@ -277,7 +298,7 @@ func (g *githubAPI) UpsertSuggestion(ctx context.Context, pr *PullRequest, s *Su return c.Path == s.Path && strings.Contains(c.Body, marker) }) if found != -1 { - if err := g.updateReviewComment(ctx, comments[found].ID, body); err != nil { + if err := c.updateReviewComment(ctx, comments[found].ID, body); err != nil { return err } return nil @@ -292,12 +313,12 @@ func (g *githubAPI) UpsertSuggestion(ctx context.Context, pr *PullRequest, s *Su if err != nil { return err } - url := fmt.Sprintf("%v/repos/%v/pulls/%v/comments", g.baseURL, g.repo, pr.Number) + url := fmt.Sprintf("%v/repos/%v/pulls/%v/comments", c.baseURL, c.repo, pr.Number) req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(buf)) if err != nil { return err } - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { return err } @@ -313,13 +334,13 @@ func (g *githubAPI) UpsertSuggestion(ctx context.Context, pr *PullRequest, s *Su } // listReviewComments for the trigger event pull request. -func (g *githubAPI) listReviewComments(ctx context.Context, pr *PullRequest) ([]pullRequestComment, error) { - url := fmt.Sprintf("%v/repos/%v/pulls/%v/comments", g.baseURL, g.repo, pr.Number) +func (c *githubAPI) listReviewComments(ctx context.Context, pr *PullRequest) ([]pullRequestComment, error) { + url := fmt.Sprintf("%v/repos/%v/pulls/%v/comments", c.baseURL, c.repo, pr.Number) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { return nil, err } @@ -339,7 +360,7 @@ func (g *githubAPI) listReviewComments(ctx context.Context, pr *PullRequest) ([] } // updateReviewComment updates the review comment with the given id. -func (g *githubAPI) updateReviewComment(ctx context.Context, id int, body string) error { +func (c *githubAPI) updateReviewComment(ctx context.Context, id int, body string) error { type pullRequestUpdate struct { Body string `json:"body"` } @@ -347,12 +368,12 @@ func (g *githubAPI) updateReviewComment(ctx context.Context, id int, body string if err != nil { return err } - url := fmt.Sprintf("%v/repos/%v/pulls/comments/%v", g.baseURL, g.repo, id) + url := fmt.Sprintf("%v/repos/%v/pulls/comments/%v", c.baseURL, c.repo, id) req, err := http.NewRequestWithContext(ctx, http.MethodPatch, url, bytes.NewReader(b)) if err != nil { return err } - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { return err } @@ -368,13 +389,13 @@ func (g *githubAPI) updateReviewComment(ctx context.Context, id int, body string } // ListPullRequestFiles return paths of the files in the trigger event pull request. -func (g *githubAPI) ListPullRequestFiles(ctx context.Context, pr *PullRequest) ([]string, error) { - url := fmt.Sprintf("%v/repos/%v/pulls/%v/files", g.baseURL, g.repo, pr.Number) +func (c *githubAPI) ListPullRequestFiles(ctx context.Context, pr *PullRequest) ([]string, error) { + url := fmt.Sprintf("%v/repos/%v/pulls/%v/files", c.baseURL, c.repo, pr.Number) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { return nil, err } @@ -398,19 +419,19 @@ func (g *githubAPI) ListPullRequestFiles(ctx context.Context, pr *PullRequest) ( } // OpeningPullRequest returns the latest open pull request for the given branch. -func (g *githubAPI) OpeningPullRequest(ctx context.Context, branch string) (*PullRequest, error) { - owner, _, err := g.ownerRepo() +func (c *githubAPI) OpeningPullRequest(ctx context.Context, branch string) (*PullRequest, error) { + owner, _, err := c.ownerRepo() if err != nil { return nil, err } // Get open pull requests for the branch. url := fmt.Sprintf("%s/repos/%s/pulls?state=open&head=%s:%s&sort=created&direction=desc&per_page=1&page=1", - g.baseURL, g.repo, owner, branch) + c.baseURL, c.repo, owner, branch) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { return nil, fmt.Errorf("error calling GitHub API: %w", err) } @@ -442,8 +463,8 @@ func (g *githubAPI) OpeningPullRequest(ctx context.Context, branch string) (*Pul } } -func (g *githubAPI) ownerRepo() (string, string, error) { - s := strings.Split(g.repo, "/") +func (c *githubAPI) ownerRepo() (string, string, error) { + s := strings.Split(c.repo, "/") if len(s) != 2 { return "", "", fmt.Errorf("GITHUB_REPOSITORY must be in the format of 'owner/repo'") } diff --git a/atlasaction/gitlab_ci.go b/atlasaction/gitlab_ci.go index 04bc387d..60e098ff 100644 --- a/atlasaction/gitlab_ci.go +++ b/atlasaction/gitlab_ci.go @@ -25,25 +25,23 @@ type gitlabCI struct { getenv func(string) string } -var _ Action = (*gitlabCI)(nil) - // NewGitlabCI returns a new Action for Gitlab CI. -func NewGitlabCI(getenv func(string) string, w io.Writer) Action { +func NewGitlabCI(getenv func(string) string, w io.Writer) *gitlabCI { return &gitlabCI{getenv: getenv, coloredLogger: &coloredLogger{w}} } // GetType implements the Action interface. -func (g *gitlabCI) GetType() atlasexec.TriggerType { - return "GITLAB_CI" +func (*gitlabCI) GetType() atlasexec.TriggerType { + return atlasexec.TriggerTypeGitlab } // GetInput implements the Action interface. -func (g *gitlabCI) GetInput(name string) string { - return strings.TrimSpace(g.getenv(toEnvVar("ATLAS_INPUT_" + name))) +func (a *gitlabCI) GetInput(name string) string { + return strings.TrimSpace(a.getenv(toEnvVar("ATLAS_INPUT_" + name))) } // SetOutput implements the Action interface. -func (g *gitlabCI) SetOutput(name, value string) { +func (a *gitlabCI) SetOutput(name, value string) { f, err := os.OpenFile(".env", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) if err != nil { return @@ -53,33 +51,33 @@ func (g *gitlabCI) SetOutput(name, value string) { } // GetTriggerContext implements the Action interface. -func (g *gitlabCI) GetTriggerContext(context.Context) (*TriggerContext, error) { +func (a *gitlabCI) GetTriggerContext(context.Context) (*TriggerContext, error) { ctx := &TriggerContext{ - SCM: SCM{ - Type: atlasexec.SCMTypeGitlab, - APIURL: g.getenv("CI_API_V4_URL"), - }, - Repo: g.getenv("CI_PROJECT_NAME"), - RepoURL: g.getenv("CI_PROJECT_URL"), - Branch: g.getenv("CI_COMMIT_REF_NAME"), - Commit: g.getenv("CI_COMMIT_SHA"), - Actor: &Actor{Name: g.getenv("GITLAB_USER_NAME"), ID: g.getenv("GITLAB_USER_ID")}, - } - if mr := g.getenv("CI_MERGE_REQUEST_IID"); mr != "" { + Act: a, + SCM: SCM{Type: atlasexec.SCMTypeGitlab, APIURL: a.getenv("CI_API_V4_URL")}, + Repo: a.getenv("CI_PROJECT_NAME"), + RepoURL: a.getenv("CI_PROJECT_URL"), + Branch: a.getenv("CI_COMMIT_REF_NAME"), + Commit: a.getenv("CI_COMMIT_SHA"), + Actor: &Actor{Name: a.getenv("GITLAB_USER_NAME"), ID: a.getenv("GITLAB_USER_ID")}, + } + if mr := a.getenv("CI_MERGE_REQUEST_IID"); mr != "" { num, err := strconv.Atoi(mr) if err != nil { return nil, err } ctx.PullRequest = &PullRequest{ - Commit: g.getenv("CI_COMMIT_SHA"), + Commit: a.getenv("CI_COMMIT_SHA"), Number: num, - URL: g.getenv("CI_MERGE_REQUEST_REF_PATH"), - Body: g.getenv("CI_MERGE_REQUEST_DESCRIPTION"), + URL: a.getenv("CI_MERGE_REQUEST_REF_PATH"), + Body: a.getenv("CI_MERGE_REQUEST_DESCRIPTION"), } } return ctx, nil } +var _ Action = (*gitlabCI)(nil) + type gitlabTransport struct { Token string } @@ -115,28 +113,49 @@ type GitlabComment struct { var _ SCMClient = (*gitlabAPI)(nil) -func (g *gitlabAPI) UpsertComment(ctx context.Context, pr *PullRequest, id, comment string) error { - url := fmt.Sprintf("%v/projects/%v/merge_requests/%v/notes", g.baseURL, g.project, pr.Number) +// CommentLint implements SCMClient. +func (c *gitlabAPI) CommentLint(ctx context.Context, tc *TriggerContext, r *atlasexec.SummaryReport) error { + comment, err := RenderTemplate("migrate-lint.tmpl", r) + if err != nil { + return err + } + return c.comment(ctx, tc.PullRequest, tc.Act.GetInput("dir-name"), comment) +} + +// CommentPlan implements SCMClient. +func (c *gitlabAPI) CommentPlan(ctx context.Context, tc *TriggerContext, p *atlasexec.SchemaPlan) error { + // Report the schema plan to the user and add a comment to the PR. + comment, err := RenderTemplate("schema-plan.tmpl", map[string]any{ + "Plan": p, + }) + if err != nil { + return fmt.Errorf("failed to generate schema plan comment: %w", err) + } + return c.comment(ctx, tc.PullRequest, p.File.Name, comment) +} + +func (c *gitlabAPI) comment(ctx context.Context, pr *PullRequest, id, comment string) error { + url := fmt.Sprintf("%v/projects/%v/merge_requests/%v/notes", c.baseURL, c.project, pr.Number) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return err } req.Header.Set("Content-Type", "application/json") - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { - return fmt.Errorf("error querying gitlab comments with %v/%v, %w", g.project, pr.Number, err) + return fmt.Errorf("error querying gitlab comments with %v/%v, %w", c.project, pr.Number, err) } defer res.Body.Close() buf, err := io.ReadAll(res.Body) if err != nil { - return fmt.Errorf("error reading PR issue comments from %v/%v, %v", g.project, pr.Number, err) + return fmt.Errorf("error reading PR issue comments from %v/%v, %v", c.project, pr.Number, err) } if res.StatusCode != http.StatusOK { return fmt.Errorf("unexpected status code %v when calling Gitlab API. body: %s", res.StatusCode, string(buf)) } var comments []GitlabComment if err = json.Unmarshal(buf, &comments); err != nil { - return fmt.Errorf("error parsing gitlab notes with %v/%v from %v, %w", g.project, pr.Number, string(buf), err) + return fmt.Errorf("error parsing gitlab notes with %v/%v from %v, %w", c.project, pr.Number, string(buf), err) } var ( marker = commentMarker(id) @@ -145,20 +164,20 @@ func (g *gitlabAPI) UpsertComment(ctx context.Context, pr *PullRequest, id, comm if found := slices.IndexFunc(comments, func(c GitlabComment) bool { return !c.System && strings.Contains(c.Body, marker) }); found != -1 { - return g.updateComment(ctx, pr, comments[found].ID, body) + return c.updateComment(ctx, pr, comments[found].ID, body) } - return g.createComment(ctx, pr, comment) + return c.createComment(ctx, pr, comment) } -func (g *gitlabAPI) createComment(ctx context.Context, pr *PullRequest, comment string) error { +func (c *gitlabAPI) createComment(ctx context.Context, pr *PullRequest, comment string) error { body := strings.NewReader(fmt.Sprintf(`{"body": %q}`, comment)) - url := fmt.Sprintf("%v/projects/%v/merge_requests/%v/notes", g.baseURL, g.project, pr.Number) + url := fmt.Sprintf("%v/projects/%v/merge_requests/%v/notes", c.baseURL, c.project, pr.Number) req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body) if err != nil { return err } req.Header.Set("Content-Type", "application/json") - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { return err } @@ -173,15 +192,15 @@ func (g *gitlabAPI) createComment(ctx context.Context, pr *PullRequest, comment return err } -func (g *gitlabAPI) updateComment(ctx context.Context, pr *PullRequest, NoteId int, comment string) error { +func (c *gitlabAPI) updateComment(ctx context.Context, pr *PullRequest, NoteId int, comment string) error { body := strings.NewReader(fmt.Sprintf(`{"body": %q}`, comment)) - url := fmt.Sprintf("%v/projects/%v/merge_requests/%v/notes/%v", g.baseURL, g.project, pr.Number, NoteId) + url := fmt.Sprintf("%v/projects/%v/merge_requests/%v/notes/%v", c.baseURL, c.project, pr.Number, NoteId) req, err := http.NewRequestWithContext(ctx, http.MethodPut, url, body) if err != nil { return err } req.Header.Set("Content-Type", "application/json") - res, err := g.client.Do(req) + res, err := c.client.Do(req) if err != nil { return err } diff --git a/atlasaction/testdata/gitlab/schema-plan.txtar b/atlasaction/testdata/gitlab/schema-plan.txtar index d075e45a..396a09ac 100644 --- a/atlasaction/testdata/gitlab/schema-plan.txtar +++ b/atlasaction/testdata/gitlab/schema-plan.txtar @@ -150,7 +150,7 @@ the database with the desired state. Otherwise, Atlas will report a schema drift 3\. Push the updated plan to the registry using the following command: ```bash -atlas schema plan push --pending --env --file 20241010143904.plan.hcl +atlas schema plan push --pending --file 20241010143904.plan.hcl ``` \ No newline at end of file From b0092223851fce0567e4714b15790973b9ebe312 Mon Sep 17 00:00:00 2001 From: "Giau. Tran Minh" Date: Tue, 17 Dec 2024 21:36:12 +0700 Subject: [PATCH 2/4] atlasaction: move github action logic to its implement --- atlasaction/action.go | 183 ++++----------------------------- atlasaction/action_test.go | 39 +++++-- atlasaction/bitbucket.go | 5 + atlasaction/circleci_action.go | 5 + atlasaction/gh_action.go | 144 +++++++++++++++++++++++++- atlasaction/gitlab_ci.go | 5 + 6 files changed, 204 insertions(+), 177 deletions(-) diff --git a/atlasaction/action.go b/atlasaction/action.go index ee88357b..136d8e06 100644 --- a/atlasaction/action.go +++ b/atlasaction/action.go @@ -16,7 +16,6 @@ import ( "io" "net/url" "os" - "path" "slices" "strconv" "strings" @@ -36,7 +35,6 @@ type ( Version string Atlas AtlasExec CloudClient func(string, string, *atlasexec.Version) CloudClient - Getenv func(string) string } // Action interface for Atlas. @@ -45,6 +43,8 @@ type ( // GetType returns the type of atlasexec trigger Type. e.g. "GITHUB_ACTION" // The value is used to identify the type on CI-Run page in Atlas Cloud. GetType() atlasexec.TriggerType + // Getenv returns the value of the environment variable with the given name. + Getenv(string) string // GetInput returns the value of the input with the given name. GetInput(string) string // SetOutput sets the value of the output with the given name. @@ -67,16 +67,6 @@ type ( // CommentPlan comments on the pull request with the schema plan. CommentPlan(context.Context, *TriggerContext, *atlasexec.SchemaPlan) error } - - // SCMSuggestions contains methods for interacting with SCM platforms (GitHub, Gitlab etc...) - // that support suggestions on the pull request. - SCMSuggestions interface { - // UpsertSuggestion posts or updates a pull request suggestion. - UpsertSuggestion(ctx context.Context, pr *PullRequest, s *Suggestion) error - // ListPullRequestFiles returns a list of files changed in a pull request. - ListPullRequestFiles(ctx context.Context, pr *PullRequest) ([]string, error) - } - Logger interface { // Infof logs an info message. Infof(string, ...interface{}) @@ -200,7 +190,6 @@ func New(opts ...Option) (*Actions, error) { Atlas: cfg.atlas, CloudClient: cfg.cloudClient, Version: cfg.version, - Getenv: cfg.getenv, }, nil } @@ -520,42 +509,18 @@ func (a *Actions) MigrateLint(ctx context.Context) error { if payload.URL != "" { a.SetOutput("report-url", payload.URL) } - if err := a.addChecks(&payload); err != nil { - return err - } if r, ok := a.Action.(Reporter); ok { r.MigrateLint(ctx, &payload) } - if tc.PullRequest == nil { - if isLintErr { - return fmt.Errorf("`atlas migrate lint` completed with errors, see report: %s", payload.URL) - } - return nil - } - // In case of a pull request, we need to add comments and suggestion to the PR. - switch c, err := a.SCM(tc); { - case errors.Is(err, ErrNoSCM): - case err != nil: - return err - default: - if err = c.CommentLint(ctx, tc, &payload); err != nil { - a.Errorf("failed to comment on the pull request: %v", err) - } - if c, ok := c.(SCMSuggestions); ok { - switch files, err := c.ListPullRequestFiles(ctx, tc.PullRequest); { - case err != nil: - a.Errorf("failed to list pull request files: %w", err) - default: - err = a.addSuggestions(&payload, func(s *Suggestion) error { - // Add suggestion only if the file is part of the pull request. - if slices.Contains(files, s.Path) { - return c.UpsertSuggestion(ctx, tc.PullRequest, s) - } - return nil - }) - if err != nil { - a.Errorf("failed to add suggestion on the pull request: %v", err) - } + if tc.PullRequest != nil { + // In case of a pull request, we need to add comments and suggestion to the PR. + switch c, err := tc.SCMClient(); { + case errors.Is(err, ErrNoSCM): + case err != nil: + return err + default: + if err = c.CommentLint(ctx, tc, &payload); err != nil { + a.Errorf("failed to comment on the pull request: %v", err) } } } @@ -736,7 +701,7 @@ func (a *Actions) SchemaPlan(ctx context.Context) error { if r, ok := a.Action.(Reporter); ok { r.SchemaPlan(ctx, plan) } - switch c, err := a.SCM(tc); { + switch c, err := tc.SCMClient(); { case errors.Is(err, ErrNoSCM): case err != nil: return err @@ -1073,62 +1038,26 @@ func (a *Actions) RequiredInputs(input ...string) error { return nil } -// SCM returns a SCMClient. -func (a *Actions) SCM(tc *TriggerContext) (SCMClient, error) { +// SCMClient returns a Client to interact with the SCM. +func (tc *TriggerContext) SCMClient() (SCMClient, error) { switch tc.SCM.Type { case atlasexec.SCMTypeGithub: - token := a.Getenv("GITHUB_TOKEN") + token := tc.Act.Getenv("GITHUB_TOKEN") if token == "" { - a.Warningf("GITHUB_TOKEN is not set, the action may not have all the permissions") + tc.Act.Warningf("GITHUB_TOKEN is not set, the action may not have all the permissions") } return githubClient(tc.Repo, tc.SCM.APIURL, token), nil case atlasexec.SCMTypeGitlab: - token := a.Getenv("GITLAB_TOKEN") + token := tc.Act.Getenv("GITLAB_TOKEN") if token == "" { - a.Warningf("GITLAB_TOKEN is not set, the action may not have all the permissions") + tc.Act.Warningf("GITLAB_TOKEN is not set, the action may not have all the permissions") } - return gitlabClient(a.Getenv("CI_PROJECT_ID"), tc.SCM.APIURL, token), nil + return gitlabClient(tc.Act.Getenv("CI_PROJECT_ID"), tc.SCM.APIURL, token), nil default: return nil, ErrNoSCM // Not implemented yet. } } -// addChecks runs annotations to the trigger event pull request for the given payload. -func (a *Actions) addChecks(lint *atlasexec.SummaryReport) error { - // Get the directory path from the lint report. - dir := path.Join(a.WorkingDir(), lint.Env.Dir) - for _, file := range lint.Files { - filePath := path.Join(dir, file.Name) - if file.Error != "" && len(file.Reports) == 0 { - a.WithFieldsMap(map[string]string{ - "file": filePath, - "line": "1", - }).Errorf(file.Error) - continue - } - for _, report := range file.Reports { - for _, diag := range report.Diagnostics { - msg := diag.Text - if diag.Code != "" { - msg = fmt.Sprintf("%v (%v)\n\nDetails: https://atlasgo.io/lint/analyzers#%v", msg, diag.Code, diag.Code) - } - lines := strings.Split(file.Text[:diag.Pos], "\n") - logger := a.WithFieldsMap(map[string]string{ - "file": filePath, - "line": strconv.Itoa(max(1, len(lines))), - "title": report.Text, - }) - if file.Error != "" { - logger.Errorf(msg) - } else { - logger.Warningf(msg) - } - } - } - } - return nil -} - // GetRunContext returns the run context for the action. func (tc *TriggerContext) GetRunContext() *atlasexec.RunContext { rc := &atlasexec.RunContext{ @@ -1147,80 +1076,6 @@ func (tc *TriggerContext) GetRunContext() *atlasexec.RunContext { return rc } -type Suggestion struct { - ID string // Unique identifier for the suggestion. - Path string // File path. - StartLine int // Start line numbers for the suggestion. - Line int // End line number for the suggestion. - Comment string // Comment body. -} - -// addSuggestions returns the suggestions from the lint report. -func (a *Actions) addSuggestions(lint *atlasexec.SummaryReport, fn func(*Suggestion) error) (err error) { - if !slices.ContainsFunc(lint.Files, func(f *atlasexec.FileReport) bool { - return len(f.Reports) > 0 - }) { - // No reports to add suggestions. - return nil - } - dir := a.WorkingDir() - for _, file := range lint.Files { - filePath := path.Join(dir, lint.Env.Dir, file.Name) - for reportIdx, report := range file.Reports { - for _, f := range report.SuggestedFixes { - if f.TextEdit == nil { - continue - } - s := Suggestion{Path: filePath, ID: f.Message} - if f.TextEdit.End <= f.TextEdit.Line { - s.Line = f.TextEdit.Line - } else { - s.StartLine = f.TextEdit.Line - s.Line = f.TextEdit.End - } - s.Comment, err = RenderTemplate("suggestion.tmpl", map[string]any{ - "Fix": f, - "Dir": lint.Env.Dir, - }) - if err != nil { - return fmt.Errorf("failed to render suggestion: %w", err) - } - if err = fn(&s); err != nil { - return fmt.Errorf("failed to process suggestion: %w", err) - } - } - for diagIdx, d := range report.Diagnostics { - for _, f := range d.SuggestedFixes { - if f.TextEdit == nil { - continue - } - s := Suggestion{Path: filePath, ID: f.Message} - if f.TextEdit.End <= f.TextEdit.Line { - s.Line = f.TextEdit.Line - } else { - s.StartLine = f.TextEdit.Line - s.Line = f.TextEdit.End - } - s.Comment, err = RenderTemplate("suggestion.tmpl", map[string]any{ - "Fix": f, - "Dir": lint.Env.Dir, - "File": file, - "Report": reportIdx, - "Diag": diagIdx, - }) - if err != nil { - return fmt.Errorf("failed to render suggestion: %w", err) - } - if err = fn(&s); err != nil { - return fmt.Errorf("failed to process suggestion: %w", err) - } - } - } - } - } - return nil -} - func execTime(start, end time.Time) string { return end.Sub(start).String() } diff --git a/atlasaction/action_test.go b/atlasaction/action_test.go index a8fb6501..db28fbe4 100644 --- a/atlasaction/action_test.go +++ b/atlasaction/action_test.go @@ -874,6 +874,18 @@ func TestMigrateLint(t *testing.T) { ) switch { // List comments endpoint + case path == "/repos/test-owner/test-repository/issues/0/comments" && method == http.MethodGet: + b, err := json.Marshal(comments) + require.NoError(t, err) + _, err = writer.Write(b) + require.NoError(t, err) + return + case path == "/repos/test-owner/test-repository/issues/0/comments" && method == http.MethodPost: + var payload map[string]any + require.NoError(t, json.NewDecoder(request.Body).Decode(&payload)) + payload["id"] = 123 + writer.WriteHeader(http.StatusCreated) + return case path == "/repos/test-owner/test-repository/pulls/0/comments" && method == http.MethodGet: b, err := json.Marshal(comments) require.NoError(t, err) @@ -1051,6 +1063,18 @@ func TestMigrateLint(t *testing.T) { ) switch { // List comments endpoint + case path == "/repos/test-owner/test-repository/issues/0/comments" && method == http.MethodGet: + b, err := json.Marshal(comments) + require.NoError(t, err) + _, err = writer.Write(b) + require.NoError(t, err) + return + case path == "/repos/test-owner/test-repository/issues/0/comments" && method == http.MethodPost: + var payload map[string]any + require.NoError(t, json.NewDecoder(request.Body).Decode(&payload)) + payload["id"] = 123 + writer.WriteHeader(http.StatusCreated) + return case path == "/repos/test-owner/test-repository/pulls/0/comments" && method == http.MethodGet: b, err := json.Marshal(comments) require.NoError(t, err) @@ -2204,6 +2228,7 @@ func TestSchemaPlan(t *testing.T) { // Multiple plans will fail with an error planFiles = []atlasexec.SchemaPlanFile{*planFile, *planFile} act.resetOutputs() + act.trigger.Act = act newActs := func() *atlasaction.Actions { t.Helper() a, err := atlasaction.New(atlasaction.WithAction(act), atlasaction.WithAtlas(m)) @@ -2408,6 +2433,7 @@ func (m *mockAction) MigrateApply(context.Context, *atlasexec.MigrateApply) { // MigrateLint implements atlasaction.Reporter. func (m *mockAction) MigrateLint(context.Context, *atlasexec.SummaryReport) { m.summary++ + } // SchemaApply implements atlasaction.Reporter. @@ -2433,6 +2459,11 @@ func (m *mockAction) GetType() atlasexec.TriggerType { return atlasexec.TriggerTypeGithubAction } +// Getenv implements Action. +func (m *mockAction) Getenv(e string) string { + return os.Getenv(e) +} + // GetTriggerContext implements Action. func (m *mockAction) GetTriggerContext(context.Context) (*atlasaction.TriggerContext, error) { return m.trigger, nil @@ -2492,14 +2523,6 @@ func (m *mockAction) SCM() (atlasaction.SCMClient, error) { return m.scm, nil } -func (m *mockSCM) ListPullRequestFiles(context.Context, *atlasaction.PullRequest) ([]string, error) { - return nil, nil -} - -func (m *mockSCM) UpsertSuggestion(context.Context, *atlasaction.PullRequest, *atlasaction.Suggestion) error { - return nil -} - func (m *mockSCM) CommentLint(ctx context.Context, tc *atlasaction.TriggerContext, r *atlasexec.SummaryReport) error { comment, err := atlasaction.RenderTemplate("migrate-lint.tmpl", r) if err != nil { diff --git a/atlasaction/bitbucket.go b/atlasaction/bitbucket.go index 1ca52e11..304bb825 100644 --- a/atlasaction/bitbucket.go +++ b/atlasaction/bitbucket.go @@ -37,6 +37,11 @@ func (*bbPipe) GetType() atlasexec.TriggerType { return atlasexec.TriggerTypeBitbucket } +// Getenv implements Action. +func (a *bbPipe) Getenv(key string) string { + return a.getenv(key) +} + // GetTriggerContext implements Action. func (a *bbPipe) GetTriggerContext(context.Context) (*TriggerContext, error) { tc := &TriggerContext{ diff --git a/atlasaction/circleci_action.go b/atlasaction/circleci_action.go index 3ebae7d5..4cec5823 100644 --- a/atlasaction/circleci_action.go +++ b/atlasaction/circleci_action.go @@ -31,6 +31,11 @@ func (a *circleCIOrb) GetType() atlasexec.TriggerType { return atlasexec.TriggerTypeCircleCIOrb } +// Getenv implements Action. +func (a *circleCIOrb) Getenv(key string) string { + return a.getenv(key) +} + // GetInput implements the Action interface. func (a *circleCIOrb) GetInput(name string) string { return strings.TrimSpace(a.getenv(toEnvVar("INPUT_" + name))) diff --git a/atlasaction/gh_action.go b/atlasaction/gh_action.go index a639e048..1fc93e80 100644 --- a/atlasaction/gh_action.go +++ b/atlasaction/gh_action.go @@ -11,7 +11,9 @@ import ( "fmt" "io" "net/http" + "path" "slices" + "strconv" "strings" "time" @@ -49,6 +51,9 @@ func (a *ghAction) MigrateApply(_ context.Context, r *atlasexec.MigrateApply) { // MigrateLint implements Reporter. func (a *ghAction) MigrateLint(_ context.Context, r *atlasexec.SummaryReport) { + if err := a.addChecks(r); err != nil { + a.Errorf("failed to add checks: %v", err) + } summary, err := RenderTemplate("migrate-lint.tmpl", r) if err != nil { a.Errorf("failed to create summary: %v", err) @@ -125,6 +130,42 @@ func (a *ghAction) WithFieldsMap(m map[string]string) Logger { return &ghAction{a.Action.WithFieldsMap(m)} } +// addChecks runs annotations to the trigger event pull request for the given payload. +func (a *ghAction) addChecks(lint *atlasexec.SummaryReport) error { + // Get the directory path from the lint report. + dir := path.Join(a.GetInput("working-directory"), lint.Env.Dir) + for _, file := range lint.Files { + filePath := path.Join(dir, file.Name) + if file.Error != "" && len(file.Reports) == 0 { + a.WithFieldsMap(map[string]string{ + "file": filePath, + "line": "1", + }).Errorf(file.Error) + continue + } + for _, report := range file.Reports { + for _, diag := range report.Diagnostics { + msg := diag.Text + if diag.Code != "" { + msg = fmt.Sprintf("%v (%v)\n\nDetails: https://atlasgo.io/lint/analyzers#%v", msg, diag.Code, diag.Code) + } + lines := strings.Split(file.Text[:diag.Pos], "\n") + logger := a.WithFieldsMap(map[string]string{ + "file": filePath, + "line": strconv.Itoa(max(1, len(lines))), + "title": report.Text, + }) + if file.Error != "" { + logger.Errorf(msg) + } else { + logger.Warningf(msg) + } + } + } + } + return nil +} + var _ Action = (*ghAction)(nil) var _ Reporter = (*ghAction)(nil) @@ -182,7 +223,26 @@ func (c *githubAPI) CommentLint(ctx context.Context, tc *TriggerContext, r *atla if err != nil { return err } - return c.comment(ctx, tc.PullRequest, tc.Act.GetInput("dir-name"), comment) + err = c.comment(ctx, tc.PullRequest, tc.Act.GetInput("dir-name"), comment) + if err != nil { + return err + } + switch files, err := c.listPullRequestFiles(ctx, tc.PullRequest); { + case err != nil: + tc.Act.Errorf("failed to list pull request files: %w", err) + default: + err = addSuggestions(tc.Act, r, func(s *Suggestion) error { + // Add suggestion only if the file is part of the pull request. + if slices.Contains(files, s.Path) { + return c.upsertSuggestion(ctx, tc.PullRequest, s) + } + return nil + }) + if err != nil { + tc.Act.Errorf("failed to add suggestion on the pull request: %v", err) + } + } + return nil } // CommentPlan implements SCMClient. @@ -282,8 +342,8 @@ func (c *githubAPI) updateIssueComment(ctx context.Context, id int, content io.R return err } -// UpsertSuggestion creates or updates a suggestion review comment on trigger event pull request. -func (c *githubAPI) UpsertSuggestion(ctx context.Context, pr *PullRequest, s *Suggestion) error { +// upsertSuggestion creates or updates a suggestion review comment on trigger event pull request. +func (c *githubAPI) upsertSuggestion(ctx context.Context, pr *PullRequest, s *Suggestion) error { marker := commentMarker(s.ID) body := fmt.Sprintf("%s\n%s", s.Comment, marker) // TODO: Listing the comments only once and updating the comment in the same call. @@ -388,8 +448,8 @@ func (c *githubAPI) updateReviewComment(ctx context.Context, id int, body string return err } -// ListPullRequestFiles return paths of the files in the trigger event pull request. -func (c *githubAPI) ListPullRequestFiles(ctx context.Context, pr *PullRequest) ([]string, error) { +// listPullRequestFiles return paths of the files in the trigger event pull request. +func (c *githubAPI) listPullRequestFiles(ctx context.Context, pr *PullRequest) ([]string, error) { url := fmt.Sprintf("%v/repos/%v/pulls/%v/files", c.baseURL, c.repo, pr.Number) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { @@ -471,6 +531,80 @@ func (c *githubAPI) ownerRepo() (string, string, error) { return s[0], s[1], nil } +type Suggestion struct { + ID string // Unique identifier for the suggestion. + Path string // File path. + StartLine int // Start line numbers for the suggestion. + Line int // End line number for the suggestion. + Comment string // Comment body. +} + +// addSuggestions returns the suggestions from the lint report. +func addSuggestions(a Action, lint *atlasexec.SummaryReport, fn func(*Suggestion) error) (err error) { + if !slices.ContainsFunc(lint.Files, func(f *atlasexec.FileReport) bool { + return len(f.Reports) > 0 + }) { + // No reports to add suggestions. + return nil + } + dir := a.GetInput("working-directory") + for _, file := range lint.Files { + filePath := path.Join(dir, lint.Env.Dir, file.Name) + for reportIdx, report := range file.Reports { + for _, f := range report.SuggestedFixes { + if f.TextEdit == nil { + continue + } + s := Suggestion{Path: filePath, ID: f.Message} + if f.TextEdit.End <= f.TextEdit.Line { + s.Line = f.TextEdit.Line + } else { + s.StartLine = f.TextEdit.Line + s.Line = f.TextEdit.End + } + s.Comment, err = RenderTemplate("suggestion.tmpl", map[string]any{ + "Fix": f, + "Dir": lint.Env.Dir, + }) + if err != nil { + return fmt.Errorf("failed to render suggestion: %w", err) + } + if err = fn(&s); err != nil { + return fmt.Errorf("failed to process suggestion: %w", err) + } + } + for diagIdx, d := range report.Diagnostics { + for _, f := range d.SuggestedFixes { + if f.TextEdit == nil { + continue + } + s := Suggestion{Path: filePath, ID: f.Message} + if f.TextEdit.End <= f.TextEdit.Line { + s.Line = f.TextEdit.Line + } else { + s.StartLine = f.TextEdit.Line + s.Line = f.TextEdit.End + } + s.Comment, err = RenderTemplate("suggestion.tmpl", map[string]any{ + "Fix": f, + "Dir": lint.Env.Dir, + "File": file, + "Report": reportIdx, + "Diag": diagIdx, + }) + if err != nil { + return fmt.Errorf("failed to render suggestion: %w", err) + } + if err = fn(&s); err != nil { + return fmt.Errorf("failed to process suggestion: %w", err) + } + } + } + } + } + return nil +} + // githubTriggerEvent is the structure of the GitHub trigger event. type githubTriggerEvent struct { PullRequest struct { diff --git a/atlasaction/gitlab_ci.go b/atlasaction/gitlab_ci.go index 60e098ff..e2480dec 100644 --- a/atlasaction/gitlab_ci.go +++ b/atlasaction/gitlab_ci.go @@ -35,6 +35,11 @@ func (*gitlabCI) GetType() atlasexec.TriggerType { return atlasexec.TriggerTypeGitlab } +// Getenv implements Action. +func (a *gitlabCI) Getenv(key string) string { + return a.getenv(key) +} + // GetInput implements the Action interface. func (a *gitlabCI) GetInput(name string) string { return strings.TrimSpace(a.getenv(toEnvVar("ATLAS_INPUT_" + name))) From 47272fffd8dbffaaca287220bc7a277815e5b252 Mon Sep 17 00:00:00 2001 From: "Giau. Tran Minh" Date: Tue, 17 Dec 2024 22:58:02 +0700 Subject: [PATCH 3/4] chore: cleanup Logger --- atlasaction/action.go | 7 ------- atlasaction/action_test.go | 16 ---------------- atlasaction/gh_action.go | 5 ----- 3 files changed, 28 deletions(-) diff --git a/atlasaction/action.go b/atlasaction/action.go index 136d8e06..e031d2bf 100644 --- a/atlasaction/action.go +++ b/atlasaction/action.go @@ -76,8 +76,6 @@ type ( Errorf(string, ...interface{}) // Fatalf logs a fatal error message and exits the action. Fatalf(string, ...interface{}) - // WithFieldsMap returns a new Logger with the given fields. - WithFieldsMap(map[string]string) Logger } // AtlasExec is the interface for the atlas exec client. @@ -1223,9 +1221,4 @@ func (l *coloredLogger) Fatalf(msg string, args ...any) { os.Exit(1) } -// WithFieldsMap implements the Logger interface. -func (l *coloredLogger) WithFieldsMap(map[string]string) Logger { - return l // unsupported -} - var _ Logger = (*coloredLogger)(nil) diff --git a/atlasaction/action_test.go b/atlasaction/action_test.go index db28fbe4..e2174783 100644 --- a/atlasaction/action_test.go +++ b/atlasaction/action_test.go @@ -2503,22 +2503,6 @@ func (m *mockAction) Fatalf(msg string, args ...interface{}) { m.fatal = true // Mark fatal called } -// WithFieldsMap implements Action. -func (m *mockAction) WithFieldsMap(args map[string]string) atlasaction.Logger { - argPairs := make([]any, 0, len(args)*2) - for k, v := range args { - argPairs = append(argPairs, k, v) - } - return &mockAction{ - inputs: m.inputs, - trigger: m.trigger, - output: m.output, - summary: m.summary, - fatal: m.fatal, - logger: m.logger.With(argPairs...), - scm: m.scm, - } -} func (m *mockAction) SCM() (atlasaction.SCMClient, error) { return m.scm, nil } diff --git a/atlasaction/gh_action.go b/atlasaction/gh_action.go index 1fc93e80..c8216657 100644 --- a/atlasaction/gh_action.go +++ b/atlasaction/gh_action.go @@ -125,11 +125,6 @@ func (a *ghAction) GetTriggerContext(context.Context) (*TriggerContext, error) { return tc, nil } -// WithFieldsMap return a new Logger with the given fields. -func (a *ghAction) WithFieldsMap(m map[string]string) Logger { - return &ghAction{a.Action.WithFieldsMap(m)} -} - // addChecks runs annotations to the trigger event pull request for the given payload. func (a *ghAction) addChecks(lint *atlasexec.SummaryReport) error { // Get the directory path from the lint report. From f99985e8241e65a138061dc5b75f75ee1eeb40fe Mon Sep 17 00:00:00 2001 From: "Giau. Tran Minh" Date: Tue, 17 Dec 2024 23:13:02 +0700 Subject: [PATCH 4/4] chore: fixed lint --- atlasaction/circleci_action_test.go | 2 +- atlasaction/gh_action.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/atlasaction/circleci_action_test.go b/atlasaction/circleci_action_test.go index 997db883..add241ec 100644 --- a/atlasaction/circleci_action_test.go +++ b/atlasaction/circleci_action_test.go @@ -41,7 +41,7 @@ func Test_circleCIOrb_GetTriggerContext(t *testing.T) { require.Equal(t, "/repos/ariga/atlas-orb/pulls", r.URL.Path) require.Equal(t, "GET", r.Method) require.Equal(t, "state=open&head=ariga:main&sort=created&direction=desc&per_page=1&page=1", r.URL.RawQuery) - w.Write([]byte(` + _, _ = w.Write([]byte(` [ {"number":1,"url":"https://api.github.com/repos/ariga/atlas-orb/pulls/9","head":{"sha":"1234567890"}}, {"number":2,"url":"https://api.github.com/repos/ariga/atlas-orb/pulls/8","head":{"sha":"1234567890"}} diff --git a/atlasaction/gh_action.go b/atlasaction/gh_action.go index c8216657..f5e6e6fa 100644 --- a/atlasaction/gh_action.go +++ b/atlasaction/gh_action.go @@ -135,7 +135,7 @@ func (a *ghAction) addChecks(lint *atlasexec.SummaryReport) error { a.WithFieldsMap(map[string]string{ "file": filePath, "line": "1", - }).Errorf(file.Error) + }).Errorf(file.Error) //nolint:govet continue } for _, report := range file.Reports { @@ -151,9 +151,9 @@ func (a *ghAction) addChecks(lint *atlasexec.SummaryReport) error { "title": report.Text, }) if file.Error != "" { - logger.Errorf(msg) + logger.Errorf(msg) //nolint:govet } else { - logger.Warningf(msg) + logger.Warningf(msg) //nolint:govet } } }