Skip to content

Commit

Permalink
runspec objects (#1560)
Browse files Browse the repository at this point in the history
* runspec objects
  • Loading branch information
motatoes authored Jun 8, 2024
1 parent c699bba commit 9a2cedb
Show file tree
Hide file tree
Showing 8 changed files with 476 additions and 15 deletions.
3 changes: 3 additions & 0 deletions cli/cmd/digger/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ var ReportStrategy reporting.ReportStrategy
var lock locking2.Lock

func PreRun(cmd *cobra.Command, args []string) {
if cmd.Name() == "run_spec" {
return
}

hostName := os.Getenv("DIGGER_HOSTNAME")
token := os.Getenv("DIGGER_TOKEN")
Expand Down
52 changes: 52 additions & 0 deletions cli/cmd/digger/run_spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package main

import (
"encoding/json"
"fmt"
"github.com/diggerhq/digger/cli/pkg/usage"
"github.com/diggerhq/digger/libs/spec"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"strings"
)

var viperRunSpec *viper.Viper

type RunSpecConfig struct {
Spec string `mapstructure:"spec"`
}

var runSpecCmd = &cobra.Command{
Use: "run_spec [flags]",
Short: "run a spec",
Long: `run a spec`,
Run: func(cmd *cobra.Command, args []string) {
var runSpecConfig RunSpecConfig
vipApply.Unmarshal(&runSpecConfig)
var spec spec.Spec
err := json.Unmarshal([]byte(runSpecConfig.Spec), &spec)
if err != nil {
usage.ReportErrorAndExit("", fmt.Sprintf("could not load spec json: %v", err), 1)
}

},
}

func init() {
flags := []pflag.Flag{
{Name: "spec", Usage: "string representing the json of a run spec"},
}

viperRunSpec = viper.New()
viperRunSpec.SetEnvPrefix("DIGGER")
viperRunSpec.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viperRunSpec.AutomaticEnv()

for _, flag := range flags {
runSpecCmd.Flags().String(flag.Name, "", flag.Usage)
vipApply.BindPFlag(flag.Name, runSpecCmd.Flags().Lookup(flag.Name))
}

rootCmd.AddCommand(runSpecCmd)
}
18 changes: 9 additions & 9 deletions cli/pkg/policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ func getPlanPolicyForNamespace(p *DiggerHttpPolicyProvider, namespace string, pr
}

// GetPolicy fetches policy for particular project, if not found then it will fallback to org level policy
func (p *DiggerHttpPolicyProvider) GetAccessPolicy(organisation string, repo string, projectName string) (string, error) {
func (p DiggerHttpPolicyProvider) GetAccessPolicy(organisation string, repo string, projectName string) (string, error) {
namespace := fmt.Sprintf("%v-%v", organisation, repo)
content, resp, err := getAccessPolicyForNamespace(p, namespace, projectName)
content, resp, err := getAccessPolicyForNamespace(&p, namespace, projectName)
if err != nil {
return "", fmt.Errorf("error while fetching access policy for namespace: %v", err)
}
Expand All @@ -195,7 +195,7 @@ func (p *DiggerHttpPolicyProvider) GetAccessPolicy(organisation string, repo str

// check if project policy was empty or not found (retrieve org policy if so)
if (resp.StatusCode == 200 && content == "") || resp.StatusCode == 404 {
content, resp, err := getAccessPolicyForOrganisation(p)
content, resp, err := getAccessPolicyForOrganisation(&p)
if err != nil {
return "", fmt.Errorf("error while fetching access policy for organisation: %v", err)
}
Expand All @@ -211,9 +211,9 @@ func (p *DiggerHttpPolicyProvider) GetAccessPolicy(organisation string, repo str
}
}

func (p *DiggerHttpPolicyProvider) GetPlanPolicy(organisation string, repo string, projectName string) (string, error) {
func (p DiggerHttpPolicyProvider) GetPlanPolicy(organisation string, repo string, projectName string) (string, error) {
namespace := fmt.Sprintf("%v-%v", organisation, repo)
content, resp, err := getPlanPolicyForNamespace(p, namespace, projectName)
content, resp, err := getPlanPolicyForNamespace(&p, namespace, projectName)
if err != nil {
return "", err
}
Expand All @@ -225,7 +225,7 @@ func (p *DiggerHttpPolicyProvider) GetPlanPolicy(organisation string, repo strin

// check if project policy was empty or not found (retrieve org policy if so)
if (resp.StatusCode == 200 && content == "") || resp.StatusCode == 404 {
content, resp, err := getPlanPolicyForOrganisation(p)
content, resp, err := getPlanPolicyForOrganisation(&p)
if err != nil {
return "", err
}
Expand All @@ -241,8 +241,8 @@ func (p *DiggerHttpPolicyProvider) GetPlanPolicy(organisation string, repo strin
}
}

func (p *DiggerHttpPolicyProvider) GetDriftPolicy() (string, error) {
content, resp, err := getDriftPolicyForOrganisation(p)
func (p DiggerHttpPolicyProvider) GetDriftPolicy() (string, error) {
content, resp, err := getDriftPolicyForOrganisation(&p)
if err != nil {
return "", err
}
Expand All @@ -255,7 +255,7 @@ func (p *DiggerHttpPolicyProvider) GetDriftPolicy() (string, error) {
}
}

func (p *DiggerHttpPolicyProvider) GetOrganisation() string {
func (p DiggerHttpPolicyProvider) GetOrganisation() string {
return p.DiggerOrganisation
}

Expand Down
98 changes: 98 additions & 0 deletions cli/pkg/spec/spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package spec

import (
"fmt"
"github.com/diggerhq/digger/cli/pkg/digger"
storage2 "github.com/diggerhq/digger/cli/pkg/storage"
"github.com/diggerhq/digger/cli/pkg/usage"
comment_summary "github.com/diggerhq/digger/libs/comment_utils/summary"
"github.com/diggerhq/digger/libs/digger_config"
"github.com/diggerhq/digger/libs/orchestrator"
orchestrator_github "github.com/diggerhq/digger/libs/orchestrator/github"
"github.com/diggerhq/digger/libs/spec"
"log"
"strconv"
"time"
)

func RunSpec(
spec spec.Spec,
vcsProvider spec.VCSProvider,
jobProvider spec.JobSpecProvider,
lockProvider spec.LockProvider,
reporterProvider spec.ReporterProvider,
backedProvider spec.BackendApiProvider,
policyProvider spec.PolicyProvider,
commentUpdaterProvider comment_summary.CommentUpdaterProvider,
) error {

diggerConfig, _, _, err := digger_config.LoadDiggerConfig("./", true)
if err != nil {
usage.ReportErrorAndExit(spec.VCS.Actor, fmt.Sprintf("Failed to read Digger digger_config. %s", err), 4)
}
log.Printf("Digger digger_config read successfully\n")

job, err := jobProvider.GetJob(spec.Job)
if err != nil {
usage.ReportErrorAndExit(spec.VCS.Actor, fmt.Sprintf("could not get job: %v", err), 1)
}

lock, err := lockProvider.GetLock(spec.Lock)
if err != nil {
usage.ReportErrorAndExit(spec.VCS.Actor, fmt.Sprintf("could not get job: %v", err), 1)

}

prService, err := vcsProvider.GetPrService(spec.VCS)
if err != nil {
usage.ReportErrorAndExit(spec.VCS.Actor, fmt.Sprintf("could not get prservice: %v", err), 1)
}

reporter, err := reporterProvider.GetReporter(spec.Reporter, prService, *spec.Job.PullRequestNumber)
if err != nil {
usage.ReportErrorAndExit(spec.VCS.Actor, fmt.Sprintf("could not get reporter: %v", err), 1)
}

backendApi, err := backedProvider.GetBackendApi(spec.Backend)
if err != nil {
usage.ReportErrorAndExit(spec.VCS.Actor, fmt.Sprintf("could not get backend api: %v", err), 1)
}

policyChecker, err := policyProvider.GetPolicyProvider(spec.Policy, spec.Backend.BackendHostname, spec.Backend.BackendOrganisationName, spec.Backend.BackendJobToken)

commentUpdater, err := commentUpdaterProvider.Get(*diggerConfig)
if err != nil {
usage.ReportErrorAndExit(spec.VCS.Actor, fmt.Sprintf("could not get comment updater: %v", err), 8)
}

planStorage := storage2.NewPlanStorage("", "", "", "", nil)

jobs := []orchestrator.Job{job}

fullRepoName := fmt.Sprintf("%v/%v", spec.VCS.RepoOwner, spec.VCS.RepoName)
serializedBatch, err := backendApi.ReportProjectJobStatus(fullRepoName, spec.Job.ProjectName, spec.JobId, "started", time.Now(), nil, "", "")
if err != nil {
usage.ReportErrorAndExit(spec.VCS.Actor, fmt.Sprintf("Failed to report jobSpec status to backend. Exiting. %v", err), 4)
}

commentId64, err := strconv.ParseInt(spec.CommentId, 10, 64)
if err != nil {
usage.ReportErrorAndExit(spec.VCS.Actor, fmt.Sprintf("failed to get comment ID: %v", err), 4)
}

// TODO: do not require conversion to gh service
ghService := prService.(orchestrator_github.GithubService)
allAppliesSuccess, _, err := digger.RunJobs(jobs, prService, ghService, lock, reporter, planStorage, policyChecker, commentUpdater, backendApi, serializedBatch.ID, true, false, commentId64, "")
if !allAppliesSuccess || err != nil {
serializedBatch, reportingError := backendApi.ReportProjectJobStatus(spec.VCS.RepoName, spec.Job.ProjectName, spec.JobId, "failed", time.Now(), nil, "", "")
if reportingError != nil {
usage.ReportErrorAndExit(spec.VCS.RepoOwner, fmt.Sprintf("Failed run commands. %s", err), 5)
}
commentUpdater.UpdateComment(serializedBatch.Jobs, serializedBatch.PrNumber, prService, commentId64)
digger.UpdateAggregateStatus(serializedBatch, prService)
usage.ReportErrorAndExit(spec.VCS.RepoOwner, fmt.Sprintf("Failed to run commands. %s", err), 5)
}
usage.ReportErrorAndExit(spec.VCS.RepoOwner, "Digger finished successfully", 0)

return nil
}
12 changes: 6 additions & 6 deletions libs/comment_utils/reporting/reporting.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ type CiReporter struct {
ReportStrategy ReportStrategy
}

func (ciReporter *CiReporter) Report(report string, reportFormatting func(report string) string) (string, string, error) {
func (ciReporter CiReporter) Report(report string, reportFormatting func(report string) string) (string, string, error) {
commentId, commentUrl, err := ciReporter.ReportStrategy.Report(ciReporter.CiService, ciReporter.PrNumber, report, reportFormatting, ciReporter.SupportsMarkdown())
return commentId, commentUrl, err
}

func (ciReporter *CiReporter) Flush() (string, string, error) {
func (ciReporter CiReporter) Flush() (string, string, error) {
return "", "", nil
}

func (ciReporter *CiReporter) Suppress() error {
func (ciReporter CiReporter) Suppress() error {
return nil
}

func (ciReporter *CiReporter) SupportsMarkdown() bool {
func (ciReporter CiReporter) SupportsMarkdown() bool {
return ciReporter.IsSupportMarkdown
}

Expand Down Expand Up @@ -182,7 +182,7 @@ type LatestRunCommentStrategy struct {
TimeOfRun time.Time
}

func (strategy *LatestRunCommentStrategy) Report(ciService orchestrator.PullRequestService, PrNumber int, report string, reportFormatter func(report string) string, supportsCollapsibleComment bool) (string, string, error) {
func (strategy LatestRunCommentStrategy) Report(ciService orchestrator.PullRequestService, PrNumber int, report string, reportFormatter func(report string) string, supportsCollapsibleComment bool) (string, string, error) {
comments, err := ciService.GetComments(PrNumber)
if err != nil {
return "", "", fmt.Errorf("error getting comments: %v", err)
Expand All @@ -195,7 +195,7 @@ func (strategy *LatestRunCommentStrategy) Report(ciService orchestrator.PullRequ

type MultipleCommentsStrategy struct{}

func (strategy *MultipleCommentsStrategy) Report(ciService orchestrator.PullRequestService, PrNumber int, report string, reportFormatter func(report string) string, supportsCollapsibleComment bool) (string, string, error) {
func (strategy MultipleCommentsStrategy) Report(ciService orchestrator.PullRequestService, PrNumber int, report string, reportFormatter func(report string) string, supportsCollapsibleComment bool) (string, string, error) {
_, err := ciService.PublishComment(PrNumber, reportFormatter(report))
return "", "", err
}
45 changes: 45 additions & 0 deletions libs/spec/models.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package spec

import "github.com/diggerhq/digger/libs/orchestrator"

type ReporterSpec struct {
ReporterType string `json:"reporter_type"`
ReportingStrategy string `json:"reporting_strategy"`
}

type LockSpec struct {
LockType string `json:"lock_type"`
LockProvider string `json:"lock_provider"`
}

type BackendSpec struct {
BackendType string `json:"backend_type"`
BackendHostname string `json:"backend_hostname"`
BackendOrganisationName string `json:"backend_organisation_hostname"`
BackendJobToken string `json:"backend_job_token"`
}

type VcsSpec struct {
Actor string `json:"actor"`
RepoName string `json:"repo_name"`
RepoOwner string `json:"repo_owner"`
VcsType string `json:"vcs_type"`
}

type PolicySpec struct {
PolicyType string `json:"policy_type"`
}

type Spec struct {
// TODO: replace these three to be nested into one of the other specs
JobId string `json:"job_id"`
CommentId string `json:"comment_id"`
RunName string `json:"run_name"`

Job orchestrator.JobJson `json:"job"`
Reporter ReporterSpec `json:"reporter"`
Lock LockSpec `json:"lock"`
Backend BackendSpec `json:"backend"`
VCS VcsSpec `json:"vcs"`
Policy PolicySpec `json:"policy_provider"`
}
63 changes: 63 additions & 0 deletions libs/spec/models_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package spec

const stubTest = `
{
"job_id": "asdf2321",
"comment_id": "123",
"run_name": "asdf",
"job": {
"job_type": "plan",
"projectName": "abc",
"projectDir": "asd",
"projectWorkspace": "",
"terragrunt": false,
"opentofu": false,
"commands": [
"digger plan"
],
"applyStage": {
"steps": [
{
"action": "init",
"extra_args": []
},
{
"action": "apply",
"extra_args": []
}
]
},
"planStage": {
"steps": [
{
"action": "init",
"extra_args": []
},
{
"action": "plan",
"extra_args": []
}
]
},
"commit": "shasha",
"branch": "",
"eventName": "pull_request",
"requestedBy": "motatoes",
"namespace": "friendly",
"runEnvVars": {},
"stateEnvVars": {},
"commandEnvVars": {},
"aws_role_region": "us-east-1",
"state_role_name": "",
"command_role_name": "",
"backend_hostname": "",
"backend_organisation_hostname": "",
"backend_token": ""
},
"reporter": {},
"lock": {},
"backend": {},
"vcs": {},
"policy_provider": {}
}
`
Loading

0 comments on commit 9a2cedb

Please sign in to comment.