Get commit message and branch from CI if unavailable (#2062)

* Get commit message and branch from CI if unavailable

* Add tests
This commit is contained in:
Chris Smith 2018-10-16 15:37:02 -07:00 committed by GitHub
parent 00a22b27f8
commit 3264012061
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 5 deletions

View file

@ -385,6 +385,11 @@ func addGitHubMetadataToEnvironment(repo *git.Repository, env map[string]string)
}
func addGitCommitMetadata(repo *git.Repository, repoRoot string, m *backend.UpdateMetadata) error {
// When running in a CI/CD environment, the current git repo may be running from a
// detached HEAD and may not have have the latest commit message. We fall back to
// CI-system specific environment variables when possible.
ciVars := ciutil.DetectVars()
// Commit at HEAD
head, err := repo.Head()
if err != nil {
@ -398,15 +403,23 @@ func addGitCommitMetadata(repo *git.Repository, repoRoot string, m *backend.Upda
return errors.Wrap(commitErr, "getting HEAD commit info")
}
// If in detached head, will be "HEAD", and fallback to use value from CI/CD system if possible.
// Otherwise, the value will be like "refs/heads/master".
headName := head.Name().String()
// Ignore when in detached HEAD state, should be "re"
if headName == "HEAD" && ciVars.BranchName != "" {
headName = ciVars.BranchName
}
if headName != "HEAD" {
m.Environment[backend.GitHeadName] = head.Name().String()
m.Environment[backend.GitHeadName] = headName
}
// If there is no message set manually, default to the Git title.
// If there is no message set manually, default to the Git commit's title.
msg := commit.Message
if msg == "" && ciVars.CommitMessage != "" {
msg = ciVars.CommitMessage
}
if m.Message == "" {
m.Message = gitCommitTitle(commit.Message)
m.Message = gitCommitTitle(msg)
}
// Store committer and author information.

View file

@ -14,6 +14,7 @@
package cmd
import (
"os"
"testing"
"github.com/pulumi/pulumi/pkg/backend"
@ -35,6 +36,13 @@ func assertEnvValue(t *testing.T, md *backend.UpdateMetadata, key, val string) {
// TestReadingGitRepo tests the functions which read data fom the local Git repo
// to add metadata to any updates.
func TestReadingGitRepo(t *testing.T) {
// Disable our CI/CD detection code, since if this unit test is ran under CI
// it will change the expected behavior.
os.Setenv("PULUMI_DISABLE_CI_DETECTION", "1")
defer func() {
os.Unsetenv("PULUMI_DISABLE_CI_DETECTION")
}()
e := pul_testing.NewEnvironment(t)
defer e.DeleteIfNotFailed()
@ -134,7 +142,7 @@ func TestReadingGitRepo(t *testing.T) {
assertEnvValue(t, test, backend.GitHeadName, "refs/heads/feature/branch2")
}
// Change refs by checkingout a tagged commit.
// Change refs by checking out a tagged commit.
// But since we'll be in a detached HEAD state, the git.headName isn't provided.
e.RunCommand("git", "checkout", "v0.0.0")
@ -146,4 +154,36 @@ func TestReadingGitRepo(t *testing.T) {
_, ok := test.Environment[backend.GitHeadName]
assert.False(t, ok, "Expected no 'git.headName' key, since in detached head state.")
}
// Confirm that data can be inferred from the CI system if unavailable.
// Fake running under Travis CI.
varsToSave := []string{"TRAVIS", "TRAVIS_BRANCH"}
origEnvVars := make(map[string]string)
for _, varName := range varsToSave {
origEnvVars[varName] = os.Getenv(varName)
}
defer func() {
for _, varName := range varsToSave {
orig := origEnvVars[varName]
if orig == "" {
os.Unsetenv(varName)
} else {
os.Setenv(varName, orig)
}
}
}()
os.Unsetenv("PULUMI_DISABLE_CI_DETECTION") // Restore our CI/CD detection logic.
os.Setenv("TRAVIS", "1")
os.Setenv("TRAVIS_BRANCH", "branch-from-ci")
{
test := &backend.UpdateMetadata{
Environment: make(map[string]string),
}
assert.NoError(t, addGitMetadata(e.RootPath, test))
name, ok := test.Environment[backend.GitHeadName]
assert.True(t, ok, "Expected 'git.headName' key, from CI util.")
assert.Equal(t, "branch-from-ci", name)
}
}

View file

@ -88,6 +88,11 @@ func IsCI() bool {
// DetectSystem returns a CI system name when the current system looks like a CI system. Detection is based on
// environment variables that CI vendors we know about set.
func DetectSystem() System {
// Provide a way to disable CI/CD detection, as it can interfere with the ability to test.
if os.Getenv("PULUMI_DISABLE_CI_DETECTION") != "" {
return ""
}
for sys, d := range detectors {
if d.IsCI() {
return sys

View file

@ -30,6 +30,10 @@ type Vars struct {
BuildURL string
// SHA is the SHA hash of the code repo at which this build/job is running.
SHA string
// BranchName is the name of the feature branch currently being built.
BranchName string
// CommitMessage is the full message of the Git commit being built.
CommitMessage string
}
// DetectVars detects and returns the CI variables for the current environment.
@ -44,12 +48,16 @@ func DetectVars() Vars {
v.BuildID = os.Getenv("CI_JOB_ID")
v.BuildURL = os.Getenv("CI_JOB_URL")
v.SHA = os.Getenv("CI_COMMIT_SHA")
v.BranchName = os.Getenv("CI_COMMIT_REF_NAME")
v.CommitMessage = os.Getenv("CI_COMMIT_MESSAGE")
case Travis:
// We are running in Travis. See https://docs.travis-ci.com/user/environment-variables/. Travis doesn't
// set a build URL in its environment -- see https://github.com/travis-ci/travis-ci/issues/8935.
v.BuildID = os.Getenv("TRAVIS_JOB_ID")
v.BuildType = os.Getenv("TRAVIS_EVENT_TYPE")
v.SHA = os.Getenv("TRAVIS_PULL_REQUEST_SHA")
v.BranchName = os.Getenv("TRAVIS_BRANCH")
v.CommitMessage = os.Getenv("TRAVIS_COMMIT_MESSAGE")
}
return v
}