Skip to content

Commit

Permalink
Support Log Streaming URLs for project without a project name (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
Aayyush committed Dec 9, 2021
1 parent a6900e7 commit 954866a
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 12 deletions.
9 changes: 8 additions & 1 deletion server/controllers/logstreaming_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@ func (p *pullInfo) String() string {

type projectInfo struct {
projectName string
workspace string
pullInfo
}

func (p *projectInfo) String() string {
return fmt.Sprintf("%s/%s/%d/%s", p.org, p.repo, p.pull, p.projectName)
return fmt.Sprintf("%s/%s/%d/%s/%s", p.org, p.repo, p.pull, p.projectName, p.workspace)
}

func newPullInfo(r *http.Request) (*pullInfo, error) {
Expand Down Expand Up @@ -87,9 +88,15 @@ func newProjectInfo(r *http.Request) (*projectInfo, error) {
return nil, fmt.Errorf("Internal error: no project in route")
}

workspace, ok := mux.Vars(r)["workspace"]
if !ok {
return nil, fmt.Errorf("Internal error: no workspace in route")
}

return &projectInfo{
pullInfo: *pullInfo,
projectName: project,
workspace: workspace,
}, nil
}

Expand Down
14 changes: 11 additions & 3 deletions server/events/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,11 +425,19 @@ func (p ProjectCommandContext) GetShowResultFileName() string {

// Gets a unique identifier for the current pull request as a single string
func (p ProjectCommandContext) PullInfo() string {
return BuildPullInfo(p.BaseRepo.FullName, p.Pull.Num, p.ProjectName)
return BuildPullInfo(p.BaseRepo.FullName, p.Pull.Num, p.ProjectName, p.RepoRelDir, p.Workspace)
}

func BuildPullInfo(repoName string, pullNum int, projectName string) string {
return fmt.Sprintf("%s/%d/%s", repoName, pullNum, projectName)
func BuildPullInfo(repoName string, pullNum int, projectName string, relDir string, workspace string) string {
projectIdentifier := GetProjectIdentifier(relDir, projectName)
return fmt.Sprintf("%s/%d/%s/%s", repoName, pullNum, projectIdentifier, workspace)
}

func GetProjectIdentifier(relRepoDir string, projectName string) string {
if projectName != "" {
return projectName
}
return strings.ReplaceAll(relRepoDir, "/", "-")
}

// SplitRepoFullName splits a repo full name up into its owner and repo
Expand Down
2 changes: 1 addition & 1 deletion server/events/pull_closed_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (p *PullClosedExecutor) CleanUpPull(repo models.Repo, pull models.PullReque
// with same dir and workspace. If a project name has not been set, we'll use the dir and
// workspace to build project key.
// Source: https://www.runatlantis.io/docs/repo-level-atlantis-yaml.html#reference
projectKey := models.BuildPullInfo(pullStatus.Pull.BaseRepo.FullName, pull.Num, project.ProjectName)
projectKey := models.BuildPullInfo(pullStatus.Pull.BaseRepo.FullName, pull.Num, project.ProjectName, project.RepoRelDir, project.Workspace)
p.LogStreamResourceCleaner.CleanUp(projectKey)
}
}
Expand Down
1 change: 1 addition & 0 deletions server/events/pull_closed_executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ func TestCleanUpLogStreaming(t *testing.T) {
BaseRepo: fixtures.GithubRepo,
Pull: fixtures.Pull,
ProjectName: *fixtures.Project.Name,
Workspace: "default",
}

go prjCmdOutHandler.Handle()
Expand Down
8 changes: 4 additions & 4 deletions server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@ func (r *Router) GenerateLockURL(lockID string) string {

func (r *Router) GenerateProjectJobURL(ctx models.ProjectCommandContext) (string, error) {
pull := ctx.Pull

projectIdentifier := models.GetProjectIdentifier(ctx.RepoRelDir, ctx.ProjectName)
jobURL, err := r.Underlying.Get(r.ProjectJobsViewRouteName).URL(
"org", pull.BaseRepo.Owner,
"repo", pull.BaseRepo.Name,
"pull", fmt.Sprintf("%d", pull.Num),
"project", ctx.ProjectName,
"project", projectIdentifier,
"workspace", ctx.Workspace,
)

if err != nil {
return "", errors.Wrapf(err, "creating job url for %s/%d/%s", pull.BaseRepo.FullName, pull.Num, ctx.ProjectName)
return "", errors.Wrapf(err, "creating job url for %s/%d/%s/%s", pull.BaseRepo.FullName, pull.Num, projectIdentifier, ctx.Workspace)
}

return r.AtlantisURL.String() + jobURL.String(), nil
Expand Down
55 changes: 55 additions & 0 deletions server/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/gorilla/mux"
"github.com/runatlantis/atlantis/server"
"github.com/runatlantis/atlantis/server/events/models"
. "github.com/runatlantis/atlantis/testing"
)

Expand Down Expand Up @@ -60,3 +61,57 @@ func TestRouter_GenerateLockURL(t *testing.T) {
})
}
}

func setupJobsRouter(t *testing.T) *server.Router {
atlantisURL, err := server.ParseAtlantisURL("http://localhost:4141")
Ok(t, err)

underlyingRouter := mux.NewRouter()
underlyingRouter.HandleFunc("/jobs/{org}/{repo}/{pull}/{project}/{workspace}", func(_ http.ResponseWriter, _ *http.Request) {}).Methods("GET").Name("project-jobs-detail")

return &server.Router{
AtlantisURL: atlantisURL,
Underlying: underlyingRouter,
ProjectJobsViewRouteName: "project-jobs-detail",
}
}

func TestGenerateProjectJobURL_ShouldGenerateURLWithProjectNameWhenProjectNameSpecified(t *testing.T) {
router := setupJobsRouter(t)
ctx := models.ProjectCommandContext{
Pull: models.PullRequest{
BaseRepo: models.Repo{
Owner: "test-owner",
Name: "test-repo",
},
Num: 1,
},
ProjectName: "test-project",
Workspace: "default",
}
expectedURL := "http://localhost:4141/jobs/test-owner/test-repo/1/test-project/default"
gotURL, err := router.GenerateProjectJobURL(ctx)
Ok(t, err)

Equals(t, expectedURL, gotURL)
}

func TestGenerateProjectJobURL_ShouldGenerateURLWithDirectoryAndWorkspaceWhenProjectNameNotSpecified(t *testing.T) {
router := setupJobsRouter(t)
ctx := models.ProjectCommandContext{
Pull: models.PullRequest{
BaseRepo: models.Repo{
Owner: "test-owner",
Name: "test-repo",
},
Num: 1,
},
RepoRelDir: "ops/terraform/test-root",
Workspace: "default",
}
expectedURL := "http://localhost:4141/jobs/test-owner/test-repo/1/ops-terraform-test-root/default"
gotURL, err := router.GenerateProjectJobURL(ctx)
Ok(t, err)

Equals(t, expectedURL, gotURL)
}
6 changes: 3 additions & 3 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ const (
// mux.Router.Get(LockViewRouteName).URL(LockViewRouteIDQueryParam, "my id")
LockViewRouteIDQueryParam = "id"
// ProjectJobsViewRouteName is the named route in mux.Router for the log stream view.
// Can be retrieved by mux.Router.Get(ProjectJobsViewRouteName)
ProjectJobsViewRouteName = "project-jobs-detail"
// binDirName is the name of the directory inside our data dir where
// we download binaries.
Expand Down Expand Up @@ -852,8 +851,9 @@ func (s *Server) Start() error {
s.Router.HandleFunc("/locks", s.LocksController.DeleteLock).Methods("DELETE").Queries("id", "{id:.*}")
s.Router.HandleFunc("/lock", s.LocksController.GetLock).Methods("GET").
Queries(LockViewRouteIDQueryParam, fmt.Sprintf("{%s}", LockViewRouteIDQueryParam)).Name(LockViewRouteName)
s.Router.HandleFunc("/jobs/{org}/{repo}/{pull}/{project}", s.JobsController.GetProjectJobs).Methods("GET").Name(ProjectJobsViewRouteName)
s.Router.HandleFunc("/jobs/{org}/{repo}/{pull}/{project}/ws", s.JobsController.GetProjectJobsWS).Methods("GET")
s.Router.HandleFunc("/jobs/{org}/{repo}/{pull}/{project}/{workspace}", s.JobsController.GetProjectJobs).Methods("GET").Name(ProjectJobsViewRouteName)
s.Router.HandleFunc("/jobs/{org}/{repo}/{pull}/{project}/{workspace}/ws", s.JobsController.GetProjectJobsWS).Methods("GET")

n := negroni.New(&negroni.Recovery{
Logger: log.New(os.Stdout, "", log.LstdFlags),
PrintStack: false,
Expand Down

0 comments on commit 954866a

Please sign in to comment.