Skip to content

Commit

Permalink
Add gitbranch and sha into spaces payload (#4734)
Browse files Browse the repository at this point in the history
  • Loading branch information
mehulkar committed May 3, 2023
1 parent 75f908f commit 8210af9
Show file tree
Hide file tree
Showing 14 changed files with 286 additions and 11 deletions.
22 changes: 16 additions & 6 deletions cli/internal/ci/vendors.go
Expand Up @@ -15,6 +15,12 @@ type Vendor struct {
Env vendorEnvs
// EvalEnv is key/value map of environment variables that can be used to quickly determine the vendor
EvalEnv map[string]string

// The name of the environment variable that contains the current git sha
ShaEnvVar string

// The name of the environment variable that contains the current checked out branch
BranchEnvVar string
}

// Vendors is a list of common CI/CD vendors (from https://github.com/watson/ci-info/blob/master/vendors.json)
Expand Down Expand Up @@ -107,9 +113,11 @@ var Vendors = []Vendor{
Env: vendorEnvs{Any: []string{"EAS_BUILD"}},
},
{
Name: "GitHub Actions",
Constant: "GITHUB_ACTIONS",
Env: vendorEnvs{Any: []string{"GITHUB_ACTIONS"}},
Name: "GitHub Actions",
Constant: "GITHUB_ACTIONS",
Env: vendorEnvs{Any: []string{"GITHUB_ACTIONS"}},
ShaEnvVar: "GITHUB_SHA",
BranchEnvVar: "GITHUB_REF_NAME",
},
{
Name: "GitLab CI",
Expand Down Expand Up @@ -224,9 +232,11 @@ var Vendors = []Vendor{
Env: vendorEnvs{Any: []string{"TRAVIS"}},
},
{
Name: "Vercel",
Constant: "VERCEL",
Env: vendorEnvs{Any: []string{"NOW_BUILDER", "VERCEL"}},
Name: "Vercel",
Constant: "VERCEL",
Env: vendorEnvs{Any: []string{"NOW_BUILDER", "VERCEL"}},
ShaEnvVar: "VERCEL_GIT_COMMIT_SHA",
BranchEnvVar: "VERCEL_GIT_COMMIT_REF",
},
{
Name: "Visual Studio App Center",
Expand Down
1 change: 1 addition & 0 deletions cli/internal/runsummary/format_json.go
Expand Up @@ -63,4 +63,5 @@ type nonMonorepoRunSummary struct {
EnvMode util.EnvMode `json:"envMode"`
ExecutionSummary *executionSummary `json:"execution,omitempty"`
Tasks []*TaskSummary `json:"tasks"`
SCM *scmState `json:"scm"`
}
2 changes: 2 additions & 0 deletions cli/internal/runsummary/run_summary.go
Expand Up @@ -64,6 +64,7 @@ type RunSummary struct {
EnvMode util.EnvMode `json:"envMode"`
ExecutionSummary *executionSummary `json:"execution,omitempty"`
Tasks []*TaskSummary `json:"tasks"`
SCM *scmState `json:"scm"`
}

// NewRunSummary returns a RunSummary instance
Expand Down Expand Up @@ -105,6 +106,7 @@ func NewRunSummary(
EnvMode: globalEnvMode,
Tasks: []*TaskSummary{},
GlobalHashSummary: globalHashSummary,
SCM: getSCMState(repoRoot),
},
ui: ui,
runType: runType,
Expand Down
41 changes: 41 additions & 0 deletions cli/internal/runsummary/scm_summary.go
@@ -0,0 +1,41 @@
package runsummary

import (
"github.com/vercel/turbo/cli/internal/ci"
"github.com/vercel/turbo/cli/internal/env"
"github.com/vercel/turbo/cli/internal/scm"
"github.com/vercel/turbo/cli/internal/turbopath"
)

type scmState struct {
Type string `json:"type"`
Sha string `json:"sha"`
Branch string `json:"branch"`
}

// getSCMState returns the sha and branch when in a git repo
// Otherwise it should return empty strings right now.
// We my add handling of other scms and non-git tracking in the future.
func getSCMState(dir turbopath.AbsoluteSystemPath) *scmState {
allEnvVars := env.GetEnvMap()

state := &scmState{Type: "git"}

// If we're in CI, try to get the values we need from environment variables
if ci.IsCi() {
vendor := ci.Info()
state.Sha = allEnvVars[vendor.ShaEnvVar]
state.Branch = allEnvVars[vendor.BranchEnvVar]
}

// Otherwise fallback to using `git`
if state.Branch == "" {
state.Branch = scm.GetCurrentBranch(dir)
}

if state.Sha == "" {
state.Sha = scm.GetCurrentSha(dir)
}

return state
}
7 changes: 5 additions & 2 deletions cli/internal/runsummary/spaces.go
Expand Up @@ -26,11 +26,11 @@ type spacesRunPayload struct {
RepositoryPath string `json:"repositoryPath,omitempty"` // where the command was invoked from
Context string `json:"context,omitempty"` // the host on which this Run was executed (e.g. Github Action, Vercel, etc)
Client spacesClientSummary `json:"client"` // Details about the turbo client
GitBranch string `json:"gitBranch"`
GitSha string `json:"gitSha"`

// TODO: we need to add these in
// originationUser string
// gitBranch string
// gitSha string
}

// spacesCacheStatus is the same as TaskCacheSummary so we can convert
Expand Down Expand Up @@ -64,13 +64,16 @@ func (rsm *Meta) newSpacesRunCreatePayload() *spacesRunPayload {
if name := ci.Constant(); name != "" {
context = name
}

return &spacesRunPayload{
StartTime: startTime,
Status: "running",
Command: rsm.synthesizedCommand,
RepositoryPath: rsm.repoPath.ToString(),
Type: "TURBO",
Context: context,
GitBranch: rsm.RunSummary.SCM.Branch,
GitSha: rsm.RunSummary.SCM.Sha,
Client: spacesClientSummary{
ID: "turbo",
Name: "Turbo",
Expand Down
27 changes: 27 additions & 0 deletions cli/internal/scm/scm.go
Expand Up @@ -7,6 +7,9 @@
package scm

import (
"os/exec"
"strings"

"github.com/pkg/errors"

"github.com/vercel/turbo/cli/internal/turbopath"
Expand Down Expand Up @@ -51,3 +54,27 @@ func FromInRepo(repoRoot turbopath.AbsoluteSystemPath) (SCM, error) {
}
return newFallback(dotGitDir.Dir())
}

// GetCurrentBranch returns the current branch
func GetCurrentBranch(dir turbopath.AbsoluteSystemPath) string {
cmd := exec.Command("git", []string{"branch", "--show-current"}...)
cmd.Dir = dir.ToString()

out, err := cmd.Output()
if err != nil {
return ""
}
return strings.TrimRight(string(out), "\n")
}

// GetCurrentSha returns the current SHA
func GetCurrentSha(dir turbopath.AbsoluteSystemPath) string {
cmd := exec.Command("git", []string{"rev-parse", "HEAD"}...)
cmd.Dir = dir.ToString()

out, err := cmd.Output()
if err != nil {
return ""
}
return strings.TrimRight(string(out), "\n")
}
136 changes: 136 additions & 0 deletions cli/internal/scm/scm_test.go
@@ -0,0 +1,136 @@
package scm

import (
"os"
"os/exec"
"testing"

"github.com/stretchr/testify/assert"
"github.com/vercel/turbo/cli/internal/fs"
"github.com/vercel/turbo/cli/internal/turbopath"
)

func TestGetCurrentBranchMain(t *testing.T) {
targetbranch := "main"
testDir := getTestDir(t, "myrepo")
originalName, originalEmail := getOriginalConfig(testDir)

// Setup git
gitCommand(t, testDir, []string{"config", "--global", "user.email", "turbo@vercel.com"})
gitCommand(t, testDir, []string{"config", "--global", "user.name", "Turbobot"})
gitCommand(t, testDir, []string{"init"})

gitCommand(t, testDir, []string{"checkout", "-B", targetbranch})
branch := GetCurrentBranch(testDir)
assert.Equal(t, branch, targetbranch)

// cleanup
gitRm(t, testDir)
gitCommand(t, testDir, []string{"config", "--global", "user.email", originalEmail})
gitCommand(t, testDir, []string{"config", "--global", "user.name", originalName})
}

func TestGetCurrentBranchNonMain(t *testing.T) {
targetbranch := "mybranch"
testDir := getTestDir(t, "myrepo")

originalName, originalEmail := getOriginalConfig(testDir)

// Setup git
gitCommand(t, testDir, []string{"config", "--global", "user.email", "turbo@vercel.com"})
gitCommand(t, testDir, []string{"config", "--global", "user.name", "Turbobot"})
gitCommand(t, testDir, []string{"init"})
gitCommand(t, testDir, []string{"checkout", "-B", targetbranch})

branch := GetCurrentBranch(testDir)
assert.Equal(t, branch, targetbranch)

// cleanup
gitRm(t, testDir)
gitCommand(t, testDir, []string{"config", "--global", "user.email", originalEmail})
gitCommand(t, testDir, []string{"config", "--global", "user.name", originalName})
}

func TestGetCurrentSHA(t *testing.T) {
testDir := getTestDir(t, "myrepo")
originalName, originalEmail := getOriginalConfig(testDir)

// Setup git
gitCommand(t, testDir, []string{"config", "--global", "user.email", "turbo@vercel.com"})
gitCommand(t, testDir, []string{"config", "--global", "user.name", "Turbobot"})
gitCommand(t, testDir, []string{"init"})

// initial sha is blank because there are no commits
initSha := GetCurrentSha(testDir)
assert.True(t, initSha == "", "initial sha is empty")

// first commit
gitCommand(t, testDir, []string{"commit", "--allow-empty", "-am", "new commit"})
sha1 := GetCurrentSha(testDir)
assert.True(t, sha1 != "sha on commit 1 is not empty")

// second commit
gitCommand(t, testDir, []string{"commit", "--allow-empty", "-am", "new commit"})
sha2 := GetCurrentSha(testDir)
assert.True(t, sha2 != "", "sha on commit 2 is not empty")
assert.True(t, sha2 != sha1, "sha on commit 2 changes from commit 1")

// cleanup
gitRm(t, testDir)
gitCommand(t, testDir, []string{"config", "--global", "user.email", originalEmail})
gitCommand(t, testDir, []string{"config", "--global", "user.name", originalName})
}

// Helper functions
func getTestDir(t *testing.T, testName string) turbopath.AbsoluteSystemPath {
defaultCwd, err := os.Getwd()
if err != nil {
t.Errorf("failed to get cwd: %v", err)
}
cwd, err := fs.CheckedToAbsoluteSystemPath(defaultCwd)
if err != nil {
t.Fatalf("cwd is not an absolute directory %v: %v", defaultCwd, err)
}

return cwd.UntypedJoin("testdata", testName)
}

func gitRm(t *testing.T, dir turbopath.AbsoluteSystemPath) {
cmd := exec.Command("rm", []string{"-rf", ".git"}...)
cmd.Dir = dir.ToString()
if out, err := cmd.Output(); err != nil {
t.Fatalf("Failed to cleanup git dir: %s\n%v", out, err)
}
}

func getOriginalConfig(cwd turbopath.AbsoluteSystemPath) (string, string) {
// Ignore errors. If there was an error, it's likely because there was no value for these
// configs (e.g. in CI), so git is returning non-zero status code. This is ok, and we'll use the
// zero-value empty strings.
name, _ := _gitCommand(cwd, []string{"config", "--global", "user.name"})
email, _ := _gitCommand(cwd, []string{"config", "--global", "user.name"})

return name, email
}

func gitCommand(t *testing.T, cwd turbopath.AbsoluteSystemPath, args []string) string {
out, err := _gitCommand(cwd, args)

if err != nil {
t.Fatalf("Failed git command %s: %s\n%v", args, out, err)
}

return string(out)
}

func _gitCommand(cwd turbopath.AbsoluteSystemPath, args []string) (string, error) {
cmd := exec.Command("git", args...)
cmd.Dir = cwd.ToString()
out, err := cmd.CombinedOutput()

if err != nil {
return "", err
}

return string(out), nil
}
Empty file.
1 change: 1 addition & 0 deletions turborepo-tests/integration/tests/dry_json/monorepo.t
Expand Up @@ -76,6 +76,7 @@ Setup
"globalCacheInputs",
"id",
"packages",
"scm",
"tasks",
"turboVersion",
"version"
Expand Down
7 changes: 6 additions & 1 deletion turborepo-tests/integration/tests/dry_json/single_package.t
Expand Up @@ -82,5 +82,10 @@ Setup
"globalPassthrough": null
}
}
]
],
"scm": {
"type": "git",
"sha": "[a-z0-9]+", (re)
"branch": ".+" (re)
}
}
Expand Up @@ -76,5 +76,10 @@ Setup
"globalPassthrough": null
}
}
]
],
"scm": {
"type": "git",
"sha": "[a-z0-9]+", (re)
"branch": ".+" (re)
}
}
Expand Up @@ -143,5 +143,10 @@ Setup
"globalPassthrough": null
}
}
]
],
"scm": {
"type": "git",
"sha": "[a-z0-9]+", (re)
"branch": ".+" (re)
}
}
20 changes: 20 additions & 0 deletions turborepo-tests/integration/tests/run_summary/monorepo.t
Expand Up @@ -29,7 +29,27 @@ Setup
$ FIRST=$(/bin/ls .turbo/runs/*.json | head -n1)
$ SECOND=$(/bin/ls .turbo/runs/*.json | tail -n1)

$ cat $FIRST | jq 'keys'
[
"envMode",
"execution",
"globalCacheInputs",
"id",
"packages",
"scm",
"tasks",
"turboVersion",
"version"
]

# some top level run summary validation
$ cat $FIRST | jq '.scm'
{
"type": "git",
"sha": "[a-z0-9]+", (re)
"branch": ".+" (re)
}

$ cat $FIRST | jq '.tasks | length'
2
$ cat $FIRST | jq '.version'
Expand Down

0 comments on commit 8210af9

Please sign in to comment.