Skip to content

Commit

Permalink
feat(cd): add ref and test selector to workflow notifs
Browse files Browse the repository at this point in the history
  • Loading branch information
smrz2001 committed Nov 8, 2023
1 parent d75c80a commit 4167ea1
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 49 deletions.
24 changes: 24 additions & 0 deletions cd/manager/common/job/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package job

import (
"context"
"fmt"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
Expand Down Expand Up @@ -113,3 +114,26 @@ func CreateJobTable(ctx context.Context, client *dynamodb.Client, table string)
}
return utils.CreateTable(ctx, client, &createTableInput)
}

func CreateWorkflowJob(jobState JobState) (Workflow, error) {
if org, found := jobState.Params[WorkflowJobParam_Org].(string); !found {
return Workflow{}, fmt.Errorf("missing org")
} else if repo, found := jobState.Params[WorkflowJobParam_Repo].(string); !found {
return Workflow{}, fmt.Errorf("missing repo")
} else if ref, found := jobState.Params[WorkflowJobParam_Ref].(string); !found {
return Workflow{}, fmt.Errorf("missing ref")
} else if workflow, found := jobState.Params[WorkflowJobParam_Workflow].(string); !found {
return Workflow{}, fmt.Errorf("missing workflow")
} else {
workflowInputs := make(map[string]interface{}, 0)
if inputs, found := jobState.Params[WorkflowJobParam_Inputs].(map[string]interface{}); found {
workflowInputs = inputs
}
workflowRunUrl, _ := jobState.Params[WorkflowJobParam_Url].(string)
var workflowRunId int64 = 0
if id, found := jobState.Params[JobParam_Id].(float64); found {
workflowRunId = int64(id)
}
return Workflow{org, repo, workflow, ref, workflowInputs, workflowRunUrl, workflowRunId}, nil
}
}
10 changes: 10 additions & 0 deletions cd/manager/common/job/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,13 @@ type JobState struct {
Id string `dynamodbav:"id" json:"-"` // Globally unique ID for each job update
Ttl time.Time `dynamodbav:"ttl,unixtime" json:"-"` // Record expiration
}

type Workflow struct {
Org string
Repo string
Workflow string
Ref string
Inputs map[string]interface{}
Url string
Id int64
}
28 changes: 6 additions & 22 deletions cd/manager/jobs/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,21 @@ var _ manager.JobSm = &githubWorkflowJob{}

type githubWorkflowJob struct {
baseJob
workflow manager.Workflow
workflow job.Workflow
env string
client *github.Client
r manager.Repository
}

func GitHubWorkflowJob(jobState job.JobState, db manager.Database, notifs manager.Notifs, r manager.Repository) (manager.JobSm, error) {
if org, found := jobState.Params[job.WorkflowJobParam_Org].(string); !found {
return nil, fmt.Errorf("githubWorkflowJob: missing org")
} else if repo, found := jobState.Params[job.WorkflowJobParam_Repo].(string); !found {
return nil, fmt.Errorf("githubWorkflowJob: missing repo")
} else if ref, found := jobState.Params[job.WorkflowJobParam_Ref].(string); !found {
return nil, fmt.Errorf("githubWorkflowJob: missing ref")
} else if workflow, found := jobState.Params[job.WorkflowJobParam_Workflow].(string); !found {
return nil, fmt.Errorf("githubWorkflowJob: missing workflow")
if workflow, err := job.CreateWorkflowJob(jobState); err != nil {
return nil, err
} else {
inputs, _ := jobState.Params[job.WorkflowJobParam_Inputs].(map[string]interface{})
if len(inputs) == 0 {
inputs = make(map[string]interface{}, 1)
}
// Add the job ID to the inputs, so we can track the right workflow corresponding to this job.
inputs[job.WorkflowJobParam_JobId] = jobState.JobId
workflow.Inputs[job.WorkflowJobParam_JobId] = jobState.JobId
// Set the environment so that the workflow knows which environment to target
env := os.Getenv(manager.EnvVar_Env)
inputs[job.WorkflowJobParam_Environment] = env
workflow.Inputs[job.WorkflowJobParam_Environment] = env

var httpClient *http.Client = nil
if accessToken, found := os.LookupEnv("GITHUB_ACCESS_TOKEN"); found {
Expand All @@ -57,13 +47,7 @@ func GitHubWorkflowJob(jobState job.JobState, db manager.Database, notifs manage
httpClient = oauth2.NewClient(context.Background(), ts)
}

return &githubWorkflowJob{
baseJob{jobState, db, notifs},
manager.Workflow{org, repo, workflow, ref, inputs},
env,
github.NewClient(httpClient),
r,
}, nil
return &githubWorkflowJob{baseJob{jobState, db, notifs}, workflow, env, github.NewClient(httpClient), r}, nil
}
}

Expand Down
14 changes: 3 additions & 11 deletions cd/manager/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,6 @@ type Task struct {
Name string `dynamodbav:"name,omitempty"` // Container name
}

type Workflow struct {
Org string
Repo string
Workflow string
Ref string
Inputs map[string]interface{}
}

// JobSm represents job state machine objects processed by the job manager
type JobSm interface {
Advance() (job.JobState, error)
Expand Down Expand Up @@ -168,7 +160,7 @@ type Manager interface {
// Repository represents a git service hosting our repositories (e.g. GitHub)
type Repository interface {
GetLatestCommitHash(org, repo, branch, shaTag string) (string, error)
StartWorkflow(Workflow) error
FindMatchingWorkflowRun(workflow Workflow, jobId string, searchTime time.Time) (int64, string, error)
CheckWorkflowStatus(workflow Workflow, workflowRunId int64) (WorkflowStatus, error)
StartWorkflow(job.Workflow) error
FindMatchingWorkflowRun(workflow job.Workflow, jobId string, searchTime time.Time) (int64, string, error)
CheckWorkflowStatus(workflow job.Workflow, workflowRunId int64) (WorkflowStatus, error)
}
53 changes: 41 additions & 12 deletions cd/manager/notifs/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,29 @@ import (
var _ jobNotif = &workflowNotif{}

const defaultWorkflowJobName = "Workflow"
const workflowLogsFieldName = "Logs"
const (
workflowNotifField_Ref = "Ref"
workflowNotifField_TestSelector = "Test Selector"
workflowNotifField_Logs = "Logs"
)
const (
workflowTestSelector_Wildcard = "."
workflowTestSelector_All = "all"
)

type workflowNotif struct {
state job.JobState
workflow job.Workflow
workflowWebhook webhook.Client
}

func newWorkflowNotif(jobState job.JobState) (jobNotif, error) {
if w, err := parseDiscordWebhookUrl("DISCORD_WORKFLOWS_WEBHOOK"); err != nil {
return nil, err
} else if workflow, err := job.CreateWorkflowJob(jobState); err != nil {
return nil, err
} else {
return &workflowNotif{jobState, w}, nil
return &workflowNotif{jobState, workflow, w}, nil
}
}

Expand All @@ -46,18 +57,36 @@ func (w workflowNotif) getTitle() string {
}

func (w workflowNotif) getFields() []discord.EmbedField {
if workflowUrl, found := w.state.Params[job.WorkflowJobParam_Url].(string); found {
repo, _ := w.state.Params[job.WorkflowJobParam_Repo].(string)
// The workflow run ID should have been filled in by this point
workflowRunId, _ := w.state.Params[job.JobParam_Id].(float64)
return []discord.EmbedField{
{
Name: workflowLogsFieldName,
Value: fmt.Sprintf("[%s (%s)](%s)", repo, strconv.Itoa(int(workflowRunId)), workflowUrl),
},
notifFields := []discord.EmbedField{
{
Name: workflowNotifField_Ref,
Value: fmt.Sprintf("[%s](https://github.com/%s/%s/tree/%s)", w.workflow.Ref, w.workflow.Org, w.workflow.Repo, w.workflow.Ref),
},
}
// If this is a test workflow, also report the test selector.
if testSelector, found := w.workflow.Inputs[job.WorkflowJobParam_TestSelector].(string); found {
// Convert wildcard selector to "all" selector
if testSelector == workflowTestSelector_Wildcard {
testSelector = workflowTestSelector_All
}
notifFields = append(
notifFields,
discord.EmbedField{
Name: workflowNotifField_TestSelector,
Value: testSelector,
},
)
}
return nil
if len(w.workflow.Url) > 0 {
notifFields = append(
notifFields,
discord.EmbedField{
Name: workflowNotifField_Logs,
Value: fmt.Sprintf("[%s (%s)](%s)", w.workflow.Repo, strconv.Itoa(int(w.workflow.Id)), w.workflow.Url),
},
)
}
return notifFields
}

func (w workflowNotif) getColor() discordColor {
Expand Down
9 changes: 5 additions & 4 deletions cd/manager/repository/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/google/go-github/v56/github"

"github.com/3box/pipeline-tools/cd/manager"
"github.com/3box/pipeline-tools/cd/manager/common/job"
)

var _ manager.Repository = &Github{}
Expand Down Expand Up @@ -122,7 +123,7 @@ func (g Github) checkRefStatus(org, repo, ref string) (bool, error) {
return false, nil
}

func (g Github) StartWorkflow(workflow manager.Workflow) error {
func (g Github) StartWorkflow(workflow job.Workflow) error {
ctx, cancel := context.WithTimeout(context.Background(), manager.DefaultHttpWaitTime)
defer cancel()

Expand All @@ -138,7 +139,7 @@ func (g Github) StartWorkflow(workflow manager.Workflow) error {
return nil
}

func (g Github) FindMatchingWorkflowRun(workflow manager.Workflow, jobId string, searchTime time.Time) (int64, string, error) {
func (g Github) FindMatchingWorkflowRun(workflow job.Workflow, jobId string, searchTime time.Time) (int64, string, error) {
if workflowRuns, count, err := g.getWorkflowRuns(workflow, searchTime); err != nil {
return -1, "", err
} else if count > 0 {
Expand All @@ -161,7 +162,7 @@ func (g Github) FindMatchingWorkflowRun(workflow manager.Workflow, jobId string,
return -1, "", nil
}

func (g Github) getWorkflowRuns(workflow manager.Workflow, searchTime time.Time) ([]*github.WorkflowRun, int, error) {
func (g Github) getWorkflowRuns(workflow job.Workflow, searchTime time.Time) ([]*github.WorkflowRun, int, error) {
ctx, cancel := context.WithTimeout(context.Background(), manager.DefaultHttpWaitTime)
defer cancel()

Expand Down Expand Up @@ -192,7 +193,7 @@ func (g Github) getWorkflowJobs(org, repo string, workflowRun *github.WorkflowRu
}
}

func (g Github) CheckWorkflowStatus(workflow manager.Workflow, workflowRunId int64) (manager.WorkflowStatus, error) {
func (g Github) CheckWorkflowStatus(workflow job.Workflow, workflowRunId int64) (manager.WorkflowStatus, error) {
if workflowRun, err := g.getWorkflowRun(workflow.Org, workflow.Repo, workflowRunId); err != nil {
return manager.WorkflowStatus_Failure, err
} else {
Expand Down

0 comments on commit 4167ea1

Please sign in to comment.