Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
**/digger
!/pkg/digger
!/cmd/digger
59 changes: 59 additions & 0 deletions cli/cmd/digger/apply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package main

import (
core_backend "github.com/diggerhq/digger/cli/pkg/core/backend"
core_locking "github.com/diggerhq/digger/cli/pkg/core/locking"
core_policy "github.com/diggerhq/digger/cli/pkg/core/policy"
core_reporting "github.com/diggerhq/digger/cli/pkg/core/reporting"
"github.com/diggerhq/digger/libs/orchestrator"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"strings"
)

var vipApply *viper.Viper

func apply(actor string, projectName string, repoNamespace string, prNumber int, lock core_locking.Lock, policyChecker core_policy.Checker, reporter core_reporting.Reporter, prService orchestrator.PullRequestService, orgService orchestrator.OrgService, backendApi core_backend.Api) {
exec(actor, projectName, repoNamespace, "digger apply", prNumber, lock, policyChecker, prService, orgService, reporter, backendApi)
}

var applyCmd = &cobra.Command{
Use: "apply project_name [flags]",
Short: "Apply a project, if no project specified it will plan for all projects",
Long: `Apply a project, if no project specified it will plan for all projects`,
Run: func(cmd *cobra.Command, args []string) {
var runConfig RunConfig
vipApply.Unmarshal(&runConfig)

prService, orgService, reporter, err := runConfig.GetServices()
if err != nil {
reportErrorAndExit(runConfig.Actor, "Unrecognised reporter: "+runConfig.Reporter, 1)
}

apply(runConfig.Actor, args[0], runConfig.RepoNamespace, runConfig.PRNumber, lock, PolicyChecker, *reporter, *prService, *orgService, BackendApi)
},
}

func init() {
flags := []pflag.Flag{
{Name: "github-token", Usage: "Github token (for github reporter)"},
{Name: "repo-namespace", Usage: "The namespace of this repo"},
{Name: "actor", Usage: "The actor of this command"},
{Name: "reporter", Usage: "The reporter to use (defaults to stdout)"},
{Name: "pr-number", Usage: "The PR number for reporting"},
{Name: "comment-id", Usage: "The PR comment for reporting"},
}

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

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

rootCmd.AddCommand(applyCmd)
}
59 changes: 59 additions & 0 deletions cli/cmd/digger/default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package main

import (
"fmt"
"github.com/diggerhq/digger/cli/pkg/azure"
"github.com/diggerhq/digger/cli/pkg/digger"
"github.com/diggerhq/digger/cli/pkg/usage"
"github.com/spf13/cobra"
"log"
"os"
"runtime/debug"
)

var defaultCmd = &cobra.Command{
Use: "default",
Run: func(cmd *cobra.Command, args []string) {
var logLeader = "Unknown CI"
ci := digger.DetectCI()

switch ci {
case digger.GitHub:
logLeader = os.Getenv("GITHUB_ACTOR")
gitHubCI(lock, PolicyChecker, BackendApi, ReportStrategy)
case digger.GitLab:
logLeader = os.Getenv("CI_PROJECT_NAME")
gitLabCI(lock, PolicyChecker, BackendApi, ReportStrategy)
case digger.Azure:
// This should be refactored in the future because in this way the parsing
// is done twice, both here and inside azureCI, a better solution might be
// to encapsulate it into a method on the azure package and then grab the
// value here and pass it into the azureCI call.
azureContext := os.Getenv("AZURE_CONTEXT")
parsedAzureContext, _ := azure.GetAzureReposContext(azureContext)
logLeader = parsedAzureContext.BaseUrl
azureCI(lock, PolicyChecker, BackendApi, ReportStrategy)
case digger.BitBucket:
logLeader = os.Getenv("BITBUCKET_STEP_TRIGGERER_UUID")
bitbucketCI(lock, PolicyChecker, BackendApi, ReportStrategy)
case digger.None:
print("No CI detected.")
os.Exit(10)
}

defer func() {
if r := recover(); r != nil {
log.Println(fmt.Sprintf("stacktrace from panic: \n" + string(debug.Stack())))
err := usage.SendLogRecord(logLeader, fmt.Sprintf("Panic occurred. %s", r))
if err != nil {
log.Printf("Failed to send log record. %s\n", err)
}
os.Exit(1)
}
}()
},
}

func init() {
rootCmd.AddCommand(defaultCmd)
}
59 changes: 59 additions & 0 deletions cli/cmd/digger/destroy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package main

import (
core_backend "github.com/diggerhq/digger/cli/pkg/core/backend"
core_locking "github.com/diggerhq/digger/cli/pkg/core/locking"
core_policy "github.com/diggerhq/digger/cli/pkg/core/policy"
core_reporting "github.com/diggerhq/digger/cli/pkg/core/reporting"
"github.com/diggerhq/digger/libs/orchestrator"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"strings"
)

var vipDestroy *viper.Viper

func destroy(actor string, projectName string, repoNamespace string, prNumber int, lock core_locking.Lock, policyChecker core_policy.Checker, reporter core_reporting.Reporter, prService orchestrator.PullRequestService, orgService orchestrator.OrgService, backendApi core_backend.Api) {
exec(actor, projectName, repoNamespace, "digger destroy", prNumber, lock, policyChecker, prService, orgService, reporter, backendApi)
}

var destroyCmd = &cobra.Command{
Use: "destroy project_name [flags]",
Short: "Destroy a project",
Long: `Destroy a project`,
Run: func(cmd *cobra.Command, args []string) {
var runConfig RunConfig
vipDestroy.Unmarshal(&runConfig)

prService, orgService, reporter, err := runConfig.GetServices()
if err != nil {
reportErrorAndExit(runConfig.Actor, "Unrecognised reporter: "+runConfig.Reporter, 1)
}

destroy(runConfig.Actor, args[0], runConfig.RepoNamespace, runConfig.PRNumber, lock, PolicyChecker, *reporter, *prService, *orgService, BackendApi)
},
}

func init() {
flags := []pflag.Flag{
{Name: "github-token", Usage: "Github token (for github reporter)"},
{Name: "repo-namespace", Usage: "The namespace of this repo"},
{Name: "actor", Usage: "The actor of this command"},
{Name: "reporter", Usage: "The reporter to use (defaults to stdout)"},
{Name: "pr-number", Usage: "The PR number for reporting"},
{Name: "comment-id", Usage: "The PR comment for reporting"},
}

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

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

rootCmd.AddCommand(destroyCmd)
}
130 changes: 33 additions & 97 deletions cli/cmd/digger/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
core_reporting "github.com/diggerhq/digger/cli/pkg/core/reporting"
"log"
"net/http"
"os"
"runtime/debug"
"strconv"
"strings"
"time"

"github.com/diggerhq/digger/cli/pkg/azure"
"github.com/diggerhq/digger/cli/pkg/backend"
"github.com/diggerhq/digger/cli/pkg/bitbucket"
core_backend "github.com/diggerhq/digger/cli/pkg/core/backend"
core_locking "github.com/diggerhq/digger/cli/pkg/core/locking"
Expand All @@ -23,8 +22,6 @@ import (
"github.com/diggerhq/digger/cli/pkg/gcp"
github_models "github.com/diggerhq/digger/cli/pkg/github/models"
"github.com/diggerhq/digger/cli/pkg/gitlab"
"github.com/diggerhq/digger/cli/pkg/locking"
"github.com/diggerhq/digger/cli/pkg/policy"
"github.com/diggerhq/digger/cli/pkg/reporting"
"github.com/diggerhq/digger/cli/pkg/storage"
"github.com/diggerhq/digger/cli/pkg/usage"
Expand Down Expand Up @@ -86,8 +83,7 @@ func gitHubCI(lock core_locking.Lock, policyChecker core_policy.Checker, backend
reportErrorAndExit(githubActor, "GITHUB_REPOSITORY is not defined", 3)
}

splitRepositoryName := strings.Split(ghRepository, "/")
repoOwner, repositoryName := splitRepositoryName[0], splitRepositoryName[1]
repoOwner, repositoryName := utils.ParseRepoNamespace(ghRepository)
githubPrService := dg_github.NewGitHubService(ghToken, repositoryName, repoOwner)

currentDir, err := os.Getwd()
Expand Down Expand Up @@ -771,6 +767,33 @@ func bitbucketCI(lock core_locking.Lock, policyChecker core_policy.Checker, back
reportErrorAndExit(actor, "Digger finished successfully", 0)
}

func exec(actor string, projectName string, repoNamespace string, command string, prNumber int, lock core_locking.Lock, policyChecker core_policy.Checker, prService orchestrator.PullRequestService, orgService orchestrator.OrgService, reporter core_reporting.Reporter, backendApi core_backend.Api) {

//SCMOrganisation, SCMrepository := utils.ParseRepoNamespace(runConfig.RepoNamespace)
currentDir, err := os.Getwd()
if err != nil {

reportErrorAndExit(actor, fmt.Sprintf("Failed to get current dir. %s", err), 4)

}

planStorage := newPlanStorage("", "", "", actor, nil)

diggerConfig, _, dependencyGraph, err := digger_config.LoadDiggerConfig("./")
if err != nil {
reportErrorAndExit(actor, fmt.Sprintf("Failed to load digger config. %s", err), 4)
}
//impactedProjects := diggerConfig.GetModifiedProjects(strings.Split(runConfig.FilesChanged, ","))
impactedProjects := diggerConfig.GetProjects(projectName)
jobs, _, err := orchestrator.ConvertProjectsToJobs(actor, repoNamespace, command, prNumber, impactedProjects, nil, diggerConfig.Workflows)
if err != nil {
reportErrorAndExit(actor, fmt.Sprintf("Failed to convert impacted projects to commands. %s", err), 4)
}

jobs = digger.SortedCommandsByDependency(jobs, &dependencyGraph)
_, _, err = digger.RunJobs(jobs, prService, orgService, lock, reporter, planStorage, policyChecker, backendApi, "", false, 123, currentDir)
}

/*
Exit codes:
0 - No errors
Expand All @@ -786,100 +809,13 @@ Exit codes:
*/

func main() {
args := os.Args[1:]
if len(args) > 0 && args[0] == "version" {
log.Println(utils.GetVersion())
os.Exit(0)
if len(os.Args) == 1 {
os.Args = append([]string{os.Args[0]}, "default")
}
if len(args) > 0 && args[0] == "help" {
utils.DisplayCommands()
os.Exit(0)
}
var policyChecker core_policy.Checker
var backendApi core_backend.Api
if os.Getenv("NO_BACKEND") == "true" {
log.Println("WARNING: running in 'backendless' mode. Features that require backend will not be available.")
policyChecker = policy.NoOpPolicyChecker{}
backendApi = backend.NoopApi{}
} else if os.Getenv("DIGGER_TOKEN") != "" {
if os.Getenv("DIGGER_ORGANISATION") == "" {
log.Fatalf("Token specified but missing organisation: DIGGER_ORGANISATION. Please set this value in action digger_config.")
}
policyChecker = policy.DiggerPolicyChecker{
PolicyProvider: &policy.DiggerHttpPolicyProvider{
DiggerHost: os.Getenv("DIGGER_HOSTNAME"),
DiggerOrganisation: os.Getenv("DIGGER_ORGANISATION"),
AuthToken: os.Getenv("DIGGER_TOKEN"),
HttpClient: http.DefaultClient,
}}
backendApi = backend.DiggerApi{
DiggerHost: os.Getenv("DIGGER_HOSTNAME"),
AuthToken: os.Getenv("DIGGER_TOKEN"),
HttpClient: http.DefaultClient,
}
} else {
reportErrorAndExit("", "DIGGER_TOKEN not specified. You can get one at https://cloud.digger.dev, or self-manage a backend of Digger Community Edition (change DIGGER_HOSTNAME). You can also pass 'no-backend: true' option; in this case some of the features may not be available.", 1)
if err := rootCmd.Execute(); err != nil {
reportErrorAndExit("", fmt.Sprintf("Error occured during command exec: %v", err), 8)
}

var reportStrategy reporting.ReportStrategy

if os.Getenv("REPORTING_STRATEGY") == "comments_per_run" || os.Getenv("ACCUMULATE_PLANS") == "true" {
reportStrategy = &reporting.CommentPerRunStrategy{
TimeOfRun: time.Now(),
}
} else if os.Getenv("REPORTING_STRATEGY") == "latest_run_comment" {
reportStrategy = &reporting.LatestRunCommentStrategy{
TimeOfRun: time.Now(),
}
} else {
reportStrategy = &reporting.MultipleCommentsStrategy{}
}

lock, err := locking.GetLock()
if err != nil {
log.Printf("Failed to create lock provider. %s\n", err)
os.Exit(2)
}
log.Println("Lock provider has been created successfully")

ci := digger.DetectCI()

var logLeader = "Unknown CI"

switch ci {
case digger.GitHub:
logLeader = os.Getenv("GITHUB_ACTOR")
gitHubCI(lock, policyChecker, backendApi, reportStrategy)
case digger.GitLab:
logLeader = os.Getenv("CI_PROJECT_NAME")
gitLabCI(lock, policyChecker, backendApi, reportStrategy)
case digger.Azure:
// This should be refactored in the future because in this way the parsing
// is done twice, both here and inside azureCI, a better solution might be
// to encapsulate it into a method on the azure package and then grab the
// value here and pass it into the azureCI call.
azureContext := os.Getenv("AZURE_CONTEXT")
parsedAzureContext, _ := azure.GetAzureReposContext(azureContext)
logLeader = parsedAzureContext.BaseUrl
azureCI(lock, policyChecker, backendApi, reportStrategy)
case digger.BitBucket:
logLeader = os.Getenv("BITBUCKET_STEP_TRIGGERER_UUID")
bitbucketCI(lock, policyChecker, backendApi, reportStrategy)
case digger.None:
print("No CI detected.")
os.Exit(10)
}

defer func() {
if r := recover(); r != nil {
log.Println(fmt.Sprintf("stacktrace from panic: \n" + string(debug.Stack())))
err := usage.SendLogRecord(logLeader, fmt.Sprintf("Panic occurred. %s", r))
if err != nil {
log.Printf("Failed to send log record. %s\n", err)
}
os.Exit(1)
}
}()
}

func newPlanStorage(ghToken string, ghRepoOwner string, ghRepositoryName string, requestedBy string, prNumber *int) core_storage.PlanStorage {
Expand Down
Loading