Skip to content

Commit

Permalink
Add support for Buildkite
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonrudolph committed Aug 9, 2020
1 parent 7416909 commit 47bc0d8
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 1 deletion.
77 changes: 76 additions & 1 deletion metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ type AbstractMetadata struct {
// NewMetadata creates a new Metadata instance from the given environment.
func NewMetadata(envs map[string]string, now func() time.Time) (Metadata, error) {
switch {
case envs["BUILDKITE"] == "true":
return newBuildkiteMetadata(envs, now)
case envs["CIRCLECI"] == "true":
return newCircleMetadata(envs, now)
case envs["GITHUB_ACTIONS"] == "true":
Expand All @@ -42,10 +44,72 @@ func NewMetadata(envs map[string]string, now func() time.Time) (Metadata, error)
case envs["TRAVIS"] == "true":
return newTravisMetadata(envs, now)
default:
return nil, fmt.Errorf("unrecognized environment: system does not appear to be a supported CI provider (CircleCI, GitHub Actions, Semaphore, or Travis CI)")
return nil, fmt.Errorf("unrecognized environment: system does not appear to be a supported CI provider (Buildkite, CircleCI, GitHub Actions, Semaphore, or Travis CI)")
}
}

var _ Metadata = (*buildkiteMetadata)(nil)

type buildkiteMetadata struct {
AbstractMetadata `yaml:",inline"`

BuildkiteBranch string `env:"BUILDKITE_BRANCH" yaml:"-"`
BuildkiteBuildID string `env:"BUILDKITE_BUILD_ID" yaml:":buildkite_build_id"`
BuildkiteBuildNumber uint `env:"BUILDKITE_BUILD_NUMBER" yaml:":buildkite_build_number"`
BuildkiteBuildURL string `env:"BUILDKITE_BUILD_URL" yaml:"-"`
BuildkiteCommit string `env:"BUILDKITE_COMMIT" yaml:"-"`
BuildkiteJobID string `env:"BUILDKITE_JOB_ID" yaml:":buildkite_job_id"`
BuildkiteLabel string `env:"BUILDKITE_LABEL" yaml:":buildkite_label"`
BuildkiteOrganizationSlug string `env:"BUILDKITE_ORGANIZATION_SLUG" yaml:":buildkite_organization_slug"`
BuildkitePipelineID string `env:"BUILDKITE_PIPELINE_ID" yaml:":buildkite_pipeline_id"`
BuildkitePipelineSlug string `env:"BUILDKITE_PIPELINE_SLUG" yaml:":buildkite_pipeline_slug"`
BuildkiteProjectSlug string `env:"BUILDKITE_PROJECT_SLUG" yaml:":buildkite_project_slug"`
BuildkitePullRequest string `env:"BUILDKITE_PULL_REQUEST" yaml:"-"`
BuildkitePullRequestBaseBranch string `env:"BUILDKITE_PULL_REQUEST_BASE_BRANCH" yaml:":buildkite_pull_request_base_branch,omitempty"`
BuildkitePullRequestNumber uint `yaml:":buildkite_pull_request_number,omitempty"`
BuildkitePullRequestRepo string `env:"BUILDKITE_PULL_REQUEST_REPO" yaml:":buildkite_pull_request_repo,omitempty"`
BuildkiteRebuiltFromBuildID string `env:"BUILDKITE_REBUILT_FROM_BUILD_ID" yaml:":buildkite_rebuilt_from_build_id,omitempty"`
BuildkiteRebuiltFromBuildNumber uint `env:"BUILDKITE_REBUILT_FROM_BUILD_NUMBER" yaml:":buildkite_rebuilt_from_build_number,omitempty"`
BuildkiteRepoURL string `env:"BUILDKITE_REPO" yaml:"-"`
BuildkiteRetryCount uint `env:"BUILDKITE_RETRY_COUNT" yaml:":buildkite_retry_count"`
BuildkiteTag string `env:"BUILDKITE_TAG" yaml:":buildkite_tag,omitempty"`
}

func newBuildkiteMetadata(envs map[string]string, now func() time.Time) (Metadata, error) {
m := &buildkiteMetadata{}

if err := env.Parse(m, env.Options{Environment: envs}); err != nil {
return nil, err
}

m.Branch = m.BuildkiteBranch
m.BuildURL = m.BuildkiteBuildURL
m.CIProvider = "buildkite"
m.Commit = m.BuildkiteCommit
m.Timestamp = now()

nwo, err := nameWithOwnerFromGitURL(m.BuildkiteRepoURL)
if err != nil {
return nil, err
}
m.RepoNameWithOwner = nwo

prNum, err := strconv.ParseUint(m.BuildkitePullRequest, 0, 0)
if err == nil {
m.BuildkitePullRequestNumber = uint(prNum)
}

if m.Check == "" {
m.Check = "buildkite"
}

return m, nil
}

func (b *buildkiteMetadata) MarshalYAML() (out []byte, err error) {
return marshalYAML(b)
}

var _ Metadata = (*circleMetadata)(nil)

type circleMetadata struct {
Expand Down Expand Up @@ -275,3 +339,14 @@ func marshalYAML(m interface{}) (out []byte, err error) {

return data, nil
}

func nameWithOwnerFromGitURL(url string) (string, error) {
re := regexp.MustCompile(`github.com[:/](.*)`)

matches := re.FindStringSubmatch(url)
if len(matches) != 2 {
return "", fmt.Errorf("unable to extract repository name-with-owner from URL: %s", url)
}

return strings.TrimSuffix(matches[1], ".git"), nil
}
111 changes: 111 additions & 0 deletions metadata/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,27 @@ func TestNewMetadata(t *testing.T) {
envs map[string]string
fixture string
}{
{
name: "Buildkite",
envs: map[string]string{
"BUILDKITE_BRANCH": "some-branch",
"BUILDKITE_BUILD_ID": "00000000-0000-0000-0000-000000000000",
"BUILDKITE_BUILD_NUMBER": "42",
"BUILDKITE_BUILD_URL": "https://buildkite.com/some-org/some-project/builds/8675309",
"BUILDKITE_COMMIT": "1f192ff735f887dd7a25229b2ece0422d17931f5",
"BUILDKITE_JOB_ID": "11111111-1111-1111-1111-111111111111",
"BUILDKITE_LABEL": ":test_tube: Run tests",
"BUILDKITE_ORGANIZATION_SLUG": "some-org",
"BUILDKITE_PIPELINE_ID": "22222222-2222-2222-2222-222222222222",
"BUILDKITE_PIPELINE_SLUG": "some-pipeline",
"BUILDKITE_PROJECT_SLUG": "some-org/some-project",
"BUILDKITE_PULL_REQUEST": "false",
"BUILDKITE_REPO": "[email protected]:some-owner/some-repo.git",
"BUILDKITE_RETRY_COUNT": "2",
"BUILDKITE": "true",
},
fixture: "./testdata/buildkite.yml",
},
{
name: "CircleCI",
envs: map[string]string{
Expand Down Expand Up @@ -140,6 +161,16 @@ func TestNewMetadata_customCheckName(t *testing.T) {
expectedProvider string
expectedCheck string
}{
{
name: "Buildkite",
envs: map[string]string{
"BUILDKITE": "true",
"BUILDPULSE_CHECK_NAME": "some-custom-check-name",
"BUILDKITE_REPO": "[email protected]:x/y.git",
},
expectedProvider: "buildkite",
expectedCheck: "some-custom-check-name",
},
{
name: "Circle",
envs: map[string]string{
Expand Down Expand Up @@ -190,6 +221,61 @@ func TestNewMetadata_customCheckName(t *testing.T) {
}
}

func TestNewBuildkiteMetadata_extraFields(t *testing.T) {
tests := []struct {
name string
envs map[string]string
expectedLines []string
}{
{
name: "when rebuilt",
envs: map[string]string{
"BUILDKITE_REBUILT_FROM_BUILD_ID": "00000000-0000-0000-0000-000000000000",
"BUILDKITE_REBUILT_FROM_BUILD_NUMBER": "42",
"BUILDKITE_REPO": "[email protected]:x/y.git",
},
expectedLines: []string{
":buildkite_rebuilt_from_build_id: 00000000-0000-0000-0000-000000000000",
":buildkite_rebuilt_from_build_number: 42",
},
},
{
name: "with pull request",
envs: map[string]string{
"BUILDKITE_PULL_REQUEST_BASE_BRANCH": "some-base-branch",
"BUILDKITE_PULL_REQUEST_REPO": "git://github.com/some-forker/some-repo.git",
"BUILDKITE_PULL_REQUEST": "99",
"BUILDKITE_REPO": "[email protected]:x/y.git",
},
expectedLines: []string{
":buildkite_pull_request_base_branch: some-base-branch",
":buildkite_pull_request_repo: git://github.com/some-forker/some-repo.git",
":buildkite_pull_request_number: 99",
},
},
{
name: "with tag",
envs: map[string]string{
"BUILDKITE_REPO": "[email protected]:x/y.git",
"BUILDKITE_TAG": "v0.1.0",
},
expectedLines: []string{":buildkite_tag: v0.1.0"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
meta, err := newBuildkiteMetadata(tt.envs, time.Now)
assert.NoError(t, err)

yaml, err := meta.MarshalYAML()
assert.NoError(t, err)
for _, line := range tt.expectedLines {
assert.Regexp(t, line, string(yaml))
}
})
}
}

func TestNewCircleMetadata_extraFields(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -320,3 +406,28 @@ func TestNewTravisMetadata_extraFields(t *testing.T) {
})
}
}

func Test_nameWithOwnerFromGitURL(t *testing.T) {
tests := []struct {
name string
url string
nwo string
err bool
}{
{name: "https", url: "https://github.com/some-owner/some-repo.git", nwo: "some-owner/some-repo", err: false},
{name: "ssh", url: "[email protected]:some-owner/some-repo.git", nwo: "some-owner/some-repo", err: false},
{name: "malformed", url: "some-malformed-url", nwo: "", err: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
nwo, err := nameWithOwnerFromGitURL(tt.url)

if tt.err {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, nwo, tt.nwo)
}
})
}
}
16 changes: 16 additions & 0 deletions metadata/testdata/buildkite.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
:branch: some-branch
:build_url: https://buildkite.com/some-org/some-project/builds/8675309
:check: buildkite
:ci_provider: buildkite
:commit: 1f192ff735f887dd7a25229b2ece0422d17931f5
:repo_name_with_owner: some-owner/some-repo
:timestamp: 2020-07-11T01:02:03Z
:buildkite_build_id: 00000000-0000-0000-0000-000000000000
:buildkite_build_number: 42
:buildkite_job_id: 11111111-1111-1111-1111-111111111111
:buildkite_label: ':test_tube: Run tests'
:buildkite_organization_slug: some-org
:buildkite_pipeline_id: 22222222-2222-2222-2222-222222222222
:buildkite_pipeline_slug: some-pipeline
:buildkite_project_slug: some-org/some-project
:buildkite_retry_count: 2

0 comments on commit 47bc0d8

Please sign in to comment.