clicommand

package
v3.22.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2020 License: MIT Imports: 32 Imported by: 2

Documentation

Index

Constants

View Source
const (
	DefaultEndpoint = "https://agent.buildkite.com/v3"
)

Variables

View Source
var AgentAccessTokenFlag = cli.StringFlag{
	Name:   "agent-access-token",
	Value:  "",
	Usage:  "The access token used to identify the agent",
	EnvVar: "BUILDKITE_AGENT_ACCESS_TOKEN",
}
View Source
var AgentRegisterTokenFlag = cli.StringFlag{
	Name:   "token",
	Value:  "",
	Usage:  "Your account agent token",
	EnvVar: "BUILDKITE_AGENT_TOKEN",
}
View Source
var AgentStartCommand = cli.Command{
	Name:        "start",
	Usage:       "Starts a Buildkite agent",
	Description: StartDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:   "config",
			Value:  "",
			Usage:  "Path to a configuration file",
			EnvVar: "BUILDKITE_AGENT_CONFIG",
		},
		cli.StringFlag{
			Name:   "name",
			Value:  "",
			Usage:  "The name of the agent",
			EnvVar: "BUILDKITE_AGENT_NAME",
		},
		cli.StringFlag{
			Name:   "priority",
			Value:  "",
			Usage:  "The priority of the agent (higher priorities are assigned work first)",
			EnvVar: "BUILDKITE_AGENT_PRIORITY",
		},
		cli.StringFlag{
			Name:   "acquire-job",
			Value:  "",
			Usage:  "Start this agent and only run the specified job, disconnecting after it's finished",
			EnvVar: "BUILDKITE_AGENT_ACQUIRE_JOB",
		},
		cli.BoolFlag{
			Name:   "disconnect-after-job",
			Usage:  "Disconnect the agent after running a job",
			EnvVar: "BUILDKITE_AGENT_DISCONNECT_AFTER_JOB",
		},
		cli.IntFlag{
			Name:   "disconnect-after-idle-timeout",
			Value:  0,
			Usage:  "If no jobs have come in for the specified number of seconds, disconnect the agent",
			EnvVar: "BUILDKITE_AGENT_DISCONNECT_AFTER_IDLE_TIMEOUT",
		},
		cli.IntFlag{
			Name:   "cancel-grace-period",
			Value:  10,
			Usage:  "The number of seconds a canceled or timed out job is given to gracefully terminate and upload its artifacts",
			EnvVar: "BUILDKITE_CANCEL_GRACE_PERIOD",
		},
		cli.StringFlag{
			Name:   "shell",
			Value:  DefaultShell(),
			Usage:  "The shell commamnd used to interpret build commands, e.g /bin/bash -e -c",
			EnvVar: "BUILDKITE_SHELL",
		},
		cli.StringSliceFlag{
			Name:   "tags",
			Value:  &cli.StringSlice{},
			Usage:  "A comma-separated list of tags for the agent (e.g. \"linux\" or \"mac,xcode=8\")",
			EnvVar: "BUILDKITE_AGENT_TAGS",
		},
		cli.BoolFlag{
			Name:   "tags-from-host",
			Usage:  "Include tags from the host (hostname, machine-id, os)",
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_HOST",
		},
		cli.StringSliceFlag{
			Name:   "tags-from-ec2-meta-data",
			Value:  &cli.StringSlice{},
			Usage:  "Include the default set of host EC2 meta-data as tags (instance-id, instance-type, and ami-id)",
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_EC2_META_DATA",
		},
		cli.StringSliceFlag{
			Name:   "tags-from-ec2-meta-data-paths",
			Value:  &cli.StringSlice{},
			Usage:  "Include additional tags fetched from EC2 meta-data via tag & path suffix pairs, e.g \"tag_name=path/to/value\"",
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_EC2_META_DATA_PATHS",
		},
		cli.BoolFlag{
			Name:   "tags-from-ec2-tags",
			Usage:  "Include the host's EC2 tags as tags",
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_EC2_TAGS",
		},
		cli.StringSliceFlag{
			Name:   "tags-from-gcp-meta-data",
			Value:  &cli.StringSlice{},
			Usage:  "Include the default set of host Google Cloud instance meta-data as tags (instance-id, machine-type, preemptible, project-id, region, and zone)",
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_GCP_META_DATA",
		},
		cli.StringSliceFlag{
			Name:   "tags-from-gcp-meta-data-paths",
			Value:  &cli.StringSlice{},
			Usage:  "Include additional tags fetched from Google Cloud instance meta-data via tag & path suffix pairs, e.g \"tag_name=path/to/value\"",
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_GCP_META_DATA_PATHS",
		},
		cli.BoolFlag{
			Name:   "tags-from-gcp-labels",
			Usage:  "Include the host's Google Cloud instance labels as tags",
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_GCP_LABELS",
		},
		cli.DurationFlag{
			Name:   "wait-for-ec2-tags-timeout",
			Usage:  "The amount of time to wait for tags from EC2 before proceeding",
			EnvVar: "BUILDKITE_AGENT_WAIT_FOR_EC2_TAGS_TIMEOUT",
			Value:  time.Second * 10,
		},
		cli.DurationFlag{
			Name:   "wait-for-gcp-labels-timeout",
			Usage:  "The amount of time to wait for labels from GCP before proceeding",
			EnvVar: "BUILDKITE_AGENT_WAIT_FOR_GCP_LABELS_TIMEOUT",
			Value:  time.Second * 10,
		},
		cli.StringFlag{
			Name:   "git-clone-flags",
			Value:  "-v",
			Usage:  "Flags to pass to the \"git clone\" command",
			EnvVar: "BUILDKITE_GIT_CLONE_FLAGS",
		},
		cli.StringFlag{
			Name:   "git-clean-flags",
			Value:  "-ffxdq",
			Usage:  "Flags to pass to \"git clean\" command",
			EnvVar: "BUILDKITE_GIT_CLEAN_FLAGS",
		},
		cli.StringFlag{
			Name:   "git-fetch-flags",
			Value:  "-v --prune",
			Usage:  "Flags to pass to \"git fetch\" command",
			EnvVar: "BUILDKITE_GIT_FETCH_FLAGS",
		},
		cli.StringFlag{
			Name:   "git-clone-mirror-flags",
			Value:  "-v --mirror",
			Usage:  "Flags to pass to the \"git clone\" command when used for mirroring",
			EnvVar: "BUILDKITE_GIT_CLONE_MIRROR_FLAGS",
		},
		cli.StringFlag{
			Name:   "git-mirrors-path",
			Value:  "",
			Usage:  "Path to where mirrors of git repositories are stored",
			EnvVar: "BUILDKITE_GIT_MIRRORS_PATH",
		},
		cli.IntFlag{
			Name:   "git-mirrors-lock-timeout",
			Value:  300,
			Usage:  "Seconds to lock a git mirror during clone, should exceed your longest checkout",
			EnvVar: "BUILDKITE_GIT_MIRRORS_LOCK_TIMEOUT",
		},
		cli.StringFlag{
			Name:   "bootstrap-script",
			Value:  "",
			Usage:  "The command that is executed for bootstrapping a job, defaults to the bootstrap sub-command of this binary",
			EnvVar: "BUILDKITE_BOOTSTRAP_SCRIPT_PATH",
		},
		cli.StringFlag{
			Name:   "build-path",
			Value:  "",
			Usage:  "Path to where the builds will run from",
			EnvVar: "BUILDKITE_BUILD_PATH",
		},
		cli.StringFlag{
			Name:   "hooks-path",
			Value:  "",
			Usage:  "Directory where the hook scripts are found",
			EnvVar: "BUILDKITE_HOOKS_PATH",
		},
		cli.StringFlag{
			Name:   "plugins-path",
			Value:  "",
			Usage:  "Directory where the plugins are saved to",
			EnvVar: "BUILDKITE_PLUGINS_PATH",
		},
		cli.BoolFlag{
			Name:   "timestamp-lines",
			Usage:  "Prepend timestamps on each line of output.",
			EnvVar: "BUILDKITE_TIMESTAMP_LINES",
		},
		cli.StringFlag{
			Name:   "health-check-addr",
			Usage:  "Start an HTTP server on this addr:port that returns whether the agent is healthy, disabled by default",
			EnvVar: "BUILDKITE_AGENT_HEALTH_CHECK_ADDR",
		},
		cli.BoolFlag{
			Name:   "no-pty",
			Usage:  "Do not run jobs within a pseudo terminal",
			EnvVar: "BUILDKITE_NO_PTY",
		},
		cli.BoolFlag{
			Name:   "no-ssh-keyscan",
			Usage:  "Don't automatically run ssh-keyscan before checkout",
			EnvVar: "BUILDKITE_NO_SSH_KEYSCAN",
		},
		cli.BoolFlag{
			Name:   "no-command-eval",
			Usage:  "Don't allow this agent to run arbitrary console commands, including plugins",
			EnvVar: "BUILDKITE_NO_COMMAND_EVAL",
		},
		cli.BoolFlag{
			Name:   "no-plugins",
			Usage:  "Don't allow this agent to load plugins",
			EnvVar: "BUILDKITE_NO_PLUGINS",
		},
		cli.BoolTFlag{
			Name:   "no-plugin-validation",
			Usage:  "Don't validate plugin configuration and requirements",
			EnvVar: "BUILDKITE_NO_PLUGIN_VALIDATION",
		},
		cli.BoolFlag{
			Name:   "no-local-hooks",
			Usage:  "Don't allow local hooks to be run from checked out repositories",
			EnvVar: "BUILDKITE_NO_LOCAL_HOOKS",
		},
		cli.BoolFlag{
			Name:   "no-git-submodules",
			Usage:  "Don't automatically checkout git submodules",
			EnvVar: "BUILDKITE_NO_GIT_SUBMODULES,BUILDKITE_DISABLE_GIT_SUBMODULES",
		},
		cli.BoolFlag{
			Name:   "metrics-datadog",
			Usage:  "Send metrics to DogStatsD for Datadog",
			EnvVar: "BUILDKITE_METRICS_DATADOG",
		},
		cli.StringFlag{
			Name:   "metrics-datadog-host",
			Usage:  "The dogstatsd instance to send metrics to via udp",
			EnvVar: "BUILDKITE_METRICS_DATADOG_HOST",
			Value:  "127.0.0.1:8125",
		},
		cli.StringFlag{
			Name:   "log-format",
			Usage:  "The format to use for the logger output",
			EnvVar: "BUILDKITE_LOG_FORMAT",
			Value:  "text",
		},
		cli.IntFlag{
			Name:   "spawn",
			Usage:  "The number of agents to spawn in parallel",
			Value:  1,
			EnvVar: "BUILDKITE_AGENT_SPAWN",
		},
		cli.StringFlag{
			Name:   "cancel-signal",
			Usage:  "The signal to use for cancellation",
			EnvVar: "BUILDKITE_CANCEL_SIGNAL",
			Value:  "SIGTERM",
		},
		cli.StringSliceFlag{
			Name:   "redacted-vars",
			Usage:  "Pattern of environment variable names containing sensitive values",
			EnvVar: "BUILDKITE_REDACTED_VARS",
			Value:  &cli.StringSlice{"*_PASSWORD", "*_SECRET", "*_TOKEN"},
		},

		AgentRegisterTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,

		cli.StringSliceFlag{
			Name:   "meta-data",
			Value:  &cli.StringSlice{},
			Hidden: true,
			EnvVar: "BUILDKITE_AGENT_META_DATA",
		},
		cli.BoolFlag{
			Name:   "meta-data-ec2",
			Hidden: true,
			EnvVar: "BUILDKITE_AGENT_META_DATA_EC2",
		},
		cli.BoolFlag{
			Name:   "meta-data-ec2-tags",
			Hidden: true,
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_EC2_TAGS",
		},
		cli.BoolFlag{
			Name:   "meta-data-gcp",
			Hidden: true,
			EnvVar: "BUILDKITE_AGENT_META_DATA_GCP",
		},
		cli.BoolFlag{
			Name:   "no-automatic-ssh-fingerprint-verification",
			Hidden: true,
			EnvVar: "BUILDKITE_NO_AUTOMATIC_SSH_FINGERPRINT_VERIFICATION",
		},
		cli.BoolFlag{
			Name:   "tags-from-ec2",
			Usage:  "Include the host's EC2 meta-data as tags (instance-id, instance-type, and ami-id)",
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_EC2",
		},
		cli.BoolFlag{
			Name:   "tags-from-gcp",
			Usage:  "Include the host's Google Cloud instance meta-data as tags (instance-id, machine-type, preemptible, project-id, region, and zone)",
			EnvVar: "BUILDKITE_AGENT_TAGS_FROM_GCP",
		},
		cli.IntFlag{
			Name:   "disconnect-after-job-timeout",
			Hidden: true,
			Usage:  "When --disconnect-after-job is specified, the number of seconds to wait for a job before shutting down",
			EnvVar: "BUILDKITE_AGENT_DISCONNECT_AFTER_JOB_TIMEOUT",
		},
	},
	Action: func(c *cli.Context) {

		cfg := AgentStartConfig{}

		loader := cliconfig.Loader{
			CLI:                    c,
			Config:                 &cfg,
			DefaultConfigFilePaths: DefaultConfigFilePaths(),
		}

		warnings, err := loader.Load()
		if err != nil {
			fmt.Printf("%s", err)
			os.Exit(1)
		}

		l := CreateLogger(cfg)

		for _, warning := range warnings {
			l.Warn("%s", warning)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		UnsetConfigFromEnvironment(c)

		if experiments.IsEnabled(`git-mirrors`) {
			if cfg.GitMirrorsPath == `` {
				l.Fatal("Must provide a git-mirrors-path in your configuration for git-mirrors experiment")
			}
		}

		if runtime.GOOS == "windows" {
			cfg.NoPTY = true
		}

		if cfg.BootstrapScript == "" {
			cfg.BootstrapScript = fmt.Sprintf("%s bootstrap", shellwords.Quote(os.Args[0]))
		}

		if c.IsSet("no-plugins") && cfg.NoPlugins == false {
			msg := `Plugins have been specifically enabled, despite %s being enabled. ` +
				`Plugins can execute arbitrary hooks and commands, make sure you are ` +
				`whitelisting your plugins in ` +
				`your environment hook.`

			switch {
			case cfg.NoCommandEval:
				l.Warn(msg, `no-command-eval`)
			case cfg.NoLocalHooks:
				l.Warn(msg, `no-local-hooks`)
			}
		}

		if (cfg.NoCommandEval || cfg.NoLocalHooks) && !c.IsSet("no-plugins") {
			cfg.NoPlugins = true
		}

		if cfg.Shell == "" {
			cfg.Shell = DefaultShell()
		}

		if cfg.DisconnectAfterJobTimeout > 0 {
			cfg.DisconnectAfterIdleTimeout = cfg.DisconnectAfterJobTimeout
		}

		var ec2TagTimeout time.Duration
		if t := cfg.WaitForEC2TagsTimeout; t != "" {
			var err error
			ec2TagTimeout, err = time.ParseDuration(t)
			if err != nil {
				l.Fatal("Failed to parse ec2 tag timeout: %v", err)
			}
		}

		var gcpLabelsTimeout time.Duration
		if t := cfg.WaitForGCPLabelsTimeout; t != "" {
			var err error
			gcpLabelsTimeout, err = time.ParseDuration(t)
			if err != nil {
				l.Fatal("Failed to parse gcp labels timeout: %v", err)
			}
		}

		mc := metrics.NewCollector(l, metrics.CollectorConfig{
			Datadog:     cfg.MetricsDatadog,
			DatadogHost: cfg.MetricsDatadogHost,
		})

		agentConf := agent.AgentConfiguration{
			BootstrapScript:            cfg.BootstrapScript,
			BuildPath:                  cfg.BuildPath,
			GitMirrorsPath:             cfg.GitMirrorsPath,
			GitMirrorsLockTimeout:      cfg.GitMirrorsLockTimeout,
			HooksPath:                  cfg.HooksPath,
			PluginsPath:                cfg.PluginsPath,
			GitCloneFlags:              cfg.GitCloneFlags,
			GitCloneMirrorFlags:        cfg.GitCloneMirrorFlags,
			GitCleanFlags:              cfg.GitCleanFlags,
			GitFetchFlags:              cfg.GitFetchFlags,
			GitSubmodules:              !cfg.NoGitSubmodules,
			SSHKeyscan:                 !cfg.NoSSHKeyscan,
			CommandEval:                !cfg.NoCommandEval,
			PluginsEnabled:             !cfg.NoPlugins,
			PluginValidation:           !cfg.NoPluginValidation,
			LocalHooksEnabled:          !cfg.NoLocalHooks,
			RunInPty:                   !cfg.NoPTY,
			TimestampLines:             cfg.TimestampLines,
			DisconnectAfterJob:         cfg.DisconnectAfterJob,
			DisconnectAfterIdleTimeout: cfg.DisconnectAfterIdleTimeout,
			CancelGracePeriod:          cfg.CancelGracePeriod,
			Shell:                      cfg.Shell,
			RedactedVars:               cfg.RedactedVars,
			AcquireJob:                 cfg.AcquireJob,
		}

		if loader.File != nil {
			agentConf.ConfigPath = loader.File.Path
		}

		if cfg.LogFormat == `text` {
			welcomeMessage :=
				"\n" +
					"%s   _           _ _     _ _    _ _                                _\n" +
					"  | |         (_) |   | | |  (_) |                              | |\n" +
					"  | |__  _   _ _| | __| | | ___| |_ ___    __ _  __ _  ___ _ __ | |_\n" +
					"  | '_ \\| | | | | |/ _` | |/ / | __/ _ \\  / _` |/ _` |/ _ \\ '_ \\| __|\n" +
					"  | |_) | |_| | | | (_| |   <| | ||  __/ | (_| | (_| |  __/ | | | |_\n" +
					"  |_.__/ \\__,_|_|_|\\__,_|_|\\_\\_|\\__\\___|  \\__,_|\\__, |\\___|_| |_|\\__|\n" +
					"                                                 __/ |\n" +
					" https://buildkite.com/agent                    |___/\n%s\n"

			if !cfg.NoColor {
				fmt.Fprintf(os.Stderr, welcomeMessage, "\x1b[38;5;48m", "\x1b[0m")
			} else {
				fmt.Fprintf(os.Stderr, welcomeMessage, "", "")
			}
		}

		l.Notice("Starting buildkite-agent v%s with PID: %s", agent.Version(), fmt.Sprintf("%d", os.Getpid()))
		l.Notice("The agent source code can be found here: https://github.com/buildkite/agent/v3")
		l.Notice("For questions and support, email us at: hello@buildkite.com")

		if agentConf.ConfigPath != "" {
			l.WithFields(logger.StringField(`path`, agentConf.ConfigPath)).Info("Configuration loaded")
		}

		l.Debug("Bootstrap command: %s", agentConf.BootstrapScript)
		l.Debug("Build path: %s", agentConf.BuildPath)
		l.Debug("Hooks directory: %s", agentConf.HooksPath)
		l.Debug("Plugins directory: %s", agentConf.PluginsPath)

		if !agentConf.SSHKeyscan {
			l.Info("Automatic ssh-keyscan has been disabled")
		}

		if !agentConf.CommandEval {
			l.Info("Evaluating console commands has been disabled")
		}

		if !agentConf.PluginsEnabled {
			l.Info("Plugins have been disabled")
		}

		if !agentConf.RunInPty {
			l.Info("Running builds within a pseudoterminal (PTY) has been disabled")
		}

		if agentConf.DisconnectAfterJob {
			l.Info("Agents will disconnect after a job run has completed")
		}

		if agentConf.DisconnectAfterIdleTimeout > 0 {
			l.Info("Agents will disconnect after %d seconds of inactivity", agentConf.DisconnectAfterIdleTimeout)
		}

		cancelSig, err := process.ParseSignal(cfg.CancelSignal)
		if err != nil {
			l.Fatal("Failed to parse cancel-signal: %v", err)
		}

		client := api.NewClient(l, loadAPIClientConfig(cfg, `Token`))

		registerReq := api.AgentRegisterRequest{
			Name:              cfg.Name,
			Priority:          cfg.Priority,
			ScriptEvalEnabled: !cfg.NoCommandEval,
			Tags: agent.FetchTags(l, agent.FetchTagsConfig{
				Tags:                     cfg.Tags,
				TagsFromEC2MetaData:      (cfg.TagsFromEC2MetaData || cfg.TagsFromEC2),
				TagsFromEC2MetaDataPaths: cfg.TagsFromEC2MetaDataPaths,
				TagsFromEC2Tags:          cfg.TagsFromEC2Tags,
				TagsFromGCPMetaData:      (cfg.TagsFromGCPMetaData || cfg.TagsFromGCP),
				TagsFromGCPMetaDataPaths: cfg.TagsFromGCPMetaDataPaths,
				TagsFromGCPLabels:        cfg.TagsFromGCPLabels,
				TagsFromHost:             cfg.TagsFromHost,
				WaitForEC2TagsTimeout:    ec2TagTimeout,
				WaitForGCPLabelsTimeout:  gcpLabelsTimeout,
			}),

			IgnoreInDispatches: cfg.AcquireJob != "",
		}

		if cfg.Spawn > 1 && cfg.AcquireJob != "" {
			l.Fatal("You can't spawn multiple agents and acquire a job at the same time")
		}

		var workers []*agent.AgentWorker

		for i := 1; i <= cfg.Spawn; i++ {
			if cfg.Spawn == 1 {
				l.Info("Registering agent with Buildkite...")
			} else {
				l.Info("Registering agent %d of %d with Buildkite...", i, cfg.Spawn)
			}

			ag, err := agent.Register(l, client, registerReq)
			if err != nil {
				l.Fatal("%s", err)
			}

			workers = append(workers,
				agent.NewAgentWorker(
					l.WithFields(logger.StringField(`agent`, ag.Name)), ag, mc, client, agent.AgentWorkerConfig{
						AgentConfiguration: agentConf,
						CancelSignal:       cancelSig,
						Debug:              cfg.Debug,
						SpawnIndex:         i,
					}))
		}

		pool := agent.NewAgentPool(workers)

		signals := handlePoolSignals(l, pool)
		defer close(signals)

		l.Info("Starting %d Agent(s)", cfg.Spawn)
		l.Info("You can press Ctrl-C to stop the agents")

		if cfg.HealthCheckAddr != "" {
			http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
				if r.URL.Path != "/" {
					http.NotFound(w, r)
				} else {
					fmt.Fprintf(w, "OK: Buildkite agent is running")
				}
			})

			go func() {
				l.Notice("Starting HTTP health check server on %v", cfg.HealthCheckAddr)
				err := http.ListenAndServe(cfg.HealthCheckAddr, nil)
				if err != nil {
					l.Error("Could not start health check server: %v", err)
				}
			}()
		}

		if err := pool.Start(); err != nil {
			l.Fatal("%s", err)
		}
	},
}
View Source
var AnnotateCommand = cli.Command{
	Name:        "annotate",
	Usage:       "Annotate the build page within the Buildkite UI with text from within a Buildkite job",
	Description: AnnotateHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:   "context",
			Usage:  "The context of the annotation used to differentiate this annotation from others",
			EnvVar: "BUILDKITE_ANNOTATION_CONTEXT",
		},
		cli.StringFlag{
			Name:   "style",
			Usage:  "The style of the annotation (`success`, `info`, `warning` or `error`)",
			EnvVar: "BUILDKITE_ANNOTATION_STYLE",
		},
		cli.BoolFlag{
			Name:   "append",
			Usage:  "Append to the body of an existing annotation",
			EnvVar: "BUILDKITE_ANNOTATION_APPEND",
		},
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "Which job should the annotation come from",
			EnvVar: "BUILDKITE_JOB_ID",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := AnnotateConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		var body string
		var err error

		if cfg.Body != "" {
			body = cfg.Body
		} else if stdin.IsReadable() {
			l.Info("Reading annotation body from STDIN")

			stdin, err := ioutil.ReadAll(os.Stdin)
			if err != nil {
				l.Fatal("Failed to read from STDIN: %s", err)
			}

			body = string(stdin[:])
		}

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		annotation := &api.Annotation{
			Body:    body,
			Style:   cfg.Style,
			Context: cfg.Context,
			Append:  cfg.Append,
		}

		err = retry.Do(func(s *retry.Stats) error {

			resp, err := client.Annotate(cfg.Job, annotation)

			if resp != nil && (resp.StatusCode == 401 || resp.StatusCode == 404 || resp.StatusCode == 400) {
				s.Break()
				return err
			}

			if err != nil {
				l.Warn("%s (%s)", err, s)
			}

			return err
		}, &retry.Config{Maximum: 5, Interval: 1 * time.Second, Jitter: true})

		if err != nil {
			l.Fatal("Failed to annotate build: %s", err)
		}

		l.Debug("Successfully annotated build")
	},
}
View Source
var AnnotateHelpDescription = `` /* 1294-byte string literal not displayed */
View Source
var ArtifactDownloadCommand = cli.Command{
	Name:        "download",
	Usage:       "Downloads artifacts from Buildkite to the local machine",
	Description: DownloadHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "step",
			Value: "",
			Usage: "Scope the search to a particular step by using either its name or job ID",
		},
		cli.StringFlag{
			Name:   "build",
			Value:  "",
			EnvVar: "BUILDKITE_BUILD_ID",
			Usage:  "The build that the artifacts were uploaded to",
		},
		cli.BoolFlag{
			Name:   "include-retried-jobs",
			EnvVar: "BUILDKITE_AGENT_INCLUDE_RETRIED_JOBS",
			Usage:  "Include artifacts from retried jobs in the search",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := ArtifactDownloadConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		downloader := agent.NewArtifactDownloader(l, client, agent.ArtifactDownloaderConfig{
			Query:              cfg.Query,
			Destination:        cfg.Destination,
			BuildID:            cfg.Build,
			Step:               cfg.Step,
			IncludeRetriedJobs: cfg.IncludeRetriedJobs,
			DebugHTTP:          cfg.DebugHTTP,
		})

		if err := downloader.Download(); err != nil {
			l.Fatal("Failed to download artifacts: %s", err)
		}
	},
}
View Source
var ArtifactShasumCommand = cli.Command{
	Name:        "shasum",
	Usage:       "Prints the SHA-1 checksum for the artifact provided to STDOUT",
	Description: ShasumHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "step",
			Value: "",
			Usage: "Scope the search to a particular step by using either its name of job ID",
		},
		cli.StringFlag{
			Name:   "build",
			Value:  "",
			EnvVar: "BUILDKITE_BUILD_ID",
			Usage:  "The build that the artifacts were uploaded to",
		},
		cli.BoolFlag{
			Name:   "include-retried-jobs",
			EnvVar: "BUILDKITE_AGENT_INCLUDE_RETRIED_JOBS",
			Usage:  "Include artifacts from retried jobs in the search",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := ArtifactShasumConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		searcher := agent.NewArtifactSearcher(l, client, cfg.Build)

		artifacts, err := searcher.Search(cfg.Query, cfg.Step, cfg.IncludeRetriedJobs)
		if err != nil {
			l.Fatal("Failed to find artifacts: %s", err)
		}

		artifactsFoundLength := len(artifacts)

		if artifactsFoundLength == 0 {
			l.Fatal("No artifacts found for downloading")
		} else if artifactsFoundLength > 1 {
			l.Fatal("Multiple artifacts were found. Try being more specific with the search or scope by step")
		} else {
			l.Debug("Artifact \"%s\" found", artifacts[0].Path)

			fmt.Printf("%s\n", artifacts[0].Sha1Sum)
		}
	},
}
View Source
var ArtifactUploadCommand = cli.Command{
	Name:        "upload",
	Usage:       "Uploads files to a job as artifacts",
	Description: UploadHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "Which job should the artifacts be uploaded to",
			EnvVar: "BUILDKITE_JOB_ID",
		},
		cli.StringFlag{
			Name:   "content-type",
			Value:  "",
			Usage:  "A specific Content-Type to set for the artifacts (otherwise detected)",
			EnvVar: "BUILDKITE_ARTIFACT_CONTENT_TYPE",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := ArtifactUploadConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		uploader := agent.NewArtifactUploader(l, client, agent.ArtifactUploaderConfig{
			JobID:       cfg.Job,
			Paths:       cfg.UploadPaths,
			Destination: cfg.Destination,
			ContentType: cfg.ContentType,
			DebugHTTP:   cfg.DebugHTTP,
		})

		if err := uploader.Upload(); err != nil {
			l.Fatal("Failed to upload artifacts: %s", err)
		}
	},
}
View Source
var BootstrapCommand = cli.Command{
	Name:        "bootstrap",
	Usage:       "Run a Buildkite job locally",
	Description: BootstrapHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:   "command",
			Value:  "",
			Usage:  "The command to run",
			EnvVar: "BUILDKITE_COMMAND",
		},
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "The ID of the job being run",
			EnvVar: "BUILDKITE_JOB_ID",
		},
		cli.StringFlag{
			Name:   "repository",
			Value:  "",
			Usage:  "The repository to clone and run the job from",
			EnvVar: "BUILDKITE_REPO",
		},
		cli.StringFlag{
			Name:   "commit",
			Value:  "",
			Usage:  "The commit to checkout in the repository",
			EnvVar: "BUILDKITE_COMMIT",
		},
		cli.StringFlag{
			Name:   "branch",
			Value:  "",
			Usage:  "The branch the commit is in",
			EnvVar: "BUILDKITE_BRANCH",
		},
		cli.StringFlag{
			Name:   "tag",
			Value:  "",
			Usage:  "The tag the commit",
			EnvVar: "BUILDKITE_TAG",
		},
		cli.StringFlag{
			Name:   "refspec",
			Value:  "",
			Usage:  "Optional refspec to override git fetch",
			EnvVar: "BUILDKITE_REFSPEC",
		},
		cli.StringFlag{
			Name:   "plugins",
			Value:  "",
			Usage:  "The plugins for the job",
			EnvVar: "BUILDKITE_PLUGINS",
		},
		cli.StringFlag{
			Name:   "pullrequest",
			Value:  "",
			Usage:  "The number/id of the pull request this commit belonged to",
			EnvVar: "BUILDKITE_PULL_REQUEST",
		},
		cli.StringFlag{
			Name:   "agent",
			Value:  "",
			Usage:  "The name of the agent running the job",
			EnvVar: "BUILDKITE_AGENT_NAME",
		},
		cli.StringFlag{
			Name:   "organization",
			Value:  "",
			Usage:  "The slug of the organization that the job is a part of",
			EnvVar: "BUILDKITE_ORGANIZATION_SLUG",
		},
		cli.StringFlag{
			Name:   "pipeline",
			Value:  "",
			Usage:  "The slug of the pipeline that the job is a part of",
			EnvVar: "BUILDKITE_PIPELINE_SLUG",
		},
		cli.StringFlag{
			Name:   "pipeline-provider",
			Value:  "",
			Usage:  "The id of the SCM provider that the repository is hosted on",
			EnvVar: "BUILDKITE_PIPELINE_PROVIDER",
		},
		cli.StringFlag{
			Name:   "artifact-upload-paths",
			Value:  "",
			Usage:  "Paths to files to automatically upload at the end of a job",
			EnvVar: "BUILDKITE_ARTIFACT_PATHS",
		},
		cli.StringFlag{
			Name:   "artifact-upload-destination",
			Value:  "",
			Usage:  "A custom location to upload artifact paths to (i.e. s3://my-custom-bucket)",
			EnvVar: "BUILDKITE_ARTIFACT_UPLOAD_DESTINATION",
		},
		cli.BoolFlag{
			Name:   "clean-checkout",
			Usage:  "Whether or not the bootstrap should remove the existing repository before running the command",
			EnvVar: "BUILDKITE_CLEAN_CHECKOUT",
		},
		cli.StringFlag{
			Name:   "git-clone-flags",
			Value:  "-v",
			Usage:  "Flags to pass to \"git clone\" command",
			EnvVar: "BUILDKITE_GIT_CLONE_FLAGS",
		},
		cli.StringFlag{
			Name:   "git-clone-mirror-flags",
			Value:  "-v --mirror",
			Usage:  "Flags to pass to \"git clone\" command when mirroring",
			EnvVar: "BUILDKITE_GIT_CLONE_MIRROR_FLAGS",
		},
		cli.StringFlag{
			Name:   "git-clean-flags",
			Value:  "-ffxdq",
			Usage:  "Flags to pass to \"git clean\" command",
			EnvVar: "BUILDKITE_GIT_CLEAN_FLAGS",
		},
		cli.StringFlag{
			Name:   "git-fetch-flags",
			Value:  "",
			Usage:  "Flags to pass to \"git fetch\" command",
			EnvVar: "BUILDKITE_GIT_FETCH_FLAGS",
		},
		cli.StringFlag{
			Name:   "git-mirrors-path",
			Value:  "",
			Usage:  "Path to where mirrors of git repositories are stored",
			EnvVar: "BUILDKITE_GIT_MIRRORS_PATH",
		},
		cli.IntFlag{
			Name:   "git-mirrors-lock-timeout",
			Value:  300,
			Usage:  "Seconds to lock a git mirror during clone, should exceed your longest checkout",
			EnvVar: "BUILDKITE_GIT_MIRRORS_LOCK_TIMEOUT",
		},
		cli.StringFlag{
			Name:   "bin-path",
			Value:  "",
			Usage:  "Directory where the buildkite-agent binary lives",
			EnvVar: "BUILDKITE_BIN_PATH",
		},
		cli.StringFlag{
			Name:   "build-path",
			Value:  "",
			Usage:  "Directory where builds will be created",
			EnvVar: "BUILDKITE_BUILD_PATH",
		},
		cli.StringFlag{
			Name:   "hooks-path",
			Value:  "",
			Usage:  "Directory where the hook scripts are found",
			EnvVar: "BUILDKITE_HOOKS_PATH",
		},
		cli.StringFlag{
			Name:   "plugins-path",
			Value:  "",
			Usage:  "Directory where the plugins are saved to",
			EnvVar: "BUILDKITE_PLUGINS_PATH",
		},
		cli.BoolTFlag{
			Name:   "command-eval",
			Usage:  "Allow running of arbitary commands",
			EnvVar: "BUILDKITE_COMMAND_EVAL",
		},
		cli.BoolTFlag{
			Name:   "plugins-enabled",
			Usage:  "Allow plugins to be run",
			EnvVar: "BUILDKITE_PLUGINS_ENABLED",
		},
		cli.BoolFlag{
			Name:   "plugin-validation",
			Usage:  "Validate plugin configuration",
			EnvVar: "BUILDKITE_PLUGIN_VALIDATION",
		},
		cli.BoolTFlag{
			Name:   "local-hooks-enabled",
			Usage:  "Allow local hooks to be run",
			EnvVar: "BUILDKITE_LOCAL_HOOKS_ENABLED",
		},
		cli.BoolTFlag{
			Name:   "ssh-keyscan",
			Usage:  "Automatically run ssh-keyscan before checkout",
			EnvVar: "BUILDKITE_SSH_KEYSCAN",
		},
		cli.BoolTFlag{
			Name:   "git-submodules",
			Usage:  "Enable git submodules",
			EnvVar: "BUILDKITE_GIT_SUBMODULES",
		},
		cli.BoolTFlag{
			Name:   "pty",
			Usage:  "Run jobs within a pseudo terminal",
			EnvVar: "BUILDKITE_PTY",
		},
		cli.StringFlag{
			Name:   "shell",
			Usage:  "The shell to use to interpret build commands",
			EnvVar: "BUILDKITE_SHELL",
			Value:  DefaultShell(),
		},
		cli.StringSliceFlag{
			Name:   "phases",
			Usage:  "The specific phases to execute. The order they're defined is is irrelevant.",
			EnvVar: "BUILDKITE_BOOTSTRAP_PHASES",
		},
		cli.StringSliceFlag{
			Name:   "redacted-vars",
			Usage:  "Pattern of environment variable names containing sensitive values",
			EnvVar: "BUILDKITE_REDACTED_VARS",
		},
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := BootstrapConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		for _, name := range cfg.Experiments {
			experiments.Enable(name)
		}

		if cfg.Debug {
			l.SetLevel(logger.DEBUG)
		}

		done := HandleProfileFlag(l, cfg)
		defer done()

		runInPty := cfg.PTY
		if runtime.GOOS == "windows" {
			runInPty = false
		}

		for _, phase := range cfg.Phases {
			switch phase {
			case "plugin", "checkout", "command":

			default:
				l.Fatal("Invalid phase %q", phase)
			}
		}

		bootstrap := bootstrap.New(bootstrap.Config{
			Command:                      cfg.Command,
			JobID:                        cfg.JobID,
			Repository:                   cfg.Repository,
			Commit:                       cfg.Commit,
			Branch:                       cfg.Branch,
			Tag:                          cfg.Tag,
			RefSpec:                      cfg.RefSpec,
			Plugins:                      cfg.Plugins,
			GitSubmodules:                cfg.GitSubmodules,
			PullRequest:                  cfg.PullRequest,
			GitCloneFlags:                cfg.GitCloneFlags,
			GitFetchFlags:                cfg.GitFetchFlags,
			GitCloneMirrorFlags:          cfg.GitCloneMirrorFlags,
			GitCleanFlags:                cfg.GitCleanFlags,
			AgentName:                    cfg.AgentName,
			PipelineProvider:             cfg.PipelineProvider,
			PipelineSlug:                 cfg.PipelineSlug,
			OrganizationSlug:             cfg.OrganizationSlug,
			AutomaticArtifactUploadPaths: cfg.AutomaticArtifactUploadPaths,
			ArtifactUploadDestination:    cfg.ArtifactUploadDestination,
			CleanCheckout:                cfg.CleanCheckout,
			BuildPath:                    cfg.BuildPath,
			GitMirrorsPath:               cfg.GitMirrorsPath,
			GitMirrorsLockTimeout:        cfg.GitMirrorsLockTimeout,
			BinPath:                      cfg.BinPath,
			HooksPath:                    cfg.HooksPath,
			PluginsPath:                  cfg.PluginsPath,
			PluginValidation:             cfg.PluginValidation,
			Debug:                        cfg.Debug,
			RunInPty:                     runInPty,
			CommandEval:                  cfg.CommandEval,
			PluginsEnabled:               cfg.PluginsEnabled,
			LocalHooksEnabled:            cfg.LocalHooksEnabled,
			SSHKeyscan:                   cfg.SSHKeyscan,
			Shell:                        cfg.Shell,
			Phases:                       cfg.Phases,
			RedactedVars:                 cfg.RedactedVars,
		})

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		signals := make(chan os.Signal, 1)
		signal.Notify(signals, os.Interrupt,
			syscall.SIGHUP,
			syscall.SIGTERM,
			syscall.SIGINT,
			syscall.SIGQUIT)
		defer signal.Stop(signals)

		var (
			cancelled bool
			received  os.Signal
			signalMu  sync.Mutex
		)

		go func() {
			sig := <-signals
			signalMu.Lock()
			defer signalMu.Unlock()

			bootstrap.Cancel()

			cancelled = true
			received = sig

			signal.Stop(signals)
		}()

		exitCode := bootstrap.Run(ctx)

		signalMu.Lock()
		defer signalMu.Unlock()

		if cancelled && runtime.GOOS != `windows` {
			p, err := os.FindProcess(os.Getpid())
			if err != nil {
				l.Error("Failed to find current process: %v", err)
			}

			l.Debug("Terminating bootstrap after cancellation with %v", received)
			err = p.Signal(received)
			if err != nil {
				l.Error("Failed to signal self: %v", err)
			}
		}

		os.Exit(exitCode)
	},
}
View Source
var BootstrapHelpDescription = `` /* 1025-byte string literal not displayed */
View Source
var DebugFlag = cli.BoolFlag{
	Name:   "debug",
	Usage:  "Enable debug mode",
	EnvVar: "BUILDKITE_AGENT_DEBUG",
}
View Source
var DebugHTTPFlag = cli.BoolFlag{
	Name:   "debug-http",
	Usage:  "Enable HTTP debug mode, which dumps all request and response bodies to the log",
	EnvVar: "BUILDKITE_AGENT_DEBUG_HTTP",
}
View Source
var DownloadHelpDescription = `` /* 1020-byte string literal not displayed */
View Source
var EndpointFlag = cli.StringFlag{
	Name:   "endpoint",
	Value:  DefaultEndpoint,
	Usage:  "The Agent API endpoint",
	EnvVar: "BUILDKITE_AGENT_ENDPOINT",
}
View Source
var ExperimentsFlag = cli.StringSliceFlag{
	Name:   "experiment",
	Value:  &cli.StringSlice{},
	Usage:  "Enable experimental features within the buildkite-agent",
	EnvVar: "BUILDKITE_AGENT_EXPERIMENT",
}
View Source
var MetaDataExistsCommand = cli.Command{
	Name:        "exists",
	Usage:       "Check to see if the meta data key exists for a build",
	Description: MetaDataExistsHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "Which job's build should the meta-data be checked for",
			EnvVar: "BUILDKITE_JOB_ID",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := MetaDataExistsConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		// Find the meta data value
		var err error
		var exists *api.MetaDataExists
		var resp *api.Response
		err = retry.Do(func(s *retry.Stats) error {
			exists, resp, err = client.ExistsMetaData(cfg.Job, cfg.Key)
			if resp != nil && (resp.StatusCode == 401 || resp.StatusCode == 404) {
				s.Break()
			}
			if err != nil {
				l.Warn("%s (%s)", err, s)
			}

			return err
		}, &retry.Config{Maximum: 10, Interval: 5 * time.Second})
		if err != nil {
			l.Fatal("Failed to see if meta-data exists: %s", err)
		}

		if !exists.Exists {
			os.Exit(100)
		}
	},
}
View Source
var MetaDataExistsHelpDescription = `` /* 265-byte string literal not displayed */
View Source
var MetaDataGetCommand = cli.Command{
	Name:        "get",
	Usage:       "Get data from a build",
	Description: MetaDataGetHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "default",
			Value: "",
			Usage: "If the meta-data value doesn't exist return this instead",
		},
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "Which job's build should the meta-data be retrieved from",
			EnvVar: "BUILDKITE_JOB_ID",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := MetaDataGetConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		// Find the meta data value
		var metaData *api.MetaData
		var err error
		var resp *api.Response
		err = retry.Do(func(s *retry.Stats) error {
			metaData, resp, err = client.GetMetaData(cfg.Job, cfg.Key)

			if resp != nil && (resp.StatusCode == 401 || resp.StatusCode == 404 || resp.StatusCode == 400) {
				s.Break()
				return err
			}
			if err != nil {
				l.Warn("%s (%s)", err, s)
			}

			return err
		}, &retry.Config{Maximum: 10, Interval: 5 * time.Second})

		if err != nil {

			if resp.StatusCode == 404 && c.IsSet("default") {
				l.Warn("No meta-data value exists with key `%s`, returning the supplied default \"%s\"", cfg.Key, cfg.Default)

				fmt.Print(cfg.Default)
				return
			} else {
				l.Fatal("Failed to get meta-data: %s", err)
			}
		}

		fmt.Print(metaData.Value)
	},
}
View Source
var MetaDataGetHelpDescription = `` /* 171-byte string literal not displayed */
View Source
var MetaDataKeysCommand = cli.Command{
	Name:        "keys",
	Usage:       "Lists all meta-data keys that have been previously set",
	Description: MetaDataKeysHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "Which job's build should the meta-data be checked for",
			EnvVar: "BUILDKITE_JOB_ID",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := MetaDataKeysConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		// Find the meta data keys
		var err error
		var keys []string
		var resp *api.Response
		err = retry.Do(func(s *retry.Stats) error {
			keys, resp, err = client.MetaDataKeys(cfg.Job)
			if resp != nil && (resp.StatusCode == 401 || resp.StatusCode == 404) {
				s.Break()
			}
			if err != nil {
				l.Warn("%s (%s)", err, s)
			}

			return err
		}, &retry.Config{Maximum: 10, Interval: 5 * time.Second})
		if err != nil {
			l.Fatal("Failed to find meta-data keys: %s", err)
		}

		for _, key := range keys {
			fmt.Printf("%s\n", key)
		}
	},
}
View Source
var MetaDataKeysHelpDescription = `` /* 243-byte string literal not displayed */
View Source
var MetaDataSetCommand = cli.Command{
	Name:        "set",
	Usage:       "Set data on a build",
	Description: MetaDataSetHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "Which job's build should the meta-data be set on",
			EnvVar: "BUILDKITE_JOB_ID",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := MetaDataSetConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		if len(c.Args()) < 2 {
			l.Info("Reading meta-data value from STDIN")

			input, err := ioutil.ReadAll(os.Stdin)
			if err != nil {
				l.Fatal("Failed to read from STDIN: %s", err)
			}
			cfg.Value = string(input)
		}

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		metaData := &api.MetaData{
			Key:   cfg.Key,
			Value: cfg.Value,
		}

		err := retry.Do(func(s *retry.Stats) error {
			resp, err := client.SetMetaData(cfg.Job, metaData)
			if resp != nil && (resp.StatusCode == 401 || resp.StatusCode == 404) {
				s.Break()
			}
			if err != nil {
				l.Warn("%s (%s)", err, s)
			}

			return err
		}, &retry.Config{Maximum: 10, Interval: 5 * time.Second})
		if err != nil {
			l.Fatal("Failed to set meta-data: %s", err)
		}
	},
}
View Source
var MetaDataSetHelpDescription = `` /* 444-byte string literal not displayed */
View Source
var NoColorFlag = cli.BoolFlag{
	Name:   "no-color",
	Usage:  "Don't show colors in logging",
	EnvVar: "BUILDKITE_AGENT_NO_COLOR",
}
View Source
var NoHTTP2Flag = cli.BoolFlag{
	Name:   "no-http2",
	Usage:  "Disable HTTP2 when communicating with the Agent API.",
	EnvVar: "BUILDKITE_NO_HTTP2",
}
View Source
var PipelineUploadCommand = cli.Command{
	Name:        "upload",
	Usage:       "Uploads a description of a build pipeline adds it to the currently running build after the current job.",
	Description: PipelineUploadHelpDescription,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:   "replace",
			Usage:  "Replace the rest of the existing pipeline with the steps uploaded. Jobs that are already running are not removed.",
			EnvVar: "BUILDKITE_PIPELINE_REPLACE",
		},
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "The job that is making the changes to its build",
			EnvVar: "BUILDKITE_JOB_ID",
		},
		cli.BoolFlag{
			Name:   "dry-run",
			Usage:  "Rather than uploading the pipeline, it will be echoed to stdout",
			EnvVar: "BUILDKITE_PIPELINE_UPLOAD_DRY_RUN",
		},
		cli.BoolFlag{
			Name:   "no-interpolation",
			Usage:  "Skip variable interpolation the pipeline when uploaded",
			EnvVar: "BUILDKITE_PIPELINE_NO_INTERPOLATION",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := PipelineUploadConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		// Find the pipeline file either from STDIN or the first
		// argument
		var input []byte
		var err error
		var filename string

		if cfg.FilePath != "" {
			l.Info("Reading pipeline config from \"%s\"", cfg.FilePath)

			filename = filepath.Base(cfg.FilePath)
			input, err = ioutil.ReadFile(cfg.FilePath)
			if err != nil {
				l.Fatal("Failed to read file: %s", err)
			}
		} else if stdin.IsReadable() {
			l.Info("Reading pipeline config from STDIN")

			input, err = ioutil.ReadAll(os.Stdin)
			if err != nil {
				l.Fatal("Failed to read from STDIN: %s", err)
			}
		} else {
			l.Info("Searching for pipeline config...")

			paths := []string{
				"buildkite.yml",
				"buildkite.yaml",
				"buildkite.json",
				filepath.FromSlash(".buildkite/pipeline.yml"),
				filepath.FromSlash(".buildkite/pipeline.yaml"),
				filepath.FromSlash(".buildkite/pipeline.json"),
				filepath.FromSlash("buildkite/pipeline.yml"),
				filepath.FromSlash("buildkite/pipeline.yaml"),
				filepath.FromSlash("buildkite/pipeline.json"),
			}

			exists := []string{}
			for _, path := range paths {
				if _, err := os.Stat(path); err == nil {
					exists = append(exists, path)
				}
			}

			if len(exists) > 1 {
				l.Fatal("Found multiple configuration files: %s. Please only have 1 configuration file present.", strings.Join(exists, ", "))
			} else if len(exists) == 0 {
				l.Fatal("Could not find a default pipeline configuration file. See `buildkite-agent pipeline upload --help` for more information.")
			}

			found := exists[0]

			l.Info("Found config file \"%s\"", found)

			filename = path.Base(found)
			input, err = ioutil.ReadFile(found)
			if err != nil {
				l.Fatal("Failed to read file \"%s\" (%s)", found, err)
			}
		}

		if len(input) == 0 {
			l.Fatal("Config file is empty")
		}

		environ := env.FromSlice(os.Environ())

		if commitRef, ok := environ.Get(`BUILDKITE_COMMIT`); ok {
			cmdOut, err := exec.Command(`git`, `rev-parse`, commitRef).Output()
			if err != nil {
				l.Warn("Error running git rev-parse %q: %v", commitRef, err)
			} else {
				trimmedCmdOut := strings.TrimSpace(string(cmdOut))
				l.Info("Updating BUILDKITE_COMMIT to %q", trimmedCmdOut)
				environ.Set(`BUILDKITE_COMMIT`, trimmedCmdOut)
			}
		}

		result, err := agent.PipelineParser{
			Env:             environ,
			Filename:        filename,
			Pipeline:        input,
			NoInterpolation: cfg.NoInterpolation,
		}.Parse()
		if err != nil {
			src := filename
			if src == "" {
				src = "(stdin)"
			}
			l.Fatal("Pipeline parsing of \"%s\" failed (%s)", src, err)
		}

		if cfg.DryRun {
			enc := json.NewEncoder(os.Stdout)
			enc.SetIndent("", "  ")

			if err := enc.Encode(result); err != nil {
				l.Fatal("%#v", err)
			}

			return
		}

		if cfg.Job == "" {
			l.Fatal("Missing job parameter. Usually this is set in the environment for a Buildkite job via BUILDKITE_JOB_ID.")
		}

		if cfg.AgentAccessToken == "" {
			l.Fatal("Missing agent-access-token parameter. Usually this is set in the environment for a Buildkite job via BUILDKITE_AGENT_ACCESS_TOKEN.")
		}

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		uuid := api.NewUUID()

		err = retry.Do(func(s *retry.Stats) error {
			_, err = client.UploadPipeline(cfg.Job, &api.Pipeline{UUID: uuid, Pipeline: result, Replace: cfg.Replace})
			if err != nil {
				l.Warn("%s (%s)", err, s)

				if apierr, ok := err.(*api.ErrorResponse); ok && apierr.Response.StatusCode == 422 {
					l.Error("Unrecoverable error, skipping retries")
					s.Break()
				}
			}

			return err

		}, &retry.Config{Maximum: 60, Interval: 5 * time.Second})
		if err != nil {
			l.Fatal("Failed to upload and process pipeline: %s", err)
		}

		l.Info("Successfully uploaded and parsed pipeline config")
	},
}
View Source
var PipelineUploadHelpDescription = `` /* 841-byte string literal not displayed */
View Source
var ProfileFlag = cli.StringFlag{
	Name:   "profile",
	Usage:  "Enable a profiling mode, either cpu, memory, mutex or block",
	EnvVar: "BUILDKITE_AGENT_PROFILE",
}
View Source
var ShasumHelpDescription = `` /* 925-byte string literal not displayed */
View Source
var StartDescription = `` /* 450-byte string literal not displayed */
View Source
var StepGetCommand = cli.Command{
	Name:        "get",
	Usage:       "Get the value of an attribute",
	Description: StepGetHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:   "step",
			Value:  "",
			Usage:  "The step to get. Can be either its ID (BUILDKITE_STEP_ID) or key (BUILDKITE_STEP_KEY)",
			EnvVar: "BUILDKITE_STEP_ID",
		},
		cli.StringFlag{
			Name:   "build",
			Value:  "",
			Usage:  "The build to look for the step in. Only required when targeting a step using its key (BUILDKITE_STEP_KEY)",
			EnvVar: "BUILDKITE_BUILD_ID",
		},
		cli.StringFlag{
			Name:   "format",
			Value:  "",
			Usage:  "The format to output the attribute value in (currently only JSON is supported)",
			EnvVar: "BUILDKITE_STEP_GET_FORMAT",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := StepGetConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		stepExportRequest := &api.StepExportRequest{
			Build:     cfg.Build,
			Attribute: cfg.Attribute,
			Format:    cfg.Format,
		}

		// Find the step attribute
		var err error
		var resp *api.Response
		var stepExportResponse *api.StepExportResponse
		err = retry.Do(func(s *retry.Stats) error {
			stepExportResponse, resp, err = client.StepExport(cfg.StepOrKey, stepExportRequest)

			if resp != nil && (resp.StatusCode == 401 || resp.StatusCode == 404 || resp.StatusCode == 400) {
				s.Break()
				return err
			}
			if err != nil {
				l.Warn("%s (%s)", err, s)
			}

			return err
		}, &retry.Config{Maximum: 10, Interval: 5 * time.Second})

		if err != nil {
			l.Fatal("Failed to get step: %s", err)
		}

		fmt.Print(stepExportResponse.Output)
	},
}
View Source
var StepGetHelpDescription = `` /* 604-byte string literal not displayed */
View Source
var StepUpdateCommand = cli.Command{
	Name:        "update",
	Usage:       "Change the value of an attribute",
	Description: StepUpdateHelpDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:   "step",
			Value:  "",
			Usage:  "The step to update. Can be either its ID (BUILDKITE_STEP_ID) or key (BUILDKITE_STEP_KEY)",
			EnvVar: "BUILDKITE_STEP_ID",
		},
		cli.StringFlag{
			Name:   "build",
			Value:  "",
			Usage:  "The build to look for the step in. Only required when targeting a step using its key (BUILDKITE_STEP_KEY)",
			EnvVar: "BUILDKITE_BUILD_ID",
		},
		cli.BoolFlag{
			Name:   "append",
			Usage:  "Append to current attribute instead of replacing it",
			EnvVar: "BUILDKITE_STEP_UPDATE_APPEND",
		},

		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		NoColorFlag,
		DebugFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) {

		cfg := StepUpdateConfig{}

		l := CreateLogger(&cfg)

		if err := cliconfig.Load(c, l, &cfg); err != nil {
			l.Fatal("%s", err)
		}

		done := HandleGlobalFlags(l, cfg)
		defer done()

		if len(c.Args()) < 2 {
			l.Info("Reading value from STDIN")

			input, err := ioutil.ReadAll(os.Stdin)
			if err != nil {
				l.Fatal("Failed to read from STDIN: %s", err)
			}
			cfg.Value = string(input)
		}

		client := api.NewClient(l, loadAPIClientConfig(cfg, `AgentAccessToken`))

		idempotencyUUID := api.NewUUID()

		update := &api.StepUpdate{
			IdempotencyUUID: idempotencyUUID,
			Build:           cfg.Build,
			Attribute:       cfg.Attribute,
			Value:           cfg.Value,
			Append:          cfg.Append,
		}

		err := retry.Do(func(s *retry.Stats) error {
			resp, err := client.StepUpdate(cfg.StepOrKey, update)
			if resp != nil && (resp.StatusCode == 400 || resp.StatusCode == 401 || resp.StatusCode == 404) {
				s.Break()
			}
			if err != nil {
				l.Warn("%s (%s)", err, s)
			}

			return err
		}, &retry.Config{Maximum: 10, Interval: 5 * time.Second})
		if err != nil {
			l.Fatal("Failed to change step: %s", err)
		}
	},
}
View Source
var StepUpdateHelpDescription = `` /* 405-byte string literal not displayed */
View Source
var UploadHelpDescription = `` /* 1628-byte string literal not displayed */

Functions

func CreateLogger

func CreateLogger(cfg interface{}) logger.Logger

func DefaultConfigFilePaths

func DefaultConfigFilePaths() (paths []string)

func DefaultShell

func DefaultShell() string

func HandleGlobalFlags

func HandleGlobalFlags(l logger.Logger, cfg interface{}) func()

func HandleProfileFlag

func HandleProfileFlag(l logger.Logger, cfg interface{}) func()

func Profile

func Profile(l logger.Logger, mode string) func()

Profile starts a profiling session

func UnsetConfigFromEnvironment

func UnsetConfigFromEnvironment(c *cli.Context)

Types

type AgentStartConfig

type AgentStartConfig struct {
	Config                     string   `cli:"config"`
	Name                       string   `cli:"name"`
	Priority                   string   `cli:"priority"`
	AcquireJob                 string   `cli:"acquire-job"`
	DisconnectAfterJob         bool     `cli:"disconnect-after-job"`
	DisconnectAfterIdleTimeout int      `cli:"disconnect-after-idle-timeout"`
	BootstrapScript            string   `cli:"bootstrap-script" normalize:"commandpath"`
	CancelGracePeriod          int      `cli:"cancel-grace-period"`
	BuildPath                  string   `cli:"build-path" normalize:"filepath" validate:"required"`
	HooksPath                  string   `cli:"hooks-path" normalize:"filepath"`
	PluginsPath                string   `cli:"plugins-path" normalize:"filepath"`
	Shell                      string   `cli:"shell"`
	Tags                       []string `cli:"tags" normalize:"list"`
	TagsFromEC2MetaData        bool     `cli:"tags-from-ec2-meta-data"`
	TagsFromEC2MetaDataPaths   []string `cli:"tags-from-ec2-meta-data-paths" normalize:"list"`
	TagsFromEC2Tags            bool     `cli:"tags-from-ec2-tags"`
	TagsFromGCPMetaData        bool     `cli:"tags-from-gcp-meta-data"`
	TagsFromGCPMetaDataPaths   []string `cli:"tags-from-gcp-meta-data-paths" normalize:"list"`
	TagsFromGCPLabels          bool     `cli:"tags-from-gcp-labels"`
	TagsFromHost               bool     `cli:"tags-from-host"`
	WaitForEC2TagsTimeout      string   `cli:"wait-for-ec2-tags-timeout"`
	WaitForGCPLabelsTimeout    string   `cli:"wait-for-gcp-labels-timeout"`
	GitCloneFlags              string   `cli:"git-clone-flags"`
	GitCloneMirrorFlags        string   `cli:"git-clone-mirror-flags"`
	GitCleanFlags              string   `cli:"git-clean-flags"`
	GitFetchFlags              string   `cli:"git-fetch-flags"`
	GitMirrorsPath             string   `cli:"git-mirrors-path" normalize:"filepath"`
	GitMirrorsLockTimeout      int      `cli:"git-mirrors-lock-timeout"`
	NoGitSubmodules            bool     `cli:"no-git-submodules"`
	NoSSHKeyscan               bool     `cli:"no-ssh-keyscan"`
	NoCommandEval              bool     `cli:"no-command-eval"`
	NoLocalHooks               bool     `cli:"no-local-hooks"`
	NoPlugins                  bool     `cli:"no-plugins"`
	NoPluginValidation         bool     `cli:"no-plugin-validation"`
	NoPTY                      bool     `cli:"no-pty"`
	TimestampLines             bool     `cli:"timestamp-lines"`
	HealthCheckAddr            string   `cli:"health-check-addr"`
	MetricsDatadog             bool     `cli:"metrics-datadog"`
	MetricsDatadogHost         string   `cli:"metrics-datadog-host"`
	Spawn                      int      `cli:"spawn"`
	LogFormat                  string   `cli:"log-format"`
	CancelSignal               string   `cli:"cancel-signal"`
	RedactedVars               []string `cli:"redacted-vars" normalize:"list"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP bool   `cli:"debug-http"`
	Token     string `cli:"token" validate:"required"`
	Endpoint  string `cli:"endpoint" validate:"required"`
	NoHTTP2   bool   `cli:"no-http2"`

	// Deprecated
	NoSSHFingerprintVerification bool     `cli:"no-automatic-ssh-fingerprint-verification" deprecated-and-renamed-to:"NoSSHKeyscan"`
	MetaData                     []string `cli:"meta-data" deprecated-and-renamed-to:"Tags"`
	MetaDataEC2                  bool     `cli:"meta-data-ec2" deprecated-and-renamed-to:"TagsFromEC2"`
	MetaDataEC2Tags              bool     `cli:"meta-data-ec2-tags" deprecated-and-renamed-to:"TagsFromEC2Tags"`
	MetaDataGCP                  bool     `cli:"meta-data-gcp" deprecated-and-renamed-to:"TagsFromGCP"`
	TagsFromEC2                  bool     `cli:"tags-from-ec2" deprecated-and-renamed-to:"TagsFromEC2MetaData"`
	TagsFromGCP                  bool     `cli:"tags-from-gcp" deprecated-and-renamed-to:"TagsFromGCPMetaData"`
	DisconnectAfterJobTimeout    int      `cli:"disconnect-after-job-timeout" deprecated:"Use disconnect-after-idle-timeout instead"`
}

type AnnotateConfig

type AnnotateConfig struct {
	Body    string `cli:"arg:0" label:"annotation body"`
	Style   string `cli:"style"`
	Context string `cli:"context"`
	Append  bool   `cli:"append"`
	Job     string `cli:"job" validate:"required"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type ArtifactDownloadConfig

type ArtifactDownloadConfig struct {
	Query              string `cli:"arg:0" label:"artifact search query" validate:"required"`
	Destination        string `cli:"arg:1" label:"artifact download path" validate:"required"`
	Step               string `cli:"step"`
	Build              string `cli:"build" validate:"required"`
	IncludeRetriedJobs bool   `cli:"include-retried-jobs"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type ArtifactShasumConfig

type ArtifactShasumConfig struct {
	Query              string `cli:"arg:0" label:"artifact search query" validate:"required"`
	Step               string `cli:"step"`
	Build              string `cli:"build" validate:"required"`
	IncludeRetriedJobs bool   `cli:"include-retried-jobs"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type ArtifactUploadConfig

type ArtifactUploadConfig struct {
	UploadPaths string `cli:"arg:0" label:"upload paths" validate:"required"`
	Destination string `cli:"arg:1" label:"destination" env:"BUILDKITE_ARTIFACT_UPLOAD_DESTINATION"`
	Job         string `cli:"job" validate:"required"`
	ContentType string `cli:"content-type"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type BootstrapConfig

type BootstrapConfig struct {
	Command                      string   `cli:"command"`
	JobID                        string   `cli:"job" validate:"required"`
	Repository                   string   `cli:"repository" validate:"required"`
	Commit                       string   `cli:"commit" validate:"required"`
	Branch                       string   `cli:"branch" validate:"required"`
	Tag                          string   `cli:"tag"`
	RefSpec                      string   `cli:"refspec"`
	Plugins                      string   `cli:"plugins"`
	PullRequest                  string   `cli:"pullrequest"`
	GitSubmodules                bool     `cli:"git-submodules"`
	SSHKeyscan                   bool     `cli:"ssh-keyscan"`
	AgentName                    string   `cli:"agent" validate:"required"`
	OrganizationSlug             string   `cli:"organization" validate:"required"`
	PipelineSlug                 string   `cli:"pipeline" validate:"required"`
	PipelineProvider             string   `cli:"pipeline-provider" validate:"required"`
	AutomaticArtifactUploadPaths string   `cli:"artifact-upload-paths"`
	ArtifactUploadDestination    string   `cli:"artifact-upload-destination"`
	CleanCheckout                bool     `cli:"clean-checkout"`
	GitCloneFlags                string   `cli:"git-clone-flags"`
	GitFetchFlags                string   `cli:"git-fetch-flags"`
	GitCloneMirrorFlags          string   `cli:"git-clone-mirror-flags"`
	GitCleanFlags                string   `cli:"git-clean-flags"`
	GitMirrorsPath               string   `cli:"git-mirrors-path" normalize:"filepath"`
	GitMirrorsLockTimeout        int      `cli:"git-mirrors-lock-timeout"`
	BinPath                      string   `cli:"bin-path" normalize:"filepath"`
	BuildPath                    string   `cli:"build-path" normalize:"filepath"`
	HooksPath                    string   `cli:"hooks-path" normalize:"filepath"`
	PluginsPath                  string   `cli:"plugins-path" normalize:"filepath"`
	CommandEval                  bool     `cli:"command-eval"`
	PluginsEnabled               bool     `cli:"plugins-enabled"`
	PluginValidation             bool     `cli:"plugin-validation"`
	LocalHooksEnabled            bool     `cli:"local-hooks-enabled"`
	PTY                          bool     `cli:"pty"`
	Debug                        bool     `cli:"debug"`
	Shell                        string   `cli:"shell"`
	Experiments                  []string `cli:"experiment" normalize:"list"`
	Phases                       []string `cli:"phases" normalize:"list"`
	Profile                      string   `cli:"profile"`
	RedactedVars                 []string `cli:"redacted-vars" normalize:"list"`
}

type MetaDataExistsConfig

type MetaDataExistsConfig struct {
	Key string `cli:"arg:0" label:"meta-data key" validate:"required"`
	Job string `cli:"job" validate:"required"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type MetaDataGetConfig

type MetaDataGetConfig struct {
	Key     string `cli:"arg:0" label:"meta-data key" validate:"required"`
	Default string `cli:"default"`
	Job     string `cli:"job" validate:"required"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type MetaDataKeysConfig

type MetaDataKeysConfig struct {
	Job string `cli:"job" validate:"required"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type MetaDataSetConfig

type MetaDataSetConfig struct {
	Key   string `cli:"arg:0" label:"meta-data key" validate:"required"`
	Value string `cli:"arg:1" label:"meta-data value"`
	Job   string `cli:"job" validate:"required"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type PipelineUploadConfig

type PipelineUploadConfig struct {
	FilePath        string `cli:"arg:0" label:"upload paths"`
	Replace         bool   `cli:"replace"`
	Job             string `cli:"job"`
	DryRun          bool   `cli:"dry-run"`
	NoInterpolation bool   `cli:"no-interpolation"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type StepGetConfig

type StepGetConfig struct {
	Attribute string `cli:"arg:0" label:"step attribute"`
	StepOrKey string `cli:"step" validate:"required"`
	Build     string `cli:"build"`
	Format    string `cli:"format"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

type StepUpdateConfig

type StepUpdateConfig struct {
	Attribute string `cli:"arg:0" label:"attribute" validate:"required"`
	Value     string `cli:"arg:1" label:"value"`
	Append    bool   `cli:"append"`
	StepOrKey string `cli:"step" validate:"required"`
	Build     string `cli:"build"`

	// Global flags
	Debug       bool     `cli:"debug"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint" validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL