Example #1
0
func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {

	if c.GlobalIsSet("http-timeout") {
		acme.HTTPClient = http.Client{Timeout: time.Duration(c.GlobalInt("http-timeout")) * time.Second}
	}

	if c.GlobalIsSet("dns-timeout") {
		acme.DNSTimeout = time.Duration(c.GlobalInt("dns-timeout")) * time.Second
	}

	if len(c.GlobalStringSlice("dns-resolvers")) > 0 {
		resolvers := []string{}
		for _, resolver := range c.GlobalStringSlice("dns-resolvers") {
			if !strings.Contains(resolver, ":") {
				resolver += ":53"
			}
			resolvers = append(resolvers, resolver)
		}
		acme.RecursiveNameservers = resolvers
	}

	err := checkFolder(c.GlobalString("path"))
	if err != nil {
		logger().Fatalf("Could not check/create path: %s", err.Error())
	}

	conf := NewConfiguration(c)
	if len(c.GlobalString("email")) == 0 {
		logger().Fatal("You have to pass an account (email address) to the program using --email or -m")
	}

	//TODO: move to account struct? Currently MUST pass email.
	acc := NewAccount(c.GlobalString("email"), conf)

	keyType, err := conf.KeyType()
	if err != nil {
		logger().Fatal(err.Error())
	}

	client, err := acme.NewClient(c.GlobalString("server"), acc, keyType)
	if err != nil {
		logger().Fatalf("Could not create client: %s", err.Error())
	}

	if len(c.GlobalStringSlice("exclude")) > 0 {
		client.ExcludeChallenges(conf.ExcludedSolvers())
	}

	if c.GlobalIsSet("webroot") {
		provider, err := webroot.NewHTTPProvider(c.GlobalString("webroot"))
		if err != nil {
			logger().Fatal(err)
		}

		client.SetChallengeProvider(acme.HTTP01, provider)

		// --webroot=foo indicates that the user specifically want to do a HTTP challenge
		// infer that the user also wants to exclude all other challenges
		client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSSNI01})
	}
	if c.GlobalIsSet("memcached-host") {
		provider, err := memcached.NewMemcachedProvider(c.GlobalStringSlice("memcached-host"))
		if err != nil {
			logger().Fatal(err)
		}

		client.SetChallengeProvider(acme.HTTP01, provider)

		// --memcached-host=foo:11211 indicates that the user specifically want to do a HTTP challenge
		// infer that the user also wants to exclude all other challenges
		client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSSNI01})
	}
	if c.GlobalIsSet("http") {
		if strings.Index(c.GlobalString("http"), ":") == -1 {
			logger().Fatalf("The --http switch only accepts interface:port or :port for its argument.")
		}
		client.SetHTTPAddress(c.GlobalString("http"))
	}

	if c.GlobalIsSet("tls") {
		if strings.Index(c.GlobalString("tls"), ":") == -1 {
			logger().Fatalf("The --tls switch only accepts interface:port or :port for its argument.")
		}
		client.SetTLSAddress(c.GlobalString("tls"))
	}

	if c.GlobalIsSet("dns") {
		var err error
		var provider acme.ChallengeProvider
		switch c.GlobalString("dns") {
		case "azure":
			provider, err = azure.NewDNSProvider()
		case "auroradns":
			provider, err = auroradns.NewDNSProvider()
		case "cloudflare":
			provider, err = cloudflare.NewDNSProvider()
		case "digitalocean":
			provider, err = digitalocean.NewDNSProvider()
		case "dnsimple":
			provider, err = dnsimple.NewDNSProvider()
		case "dnsmadeeasy":
			provider, err = dnsmadeeasy.NewDNSProvider()
		case "exoscale":
			provider, err = exoscale.NewDNSProvider()
		case "dyn":
			provider, err = dyn.NewDNSProvider()
		case "gandi":
			provider, err = gandi.NewDNSProvider()
		case "gcloud":
			provider, err = googlecloud.NewDNSProvider()
		case "linode":
			provider, err = linode.NewDNSProvider()
		case "manual":
			provider, err = acme.NewDNSProviderManual()
		case "namecheap":
			provider, err = namecheap.NewDNSProvider()
		case "rackspace":
			provider, err = rackspace.NewDNSProvider()
		case "route53":
			provider, err = route53.NewDNSProvider()
		case "rfc2136":
			provider, err = rfc2136.NewDNSProvider()
		case "vultr":
			provider, err = vultr.NewDNSProvider()
		case "ovh":
			provider, err = ovh.NewDNSProvider()
		case "pdns":
			provider, err = pdns.NewDNSProvider()
		case "ns1":
			provider, err = ns1.NewDNSProvider()
		case "dnspod":
			provider, err = dnspod.NewDNSProvider()
		}

		if err != nil {
			logger().Fatal(err)
		}

		client.SetChallengeProvider(acme.DNS01, provider)

		// --dns=foo indicates that the user specifically want to do a DNS challenge
		// infer that the user also wants to exclude all other challenges
		client.ExcludeChallenges([]acme.Challenge{acme.HTTP01, acme.TLSSNI01})
	}

	return conf, acc, client
}
Example #2
0
func run(c *cli.Context) error {
	PrintBitriseHeaderASCIIArt(version.VERSION)

	//
	// Expand cli.Context
	var prGlobalFlagPtr *bool
	if c.GlobalIsSet(PRKey) {
		prGlobalFlagPtr = pointers.NewBoolPtr(c.GlobalBool(PRKey))
	}

	var ciGlobalFlagPtr *bool
	if c.GlobalIsSet(CIKey) {
		ciGlobalFlagPtr = pointers.NewBoolPtr(c.GlobalBool(CIKey))
	}

	workflowToRunID := c.String(WorkflowKey)
	if workflowToRunID == "" && len(c.Args()) > 0 {
		workflowToRunID = c.Args()[0]
	}

	bitriseConfigBase64Data := c.String(ConfigBase64Key)
	bitriseConfigPath := c.String(ConfigKey)
	deprecatedBitriseConfigPath := c.String(PathKey)
	if bitriseConfigPath == "" && deprecatedBitriseConfigPath != "" {
		log.Warn("'path' key is deprecated, use 'config' instead!")
		bitriseConfigPath = deprecatedBitriseConfigPath
	}

	inventoryBase64Data := c.String(InventoryBase64Key)
	inventoryPath := c.String(InventoryKey)

	jsonParams := c.String(JSONParamsKey)
	jsonParamsBase64 := c.String(JSONParamsBase64Key)

	runParams, err := parseRunParams(
		workflowToRunID,
		bitriseConfigPath, bitriseConfigBase64Data,
		inventoryPath, inventoryBase64Data,
		jsonParams, jsonParamsBase64)
	if err != nil {
		return fmt.Errorf("Failed to parse command params, error: %s", err)
	}
	//

	// Inventory validation
	inventoryEnvironments, err := CreateInventoryFromCLIParams(runParams.InventoryBase64Data, runParams.InventoryPath)
	if err != nil {
		log.Fatalf("Failed to create inventory, error: %s", err)
	}

	// Config validation
	bitriseConfig, warnings, err := CreateBitriseConfigFromCLIParams(runParams.BitriseConfigBase64Data, runParams.BitriseConfigPath)
	for _, warning := range warnings {
		log.Warnf("warning: %s", warning)
	}
	if err != nil {
		log.Fatalf("Failed to create bitrise config, error: %s", err)
	}

	// Workflow id validation
	if runParams.WorkflowToRunID == "" {
		// no workflow specified
		//  list all the available ones and then exit
		log.Error("No workfow specified!")
		fmt.Println()
		printAvailableWorkflows(bitriseConfig)
		os.Exit(1)
	}
	if strings.HasPrefix(runParams.WorkflowToRunID, "_") {
		// util workflow specified
		//  print about util workflows and then exit
		log.Error("Utility workflows can't be triggered directly")
		fmt.Println()
		printAboutUtilityWorkflowsText()
		os.Exit(1)
	}
	//

	//
	// Main
	isPRMode, err := isPRMode(prGlobalFlagPtr, inventoryEnvironments)
	if err != nil {
		log.Fatalf("Failed to check  PR mode, error: %s", err)
	}

	if err := registerPrMode(isPRMode); err != nil {
		log.Fatalf("Failed to register  PR mode, error: %s", err)
	}

	isCIMode, err := isCIMode(ciGlobalFlagPtr, inventoryEnvironments)
	if err != nil {
		log.Fatalf("Failed to check  CI mode, error: %s", err)
	}

	if err := registerCIMode(isCIMode); err != nil {
		log.Fatalf("Failed to register  CI mode, error: %s", err)
	}

	log.Infoln(colorstring.Green("Running workflow:"), runParams.WorkflowToRunID)

	runAndExit(bitriseConfig, inventoryEnvironments, runParams.WorkflowToRunID)
	//

	return nil
}
Example #3
0
func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {

	if c.GlobalIsSet("http-timeout") {
		acme.HTTPClient = http.Client{Timeout: time.Duration(c.GlobalInt("http-timeout")) * time.Second}
	}

	if c.GlobalIsSet("dns-timeout") {
		acme.DNSTimeout = time.Duration(c.GlobalInt("dns-timeout")) * time.Second
	}

	if len(c.GlobalStringSlice("dns-resolvers")) > 0 {
		resolvers := []string{}
		for _, resolver := range c.GlobalStringSlice("dns-resolvers") {
			if !strings.Contains(resolver, ":") {
				resolver += ":53"
			}
			resolvers = append(resolvers, resolver)
		}
		acme.RecursiveNameservers = resolvers
	}

	err := checkFolder(c.GlobalString("path"))
	if err != nil {
		logger().Fatalf("Could not check/create path: %s", err.Error())
	}

	conf := NewConfiguration(c)
	if len(c.GlobalString("email")) == 0 {
		logger().Fatal("You have to pass an account (email address) to the program using --email or -m")
	}

	//TODO: move to account struct? Currently MUST pass email.
	acc := NewAccount(c.GlobalString("email"), conf)

	keyType, err := conf.KeyType()
	if err != nil {
		logger().Fatal(err.Error())
	}

	client, err := acme.NewClient(c.GlobalString("server"), acc, keyType)
	if err != nil {
		logger().Fatalf("Could not create client: %s", err.Error())
	}

	if len(c.GlobalStringSlice("exclude")) > 0 {
		client.ExcludeChallenges(conf.ExcludedSolvers())
	}

	if c.GlobalIsSet("webroot") {
		provider, err := webroot.NewHTTPProvider(c.GlobalString("webroot"))
		if err != nil {
			logger().Fatal(err)
		}

		client.SetChallengeProvider(acme.HTTP01, provider)

		// --webroot=foo indicates that the user specifically want to do a HTTP challenge
		// infer that the user also wants to exclude all other challenges
		client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSSNI01})
	}
	if c.GlobalIsSet("memcached-host") {
		provider, err := memcached.NewMemcachedProvider(c.GlobalStringSlice("memcached-host"))
		if err != nil {
			logger().Fatal(err)
		}

		client.SetChallengeProvider(acme.HTTP01, provider)

		// --memcached-host=foo:11211 indicates that the user specifically want to do a HTTP challenge
		// infer that the user also wants to exclude all other challenges
		client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSSNI01})
	}
	if c.GlobalIsSet("http") {
		if strings.Index(c.GlobalString("http"), ":") == -1 {
			logger().Fatalf("The --http switch only accepts interface:port or :port for its argument.")
		}
		client.SetHTTPAddress(c.GlobalString("http"))
	}

	if c.GlobalIsSet("tls") {
		if strings.Index(c.GlobalString("tls"), ":") == -1 {
			logger().Fatalf("The --tls switch only accepts interface:port or :port for its argument.")
		}
		client.SetTLSAddress(c.GlobalString("tls"))
	}

	if c.GlobalIsSet("dns") {
		provider, err := dns.NewDNSChallengeProviderByName(c.GlobalString("dns"))
		if err != nil {
			logger().Fatal(err)
		}

		client.SetChallengeProvider(acme.DNS01, provider)

		// --dns=foo indicates that the user specifically want to do a DNS challenge
		// infer that the user also wants to exclude all other challenges
		client.ExcludeChallenges([]acme.Challenge{acme.HTTP01, acme.TLSSNI01})
	}

	return conf, acc, client
}
Example #4
0
func triggerCheck(c *cli.Context) error {
	warnings := []string{}

	//
	// Expand cli.Context
	var prGlobalFlagPtr *bool
	if c.GlobalIsSet(PRKey) {
		prGlobalFlagPtr = pointers.NewBoolPtr(c.GlobalBool(PRKey))
	}

	triggerPattern := c.String(PatternKey)
	if triggerPattern == "" && len(c.Args()) > 0 {
		triggerPattern = c.Args()[0]
	}

	pushBranch := c.String(PushBranchKey)
	prSourceBranch := c.String(PRSourceBranchKey)
	prTargetBranch := c.String(PRTargetBranchKey)
	tag := c.String(TagKey)

	bitriseConfigBase64Data := c.String(ConfigBase64Key)
	bitriseConfigPath := c.String(ConfigKey)
	deprecatedBitriseConfigPath := c.String(PathKey)
	if bitriseConfigPath == "" && deprecatedBitriseConfigPath != "" {
		warnings = append(warnings, "'path' key is deprecated, use 'config' instead!")
		bitriseConfigPath = deprecatedBitriseConfigPath
	}

	inventoryBase64Data := c.String(InventoryBase64Key)
	inventoryPath := c.String(InventoryKey)

	jsonParams := c.String(JSONParamsKey)
	jsonParamsBase64 := c.String(JSONParamsBase64Key)

	format := c.String(OuputFormatKey)

	triggerParams, err := parseTriggerCheckParams(
		triggerPattern,
		pushBranch, prSourceBranch, prTargetBranch, tag,
		format,
		bitriseConfigPath, bitriseConfigBase64Data,
		inventoryPath, inventoryBase64Data,
		jsonParams, jsonParamsBase64)
	if err != nil {
		registerFatal(fmt.Sprintf("Failed to parse trigger check params, err: %s", err), warnings, triggerParams.Format)
	}
	//

	// Inventory validation
	inventoryEnvironments, err := CreateInventoryFromCLIParams(triggerParams.InventoryBase64Data, triggerParams.InventoryPath)
	if err != nil {
		registerFatal(fmt.Sprintf("Failed to create inventory, err: %s", err), warnings, triggerParams.Format)
	}

	// Config validation
	bitriseConfig, warns, err := CreateBitriseConfigFromCLIParams(triggerParams.BitriseConfigBase64Data, triggerParams.BitriseConfigPath)
	warnings = append(warnings, warns...)
	if err != nil {
		registerFatal(fmt.Sprintf("Failed to create config, err: %s", err), warnings, triggerParams.Format)
	}

	// Format validation
	if triggerParams.Format == "" {
		triggerParams.Format = output.FormatRaw
	} else if !(triggerParams.Format == output.FormatRaw || triggerParams.Format == output.FormatJSON) {
		registerFatal(fmt.Sprintf("Invalid format: %s", triggerParams.Format), warnings, output.FormatJSON)
	}

	// Trigger filter validation
	if triggerParams.TriggerPattern == "" &&
		triggerParams.PushBranch == "" && triggerParams.PRSourceBranch == "" && triggerParams.PRTargetBranch == "" && triggerParams.Tag == "" {
		registerFatal("No trigger pattern nor trigger params specified", warnings, triggerParams.Format)
	}
	//

	//
	// Main
	isPRMode, err := isPRMode(prGlobalFlagPtr, inventoryEnvironments)
	if err != nil {
		registerFatal(fmt.Sprintf("Failed to check  PR mode, err: %s", err), warnings, triggerParams.Format)
	}

	workflowToRunID, err := getWorkflowIDByParamsInCompatibleMode(bitriseConfig.TriggerMap, triggerParams, isPRMode)
	if err != nil {
		registerFatal(err.Error(), warnings, triggerParams.Format)
	}

	triggerModel := map[string]string{"workflow": workflowToRunID}

	if triggerParams.TriggerPattern != "" {
		triggerModel["pattern"] = triggerParams.TriggerPattern
	} else {
		if triggerParams.PushBranch != "" {
			triggerModel["push-branch"] = triggerParams.PushBranch
		} else if triggerParams.PRSourceBranch != "" || triggerParams.PRTargetBranch != "" {
			if triggerParams.PRSourceBranch != "" {
				triggerModel["pr-source-branch"] = triggerParams.PRSourceBranch
			}
			if triggerParams.PRTargetBranch != "" {
				triggerModel["pr-target-branch"] = triggerParams.PRTargetBranch
			}
		} else if triggerParams.Tag != "" {
			triggerModel["tag"] = triggerParams.Tag
		}
	}

	switch triggerParams.Format {
	case output.FormatRaw:
		msg := ""
		for key, value := range triggerModel {
			if key == "workflow" {
				msg = msg + fmt.Sprintf("-> %s", colorstring.Blue(value))
			} else {
				msg = fmt.Sprintf("%s: %s ", key, value) + msg
			}
		}
		fmt.Println(msg)
		break
	case output.FormatJSON:
		bytes, err := json.Marshal(triggerModel)
		if err != nil {
			registerFatal(fmt.Sprintf("Failed to parse trigger model, err: %s", err), warnings, triggerParams.Format)
		}

		fmt.Println(string(bytes))
		break
	default:
		registerFatal(fmt.Sprintf("Invalid format: %s", triggerParams.Format), warnings, output.FormatJSON)
	}
	//

	return nil
}
Example #5
0
func trigger(c *cli.Context) error {
	PrintBitriseHeaderASCIIArt(version.VERSION)

	// Expand cli.Context
	var prGlobalFlagPtr *bool
	if c.GlobalIsSet(PRKey) {
		prGlobalFlagPtr = pointers.NewBoolPtr(c.GlobalBool(PRKey))
	}

	var ciGlobalFlagPtr *bool
	if c.GlobalIsSet(CIKey) {
		ciGlobalFlagPtr = pointers.NewBoolPtr(c.GlobalBool(CIKey))
	}

	triggerPattern := c.String(PatternKey)
	if triggerPattern == "" && len(c.Args()) > 0 {
		triggerPattern = c.Args()[0]
	}

	pushBranch := c.String(PushBranchKey)
	prSourceBranch := c.String(PRSourceBranchKey)
	prTargetBranch := c.String(PRTargetBranchKey)
	tag := c.String(TagKey)

	bitriseConfigBase64Data := c.String(ConfigBase64Key)
	bitriseConfigPath := c.String(ConfigKey)
	deprecatedBitriseConfigPath := c.String(PathKey)
	if bitriseConfigPath == "" && deprecatedBitriseConfigPath != "" {
		log.Warn("'path' key is deprecated, use 'config' instead!")
		bitriseConfigPath = deprecatedBitriseConfigPath
	}

	inventoryBase64Data := c.String(InventoryBase64Key)
	inventoryPath := c.String(InventoryKey)

	jsonParams := c.String(JSONParamsKey)
	jsonParamsBase64 := c.String(JSONParamsBase64Key)

	triggerParams, err := parseTriggerParams(
		triggerPattern,
		pushBranch, prSourceBranch, prTargetBranch, tag,
		bitriseConfigPath, bitriseConfigBase64Data,
		inventoryPath, inventoryBase64Data,
		jsonParams, jsonParamsBase64)
	if err != nil {
		return fmt.Errorf("Failed to parse trigger command params, error: %s", err)
	}

	// Inventory validation
	inventoryEnvironments, err := CreateInventoryFromCLIParams(triggerParams.InventoryBase64Data, triggerParams.InventoryPath)
	if err != nil {
		log.Fatalf("Failed to create inventory, error: %s", err)
	}

	// Config validation
	bitriseConfig, warnings, err := CreateBitriseConfigFromCLIParams(triggerParams.BitriseConfigBase64Data, triggerParams.BitriseConfigPath)
	for _, warning := range warnings {
		log.Warnf("warning: %s", warning)
	}
	if err != nil {
		log.Fatalf("Failed to create bitrise config, error: %s", err)
	}

	// Trigger filter validation
	if triggerParams.TriggerPattern == "" &&
		triggerParams.PushBranch == "" && triggerParams.PRSourceBranch == "" && triggerParams.PRTargetBranch == "" && triggerParams.Tag == "" {
		log.Error("No trigger pattern nor trigger params specified")
		printAvailableTriggerFilters(bitriseConfig.TriggerMap)
		os.Exit(1)
	}
	//

	// Main
	isPRMode, err := isPRMode(prGlobalFlagPtr, inventoryEnvironments)
	if err != nil {
		log.Fatalf("Failed to check  PR mode, error: %s", err)
	}

	if err := registerPrMode(isPRMode); err != nil {
		log.Fatalf("Failed to register  PR mode, error: %s", err)
	}

	isCIMode, err := isCIMode(ciGlobalFlagPtr, inventoryEnvironments)
	if err != nil {
		log.Fatalf("Failed to check  CI mode, error: %s", err)
	}

	if err := registerCIMode(isCIMode); err != nil {
		log.Fatalf("Failed to register  CI mode, error: %s", err)
	}

	workflowToRunID, err := getWorkflowIDByParamsInCompatibleMode(bitriseConfig.TriggerMap, triggerParams, isPRMode)
	if err != nil {
		log.Errorf("Failed to get workflow id by pattern, error: %s", err)
		if strings.Contains(err.Error(), "no matching workflow found with trigger params:") {
			printAvailableTriggerFilters(bitriseConfig.TriggerMap)
		}
		os.Exit(1)
	}

	if triggerParams.TriggerPattern != "" {
		log.Infof("pattern (%s) triggered workflow (%s)", triggerParams.TriggerPattern, workflowToRunID)
	} else {
		if triggerParams.PushBranch != "" {
			log.Infof("push-branch (%s) triggered workflow (%s)", triggerParams.PushBranch, workflowToRunID)
		} else if triggerParams.PRSourceBranch != "" || triggerParams.PRTargetBranch != "" {
			log.Infof("pr-source-branch (%s) and pr-target-branch (%s) triggered workflow (%s)", triggerParams.PRSourceBranch, triggerParams.PRTargetBranch, workflowToRunID)
		} else if triggerParams.Tag != "" {
			log.Infof("tag (%s) triggered workflow (%s)", triggerParams.Tag, workflowToRunID)
		}
	}

	runAndExit(bitriseConfig, inventoryEnvironments, workflowToRunID)
	//

	return nil
}
Example #6
0
//
// handleCommand is a generic wrapper for handling commands, or more precisely their errors
//
func handleCommand(cx *cli.Context, options []string, cmd *cliCommand, method func(*formatter, *cli.Context, *cliCommand) error) error {
	// step: handle any panics in the command
	defer func() {
		if r := recover(); r != nil {
			fmt.Fprintf(os.Stderr, "[error] internal error occurred, message: %s", r)
			os.Exit(1)
		}
	}()

	// step: check the required options were specified
	for _, k := range options {
		items := strings.Split(k, ":")
		if len(items) != 3 {
			panic("invalid required option definition, SCOPE:NAME:TYPE")
		}
		name := items[1]

		//
		// @Fix the cli lib IsSet does not check if the option was set by a environment variable, the
		// issue https://github.com/urfave/cli/issues/294 highlights problem. As a consequence, we can't determine
		// if the variable is actually set. The hack below attempts to remedy it.
		//
		var invalid bool

		switch scope := items[0]; scope {
		case "g":
			switch t := items[2]; t {
			case "s":
				invalid = !cx.GlobalIsSet(name) && cx.String(name) == ""
			case "a":
				invalid = !cx.GlobalIsSet(name) && len(cx.GlobalStringSlice(name)) == 0
			}
			if invalid {
				printError("the global option: '%s' is required", name)
			}
		default:
			switch t := items[2]; t {
			case "s":
				invalid = !cx.IsSet(name) && cx.String(name) == ""
			case "a":
				invalid = !cx.IsSet(name) && len(cx.StringSlice(name)) == 0
			}
			if invalid {
				printError("the command option: '%s' is required", name)
			}
		}
	}

	// step: create a cli output
	writer, err := newFormatter(cx.GlobalString("format"), os.Stdout)
	if err != nil {
		printError("error: %s", err)
	}

	// step: call the command and handle any errors
	if err := method(writer, cx, cmd); err != nil {
		printError("operation failed, error: %s", err)
	}

	return nil
}