Skip to content

Commit

Permalink
orchestrator(GHActions): align GetJobURL method with Piper's expectat…
Browse files Browse the repository at this point in the history
…ions (#4685)

* Align build and job urls with what is expected by piper

* Add comments, delete unused func

* Clean up

* Update tests

* Update GetJobURL

* Fix test

* Update

* Clean up
  • Loading branch information
vstarostin authored Nov 27, 2023
1 parent 0baa6a6 commit c6c02fc
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 86 deletions.
57 changes: 23 additions & 34 deletions pkg/orchestrator/gitHubActions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"fmt"
"io"
"regexp"
"strconv"
"strings"
"sync"
Expand All @@ -26,7 +27,6 @@ type GitHubActionsConfigProvider struct {
runData run
jobs []job
jobsFetched bool
currentJob job
}

type run struct {
Expand Down Expand Up @@ -180,18 +180,21 @@ func (g *GitHubActionsConfigProvider) GetReference() string {
return getEnv("GITHUB_REF", "n/a")
}

// GetBuildURL returns the builds URL. For example, https://github.com/SAP/jenkins-library/actions/runs/5815297487
// GetBuildURL returns the builds URL. The URL should point to the pipeline (not to the stage)
// that is currently being executed. For example, https://github.com/SAP/jenkins-library/actions/runs/5815297487
func (g *GitHubActionsConfigProvider) GetBuildURL() string {
return g.GetRepoURL() + "/actions/runs/" + g.GetBuildID()
}

// GetJobURL returns the current job HTML URL (not API URL).
// For example, https://github.com/SAP/jenkins-library/actions/runs/123456/jobs/7654321
// GetJobURL returns the job URL. The URL should point to project’s pipelines.
// For example, https://github.com/SAP/jenkins-library/actions/workflows/workflow-file-name.yaml
func (g *GitHubActionsConfigProvider) GetJobURL() string {
// We need to query the GitHub API here because the environment variable GITHUB_JOB returns
// the name of the job, not a numeric ID (which we need to form the URL)
g.guessCurrentJob()
return g.currentJob.HtmlURL
fileName := workflowFileName()
if fileName == "" {
return ""
}

return g.GetRepoURL() + "/actions/workflows/" + fileName
}

// GetJobName returns the current workflow name. For example, "Piper workflow"
Expand Down Expand Up @@ -301,32 +304,6 @@ func convertJobs(jobs []*github.WorkflowJob) []job {
return result
}

func (g *GitHubActionsConfigProvider) guessCurrentJob() {
// check if the current job has already been guessed
if g.currentJob.ID != 0 {
return
}

// fetch jobs if they haven't been fetched yet
if err := g.fetchJobs(); err != nil {
log.Entry().Errorf("failed to fetch jobs: %s", err)
g.jobs = []job{}
return
}

targetJobName := getEnv("GITHUB_JOB", "unknown")
log.Entry().Debugf("looking for job '%s' in jobs list: %v", targetJobName, g.jobs)
for _, j := range g.jobs {
// j.Name may be something like "piper / Init / Init"
// but GITHUB_JOB env may contain only "Init"
if strings.HasSuffix(j.Name, targetJobName) {
log.Entry().Debugf("current job id: %d", j.ID)
g.currentJob = j
return
}
}
}

func (g *GitHubActionsConfigProvider) runIdInt64() (int64, error) {
strRunId := g.GetBuildID()
runId, err := strconv.ParseInt(strRunId, 10, 64)
Expand All @@ -347,3 +324,15 @@ func getOwnerAndRepoNames() (string, string) {

return s[0], s[1]
}

func workflowFileName() string {
workflowRef := getEnv("GITHUB_WORKFLOW_REF", "")
re := regexp.MustCompile(`\.github/workflows/([a-zA-Z0-9_-]+\.(yml|yaml))`)
matches := re.FindStringSubmatch(workflowRef)
if len(matches) > 1 {
return matches[1]
}

log.Entry().Debugf("unable to determine workflow file name from GITHUB_WORKFLOW_REF: %s", workflowRef)
return ""
}
80 changes: 34 additions & 46 deletions pkg/orchestrator/gitHubActions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,50 +104,6 @@ func TestGitHubActionsConfigProvider_GetPullRequestConfig(t *testing.T) {
}
}

func TestGitHubActionsConfigProvider_guessCurrentJob(t *testing.T) {
tests := []struct {
name string
jobs []job
jobsFetched bool
targetJobName string
wantJob job
}{
{
name: "job found",
jobs: []job{{Name: "Job1"}, {Name: "Job2"}, {Name: "Job3"}},
jobsFetched: true,
targetJobName: "Job2",
wantJob: job{Name: "Job2"},
},
{
name: "job found",
jobs: []job{{Name: "Piper / Job1"}, {Name: "Piper / Job2"}, {Name: "Piper / Job3"}},
jobsFetched: true,
targetJobName: "Job2",
wantJob: job{Name: "Piper / Job2"},
},
{
name: "job not found",
jobs: []job{{Name: "Job1"}, {Name: "Job2"}, {Name: "Job3"}},
jobsFetched: true,
targetJobName: "Job123",
wantJob: job{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := &GitHubActionsConfigProvider{
jobs: tt.jobs,
jobsFetched: tt.jobsFetched,
}
_ = os.Setenv("GITHUB_JOB", tt.targetJobName)
g.guessCurrentJob()

assert.Equal(t, tt.wantJob, g.currentJob)
})
}
}

func TestGitHubActionsConfigProvider_fetchRunData(t *testing.T) {
// data
respJson := map[string]interface{}{
Expand Down Expand Up @@ -325,6 +281,7 @@ func TestGitHubActionsConfigProvider_Others(t *testing.T) {
_ = os.Setenv("GITHUB_API_URL", "https://api.github.com")
_ = os.Setenv("GITHUB_SERVER_URL", "https://github.com")
_ = os.Setenv("GITHUB_REPOSITORY", "SAP/jenkins-library")
_ = os.Setenv("GITHUB_WORKFLOW_REF", "SAP/jenkins-library/.github/workflows/piper.yml@refs/heads/main")

p := GitHubActionsConfigProvider{}
startedAt, _ := time.Parse(time.RFC3339, "2023-08-11T07:28:24Z")
Expand All @@ -333,7 +290,6 @@ func TestGitHubActionsConfigProvider_Others(t *testing.T) {
Status: "",
StartedAt: startedAt,
}
p.currentJob = job{ID: 111, Name: "job1", HtmlURL: "https://github.com/SAP/jenkins-library/actions/runs/123456/jobs/7654321"}

assert.Equal(t, "n/a", p.OrchestratorVersion())
assert.Equal(t, "GitHubActions", p.OrchestratorType())
Expand All @@ -344,10 +300,42 @@ func TestGitHubActionsConfigProvider_Others(t *testing.T) {
assert.Equal(t, "main", p.GetBranch())
assert.Equal(t, "refs/pull/42/merge", p.GetReference())
assert.Equal(t, "https://github.com/SAP/jenkins-library/actions/runs/11111", p.GetBuildURL())
assert.Equal(t, "https://github.com/SAP/jenkins-library/actions/runs/123456/jobs/7654321", p.GetJobURL())
assert.Equal(t, "https://github.com/SAP/jenkins-library/actions/workflows/piper.yml", p.GetJobURL())
assert.Equal(t, "Piper workflow", p.GetJobName())
assert.Equal(t, "ffac537e6cbbf934b08745a378932722df287a53", p.GetCommit())
assert.Equal(t, "https://api.github.com/repos/SAP/jenkins-library/actions", actionsURL())
assert.True(t, p.IsPullRequest())
assert.True(t, isGitHubActions())
}

func TestWorkflowFileName(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()

tests := []struct {
name, workflowRef, want string
}{
{
name: "valid file name (yaml)",
workflowRef: "owner/repo/.github/workflows/test-workflow.yaml@refs/heads/main",
want: "test-workflow.yaml",
},
{
name: "valid file name (yml)",
workflowRef: "owner/repo/.github/workflows/test-workflow.yml@refs/heads/main",
want: "test-workflow.yml",
},
{
name: "invalid file name",
workflowRef: "owner/repo/.github/workflows/test-workflow@refs/heads/main",
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_ = os.Setenv("GITHUB_WORKFLOW_REF", tt.workflowRef)
result := workflowFileName()
assert.Equal(t, tt.want, result)
})
}
}
11 changes: 5 additions & 6 deletions pkg/telemetry/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import (
"crypto/sha1"
"encoding/json"
"fmt"
"github.com/SAP/jenkins-library/pkg/orchestrator"
"strconv"
"time"

"net/http"
"net/url"
"strconv"
"time"

piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/orchestrator"
)

// eventType
Expand Down Expand Up @@ -81,8 +80,8 @@ func (t *Telemetry) Initialize(telemetryDisabled bool, stepName string) {
EventType: eventType,
StepName: stepName,
SiteID: t.SiteID,
PipelineURLHash: t.getPipelineURLHash(), // http://server:port/jenkins/job/foo/
BuildURLHash: t.getBuildURLHash(), // http://server:port/jenkins/job/foo/15/
PipelineURLHash: t.getPipelineURLHash(), // URL (hashed value) which points to the project’s pipelines
BuildURLHash: t.getBuildURLHash(), // URL (hashed value) which points to the pipeline that is currently running
}
t.baseMetaData = baseMetaData
}
Expand Down

0 comments on commit c6c02fc

Please sign in to comment.