From 1b874758df8e334db501a1334ebfec5468b2ee38 Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Thu, 22 Feb 2018 00:50:53 -0800 Subject: [PATCH 01/10] removed locator from config. We now have project and revision --- .fossa.yaml | 6 +- cmd/fossa/config.go | 264 ++++++++++++++++++++++++++++++++++++++++++++ cmd/fossa/test.go | 16 +-- cmd/fossa/upload.go | 10 +- 4 files changed, 280 insertions(+), 16 deletions(-) create mode 100644 cmd/fossa/config.go diff --git a/.fossa.yaml b/.fossa.yaml index a8e4338b83..73970afd5e 100644 --- a/.fossa.yaml +++ b/.fossa.yaml @@ -4,9 +4,9 @@ cli: # # Defaults to https://app.fossa.io # server: https://fossa.on-prem # api_key: some-key-here - # # If `project` or `locator` are unset, infer locator from VCS. - # project: git+github.com/fossas/fossa-cli - # locator: git+github.com/fossas/fossa-cli$revision + # # If `project` and/or `revision` are unset, infer from VCS. + # project: fossa-proj + # revision: 4.5 analyze: # ignores: diff --git a/cmd/fossa/config.go b/cmd/fossa/config.go new file mode 100644 index 0000000000..3f263b3ee9 --- /dev/null +++ b/cmd/fossa/config.go @@ -0,0 +1,264 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "strings" + "time" + + logging "github.com/op/go-logging" + "github.com/urfave/cli" + git "gopkg.in/src-d/go-git.v4" + yaml "gopkg.in/yaml.v2" + + "github.com/fossas/fossa-cli/module" +) + +type configFileV1 struct { + // config version + Version string + + CLI struct { + // Upload configuration. + APIKey string `yaml:"api_key"` + Server string + Fetcher string // for now we don't allow use to set this + Project string + Revision string + } + Analyze struct { + Modules []moduleConfig + } +} + +type moduleConfig struct { + Name string + Path string + Type module.Type +} + +func readConfigFile(path string) (configFileV1, error) { + if path != "" { + if _, err := os.Stat(path); err != nil { + return configFileV1{}, fmt.Errorf("invalid config file specified") + } + return parseConfigFile(path) + } + + _, err := os.Stat(".fossa.yml") + if err == nil { + return parseConfigFile(".fossa.yml") + } + + _, err = os.Stat(".fossa.yaml") + if err == nil { + return parseConfigFile(".fossa.yaml") + } + + return setDefaultValues(configFileV1{}) +} + +func parseConfigFile(filename string) (configFileV1, error) { + // Read configuration file. + var config configFileV1 + + bytes, err := ioutil.ReadFile(filename) + if err != nil { + return config, err + } + + err = yaml.Unmarshal(bytes, &config) + if err != nil { + return config, err + } + + config, err = setDefaultValues(config) + if err != nil { + return config, err + } + + return config, nil +} + +func setDefaultValues(c configFileV1) (configFileV1, error) { + // Set config version + if c.Version == "" { + c.Version = "1" + } + + // Set default endpoint. + if c.CLI.Server == "" { + c.CLI.Server = os.Getenv("FOSSA_ENDPOINT") + if c.CLI.Server == "" { + c.CLI.Server = "https://app.fossa.io" + } + } + + // Load API key from environment variable. + if c.CLI.APIKey == "" { + c.CLI.APIKey = os.Getenv("FOSSA_API_KEY") + } + + // default to `Custom` fetcher type + // if they run CLI inside a git repo and haven't given a project name in the config, we change fetcher to git + var fetcher = "cust" + + // Infer project and revision from `git`. + if c.CLI.Project == "" || c.CLI.Revision == "" { + // TODO: this needs to happen in the module directory, not the working directory + repo, err := git.PlainOpen(".") + if err == nil { + project := c.CLI.Project + if project == "" { + origin, err := repo.Remote("origin") + if err == nil && origin != nil { + project = origin.Config().URLs[0] + c.CLI.Project = project + fetcher = "git" // project is a git remote, so fetcher must be as well + } + } + revision := c.CLI.Revision + if revision == "" { + revision, err := repo.Head() + if err == nil { + c.CLI.Revision = revision.Hash().String() + } + } + } + } + + c.CLI.Fetcher = fetcher // set fetcher in config + + return c, nil +} + +type cliConfig struct { + apiKey string + fetcher string + project string + revision string + endpoint string + modules []moduleConfig + debug bool + + defaultConfig defaultConfig + analyzeConfig analyzeConfig + buildConfig buildConfig + testConfig testConfig + uploadConfig uploadConfig +} + +func makeLocator(fetcher string, project string, revision string) string { + if fetcher != "git" { + return fetcher + "+" + project + "$" + revision + } + // Normalise Git URL format + noGitExtension := strings.TrimSuffix(project, ".git") + handleGitHubSSH := strings.Replace(noGitExtension, "git@github.com:", "github.com/", 1) + + // Remove protocols + noHTTPPrefix := strings.TrimPrefix(handleGitHubSSH, "http://") + noHTTPSPrefix := strings.TrimPrefix(noHTTPPrefix, "https://") + + return "git+" + noHTTPSPrefix + "$" + revision +} + +type defaultConfig struct { + build bool +} + +func parseModuleFlag(moduleFlag string) []moduleConfig { + if moduleFlag == "" { + return []moduleConfig{} + } + var config []moduleConfig + + modules := strings.Split(moduleFlag, ",") + for _, m := range modules { + sections := strings.Split(m, ":") + config = append(config, moduleConfig{ + Name: sections[1], + Path: sections[1], + Type: module.Type(sections[0]), + }) + } + + return config +} + +func initialize(c *cli.Context) (cliConfig, error) { + var config = cliConfig{ + apiKey: c.String("api_key"), + fetcher: c.String("fetcher"), + project: c.String("project"), + revision: c.String("revision"), + endpoint: c.String("endpoint"), + modules: parseModuleFlag(c.String("modules")), + debug: c.Bool("debug"), + + defaultConfig: defaultConfig{ + build: c.Bool("build"), + }, + + analyzeConfig: analyzeConfig{ + output: c.Bool("output"), + allowUnresolved: c.Bool("allow-unresolved"), + noUpload: c.Bool("no-upload"), + }, + + buildConfig: buildConfig{ + force: c.Bool("force"), + }, + + testConfig: testConfig{ + timeout: time.Duration(c.Int("timeout")) * time.Second, + }, + + uploadConfig: uploadConfig{ + data: c.String("data"), + }, + } + + // Load configuration file and set overrides. + configFile, err := readConfigFile(c.String("config")) + if err != nil { + return cliConfig{}, err + } + + if config.fetcher == "" { + config.fetcher = configFile.CLI.Fetcher + } + if config.project == "" { + config.project = configFile.CLI.Project + } + if config.revision == "" { + config.revision = configFile.CLI.Revision + } + if config.apiKey == "" { + config.apiKey = configFile.CLI.APIKey + } + if config.endpoint == "" { + config.endpoint = configFile.CLI.Server + } + if len(config.modules) == 0 { + config.modules = configFile.Analyze.Modules + } + + // Configure logging. + if config.debug { + formatter := logging.MustStringFormatter(`%{color}%{time} %{level} %{module}:%{shortpkg}/%{shortfile}/%{shortfunc}%{color:reset} %{message}`) + stderrBackend := logging.AddModuleLevel(logging.NewBackendFormatter(logging.NewLogBackend(os.Stderr, "", 0), formatter)) + stderrBackend.SetLevel(logging.DEBUG, "") + logging.SetBackend(stderrBackend) + } else { + formatter := logging.MustStringFormatter(`%{color}%{level}%{color:reset} %{message}`) + stderrBackend := logging.AddModuleLevel(logging.NewBackendFormatter(logging.NewLogBackend(os.Stderr, "", 0), formatter)) + stderrBackend.SetLevel(logging.INFO, "") + logging.SetBackend(stderrBackend) + } + + mainLogger.Debugf("Configuration initialized: %#v", config) + + return config, nil +} diff --git a/cmd/fossa/test.go b/cmd/fossa/test.go index 4fdd480fb6..f05f09fd7e 100644 --- a/cmd/fossa/test.go +++ b/cmd/fossa/test.go @@ -29,13 +29,13 @@ type buildResponse struct { } } -func getBuild(endpoint, apiKey, project, revision string) (buildResponse, error) { +func getBuild(endpoint, apiKey, fetcher, project, revision string) (buildResponse, error) { server, err := url.Parse(endpoint) if err != nil { return buildResponse{}, fmt.Errorf("invalid FOSSA endpoint: %s", err.Error()) } - buildsURL, err := url.Parse(fmt.Sprintf(buildsEndpoint, url.PathEscape(config.MakeLocator(project, revision)))) + buildsURL, err := url.Parse(fmt.Sprintf(buildsEndpoint, url.PathEscape(config.MakeLocator(fetcher, project, revision)))) if err != nil { return buildResponse{}, fmt.Errorf("invalid FOSSA builds endpoint: %s", err.Error()) } @@ -72,13 +72,13 @@ type issueResponse struct { // RevisionID string // TODO: We need to get this information from /api/issues?fromRevision= } -func getRevision(endpoint, apiKey, project, revision string) (revisionResponse, error) { +func getRevision(endpoint, apiKey, fetcher, project, revision string) (revisionResponse, error) { server, err := url.Parse(endpoint) if err != nil { return revisionResponse{}, fmt.Errorf("invalid FOSSA endpoint: %s", err.Error()) } - revisionsURL, err := url.Parse(fmt.Sprintf(revisionsEndpoint, url.PathEscape(config.MakeLocator(project, revision)))) + revisionsURL, err := url.Parse(fmt.Sprintf(revisionsEndpoint, url.PathEscape(config.MakeLocator(fetcher, project, revision)))) if err != nil { return revisionResponse{}, fmt.Errorf("invalid FOSSA issues endpoint: %s", err.Error()) } @@ -98,13 +98,13 @@ func getRevision(endpoint, apiKey, project, revision string) (revisionResponse, return revisionJSON, nil } -func doTest(s *spinner.Spinner, race chan testResult, endpoint, apiKey, project, revision string) { +func doTest(s *spinner.Spinner, race chan testResult, endpoint, apiKey, fetcher, project, revision string) { s.Suffix = " Waiting for analysis to complete..." s.Start() buildLoop: for { - build, err := getBuild(endpoint, apiKey, project, revision) + build, err := getBuild(endpoint, apiKey, fetcher, project, revision) if isTimeout(err) { time.Sleep(pollRequestDelay) continue @@ -129,7 +129,7 @@ buildLoop: s.Restart() for { - revision, err := getRevision(endpoint, apiKey, project, revision) + revision, err := getRevision(endpoint, apiKey, fetcher, project, revision) if err != nil { race <- testResult{err: err, issues: nil} return @@ -157,7 +157,7 @@ func testCmd(c *cli.Context) { s := spinner.New(spinner.CharSets[11], 100*time.Millisecond) s.Writer = os.Stderr race := make(chan testResult, 1) - go doTest(s, race, conf.Endpoint, conf.APIKey, conf.Project, conf.Revision) + go doTest(s, race, conf.Endpoint, conf.APIKey, conf.Fetcher, conf.Project, conf.Revision) select { case result := <-race: s.Stop() diff --git a/cmd/fossa/upload.go b/cmd/fossa/upload.go index 07c423e04f..f47bf8a7d4 100644 --- a/cmd/fossa/upload.go +++ b/cmd/fossa/upload.go @@ -118,12 +118,12 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) return "", fmt.Errorf("invalid FOSSA endpoint") } - if conf.Revision == "" { - analysisLogger.Fatal("no revision found in working directory; try running in a git repo or passing a locator") + if config.project == "" { + analysisLogger.Fatal("Could not infer project name from either `.fossa.yml` or `git` remote named `origin`") } - if conf.Project == "" { - analysisLogger.Fatal("could not infer project name from either `.fossa.yaml` or `git` remote named `origin`") + if config.revision == "" { + analysisLogger.Fatal("Could not infer revision name from either `.fossa.yml` or `git` remote named `origin`") } // Re-marshal into build data @@ -134,7 +134,7 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) analysisLogger.Debugf("Uploading build data from (%#v) modules: %#v", len(results), string(buildData)) - postRef, _ := url.Parse("/api/builds/custom?locator=" + url.QueryEscape(config.MakeLocator(conf.Project, conf.Revision)) + "&v=" + version) + postRef, _ := url.Parse("/api/builds/custom?locator=" + url.QueryEscape(config.MakeLocator(conf.fetcher, conf.project, conf.revision)) + "&v=" + version) postURL := fossaBaseURL.ResolveReference(postRef).String() analysisLogger.Debugf("Sending build data to <%#v>", postURL) From 0e52c617a3b1c7e98a64ae12ee9cb5408ca0b361 Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Thu, 22 Feb 2018 00:54:13 -0800 Subject: [PATCH 02/10] fixed comment --- cmd/fossa/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/fossa/config.go b/cmd/fossa/config.go index 3f263b3ee9..ca68f23c69 100644 --- a/cmd/fossa/config.go +++ b/cmd/fossa/config.go @@ -23,7 +23,7 @@ type configFileV1 struct { // Upload configuration. APIKey string `yaml:"api_key"` Server string - Fetcher string // for now we don't allow use to set this + Fetcher string // for now we don't allow users to set this Project string Revision string } From c20e5744102b0e4f4ba1b335924bc86cfc709caa Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Mon, 26 Feb 2018 17:18:51 -0800 Subject: [PATCH 03/10] PR changes --- .fossa.yaml | 1 - cmd/fossa/config.go | 12 +++++------- cmd/fossa/upload.go | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.fossa.yaml b/.fossa.yaml index 73970afd5e..3cd38e2530 100644 --- a/.fossa.yaml +++ b/.fossa.yaml @@ -6,7 +6,6 @@ cli: # api_key: some-key-here # # If `project` and/or `revision` are unset, infer from VCS. # project: fossa-proj - # revision: 4.5 analyze: # ignores: diff --git a/cmd/fossa/config.go b/cmd/fossa/config.go index ca68f23c69..e213eb735f 100644 --- a/cmd/fossa/config.go +++ b/cmd/fossa/config.go @@ -21,11 +21,10 @@ type configFileV1 struct { CLI struct { // Upload configuration. - APIKey string `yaml:"api_key"` - Server string - Fetcher string // for now we don't allow users to set this - Project string - Revision string + APIKey string `yaml:"api_key"` + Server string + Fetcher string // for now we don't allow users to set this + Project string } Analyze struct { Modules []moduleConfig @@ -102,7 +101,7 @@ func setDefaultValues(c configFileV1) (configFileV1, error) { // default to `Custom` fetcher type // if they run CLI inside a git repo and haven't given a project name in the config, we change fetcher to git - var fetcher = "cust" + var fetcher = "custom" // Infer project and revision from `git`. if c.CLI.Project == "" || c.CLI.Revision == "" { @@ -190,7 +189,6 @@ func parseModuleFlag(moduleFlag string) []moduleConfig { func initialize(c *cli.Context) (cliConfig, error) { var config = cliConfig{ apiKey: c.String("api_key"), - fetcher: c.String("fetcher"), project: c.String("project"), revision: c.String("revision"), endpoint: c.String("endpoint"), diff --git a/cmd/fossa/upload.go b/cmd/fossa/upload.go index f47bf8a7d4..111c3d632c 100644 --- a/cmd/fossa/upload.go +++ b/cmd/fossa/upload.go @@ -123,7 +123,7 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) } if config.revision == "" { - analysisLogger.Fatal("Could not infer revision name from either `.fossa.yml` or `git` remote named `origin`") + analysisLogger.Fatal("Could not infer revision name from `git` remote named `origin`") } // Re-marshal into build data From 5c5bdcd2a4a05032d3dd4e706d03bb42054fff26 Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Mon, 26 Feb 2018 17:21:44 -0800 Subject: [PATCH 04/10] updated comment --- .fossa.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.fossa.yaml b/.fossa.yaml index 3cd38e2530..cfa27218df 100644 --- a/.fossa.yaml +++ b/.fossa.yaml @@ -4,7 +4,7 @@ cli: # # Defaults to https://app.fossa.io # server: https://fossa.on-prem # api_key: some-key-here - # # If `project` and/or `revision` are unset, infer from VCS. + # # If `project` is unset infer from VCS. # project: fossa-proj analyze: From d7fbaf2ff4fcd8659a58f45e5e1e6d452479f6c9 Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Wed, 28 Feb 2018 14:05:23 -0800 Subject: [PATCH 05/10] added custom-project flag --- cmd/fossa/config.go | 53 +++++++++++++++++++++------------------------ cmd/fossa/main.go | 3 +++ cmd/fossa/upload.go | 9 ++++++-- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/cmd/fossa/config.go b/cmd/fossa/config.go index e213eb735f..04f6c638e2 100644 --- a/cmd/fossa/config.go +++ b/cmd/fossa/config.go @@ -21,10 +21,10 @@ type configFileV1 struct { CLI struct { // Upload configuration. - APIKey string `yaml:"api_key"` - Server string - Fetcher string // for now we don't allow users to set this - Project string + APIKey string `yaml:"api_key"` + Server string + Project string + Revision string } Analyze struct { Modules []moduleConfig @@ -99,12 +99,8 @@ func setDefaultValues(c configFileV1) (configFileV1, error) { c.CLI.APIKey = os.Getenv("FOSSA_API_KEY") } - // default to `Custom` fetcher type - // if they run CLI inside a git repo and haven't given a project name in the config, we change fetcher to git - var fetcher = "custom" - // Infer project and revision from `git`. - if c.CLI.Project == "" || c.CLI.Revision == "" { + if c.CLI.Project == "" { // TODO: this needs to happen in the module directory, not the working directory repo, err := git.PlainOpen(".") if err == nil { @@ -114,7 +110,6 @@ func setDefaultValues(c configFileV1) (configFileV1, error) { if err == nil && origin != nil { project = origin.Config().URLs[0] c.CLI.Project = project - fetcher = "git" // project is a git remote, so fetcher must be as well } } revision := c.CLI.Revision @@ -127,19 +122,18 @@ func setDefaultValues(c configFileV1) (configFileV1, error) { } } - c.CLI.Fetcher = fetcher // set fetcher in config - return c, nil } type cliConfig struct { - apiKey string - fetcher string - project string - revision string - endpoint string - modules []moduleConfig - debug bool + apiKey string + fetcher string + project string + revision string + endpoint string + modules []moduleConfig + debug bool + customProject bool defaultConfig defaultConfig analyzeConfig analyzeConfig @@ -188,12 +182,13 @@ func parseModuleFlag(moduleFlag string) []moduleConfig { func initialize(c *cli.Context) (cliConfig, error) { var config = cliConfig{ - apiKey: c.String("api_key"), - project: c.String("project"), - revision: c.String("revision"), - endpoint: c.String("endpoint"), - modules: parseModuleFlag(c.String("modules")), - debug: c.Bool("debug"), + apiKey: c.String("api_key"), + project: c.String("project"), + revision: c.String("revision"), + endpoint: c.String("endpoint"), + modules: parseModuleFlag(c.String("modules")), + debug: c.Bool("debug"), + customProject: c.Bool("custom-project"), defaultConfig: defaultConfig{ build: c.Bool("build"), @@ -224,9 +219,6 @@ func initialize(c *cli.Context) (cliConfig, error) { return cliConfig{}, err } - if config.fetcher == "" { - config.fetcher = configFile.CLI.Fetcher - } if config.project == "" { config.project = configFile.CLI.Project } @@ -243,6 +235,11 @@ func initialize(c *cli.Context) (cliConfig, error) { config.modules = configFile.Analyze.Modules } + config.fetcher = "git" + if config.customProject { + config.fetcher = "custom" + } + // Configure logging. if config.debug { formatter := logging.MustStringFormatter(`%{color}%{time} %{level} %{module}:%{shortpkg}/%{shortfile}/%{shortfunc}%{color:reset} %{message}`) diff --git a/cmd/fossa/main.go b/cmd/fossa/main.go index f5e9638d29..2f9f4f38b7 100644 --- a/cmd/fossa/main.go +++ b/cmd/fossa/main.go @@ -31,6 +31,7 @@ const ( analyzeOutputUsage = "print results to stdout instead of uploading to FOSSA" analyzeAllowResolvedUsage = "allow unresolved dependencies" debugUsage = "print debug information to stderr" + managedBuildUsage = "upload results as a custom project to FOSSA" ) func main() { @@ -51,6 +52,7 @@ func main() { cli.BoolFlag{Name: "b, build", Usage: "run a default build in module directories if they have not been pre-built"}, cli.BoolFlag{Name: "f, force", Usage: buildForceUsage}, cli.BoolFlag{Name: "debug", Usage: debugUsage}, + cli.BoolFlag{Name: "custom-project", Usage: managedBuildUsage}, } app.Commands = []cli.Command{ @@ -89,6 +91,7 @@ func main() { cli.BoolFlag{Name: "o, output", Usage: analyzeOutputUsage}, cli.BoolFlag{Name: "allow-unresolved", Usage: analyzeAllowResolvedUsage}, cli.BoolFlag{Name: "debug", Usage: debugUsage}, + cli.BoolFlag{Name: "custom-project", Usage: managedBuildUsage}, }, }, { diff --git a/cmd/fossa/upload.go b/cmd/fossa/upload.go index 111c3d632c..a09c0faf8d 100644 --- a/cmd/fossa/upload.go +++ b/cmd/fossa/upload.go @@ -134,7 +134,12 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) analysisLogger.Debugf("Uploading build data from (%#v) modules: %#v", len(results), string(buildData)) - postRef, _ := url.Parse("/api/builds/custom?locator=" + url.QueryEscape(config.MakeLocator(conf.fetcher, conf.project, conf.revision)) + "&v=" + version) + fossaEndpoint := "/api/builds/custom?locator=" + url.QueryEscape(config.MakeLocator(conf.fetcher, conf.project, conf.revision)) + "&v=" + version + if config.customProject { + fossaEndpoint += "&managedBuild=true" + } + + postRef, _ := url.Parse(fossaEndpoint) postURL := fossaBaseURL.ResolveReference(postRef).String() analysisLogger.Debugf("Sending build data to <%#v>", postURL) @@ -156,7 +161,7 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) return "", fmt.Errorf("invalid API key (check the $FOSSA_API_KEY environment variable)") } else if resp.StatusCode == http.StatusPreconditionRequired { // TODO: handle "Managed Project" workflow - return "", fmt.Errorf("invalid project or revision; make sure this version is published and FOSSA has access to your repo") + return "", fmt.Errorf("invalid project or revision; make sure this version is published and FOSSA has access to your repo. To submit a custom project, add the --custom-project flag") } else if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("bad server response (%#v)", responseStr) } From a1fb05f03ef3812edb4d60817396786e99d021dd Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Wed, 28 Feb 2018 14:53:39 -0800 Subject: [PATCH 06/10] changes after rebase --- cmd/fossa/config.go | 259 -------------------------------------------- cmd/fossa/upload.go | 8 +- config/config.go | 37 +++---- config/file.go | 20 ++-- 4 files changed, 33 insertions(+), 291 deletions(-) delete mode 100644 cmd/fossa/config.go diff --git a/cmd/fossa/config.go b/cmd/fossa/config.go deleted file mode 100644 index 04f6c638e2..0000000000 --- a/cmd/fossa/config.go +++ /dev/null @@ -1,259 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "os" - "strings" - "time" - - logging "github.com/op/go-logging" - "github.com/urfave/cli" - git "gopkg.in/src-d/go-git.v4" - yaml "gopkg.in/yaml.v2" - - "github.com/fossas/fossa-cli/module" -) - -type configFileV1 struct { - // config version - Version string - - CLI struct { - // Upload configuration. - APIKey string `yaml:"api_key"` - Server string - Project string - Revision string - } - Analyze struct { - Modules []moduleConfig - } -} - -type moduleConfig struct { - Name string - Path string - Type module.Type -} - -func readConfigFile(path string) (configFileV1, error) { - if path != "" { - if _, err := os.Stat(path); err != nil { - return configFileV1{}, fmt.Errorf("invalid config file specified") - } - return parseConfigFile(path) - } - - _, err := os.Stat(".fossa.yml") - if err == nil { - return parseConfigFile(".fossa.yml") - } - - _, err = os.Stat(".fossa.yaml") - if err == nil { - return parseConfigFile(".fossa.yaml") - } - - return setDefaultValues(configFileV1{}) -} - -func parseConfigFile(filename string) (configFileV1, error) { - // Read configuration file. - var config configFileV1 - - bytes, err := ioutil.ReadFile(filename) - if err != nil { - return config, err - } - - err = yaml.Unmarshal(bytes, &config) - if err != nil { - return config, err - } - - config, err = setDefaultValues(config) - if err != nil { - return config, err - } - - return config, nil -} - -func setDefaultValues(c configFileV1) (configFileV1, error) { - // Set config version - if c.Version == "" { - c.Version = "1" - } - - // Set default endpoint. - if c.CLI.Server == "" { - c.CLI.Server = os.Getenv("FOSSA_ENDPOINT") - if c.CLI.Server == "" { - c.CLI.Server = "https://app.fossa.io" - } - } - - // Load API key from environment variable. - if c.CLI.APIKey == "" { - c.CLI.APIKey = os.Getenv("FOSSA_API_KEY") - } - - // Infer project and revision from `git`. - if c.CLI.Project == "" { - // TODO: this needs to happen in the module directory, not the working directory - repo, err := git.PlainOpen(".") - if err == nil { - project := c.CLI.Project - if project == "" { - origin, err := repo.Remote("origin") - if err == nil && origin != nil { - project = origin.Config().URLs[0] - c.CLI.Project = project - } - } - revision := c.CLI.Revision - if revision == "" { - revision, err := repo.Head() - if err == nil { - c.CLI.Revision = revision.Hash().String() - } - } - } - } - - return c, nil -} - -type cliConfig struct { - apiKey string - fetcher string - project string - revision string - endpoint string - modules []moduleConfig - debug bool - customProject bool - - defaultConfig defaultConfig - analyzeConfig analyzeConfig - buildConfig buildConfig - testConfig testConfig - uploadConfig uploadConfig -} - -func makeLocator(fetcher string, project string, revision string) string { - if fetcher != "git" { - return fetcher + "+" + project + "$" + revision - } - // Normalise Git URL format - noGitExtension := strings.TrimSuffix(project, ".git") - handleGitHubSSH := strings.Replace(noGitExtension, "git@github.com:", "github.com/", 1) - - // Remove protocols - noHTTPPrefix := strings.TrimPrefix(handleGitHubSSH, "http://") - noHTTPSPrefix := strings.TrimPrefix(noHTTPPrefix, "https://") - - return "git+" + noHTTPSPrefix + "$" + revision -} - -type defaultConfig struct { - build bool -} - -func parseModuleFlag(moduleFlag string) []moduleConfig { - if moduleFlag == "" { - return []moduleConfig{} - } - var config []moduleConfig - - modules := strings.Split(moduleFlag, ",") - for _, m := range modules { - sections := strings.Split(m, ":") - config = append(config, moduleConfig{ - Name: sections[1], - Path: sections[1], - Type: module.Type(sections[0]), - }) - } - - return config -} - -func initialize(c *cli.Context) (cliConfig, error) { - var config = cliConfig{ - apiKey: c.String("api_key"), - project: c.String("project"), - revision: c.String("revision"), - endpoint: c.String("endpoint"), - modules: parseModuleFlag(c.String("modules")), - debug: c.Bool("debug"), - customProject: c.Bool("custom-project"), - - defaultConfig: defaultConfig{ - build: c.Bool("build"), - }, - - analyzeConfig: analyzeConfig{ - output: c.Bool("output"), - allowUnresolved: c.Bool("allow-unresolved"), - noUpload: c.Bool("no-upload"), - }, - - buildConfig: buildConfig{ - force: c.Bool("force"), - }, - - testConfig: testConfig{ - timeout: time.Duration(c.Int("timeout")) * time.Second, - }, - - uploadConfig: uploadConfig{ - data: c.String("data"), - }, - } - - // Load configuration file and set overrides. - configFile, err := readConfigFile(c.String("config")) - if err != nil { - return cliConfig{}, err - } - - if config.project == "" { - config.project = configFile.CLI.Project - } - if config.revision == "" { - config.revision = configFile.CLI.Revision - } - if config.apiKey == "" { - config.apiKey = configFile.CLI.APIKey - } - if config.endpoint == "" { - config.endpoint = configFile.CLI.Server - } - if len(config.modules) == 0 { - config.modules = configFile.Analyze.Modules - } - - config.fetcher = "git" - if config.customProject { - config.fetcher = "custom" - } - - // Configure logging. - if config.debug { - formatter := logging.MustStringFormatter(`%{color}%{time} %{level} %{module}:%{shortpkg}/%{shortfile}/%{shortfunc}%{color:reset} %{message}`) - stderrBackend := logging.AddModuleLevel(logging.NewBackendFormatter(logging.NewLogBackend(os.Stderr, "", 0), formatter)) - stderrBackend.SetLevel(logging.DEBUG, "") - logging.SetBackend(stderrBackend) - } else { - formatter := logging.MustStringFormatter(`%{color}%{level}%{color:reset} %{message}`) - stderrBackend := logging.AddModuleLevel(logging.NewBackendFormatter(logging.NewLogBackend(os.Stderr, "", 0), formatter)) - stderrBackend.SetLevel(logging.INFO, "") - logging.SetBackend(stderrBackend) - } - - mainLogger.Debugf("Configuration initialized: %#v", config) - - return config, nil -} diff --git a/cmd/fossa/upload.go b/cmd/fossa/upload.go index a09c0faf8d..ac76714a08 100644 --- a/cmd/fossa/upload.go +++ b/cmd/fossa/upload.go @@ -118,11 +118,11 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) return "", fmt.Errorf("invalid FOSSA endpoint") } - if config.project == "" { + if conf.Project == "" { analysisLogger.Fatal("Could not infer project name from either `.fossa.yml` or `git` remote named `origin`") } - if config.revision == "" { + if conf.Revision == "" { analysisLogger.Fatal("Could not infer revision name from `git` remote named `origin`") } @@ -134,8 +134,8 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) analysisLogger.Debugf("Uploading build data from (%#v) modules: %#v", len(results), string(buildData)) - fossaEndpoint := "/api/builds/custom?locator=" + url.QueryEscape(config.MakeLocator(conf.fetcher, conf.project, conf.revision)) + "&v=" + version - if config.customProject { + fossaEndpoint := "/api/builds/custom?locator=" + url.QueryEscape(config.MakeLocator(conf.Fetcher, conf.Project, conf.Revision)) + "&v=" + version + if conf.CustomProject { fossaEndpoint += "&managedBuild=true" } diff --git a/config/config.go b/config/config.go index 933cd1454b..fdab723ce2 100644 --- a/config/config.go +++ b/config/config.go @@ -40,12 +40,14 @@ type UploadConfig struct { // CLIConfig specifies the config available to the cli type CLIConfig struct { - APIKey string - Project string - Revision string - Endpoint string - Modules []ModuleConfig - Debug bool + APIKey string + Fetcher string + Project string + Revision string + Endpoint string + Modules []ModuleConfig + Debug bool + CustomProject bool DefaultCmd DefaultConfig AnalyzeCmd AnalyzeConfig @@ -57,7 +59,10 @@ type CLIConfig struct { } // MakeLocator creates a locator string given a package and revision -func MakeLocator(project string, revision string) string { +func MakeLocator(fetcher string, project string, revision string) string { + if fetcher != "git" { + return fetcher + "+" + project + "$" + revision + } // Remove fetcher prefix (in case project is derived from splitting a locator on '$') noFetcherPrefix := strings.TrimPrefix(project, "git+") @@ -109,6 +114,7 @@ func New(c *cli.Context) (CLIConfig, error) { Modules: modules, Debug: c.Bool("debug"), ConfigFilePath: c.String("config"), + CustomProject: c.Bool("custom-project"), DefaultCmd: DefaultConfig{ Build: c.Bool("build"), @@ -139,23 +145,16 @@ func New(c *cli.Context) (CLIConfig, error) { return CLIConfig{}, err } - var locatorSections []string - var locatorProject string - var locatorRevision string - - if configFile.CLI.Locator != "" { - locatorSections = strings.Split(configFile.CLI.Locator, "$") - locatorProject = strings.TrimPrefix(locatorSections[0], "git+") - locatorRevision = locatorSections[1] + config.Fetcher = "git" + if config.CustomProject { + config.Fetcher = "custom" } + if config.Project == "" { config.Project = configFile.CLI.Project - if config.Project == "" { - config.Project = locatorProject - } } if config.Revision == "" { - config.Revision = locatorRevision + config.Revision = configFile.CLI.Revision } if config.APIKey == "" { diff --git a/config/file.go b/config/file.go index a0e752e731..f151f59b93 100644 --- a/config/file.go +++ b/config/file.go @@ -18,10 +18,10 @@ type configFileV1 struct { type configFileCLIV1 struct { // Upload configuration. - APIKey string `yaml:"api_key,omitempty"` - Server string `yaml:"server,omitempty"` - Project string `yaml:"project,omitempty"` - Locator string `yaml:"locator,omitempty"` + APIKey string `yaml:"api_key,omitempty"` + Server string `yaml:"server,omitempty"` + Project string `yaml:"project,omitempty"` + Revision string `yaml:"revision,omitempty"` } type configFileAnalyzeV1 struct { @@ -87,7 +87,7 @@ func setDefaultValues(c configFileV1) (configFileV1, error) { } // Infer default locator and project from `git`. - if c.CLI.Locator == "" { + if c.CLI.Project == "" { // TODO: this needs to happen in the module directory, not the working // directory repo, err := git.PlainOpen(".") @@ -100,10 +100,12 @@ func setDefaultValues(c configFileV1) (configFileV1, error) { c.CLI.Project = project } } - - revision, err := repo.Head() - if err == nil { - c.CLI.Locator = "git+" + project + "$" + revision.Hash().String() + revision := c.CLI.Revision + if revision == "" { + revision, err := repo.Head() + if err == nil { + c.CLI.Revision = revision.Hash().String() + } } } } From 12c077b343de725044e3bcf94410d5146e9d132b Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Wed, 28 Feb 2018 15:31:30 -0800 Subject: [PATCH 07/10] added fix to function --- cmd/fossa/update.go | 3 +++ cmd/fossa/upload.go | 4 ++-- config/config.go | 10 +++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cmd/fossa/update.go b/cmd/fossa/update.go index 6f5d1e16da..cd509c9c75 100644 --- a/cmd/fossa/update.go +++ b/cmd/fossa/update.go @@ -15,6 +15,9 @@ const updateEndpoint = "fossas/fossa-cli" var updateLogger = logging.MustGetLogger("update") func getSemver(v string) string { + if v == "" { + return "" + } if v[0] != 'v' { return "" } diff --git a/cmd/fossa/upload.go b/cmd/fossa/upload.go index ac76714a08..5a82a1ebf8 100644 --- a/cmd/fossa/upload.go +++ b/cmd/fossa/upload.go @@ -122,8 +122,8 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) analysisLogger.Fatal("Could not infer project name from either `.fossa.yml` or `git` remote named `origin`") } - if conf.Revision == "" { - analysisLogger.Fatal("Could not infer revision name from `git` remote named `origin`") + if !conf.CustomProject && conf.Revision == "" { + analysisLogger.Fatal("Could not infer revision name from `git` remote named `origin`. To submit a custom project, add the --custom-project flag") } // Re-marshal into build data diff --git a/config/config.go b/config/config.go index fdab723ce2..96c56f5aa8 100644 --- a/config/config.go +++ b/config/config.go @@ -145,11 +145,6 @@ func New(c *cli.Context) (CLIConfig, error) { return CLIConfig{}, err } - config.Fetcher = "git" - if config.CustomProject { - config.Fetcher = "custom" - } - if config.Project == "" { config.Project = configFile.CLI.Project } @@ -157,6 +152,11 @@ func New(c *cli.Context) (CLIConfig, error) { config.Revision = configFile.CLI.Revision } + config.Fetcher = "git" + if config.CustomProject { + config.Fetcher = "custom" + } + if config.APIKey == "" { config.APIKey = configFile.CLI.APIKey } From 5c98745255b26d384925123dd9a4f771f6ff5392 Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Wed, 28 Feb 2018 21:24:00 -0800 Subject: [PATCH 08/10] add or clause with revision --- config/file.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/file.go b/config/file.go index f151f59b93..2f1bec8227 100644 --- a/config/file.go +++ b/config/file.go @@ -87,7 +87,7 @@ func setDefaultValues(c configFileV1) (configFileV1, error) { } // Infer default locator and project from `git`. - if c.CLI.Project == "" { + if c.CLI.Project == "" || c.CLI.Revision == "" { // TODO: this needs to happen in the module directory, not the working // directory repo, err := git.PlainOpen(".") From 4d9806c4aa62bddc8cac2ac87a741bfb6de29ad2 Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Wed, 28 Feb 2018 22:14:08 -0800 Subject: [PATCH 09/10] change flag to ExistingProject in config. defaults to false --- cmd/fossa/upload.go | 6 +++--- config/config.go | 38 +++++++++++++++++++------------------- config/file.go | 17 +++++++++-------- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/cmd/fossa/upload.go b/cmd/fossa/upload.go index 5a82a1ebf8..9854096b22 100644 --- a/cmd/fossa/upload.go +++ b/cmd/fossa/upload.go @@ -122,8 +122,8 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) analysisLogger.Fatal("Could not infer project name from either `.fossa.yml` or `git` remote named `origin`") } - if !conf.CustomProject && conf.Revision == "" { - analysisLogger.Fatal("Could not infer revision name from `git` remote named `origin`. To submit a custom project, add the --custom-project flag") + if conf.ExistingProject && conf.Revision == "" { + analysisLogger.Fatal("Could not infer revision name from `git` remote named `origin`. To submit a custom project, set existing_project to false in `.fossa.yml`") } // Re-marshal into build data @@ -135,7 +135,7 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) analysisLogger.Debugf("Uploading build data from (%#v) modules: %#v", len(results), string(buildData)) fossaEndpoint := "/api/builds/custom?locator=" + url.QueryEscape(config.MakeLocator(conf.Fetcher, conf.Project, conf.Revision)) + "&v=" + version - if conf.CustomProject { + if !conf.ExistingProject { fossaEndpoint += "&managedBuild=true" } diff --git a/config/config.go b/config/config.go index 96c56f5aa8..233c35e1f1 100644 --- a/config/config.go +++ b/config/config.go @@ -40,14 +40,14 @@ type UploadConfig struct { // CLIConfig specifies the config available to the cli type CLIConfig struct { - APIKey string - Fetcher string - Project string - Revision string - Endpoint string - Modules []ModuleConfig - Debug bool - CustomProject bool + APIKey string + Fetcher string + Project string + Revision string + Endpoint string + Modules []ModuleConfig + Debug bool + ExistingProject bool DefaultCmd DefaultConfig AnalyzeCmd AnalyzeConfig @@ -107,14 +107,14 @@ func New(c *cli.Context) (CLIConfig, error) { } var config = CLIConfig{ - APIKey: c.String("api_key"), - Project: c.String("project"), - Revision: c.String("revision"), - Endpoint: c.String("endpoint"), - Modules: modules, - Debug: c.Bool("debug"), - ConfigFilePath: c.String("config"), - CustomProject: c.Bool("custom-project"), + APIKey: c.String("api_key"), + Project: c.String("project"), + Revision: c.String("revision"), + Endpoint: c.String("endpoint"), + Modules: modules, + Debug: c.Bool("debug"), + ConfigFilePath: c.String("config"), + ExistingProject: c.Bool("existing_project"), DefaultCmd: DefaultConfig{ Build: c.Bool("build"), @@ -152,9 +152,9 @@ func New(c *cli.Context) (CLIConfig, error) { config.Revision = configFile.CLI.Revision } - config.Fetcher = "git" - if config.CustomProject { - config.Fetcher = "custom" + config.Fetcher = "custom" + if config.ExistingProject { + config.Fetcher = "git" } if config.APIKey == "" { diff --git a/config/file.go b/config/file.go index 2f1bec8227..c4874aa067 100644 --- a/config/file.go +++ b/config/file.go @@ -18,10 +18,11 @@ type configFileV1 struct { type configFileCLIV1 struct { // Upload configuration. - APIKey string `yaml:"api_key,omitempty"` - Server string `yaml:"server,omitempty"` - Project string `yaml:"project,omitempty"` - Revision string `yaml:"revision,omitempty"` + APIKey string `yaml:"api_key,omitempty"` + Server string `yaml:"server,omitempty"` + Project string `yaml:"project,omitempty"` + Revision string `yaml:"revision,omitempty"` + ExistingProject bool `yaml:"existing_project"` // project exists in FOSSA (defaults to false as managed build is default) } type configFileAnalyzeV1 struct { @@ -127,15 +128,15 @@ func WriteConfigFile(conf *CLIConfig) error { writeConfig := configFileV1{ Version: 1, CLI: configFileCLIV1{ - APIKey: keyToWrite, - Server: conf.Endpoint, - Project: conf.Project, + APIKey: keyToWrite, + Server: conf.Endpoint, + Project: conf.Project, + ExistingProject: conf.ExistingProject, }, Analyze: configFileAnalyzeV1{ Modules: conf.Modules, }, } - yamlConfig, err := yaml.Marshal(writeConfig) if err != nil { return err From c3ccc74c5c913197df29938ac7e71800d657f724 Mon Sep 17 00:00:00 2001 From: anuccio1 Date: Thu, 1 Mar 2018 16:54:47 -0800 Subject: [PATCH 10/10] switch back to using fetcher --- .fossa.yaml | 2 ++ cmd/fossa/main.go | 8 +++++--- cmd/fossa/upload.go | 8 ++++---- config/config.go | 36 +++++++++++++++++------------------- config/file.go | 23 ++++++++++++++--------- 5 files changed, 42 insertions(+), 35 deletions(-) diff --git a/.fossa.yaml b/.fossa.yaml index cfa27218df..7a84963032 100644 --- a/.fossa.yaml +++ b/.fossa.yaml @@ -4,6 +4,8 @@ cli: # # Defaults to https://app.fossa.io # server: https://fossa.on-prem # api_key: some-key-here + # # If you're uploading to an existing git project, or a custom project in FOSSA + # fetcher: custom # # If `project` is unset infer from VCS. # project: fossa-proj diff --git a/cmd/fossa/main.go b/cmd/fossa/main.go index 2f9f4f38b7..de2fcaae2c 100644 --- a/cmd/fossa/main.go +++ b/cmd/fossa/main.go @@ -24,6 +24,7 @@ var mainLogger = logging.MustGetLogger("main") const ( configUsage = "path to config file (default: .fossa.{yml,yaml})" + fetcherUsage = "type of fetcher to use for fossa. Default's to custom" projectUsage = "the FOSSA project name (default: VCS remote 'origin')" revisionUsage = "the FOSSA project's revision hash (default: VCS hash HEAD)" endpointUsage = "the FOSSA server endpoint (default: https://app.fossa.io)" @@ -31,7 +32,6 @@ const ( analyzeOutputUsage = "print results to stdout instead of uploading to FOSSA" analyzeAllowResolvedUsage = "allow unresolved dependencies" debugUsage = "print debug information to stderr" - managedBuildUsage = "upload results as a custom project to FOSSA" ) func main() { @@ -47,12 +47,12 @@ func main() { cli.StringFlag{Name: "r, revision", Usage: revisionUsage}, cli.StringFlag{Name: "e, endpoint", Usage: endpointUsage}, cli.StringFlag{Name: "m, modules", Usage: "the modules to build and analyze"}, + cli.StringFlag{Name: "fetcher", Usage: fetcherUsage}, cli.BoolFlag{Name: "o, output", Usage: analyzeOutputUsage}, cli.BoolFlag{Name: "allow-unresolved", Usage: analyzeAllowResolvedUsage}, cli.BoolFlag{Name: "b, build", Usage: "run a default build in module directories if they have not been pre-built"}, cli.BoolFlag{Name: "f, force", Usage: buildForceUsage}, cli.BoolFlag{Name: "debug", Usage: debugUsage}, - cli.BoolFlag{Name: "custom-project", Usage: managedBuildUsage}, } app.Commands = []cli.Command{ @@ -84,6 +84,7 @@ func main() { Action: analyzeCmd, Flags: []cli.Flag{ cli.StringFlag{Name: "c, config", Usage: configUsage}, + cli.StringFlag{Name: "fetcher", Usage: fetcherUsage}, cli.StringFlag{Name: "p, project", Usage: projectUsage}, cli.StringFlag{Name: "r, revision", Usage: revisionUsage}, cli.StringFlag{Name: "e, endpoint", Usage: endpointUsage}, @@ -91,7 +92,6 @@ func main() { cli.BoolFlag{Name: "o, output", Usage: analyzeOutputUsage}, cli.BoolFlag{Name: "allow-unresolved", Usage: analyzeAllowResolvedUsage}, cli.BoolFlag{Name: "debug", Usage: debugUsage}, - cli.BoolFlag{Name: "custom-project", Usage: managedBuildUsage}, }, }, { @@ -100,6 +100,7 @@ func main() { Action: testCmd, Flags: []cli.Flag{ cli.StringFlag{Name: "c, config", Usage: configUsage}, + cli.StringFlag{Name: "fetcher", Usage: fetcherUsage}, cli.StringFlag{Name: "p, project", Usage: projectUsage}, cli.StringFlag{Name: "r, revision", Usage: revisionUsage}, cli.StringFlag{Name: "e, endpoint", Usage: endpointUsage}, @@ -113,6 +114,7 @@ func main() { Action: uploadCmd, Flags: []cli.Flag{ cli.StringFlag{Name: "c, config", Usage: configUsage}, + cli.StringFlag{Name: "fetcher", Usage: fetcherUsage}, cli.StringFlag{Name: "p, project", Usage: projectUsage}, cli.StringFlag{Name: "r, revision", Usage: revisionUsage}, cli.StringFlag{Name: "e, endpoint", Usage: endpointUsage}, diff --git a/cmd/fossa/upload.go b/cmd/fossa/upload.go index 9854096b22..209547b1e4 100644 --- a/cmd/fossa/upload.go +++ b/cmd/fossa/upload.go @@ -122,8 +122,8 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) analysisLogger.Fatal("Could not infer project name from either `.fossa.yml` or `git` remote named `origin`") } - if conf.ExistingProject && conf.Revision == "" { - analysisLogger.Fatal("Could not infer revision name from `git` remote named `origin`. To submit a custom project, set existing_project to false in `.fossa.yml`") + if conf.Fetcher != "custom" && conf.Revision == "" { + analysisLogger.Fatal("Could not infer revision name from `git` remote named `origin`. To submit a custom project, set Fetcher to `custom` in `.fossa.yml`") } // Re-marshal into build data @@ -135,7 +135,7 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) analysisLogger.Debugf("Uploading build data from (%#v) modules: %#v", len(results), string(buildData)) fossaEndpoint := "/api/builds/custom?locator=" + url.QueryEscape(config.MakeLocator(conf.Fetcher, conf.Project, conf.Revision)) + "&v=" + version - if !conf.ExistingProject { + if conf.Fetcher == "custom" { fossaEndpoint += "&managedBuild=true" } @@ -161,7 +161,7 @@ func doUpload(conf config.CLIConfig, results []normalizedModule) (string, error) return "", fmt.Errorf("invalid API key (check the $FOSSA_API_KEY environment variable)") } else if resp.StatusCode == http.StatusPreconditionRequired { // TODO: handle "Managed Project" workflow - return "", fmt.Errorf("invalid project or revision; make sure this version is published and FOSSA has access to your repo. To submit a custom project, add the --custom-project flag") + return "", fmt.Errorf("invalid project or revision; make sure this version is published and FOSSA has access to your repo. To submit a custom project, set Fetcher to `custom` in `.fossa.yml`") } else if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("bad server response (%#v)", responseStr) } diff --git a/config/config.go b/config/config.go index 233c35e1f1..bc97843c52 100644 --- a/config/config.go +++ b/config/config.go @@ -40,14 +40,13 @@ type UploadConfig struct { // CLIConfig specifies the config available to the cli type CLIConfig struct { - APIKey string - Fetcher string - Project string - Revision string - Endpoint string - Modules []ModuleConfig - Debug bool - ExistingProject bool + APIKey string + Fetcher string + Project string + Revision string + Endpoint string + Modules []ModuleConfig + Debug bool DefaultCmd DefaultConfig AnalyzeCmd AnalyzeConfig @@ -107,14 +106,14 @@ func New(c *cli.Context) (CLIConfig, error) { } var config = CLIConfig{ - APIKey: c.String("api_key"), - Project: c.String("project"), - Revision: c.String("revision"), - Endpoint: c.String("endpoint"), - Modules: modules, - Debug: c.Bool("debug"), - ConfigFilePath: c.String("config"), - ExistingProject: c.Bool("existing_project"), + APIKey: c.String("api_key"), + Fetcher: c.String("fetcher"), + Project: c.String("project"), + Revision: c.String("revision"), + Endpoint: c.String("endpoint"), + Modules: modules, + Debug: c.Bool("debug"), + ConfigFilePath: c.String("config"), DefaultCmd: DefaultConfig{ Build: c.Bool("build"), @@ -152,9 +151,8 @@ func New(c *cli.Context) (CLIConfig, error) { config.Revision = configFile.CLI.Revision } - config.Fetcher = "custom" - if config.ExistingProject { - config.Fetcher = "git" + if config.Fetcher == "" { + config.Fetcher = configFile.CLI.Fetcher } if config.APIKey == "" { diff --git a/config/file.go b/config/file.go index c4874aa067..164f292705 100644 --- a/config/file.go +++ b/config/file.go @@ -18,11 +18,11 @@ type configFileV1 struct { type configFileCLIV1 struct { // Upload configuration. - APIKey string `yaml:"api_key,omitempty"` - Server string `yaml:"server,omitempty"` - Project string `yaml:"project,omitempty"` - Revision string `yaml:"revision,omitempty"` - ExistingProject bool `yaml:"existing_project"` // project exists in FOSSA (defaults to false as managed build is default) + APIKey string `yaml:"api_key,omitempty"` + Server string `yaml:"server,omitempty"` + Project string `yaml:"project,omitempty"` + Revision string `yaml:"revision,omitempty"` + Fetcher string `yaml:"fetcher,omitempty"` // fetcher defaults to custom } type configFileAnalyzeV1 struct { @@ -87,6 +87,11 @@ func setDefaultValues(c configFileV1) (configFileV1, error) { c.CLI.APIKey = apiKey } + // Default to custom. + if c.CLI.Fetcher == "" { + c.CLI.Fetcher = "custom" + } + // Infer default locator and project from `git`. if c.CLI.Project == "" || c.CLI.Revision == "" { // TODO: this needs to happen in the module directory, not the working @@ -128,10 +133,10 @@ func WriteConfigFile(conf *CLIConfig) error { writeConfig := configFileV1{ Version: 1, CLI: configFileCLIV1{ - APIKey: keyToWrite, - Server: conf.Endpoint, - Project: conf.Project, - ExistingProject: conf.ExistingProject, + APIKey: keyToWrite, + Server: conf.Endpoint, + Project: conf.Project, + Fetcher: conf.Fetcher, }, Analyze: configFileAnalyzeV1{ Modules: conf.Modules,