Files
atlantis/e2e/e2e.go
renovate[bot] 6884238cd1 fix(deps): update module github.com/google/go-github/v58 to v59 in go.mod (main) (#4241)
* fix(deps): update module github.com/google/go-github/v58 to v59 in go.mod

* Update fixtures.go

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
2024-02-27 23:47:57 -06:00

201 lines
6.5 KiB
Go

// Copyright 2017 HootSuite Media 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
// 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.
// Modified hereafter by contributors to runatlantis/atlantis.
package main
import (
"fmt"
"log"
"os"
"os/exec"
"time"
"github.com/google/go-github/v59/github"
)
type E2ETester struct {
githubClient *GithubClient
repoURL string
ownerName string
repoName string
hookID int64
cloneDirRoot string
projectType Project
}
type E2EResult struct {
projectType string
githubPullRequestURL string
testResult string
}
var testFileData = `
resource "null_resource" "hello" {
}
`
// nolint: gosec
func (t *E2ETester) Start() (*E2EResult, error) {
cloneDir := fmt.Sprintf("%s/%s-test", t.cloneDirRoot, t.projectType.Name)
branchName := fmt.Sprintf("%s-%s", t.projectType.Name, time.Now().Format("20060102150405"))
testFileName := fmt.Sprintf("%s.tf", t.projectType.Name)
e2eResult := &E2EResult{}
e2eResult.projectType = t.projectType.Name
// create the directory and parents if necessary
log.Printf("creating dir %q", cloneDir)
if err := os.MkdirAll(cloneDir, 0700); err != nil {
return e2eResult, fmt.Errorf("failed to create dir %q prior to cloning, attempting to continue: %v", cloneDir, err)
}
cloneCmd := exec.Command("git", "clone", t.repoURL, cloneDir)
// git clone the repo
log.Printf("git cloning into %q", cloneDir)
if output, err := cloneCmd.CombinedOutput(); err != nil {
return e2eResult, fmt.Errorf("failed to clone repository: %v: %s", err, string(output))
}
// checkout a new branch for the project
log.Printf("checking out branch %q", branchName)
checkoutCmd := exec.Command("git", "checkout", "-b", branchName)
checkoutCmd.Dir = cloneDir
if output, err := checkoutCmd.CombinedOutput(); err != nil {
return e2eResult, fmt.Errorf("failed to git checkout branch %q: %v: %s", branchName, err, string(output))
}
// write a file for running the tests
randomData := []byte(testFileData)
filePath := fmt.Sprintf("%s/%s/%s", cloneDir, t.projectType.Name, testFileName)
log.Printf("creating file to commit %q", filePath)
err := os.WriteFile(filePath, randomData, 0644)
if err != nil {
return e2eResult, fmt.Errorf("couldn't write file %s: %v", filePath, err)
}
// add the file
log.Printf("git add file %q", filePath)
addCmd := exec.Command("git", "add", filePath)
addCmd.Dir = cloneDir
if output, err := addCmd.CombinedOutput(); err != nil {
return e2eResult, fmt.Errorf("failed to git add file %q: %v: %s", filePath, err, string(output))
}
// commit the file
log.Printf("git commit file %q", filePath)
commitCmd := exec.Command("git", "commit", "-am", "test commit")
commitCmd.Dir = cloneDir
if output, err := commitCmd.CombinedOutput(); err != nil {
return e2eResult, fmt.Errorf("failed to run git commit in %q: %v: %v", cloneDir, err, string(output))
}
// push the branch to remote
log.Printf("git push branch %q", branchName)
pushCmd := exec.Command("git", "push", "origin", branchName)
pushCmd.Dir = cloneDir
if output, err := pushCmd.CombinedOutput(); err != nil {
return e2eResult, fmt.Errorf("failed to git push branch %q: %v: %s", branchName, err, string(output))
}
// create a new pr
title := fmt.Sprintf("This is a test pull request for atlantis e2e test for %s project type", t.projectType.Name)
head := fmt.Sprintf("%s:%s", t.ownerName, branchName)
body := ""
base := "main"
newPullRequest := &github.NewPullRequest{Title: &title, Head: &head, Body: &body, Base: &base}
pull, _, err := t.githubClient.client.PullRequests.Create(t.githubClient.ctx, t.ownerName, t.repoName, newPullRequest)
if err != nil {
return e2eResult, fmt.Errorf("error while creating new pull request: %v", err)
}
// set pull request url
e2eResult.githubPullRequestURL = pull.GetHTMLURL()
log.Printf("created pull request %s", pull.GetHTMLURL())
// defer closing pull request and delete remote branch
defer cleanUp(t, pull.GetNumber(), branchName) // nolint: errcheck
// wait for atlantis to respond to webhook and autoplan.
time.Sleep(2 * time.Second)
state := "not started"
// waiting for atlantis run and finish
maxLoops := 20
i := 0
for ; i < maxLoops && checkStatus(state); i++ {
time.Sleep(2 * time.Second)
state, _ = getAtlantisStatus(t, branchName)
if state == "" {
log.Println("atlantis run hasn't started")
continue
}
log.Printf("atlantis run is in %s state", state)
}
if i == maxLoops {
state = "timed out"
}
log.Printf("atlantis run finished with status %q", state)
e2eResult.testResult = state
// check if atlantis run was a success
if state != "success" {
return e2eResult, fmt.Errorf("atlantis run project type %q failed with %q status", t.projectType.Name, state)
}
return e2eResult, nil
}
func getAtlantisStatus(t *E2ETester, branchName string) (string, error) {
// check repo status
combinedStatus, _, err := t.githubClient.client.Repositories.GetCombinedStatus(t.githubClient.ctx, t.ownerName, t.repoName, branchName, nil)
if err != nil {
return "", err
}
for _, status := range combinedStatus.Statuses {
if status.GetContext() == "atlantis/plan" {
return status.GetState(), nil
}
}
return "", nil
}
func checkStatus(state string) bool {
for _, s := range []string{"success", "error", "failure"} {
if state == s {
return false
}
}
return true
}
func cleanUp(t *E2ETester, pullRequestNumber int, branchName string) error {
// clean up
pullClosed, _, err := t.githubClient.client.PullRequests.Edit(t.githubClient.ctx, t.ownerName, t.repoName, pullRequestNumber, &github.PullRequest{State: github.String("closed")})
if err != nil {
return fmt.Errorf("error while closing new pull request: %v", err)
}
log.Printf("closed pull request %d", pullClosed.GetNumber())
deleteBranchName := fmt.Sprintf("%s/%s", "heads", branchName)
_, err = t.githubClient.client.Git.DeleteRef(t.githubClient.ctx, t.ownerName, t.repoName, deleteBranchName)
if err != nil {
return fmt.Errorf("error while deleting branch %s: %v", deleteBranchName, err)
}
log.Printf("deleted branch %s", deleteBranchName)
return nil
}