mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-05-14 20:03:24 +02:00
Fixes: https://gitea.com/gitea/runner/issues/859 Migration approach mirrors [actions-oss/act-cli#154](https://github.com/actions-oss/act-cli/pull/154). ### Dependency changes - `github.com/docker/docker` v25.0.15 → **removed** (v29 doesn't exist as docker/docker; the project moved to moby/moby) - `github.com/docker/cli` v25.0.7 → v29.4.3 - `github.com/docker/go-connections` v0.6.0 → v0.7.0 - `github.com/docker/docker-credential-helpers` v0.9.5 → v0.9.6 - `github.com/moby/go-archive` added at v0.2.0 - `github.com/moby/moby/api` added at v1.54.2 - `github.com/moby/moby/client` added at v0.4.1 - `github.com/moby/buildkit` removed (only used `dockerignore.ReadAll`, swapped for `moby/patternmatcher/ignorefile.ReadAll` directly) - `github.com/containerd/errdefs` v0.3.0 → v1.0.0 ### Migration - v28: type aliases moved to their subpackages (`types.{Container,Image,Network,Exec}*` → `container/image/network/...`); deprecated APIs replaced (`ImageInspectWithRaw`, `client.IsErrNotFound`, `archive.CanonicalTarNameForPath`, `opts.ValidateMACAddress`, `ListOpts.GetAll`) - v29: structural client redesign — every `cli.X(ctx, ...)` call switched to options-everywhere/Result-typed signatures, `ContainerExec*` → `Exec*`, `ContainerWait` returns a struct with `Result`/`Error` channels, `Tty`→`TTY`, `Copy*Container` takes options struct, `client.NewClientWithOpts` → `client.New`. `pkg/stdcopy` moved to `moby/moby/api/pkg/stdcopy`. The vendored copy of `cli/command/container/opts.go` was refreshed from cli v29 (now uses `netip.Addr` for IPs, port-set conversion helpers). A small local `parsePlatform` helper centralises the `os/arch[/variant]` parsing previously inlined into multiple call sites. ### Behaviour preservation The migration introduced several behavioural shifts vs the v25 client; all were caught in review and reverted/fixed in follow-up commits: - `GetDockerClient`: cli v29's `Ping(NegotiateAPIVersion: true)` returns errors that the old `NegotiateAPIVersion` silently swallowed. Restored best-effort behaviour (warn-log + continue) so daemons with blocked `_ping` or API < 1.40 keep working. The SSH-helper `client.New` call no longer inherits `client.FromEnv`, matching the old `NewClientWithOpts(WithHost, WithDialContext)` so `DOCKER_API_VERSION`/`DOCKER_TLS_VERIFY` don't leak into the SSH-tunneled client - `parsePlatform`: malformed input now returns an explicit error instead of silently dropping to "no platform constraint" and pulling the host-default architecture. Single-segment (`"linux"`), 4+-segment (`"linux/arm/v7/extra"`), and trailing-slash (`"linux/arm/"`) inputs are all rejected - `LoadDockerAuthConfig`/`LoadDockerAuthConfigs`: `config.LoadDefaultConfigFile(nil)` panics on a malformed config file (it does `fmt.Fprintln` on the nil `io.Writer`). Switched to `config.Load(config.Dir())` so load errors reach the logger and the panic path is gone. Restored the old behaviour of returning `config.Load` and `GetAuthConfig` errors to the caller (the v29 refactor had silently downgraded them to warn-only). A `reference.ParseNormalizedNamed` failure on the image string falls through to the `docker.io` default rather than aborting, since the old string-based hostname extraction was infallible Test assertions also updated for two upstream error-message string shifts (`go-connections` port-range parser; `cli/opts` envfile BOM check). Added unit-test coverage for the new `parsePlatform` helper, locking in the intentional limits (single-segment, 4+-segment, and trailing-slash platforms rejected). --- This PR was written with the help of Claude Opus 4.7 Reviewed-on: https://gitea.com/gitea/runner/pulls/943 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: silverwind <me@silverwind.io> Co-committed-by: silverwind <me@silverwind.io>
533 lines
18 KiB
Go
533 lines
18 KiB
Go
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
// Copyright 2019 nektos
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"maps"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"gitea.com/gitea/runner/act/artifactcache"
|
|
"gitea.com/gitea/runner/act/artifacts"
|
|
"gitea.com/gitea/runner/act/common"
|
|
"gitea.com/gitea/runner/act/model"
|
|
"gitea.com/gitea/runner/act/runner"
|
|
|
|
"github.com/joho/godotenv"
|
|
"github.com/moby/moby/api/types/container"
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/term"
|
|
)
|
|
|
|
type executeArgs struct {
|
|
runList bool
|
|
job string
|
|
event string
|
|
workdir string
|
|
workflowsPath string
|
|
noWorkflowRecurse bool
|
|
autodetectEvent bool
|
|
forcePull bool
|
|
forceRebuild bool
|
|
jsonLogger bool
|
|
envs []string
|
|
envfile string
|
|
secrets []string
|
|
vars []string
|
|
defaultActionsURL string
|
|
insecureSecrets bool
|
|
privileged bool
|
|
usernsMode string
|
|
containerArchitecture string
|
|
containerDaemonSocket string
|
|
useGitIgnore bool
|
|
containerCapAdd []string
|
|
containerCapDrop []string
|
|
containerOptions string
|
|
artifactServerPath string
|
|
artifactServerAddr string
|
|
artifactServerPort string
|
|
noSkipCheckout bool
|
|
debug bool
|
|
dryrun bool
|
|
image string
|
|
cacheHandler *artifactcache.Handler
|
|
network string
|
|
githubInstance string
|
|
}
|
|
|
|
// WorkflowsPath returns path to workflow file(s)
|
|
func (i *executeArgs) WorkflowsPath() string {
|
|
return i.resolve(i.workflowsPath)
|
|
}
|
|
|
|
// Envfile returns path to .env
|
|
func (i *executeArgs) Envfile() string {
|
|
return i.resolve(i.envfile)
|
|
}
|
|
|
|
func (i *executeArgs) LoadSecrets() map[string]string {
|
|
s := make(map[string]string)
|
|
for _, secretPair := range i.secrets {
|
|
secretPairParts := strings.SplitN(secretPair, "=", 2)
|
|
secretPairParts[0] = strings.ToUpper(secretPairParts[0])
|
|
if strings.EqualFold(s[secretPairParts[0]], secretPairParts[0]) {
|
|
log.Errorf("Secret %s is already defined (secrets are case insensitive)", secretPairParts[0])
|
|
}
|
|
if len(secretPairParts) == 2 {
|
|
s[secretPairParts[0]] = secretPairParts[1]
|
|
} else if env, ok := os.LookupEnv(secretPairParts[0]); ok && env != "" {
|
|
s[secretPairParts[0]] = env
|
|
} else {
|
|
fmt.Printf("Provide value for '%s': ", secretPairParts[0])
|
|
val, err := term.ReadPassword(int(os.Stdin.Fd()))
|
|
fmt.Println()
|
|
if err != nil {
|
|
log.Errorf("failed to read input: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
s[secretPairParts[0]] = string(val)
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
func readEnvs(path string, envs map[string]string) bool {
|
|
if _, err := os.Stat(path); err == nil {
|
|
env, err := godotenv.Read(path)
|
|
if err != nil {
|
|
log.Fatalf("Error loading from %s: %v", path, err)
|
|
}
|
|
maps.Copy(envs, env)
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (i *executeArgs) LoadEnvs() map[string]string {
|
|
envs := make(map[string]string)
|
|
if i.envs != nil {
|
|
for _, envVar := range i.envs {
|
|
e := strings.SplitN(envVar, `=`, 2)
|
|
if len(e) == 2 {
|
|
envs[e[0]] = e[1]
|
|
} else {
|
|
envs[e[0]] = ""
|
|
}
|
|
}
|
|
}
|
|
_ = readEnvs(i.Envfile(), envs)
|
|
|
|
envs["ACTIONS_CACHE_URL"] = i.cacheHandler.ExternalURL() + "/"
|
|
|
|
return envs
|
|
}
|
|
|
|
func (i *executeArgs) LoadVars() map[string]string {
|
|
vars := make(map[string]string)
|
|
if i.vars != nil {
|
|
for _, runVar := range i.vars {
|
|
e := strings.SplitN(runVar, `=`, 2)
|
|
if len(e) == 2 {
|
|
vars[e[0]] = e[1]
|
|
} else {
|
|
vars[e[0]] = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
return vars
|
|
}
|
|
|
|
// Workdir returns path to workdir
|
|
func (i *executeArgs) Workdir() string {
|
|
return i.resolve(".")
|
|
}
|
|
|
|
func (i *executeArgs) resolve(path string) string {
|
|
basedir, err := filepath.Abs(i.workdir)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if path == "" {
|
|
return path
|
|
}
|
|
if !filepath.IsAbs(path) {
|
|
path = filepath.Join(basedir, path)
|
|
}
|
|
return path
|
|
}
|
|
|
|
func printList(plan *model.Plan) {
|
|
type lineInfoDef struct {
|
|
jobID string
|
|
jobName string
|
|
stage string
|
|
wfName string
|
|
wfFile string
|
|
events string
|
|
}
|
|
lineInfos := []lineInfoDef{}
|
|
|
|
header := lineInfoDef{
|
|
jobID: "Job ID",
|
|
jobName: "Job name",
|
|
stage: "Stage",
|
|
wfName: "Workflow name",
|
|
wfFile: "Workflow file",
|
|
events: "Events",
|
|
}
|
|
|
|
jobs := map[string]bool{}
|
|
duplicateJobIDs := false
|
|
|
|
jobIDMaxWidth := len(header.jobID)
|
|
jobNameMaxWidth := len(header.jobName)
|
|
stageMaxWidth := len(header.stage)
|
|
wfNameMaxWidth := len(header.wfName)
|
|
wfFileMaxWidth := len(header.wfFile)
|
|
eventsMaxWidth := len(header.events)
|
|
|
|
for i, stage := range plan.Stages {
|
|
for _, r := range stage.Runs {
|
|
jobID := r.JobID
|
|
line := lineInfoDef{
|
|
jobID: jobID,
|
|
jobName: r.String(),
|
|
stage: strconv.Itoa(i),
|
|
wfName: r.Workflow.Name,
|
|
wfFile: r.Workflow.File,
|
|
events: strings.Join(r.Workflow.On(), `,`),
|
|
}
|
|
if _, ok := jobs[jobID]; ok {
|
|
duplicateJobIDs = true
|
|
} else {
|
|
jobs[jobID] = true
|
|
}
|
|
lineInfos = append(lineInfos, line)
|
|
if jobIDMaxWidth < len(line.jobID) {
|
|
jobIDMaxWidth = len(line.jobID)
|
|
}
|
|
if jobNameMaxWidth < len(line.jobName) {
|
|
jobNameMaxWidth = len(line.jobName)
|
|
}
|
|
if stageMaxWidth < len(line.stage) {
|
|
stageMaxWidth = len(line.stage)
|
|
}
|
|
if wfNameMaxWidth < len(line.wfName) {
|
|
wfNameMaxWidth = len(line.wfName)
|
|
}
|
|
if wfFileMaxWidth < len(line.wfFile) {
|
|
wfFileMaxWidth = len(line.wfFile)
|
|
}
|
|
if eventsMaxWidth < len(line.events) {
|
|
eventsMaxWidth = len(line.events)
|
|
}
|
|
}
|
|
}
|
|
|
|
jobIDMaxWidth += 2
|
|
jobNameMaxWidth += 2
|
|
stageMaxWidth += 2
|
|
wfNameMaxWidth += 2
|
|
wfFileMaxWidth += 2
|
|
|
|
fmt.Printf("%*s%*s%*s%*s%*s%*s\n",
|
|
-stageMaxWidth, header.stage,
|
|
-jobIDMaxWidth, header.jobID,
|
|
-jobNameMaxWidth, header.jobName,
|
|
-wfNameMaxWidth, header.wfName,
|
|
-wfFileMaxWidth, header.wfFile,
|
|
-eventsMaxWidth, header.events,
|
|
)
|
|
for _, line := range lineInfos {
|
|
fmt.Printf("%*s%*s%*s%*s%*s%*s\n",
|
|
-stageMaxWidth, line.stage,
|
|
-jobIDMaxWidth, line.jobID,
|
|
-jobNameMaxWidth, line.jobName,
|
|
-wfNameMaxWidth, line.wfName,
|
|
-wfFileMaxWidth, line.wfFile,
|
|
-eventsMaxWidth, line.events,
|
|
)
|
|
}
|
|
if duplicateJobIDs {
|
|
fmt.Print("\nDetected multiple jobs with the same job name, use `-W` to specify the path to the specific workflow.\n")
|
|
}
|
|
}
|
|
|
|
func runExecList(planner model.WorkflowPlanner, execArgs *executeArgs) error {
|
|
// plan with filtered jobs - to be used for filtering only
|
|
var filterPlan *model.Plan
|
|
|
|
// Determine the event name to be filtered
|
|
var filterEventName string
|
|
|
|
if len(execArgs.event) > 0 {
|
|
log.Infof("Using chosed event for filtering: %s", execArgs.event)
|
|
filterEventName = execArgs.event
|
|
} else if execArgs.autodetectEvent {
|
|
// collect all events from loaded workflows
|
|
events := planner.GetEvents()
|
|
|
|
// set default event type to first event from many available
|
|
// this way user dont have to specify the event.
|
|
log.Infof("Using first detected workflow event for filtering: %s", events[0])
|
|
|
|
filterEventName = events[0]
|
|
}
|
|
|
|
var err error
|
|
if execArgs.job != "" {
|
|
log.Infof("Preparing plan with a job: %s", execArgs.job)
|
|
filterPlan, err = planner.PlanJob(execArgs.job)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else if filterEventName != "" {
|
|
log.Infof("Preparing plan for a event: %s", filterEventName)
|
|
filterPlan, err = planner.PlanEvent(filterEventName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
log.Infof("Preparing plan with all jobs")
|
|
filterPlan, err = planner.PlanAll()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
printList(filterPlan)
|
|
|
|
return nil
|
|
}
|
|
|
|
func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command, args []string) error {
|
|
return func(cmd *cobra.Command, args []string) error {
|
|
planner, err := model.NewWorkflowPlanner(execArgs.WorkflowsPath(), execArgs.noWorkflowRecurse)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if execArgs.runList {
|
|
return runExecList(planner, execArgs)
|
|
}
|
|
|
|
// plan with triggered jobs
|
|
var plan *model.Plan
|
|
|
|
// Determine the event name to be triggered
|
|
var eventName string
|
|
|
|
// collect all events from loaded workflows
|
|
events := planner.GetEvents()
|
|
|
|
if len(execArgs.event) > 0 {
|
|
log.Infof("Using chosed event for filtering: %s", execArgs.event)
|
|
eventName = execArgs.event
|
|
} else if len(events) == 1 && len(events[0]) > 0 {
|
|
log.Infof("Using the only detected workflow event: %s", events[0])
|
|
eventName = events[0]
|
|
} else if execArgs.autodetectEvent && len(events) > 0 && len(events[0]) > 0 {
|
|
// set default event type to first event from many available
|
|
// this way user dont have to specify the event.
|
|
log.Infof("Using first detected workflow event: %s", events[0])
|
|
eventName = events[0]
|
|
} else {
|
|
log.Infof("Using default workflow event: push")
|
|
eventName = "push"
|
|
}
|
|
|
|
// build the plan for this run
|
|
if execArgs.job != "" {
|
|
log.Infof("Planning job: %s", execArgs.job)
|
|
plan, err = planner.PlanJob(execArgs.job)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
log.Infof("Planning jobs for event: %s", eventName)
|
|
plan, err = planner.PlanEvent(eventName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
maxLifetime := 3 * time.Hour
|
|
if deadline, ok := ctx.Deadline(); ok {
|
|
maxLifetime = time.Until(deadline)
|
|
}
|
|
|
|
// init a cache server
|
|
handler, err := artifactcache.StartHandler("", "", 0, "", log.StandardLogger().WithField("module", "cache_request"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Infof("cache handler listens on: %v", handler.ExternalURL())
|
|
execArgs.cacheHandler = handler
|
|
|
|
if len(execArgs.artifactServerAddr) == 0 {
|
|
ip := common.GetOutboundIP()
|
|
if ip == nil {
|
|
return errors.New("unable to determine outbound IP address")
|
|
}
|
|
execArgs.artifactServerAddr = ip.String()
|
|
}
|
|
|
|
if len(execArgs.artifactServerPath) == 0 {
|
|
tempDir, err := os.MkdirTemp("", "gitea-act-")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
execArgs.artifactServerPath = tempDir
|
|
}
|
|
|
|
// Register ACTIONS_RUNTIME_TOKEN against local cache server
|
|
env := execArgs.LoadEnvs()
|
|
const actionsRuntimeTokenEnvName = "ACTIONS_RUNTIME_TOKEN"
|
|
actionsRuntimeToken := env[actionsRuntimeTokenEnvName]
|
|
if actionsRuntimeToken == "" {
|
|
actionsRuntimeToken = os.Getenv(actionsRuntimeTokenEnvName)
|
|
}
|
|
if actionsRuntimeToken == "" {
|
|
tmpBranch := make([]byte, 12)
|
|
if _, err := rand.Read(tmpBranch); err != nil {
|
|
actionsRuntimeToken = "token"
|
|
} else {
|
|
actionsRuntimeToken = hex.EncodeToString(tmpBranch)
|
|
}
|
|
env[actionsRuntimeTokenEnvName] = actionsRuntimeToken
|
|
os.Setenv(actionsRuntimeTokenEnvName, actionsRuntimeToken)
|
|
}
|
|
handler.RegisterJob(actionsRuntimeToken, "__local/__exec")
|
|
|
|
// run the plan
|
|
config := &runner.Config{
|
|
Workdir: execArgs.Workdir(),
|
|
BindWorkdir: false,
|
|
ReuseContainers: false,
|
|
ForcePull: execArgs.forcePull,
|
|
ForceRebuild: execArgs.forceRebuild,
|
|
LogOutput: true,
|
|
JSONLogger: execArgs.jsonLogger,
|
|
Env: env,
|
|
Vars: execArgs.LoadVars(),
|
|
Secrets: execArgs.LoadSecrets(),
|
|
InsecureSecrets: execArgs.insecureSecrets,
|
|
Privileged: execArgs.privileged,
|
|
UsernsMode: execArgs.usernsMode,
|
|
ContainerArchitecture: execArgs.containerArchitecture,
|
|
ContainerDaemonSocket: execArgs.containerDaemonSocket,
|
|
UseGitIgnore: execArgs.useGitIgnore,
|
|
GitHubInstance: execArgs.githubInstance,
|
|
ContainerCapAdd: execArgs.containerCapAdd,
|
|
ContainerCapDrop: execArgs.containerCapDrop,
|
|
ContainerOptions: execArgs.containerOptions,
|
|
AutoRemove: true,
|
|
ArtifactServerPath: execArgs.artifactServerPath,
|
|
ArtifactServerPort: execArgs.artifactServerPort,
|
|
ArtifactServerAddr: execArgs.artifactServerAddr,
|
|
NoSkipCheckout: execArgs.noSkipCheckout,
|
|
// PresetGitHubContext: preset,
|
|
// EventJSON: string(eventJSON),
|
|
ContainerNamePrefix: "GITEA-ACTIONS-TASK-" + eventName,
|
|
ContainerMaxLifetime: maxLifetime,
|
|
ContainerNetworkMode: container.NetworkMode(execArgs.network),
|
|
DefaultActionInstance: execArgs.defaultActionsURL,
|
|
PlatformPicker: func(_ []string) string {
|
|
return execArgs.image
|
|
},
|
|
ValidVolumes: []string{"**"}, // All volumes are allowed for `exec` command
|
|
}
|
|
|
|
config.Env["ACT_EXEC"] = "true"
|
|
|
|
if t := config.Secrets["GITEA_TOKEN"]; t != "" {
|
|
config.Token = t
|
|
} else if t := config.Secrets["GITHUB_TOKEN"]; t != "" {
|
|
config.Token = t
|
|
}
|
|
|
|
if !execArgs.debug {
|
|
logLevel := log.InfoLevel
|
|
config.JobLoggerLevel = &logLevel
|
|
}
|
|
|
|
r, err := runner.New(config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
artifactCancel := artifacts.Serve(ctx, execArgs.artifactServerPath, execArgs.artifactServerAddr, execArgs.artifactServerPort)
|
|
log.Debugf("artifacts server started at %s:%s", execArgs.artifactServerPath, execArgs.artifactServerPort)
|
|
|
|
ctx = common.WithDryrun(ctx, execArgs.dryrun)
|
|
executor := r.NewPlanExecutor(plan).Finally(func(ctx context.Context) error {
|
|
artifactCancel()
|
|
return nil
|
|
})
|
|
|
|
return executor(ctx)
|
|
}
|
|
}
|
|
|
|
func loadExecCmd(ctx context.Context) *cobra.Command {
|
|
execArg := executeArgs{}
|
|
|
|
execCmd := &cobra.Command{
|
|
Use: "exec",
|
|
Short: "Run workflow locally.",
|
|
Args: cobra.MaximumNArgs(20),
|
|
RunE: runExec(ctx, &execArg),
|
|
}
|
|
|
|
execCmd.Flags().BoolVarP(&execArg.runList, "list", "l", false, "list workflows")
|
|
execCmd.Flags().StringVarP(&execArg.job, "job", "j", "", "run a specific job ID")
|
|
execCmd.Flags().StringVarP(&execArg.event, "event", "E", "", "run a event name")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.workflowsPath, "workflows", "W", "./.gitea/workflows/", "path to workflow file(s)")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.workdir, "directory", "C", ".", "working directory")
|
|
execCmd.PersistentFlags().BoolVarP(&execArg.noWorkflowRecurse, "no-recurse", "", false, "Flag to disable running workflows from subdirectories of specified path in '--workflows'/'-W' flag")
|
|
execCmd.Flags().BoolVarP(&execArg.autodetectEvent, "detect-event", "", false, "Use first event type from workflow as event that triggered the workflow")
|
|
execCmd.Flags().BoolVarP(&execArg.forcePull, "pull", "p", false, "pull docker image(s) even if already present")
|
|
execCmd.Flags().BoolVarP(&execArg.forceRebuild, "rebuild", "", false, "rebuild local action docker image(s) even if already present")
|
|
execCmd.PersistentFlags().BoolVar(&execArg.jsonLogger, "json", false, "Output logs in json format")
|
|
execCmd.Flags().StringArrayVarP(&execArg.envs, "env", "", []string{}, "env to make available to actions with optional value (e.g. --env myenv=foo or --env myenv)")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.envfile, "env-file", "", ".env", "environment file to read and use as env in the containers")
|
|
execCmd.Flags().StringArrayVarP(&execArg.secrets, "secret", "s", []string{}, "secret to make available to actions with optional value (e.g. -s mysecret=foo or -s mysecret)")
|
|
execCmd.Flags().StringArrayVarP(&execArg.vars, "var", "", []string{}, "variable to make available to actions with optional value (e.g. --var myvar=foo or --var myvar)")
|
|
execCmd.PersistentFlags().BoolVarP(&execArg.insecureSecrets, "insecure-secrets", "", false, "NOT RECOMMENDED! Doesn't hide secrets while printing logs.")
|
|
execCmd.Flags().BoolVar(&execArg.privileged, "privileged", false, "use privileged mode")
|
|
execCmd.Flags().StringVar(&execArg.usernsMode, "userns", "", "user namespace to use")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.containerArchitecture, "container-architecture", "", "", "Architecture which should be used to run containers, e.g.: linux/amd64. If not specified, will use host default architecture. Requires Docker server API Version 1.41+. Ignored on earlier Docker server platforms.")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.containerDaemonSocket, "container-daemon-socket", "", "/var/run/docker.sock", "Path to Docker daemon socket which will be mounted to containers")
|
|
execCmd.Flags().BoolVar(&execArg.useGitIgnore, "use-gitignore", true, "Controls whether paths specified in .gitignore should be copied into container")
|
|
execCmd.Flags().StringArrayVarP(&execArg.containerCapAdd, "container-cap-add", "", []string{}, "kernel capabilities to add to the workflow containers (e.g. --container-cap-add SYS_PTRACE)")
|
|
execCmd.Flags().StringArrayVarP(&execArg.containerCapDrop, "container-cap-drop", "", []string{}, "kernel capabilities to remove from the workflow containers (e.g. --container-cap-drop SYS_PTRACE)")
|
|
execCmd.Flags().StringVarP(&execArg.containerOptions, "container-opts", "", "", "container options")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.artifactServerPath, "artifact-server-path", "", ".", "Defines the path where the artifact server stores uploads and retrieves downloads from. If not specified the artifact server will not start.")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.artifactServerAddr, "artifact-server-addr", "", "", "Defines the address where the artifact server listens")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.artifactServerPort, "artifact-server-port", "", "34567", "Defines the port where the artifact server listens (will only bind to localhost).")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.defaultActionsURL, "default-actions-url", "", "https://github.com", "Defines the default url of action instance.")
|
|
execCmd.PersistentFlags().BoolVarP(&execArg.noSkipCheckout, "no-skip-checkout", "", false, "Do not skip actions/checkout")
|
|
execCmd.PersistentFlags().BoolVarP(&execArg.debug, "debug", "d", false, "enable debug log")
|
|
execCmd.PersistentFlags().BoolVarP(&execArg.dryrun, "dryrun", "n", false, "dryrun mode")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.image, "image", "i", "docker.gitea.com/runner-images:ubuntu-latest", "Docker image to use. Use \"-self-hosted\" to run directly on the host.")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.network, "network", "", "", "Specify the network to which the container will connect")
|
|
execCmd.PersistentFlags().StringVarP(&execArg.githubInstance, "gitea-instance", "", "", "Gitea instance to use.")
|
|
|
|
return execCmd
|
|
}
|