Skip to content

Commit

Permalink
feat(api): add new params
Browse files Browse the repository at this point in the history
As of now, the /api/plan endpoint constructs a PullRequest that uses
the provided Ref parameter as the base branch and head commit. This
causes issues when running additional steps along with plan
(e.g.: policy check, infracost, etc).

Here's an example error:

```
repo was already cloned but is not at correct commit, wanted \"pr-plan-test\" got \"7a19f2011...\"
```

This will then trigger a new clone which will override needed artifacts
from the previous steps which will then cause /api/plan to fail.

By properly setting HeadCommit from the new optional APIRequest parameter
this issue is avoided.

Signed-off-by: Raul Gutierrez Segales <[email protected]>
  • Loading branch information
rgs1 committed Jan 10, 2024
1 parent 16540be commit 2563bf8
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 4 deletions.
2 changes: 2 additions & 0 deletions runatlantis.io/docs/api-endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Execute [atlantis plan](using-atlantis.html#atlantis-plan) on the specified repo
| Type | string | Yes | Type of the VCS provider (Github/Gitlab) |
| Paths | [ [Path](api-endpoints.html#path) ] | Yes | Paths to the projects to run the plan |
| PR | int | No | Pull Request number |
| BaseBranch | string | No | The branch where the PR will be merged |
| Commit | string | No | The commit to checkout in the PR |

##### Path

Expand Down
16 changes: 14 additions & 2 deletions server/controllers/api_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type APIRequest struct {
Repository string `validate:"required"`
Ref string `validate:"required"`
Type string `validate:"required"`
Commit string
BaseBranch string
PR int
Projects []string
Paths []struct {
Expand Down Expand Up @@ -155,6 +157,13 @@ func (a *APIController) apiPlan(request *APIRequest, ctx *command.Context) (*com
return &command.Result{ProjectResults: projectResults}, nil
}

func GetOrElse(val, def string) string {
if val != "" {
return val
}
return def
}

func (a *APIController) apiApply(request *APIRequest, ctx *command.Context) (*command.Result, error) {
cmds, err := request.getCommands(ctx, a.ProjectCommandBuilder.BuildApplyCommands)
if err != nil {
Expand Down Expand Up @@ -212,13 +221,16 @@ func (a *APIController) apiParseAndValidate(r *http.Request) (*APIRequest, *comm
return nil, nil, http.StatusForbidden, fmt.Errorf("repo not allowlisted")
}

baseBranch := GetOrElse(request.BaseBranch, request.Ref)
headCommit := GetOrElse(request.Commit, request.Ref)

return &request, &command.Context{
HeadRepo: baseRepo,
Pull: models.PullRequest{
Num: request.PR,
BaseBranch: request.Ref,
BaseBranch: baseBranch,
HeadBranch: request.Ref,
HeadCommit: request.Ref,
HeadCommit: headCommit,
BaseRepo: baseRepo,
},
Scope: a.Scope,
Expand Down
36 changes: 34 additions & 2 deletions server/controllers/api_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,51 @@ const atlantisTokenHeader = "X-Atlantis-Token"
const atlantisToken = "token"

func TestAPIController_Plan(t *testing.T) {
testPlan(t, "main", "", "")
}

func TestAPIController_PlanWithNewParams(t *testing.T) {
testPlan(t, "my-feature-branch", "HEAD", "main")
}

func testPlan(t *testing.T, ref, commit, baseBranch string) {
ac, projectCommandBuilder, projectCommandRunner := setup(t)
body, _ := json.Marshal(controllers.APIRequest{
Repository: "Repo",
Ref: "main",
Ref: ref,
Type: "Gitlab",
Commit: commit,
BaseBranch: baseBranch,
PR: 100,
Projects: []string{"default"},
})
req, _ := http.NewRequest("POST", "", bytes.NewBuffer(body))
req.Header.Set(atlantisTokenHeader, atlantisToken)
w := httptest.NewRecorder()
ac.Plan(w, req)
ResponseContains(t, w, http.StatusOK, "")
projectCommandBuilder.VerifyWasCalledOnce().BuildPlanCommands(Any[*command.Context](), Any[*events.CommentCommand]())

headCommit := controllers.GetOrElse(commit, ref)
baseBranch = controllers.GetOrElse(baseBranch, ref)

repo := models.Repo{}
cmdContext := &command.Context{
HeadRepo: repo,
Pull: models.PullRequest{
Num: 100,
BaseBranch: baseBranch,
HeadBranch: ref,
HeadCommit: headCommit,
BaseRepo: repo,
},
Scope: ac.Scope,
Log: ac.Logger,
}
commentCmd := &events.CommentCommand{
ProjectName: "default",
}

projectCommandBuilder.VerifyWasCalledOnce().BuildPlanCommands(cmdContext, commentCmd)
projectCommandRunner.VerifyWasCalledOnce().Plan(Any[command.ProjectContext]())
}

Expand Down

0 comments on commit 2563bf8

Please sign in to comment.