2020-02-07 14:17:58 +08:00
|
|
|
package runner
|
|
|
|
|
|
|
|
import (
|
2022-12-09 19:16:15 +08:00
|
|
|
"archive/tar"
|
|
|
|
"bufio"
|
2020-02-07 14:17:58 +08:00
|
|
|
"context"
|
2022-11-17 05:29:45 +08:00
|
|
|
"crypto/rand"
|
2023-02-04 03:54:19 +08:00
|
|
|
"crypto/sha256"
|
2022-11-17 05:29:45 +08:00
|
|
|
"encoding/hex"
|
2020-02-14 16:41:20 +08:00
|
|
|
"encoding/json"
|
2022-11-17 05:29:45 +08:00
|
|
|
"errors"
|
2020-02-07 14:17:58 +08:00
|
|
|
"fmt"
|
2022-12-09 19:16:15 +08:00
|
|
|
"io"
|
2020-02-07 14:17:58 +08:00
|
|
|
"os"
|
2020-02-24 07:01:25 +08:00
|
|
|
"path/filepath"
|
2020-02-07 14:17:58 +08:00
|
|
|
"regexp"
|
2020-02-25 02:56:49 +08:00
|
|
|
"runtime"
|
2020-02-07 14:17:58 +08:00
|
|
|
"strings"
|
2022-11-18 16:09:51 +08:00
|
|
|
"time"
|
2020-02-07 14:17:58 +08:00
|
|
|
|
2023-04-19 11:23:28 +08:00
|
|
|
"github.com/docker/docker/errdefs"
|
2021-04-05 23:51:13 +08:00
|
|
|
"github.com/mitchellh/go-homedir"
|
2022-06-11 05:16:42 +08:00
|
|
|
"github.com/opencontainers/selinux/go-selinux"
|
2021-03-29 12:08:40 +08:00
|
|
|
log "github.com/sirupsen/logrus"
|
2021-11-26 13:18:31 +08:00
|
|
|
|
2020-02-07 14:17:58 +08:00
|
|
|
"github.com/nektos/act/pkg/common"
|
2021-03-29 12:08:40 +08:00
|
|
|
"github.com/nektos/act/pkg/container"
|
2022-05-24 21:36:06 +08:00
|
|
|
"github.com/nektos/act/pkg/exprparser"
|
2020-02-07 14:17:58 +08:00
|
|
|
"github.com/nektos/act/pkg/model"
|
|
|
|
)
|
|
|
|
|
|
|
|
// RunContext contains info about current job
|
|
|
|
type RunContext struct {
|
2022-11-17 05:29:45 +08:00
|
|
|
Name string
|
|
|
|
Config *Config
|
|
|
|
Matrix map[string]interface{}
|
|
|
|
Run *model.Run
|
|
|
|
EventJSON string
|
|
|
|
Env map[string]string
|
2023-02-04 21:35:13 +08:00
|
|
|
GlobalEnv map[string]string // to pass env changes of GITHUB_ENV and set-env correctly, due to dirty Env field
|
2022-11-17 05:29:45 +08:00
|
|
|
ExtraPath []string
|
|
|
|
CurrentStep string
|
|
|
|
StepResults map[string]*model.StepResult
|
2022-12-16 01:08:31 +08:00
|
|
|
IntraActionState map[string]map[string]string
|
2022-11-17 05:29:45 +08:00
|
|
|
ExprEval ExpressionEvaluator
|
|
|
|
JobContainer container.ExecutionsEnvironment
|
2023-04-19 11:23:28 +08:00
|
|
|
ServiceContainers []container.ExecutionsEnvironment
|
2022-11-17 05:29:45 +08:00
|
|
|
OutputMappings map[MappableOutput]MappableOutput
|
|
|
|
JobName string
|
|
|
|
ActionPath string
|
|
|
|
Parent *RunContext
|
|
|
|
Masks []string
|
|
|
|
cleanUpJobContainer common.Executor
|
2022-12-16 00:45:22 +08:00
|
|
|
caller *caller // job calling this RunContext (reusable workflows)
|
2022-03-02 16:29:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (rc *RunContext) AddMask(mask string) {
|
|
|
|
rc.Masks = append(rc.Masks, mask)
|
2021-12-23 03:19:50 +08:00
|
|
|
}
|
|
|
|
|
2021-04-03 04:40:44 +08:00
|
|
|
type MappableOutput struct {
|
|
|
|
StepID string
|
|
|
|
OutputName string
|
2020-02-14 16:41:20 +08:00
|
|
|
}
|
|
|
|
|
2020-02-27 15:29:43 +08:00
|
|
|
func (rc *RunContext) String() string {
|
2022-12-16 00:45:22 +08:00
|
|
|
name := fmt.Sprintf("%s/%s", rc.Run.Workflow.Name, rc.Name)
|
|
|
|
if rc.caller != nil {
|
|
|
|
// prefix the reusable workflow with the caller job
|
|
|
|
// this is required to create unique container names
|
|
|
|
name = fmt.Sprintf("%s/%s", rc.caller.runContext.Run.JobID, name)
|
|
|
|
}
|
|
|
|
return name
|
2020-02-27 15:29:43 +08:00
|
|
|
}
|
|
|
|
|
2020-02-07 14:17:58 +08:00
|
|
|
// GetEnv returns the env for the context
|
|
|
|
func (rc *RunContext) GetEnv() map[string]string {
|
|
|
|
if rc.Env == nil {
|
2022-11-17 05:29:45 +08:00
|
|
|
rc.Env = map[string]string{}
|
|
|
|
if rc.Run != nil && rc.Run.Workflow != nil && rc.Config != nil {
|
|
|
|
job := rc.Run.Job()
|
|
|
|
if job != nil {
|
|
|
|
rc.Env = mergeMaps(rc.Run.Workflow.Env, job.Environment(), rc.Config.Env)
|
|
|
|
}
|
|
|
|
}
|
2020-02-07 14:17:58 +08:00
|
|
|
}
|
2020-11-18 23:14:34 +08:00
|
|
|
rc.Env["ACT"] = "true"
|
2020-02-07 14:17:58 +08:00
|
|
|
return rc.Env
|
|
|
|
}
|
|
|
|
|
2020-02-24 07:01:25 +08:00
|
|
|
func (rc *RunContext) jobContainerName() string {
|
2022-11-24 14:45:32 +08:00
|
|
|
return createSimpleContainerName(rc.Config.ContainerNamePrefix, "WORKFLOW-"+rc.Run.Workflow.Name, "JOB-"+rc.Name)
|
2020-02-07 14:17:58 +08:00
|
|
|
}
|
|
|
|
|
2021-05-05 05:50:35 +08:00
|
|
|
// Returns the binds and mounts for the container, resolving paths as appopriate
|
|
|
|
func (rc *RunContext) GetBindsAndMounts() ([]string, map[string]string) {
|
|
|
|
name := rc.jobContainerName()
|
|
|
|
|
2021-05-23 22:43:09 +08:00
|
|
|
if rc.Config.ContainerDaemonSocket == "" {
|
|
|
|
rc.Config.ContainerDaemonSocket = "/var/run/docker.sock"
|
|
|
|
}
|
|
|
|
|
2021-05-05 05:50:35 +08:00
|
|
|
binds := []string{
|
2021-05-23 22:43:09 +08:00
|
|
|
fmt.Sprintf("%s:%s", rc.Config.ContainerDaemonSocket, "/var/run/docker.sock"),
|
2021-05-05 05:50:35 +08:00
|
|
|
}
|
|
|
|
|
2022-11-17 05:29:45 +08:00
|
|
|
ext := container.LinuxContainerEnvironmentExtensions{}
|
|
|
|
|
2021-05-05 05:50:35 +08:00
|
|
|
mounts := map[string]string{
|
|
|
|
"act-toolcache": "/toolcache",
|
2022-11-17 05:29:45 +08:00
|
|
|
name + "-env": ext.GetActPath(),
|
2021-05-05 05:50:35 +08:00
|
|
|
}
|
|
|
|
|
2022-04-05 02:01:13 +08:00
|
|
|
if job := rc.Run.Job(); job != nil {
|
|
|
|
if container := job.Container(); container != nil {
|
|
|
|
for _, v := range container.Volumes {
|
|
|
|
if !strings.Contains(v, ":") || filepath.IsAbs(v) {
|
|
|
|
// Bind anonymous volume or host file.
|
|
|
|
binds = append(binds, v)
|
|
|
|
} else {
|
|
|
|
// Mount existing volume.
|
|
|
|
paths := strings.SplitN(v, ":", 2)
|
|
|
|
mounts[paths[0]] = paths[1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-05 05:50:35 +08:00
|
|
|
if rc.Config.BindWorkdir {
|
|
|
|
bindModifiers := ""
|
|
|
|
if runtime.GOOS == "darwin" {
|
|
|
|
bindModifiers = ":delegated"
|
|
|
|
}
|
2021-11-26 13:18:31 +08:00
|
|
|
if selinux.GetEnabled() {
|
|
|
|
bindModifiers = ":z"
|
|
|
|
}
|
2022-11-17 05:29:45 +08:00
|
|
|
binds = append(binds, fmt.Sprintf("%s:%s%s", rc.Config.Workdir, ext.ToContainerPath(rc.Config.Workdir), bindModifiers))
|
2021-05-05 05:50:35 +08:00
|
|
|
} else {
|
2022-11-17 05:29:45 +08:00
|
|
|
mounts[name] = ext.ToContainerPath(rc.Config.Workdir)
|
2021-05-05 05:50:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return binds, mounts
|
|
|
|
}
|
|
|
|
|
2022-11-17 05:29:45 +08:00
|
|
|
func (rc *RunContext) startHostEnvironment() common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
|
|
|
logger := common.Logger(ctx)
|
|
|
|
rawLogger := logger.WithField("raw_output", true)
|
|
|
|
logWriter := common.NewLineWriter(rc.commandHandler(ctx), func(s string) bool {
|
|
|
|
if rc.Config.LogOutput {
|
|
|
|
rawLogger.Infof("%s", s)
|
|
|
|
} else {
|
|
|
|
rawLogger.Debugf("%s", s)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
cacheDir := rc.ActionCacheDir()
|
|
|
|
randBytes := make([]byte, 8)
|
|
|
|
_, _ = rand.Read(randBytes)
|
|
|
|
miscpath := filepath.Join(cacheDir, hex.EncodeToString(randBytes))
|
|
|
|
actPath := filepath.Join(miscpath, "act")
|
2023-02-16 23:34:51 +08:00
|
|
|
if err := os.MkdirAll(actPath, 0o777); err != nil {
|
2022-11-17 05:29:45 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
path := filepath.Join(miscpath, "hostexecutor")
|
2023-02-16 23:34:51 +08:00
|
|
|
if err := os.MkdirAll(path, 0o777); err != nil {
|
2022-11-17 05:29:45 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
runnerTmp := filepath.Join(miscpath, "tmp")
|
2023-02-16 23:34:51 +08:00
|
|
|
if err := os.MkdirAll(runnerTmp, 0o777); err != nil {
|
2022-11-17 05:29:45 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
toolCache := filepath.Join(cacheDir, "tool_cache")
|
|
|
|
rc.JobContainer = &container.HostEnvironment{
|
|
|
|
Path: path,
|
|
|
|
TmpDir: runnerTmp,
|
|
|
|
ToolCache: toolCache,
|
|
|
|
Workdir: rc.Config.Workdir,
|
|
|
|
ActPath: actPath,
|
|
|
|
CleanUp: func() {
|
|
|
|
os.RemoveAll(miscpath)
|
|
|
|
},
|
|
|
|
StdOut: logWriter,
|
|
|
|
}
|
|
|
|
rc.cleanUpJobContainer = rc.JobContainer.Remove()
|
2022-12-19 22:58:55 +08:00
|
|
|
for k, v := range rc.JobContainer.GetRunnerContext(ctx) {
|
|
|
|
if v, ok := v.(string); ok {
|
|
|
|
rc.Env[fmt.Sprintf("RUNNER_%s", strings.ToUpper(k))] = v
|
|
|
|
}
|
|
|
|
}
|
2022-11-17 05:29:45 +08:00
|
|
|
for _, env := range os.Environ() {
|
2023-02-16 23:16:46 +08:00
|
|
|
if k, v, ok := strings.Cut(env, "="); ok {
|
|
|
|
// don't override
|
|
|
|
if _, ok := rc.Env[k]; !ok {
|
|
|
|
rc.Env[k] = v
|
|
|
|
}
|
2022-11-17 05:29:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return common.NewPipelineExecutor(
|
|
|
|
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
|
|
|
|
Name: "workflow/event.json",
|
2023-02-16 23:34:51 +08:00
|
|
|
Mode: 0o644,
|
2022-11-17 05:29:45 +08:00
|
|
|
Body: rc.EventJSON,
|
|
|
|
}, &container.FileEntry{
|
|
|
|
Name: "workflow/envs.txt",
|
2023-02-16 23:34:51 +08:00
|
|
|
Mode: 0o666,
|
2022-11-17 05:29:45 +08:00
|
|
|
Body: "",
|
|
|
|
}),
|
|
|
|
)(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-24 07:01:25 +08:00
|
|
|
func (rc *RunContext) startJobContainer() common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
2022-06-17 23:55:21 +08:00
|
|
|
logger := common.Logger(ctx)
|
|
|
|
image := rc.platformImage(ctx)
|
|
|
|
rawLogger := logger.WithField("raw_output", true)
|
2020-02-25 04:48:12 +08:00
|
|
|
logWriter := common.NewLineWriter(rc.commandHandler(ctx), func(s string) bool {
|
2020-02-24 07:01:25 +08:00
|
|
|
if rc.Config.LogOutput {
|
2020-06-24 22:05:05 +08:00
|
|
|
rawLogger.Infof("%s", s)
|
2020-02-24 07:01:25 +08:00
|
|
|
} else {
|
2020-06-24 22:05:05 +08:00
|
|
|
rawLogger.Debugf("%s", s)
|
2020-02-24 07:01:25 +08:00
|
|
|
}
|
2020-02-25 04:48:12 +08:00
|
|
|
return true
|
2020-02-24 07:01:25 +08:00
|
|
|
})
|
|
|
|
|
2022-06-17 23:55:21 +08:00
|
|
|
username, password, err := rc.handleCredentials(ctx)
|
2021-11-28 02:05:56 +08:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to handle credentials: %s", err)
|
|
|
|
}
|
|
|
|
|
2022-06-17 23:55:21 +08:00
|
|
|
logger.Infof("\U0001f680 Start image=%s", image)
|
2020-02-24 07:01:25 +08:00
|
|
|
name := rc.jobContainerName()
|
|
|
|
|
2020-02-25 02:56:49 +08:00
|
|
|
envList := make([]string, 0)
|
|
|
|
|
2020-02-26 00:52:05 +08:00
|
|
|
envList = append(envList, fmt.Sprintf("%s=%s", "RUNNER_TOOL_CACHE", "/opt/hostedtoolcache"))
|
2020-04-23 14:57:36 +08:00
|
|
|
envList = append(envList, fmt.Sprintf("%s=%s", "RUNNER_OS", "Linux"))
|
2022-08-29 23:39:31 +08:00
|
|
|
envList = append(envList, fmt.Sprintf("%s=%s", "RUNNER_ARCH", container.RunnerArch(ctx)))
|
2020-04-23 23:18:36 +08:00
|
|
|
envList = append(envList, fmt.Sprintf("%s=%s", "RUNNER_TEMP", "/tmp"))
|
2022-12-06 18:36:39 +08:00
|
|
|
envList = append(envList, fmt.Sprintf("%s=%s", "LANG", "C.UTF-8")) // Use same locale as GitHub Actions
|
2020-02-25 02:56:49 +08:00
|
|
|
|
2022-11-17 05:29:45 +08:00
|
|
|
ext := container.LinuxContainerEnvironmentExtensions{}
|
2021-05-05 05:50:35 +08:00
|
|
|
binds, mounts := rc.GetBindsAndMounts()
|
2020-02-25 09:48:21 +08:00
|
|
|
|
2023-04-19 11:23:28 +08:00
|
|
|
// add service containers
|
|
|
|
for name, spec := range rc.Run.Job().Services {
|
|
|
|
mergedEnv := envList
|
|
|
|
for k, v := range spec.Env {
|
|
|
|
mergedEnv = append(mergedEnv, fmt.Sprintf("%s=%s", k, v))
|
|
|
|
}
|
|
|
|
serviceContainerName := createSimpleContainerName(rc.jobContainerName(), name)
|
|
|
|
c := container.NewContainer(&container.NewContainerInput{
|
|
|
|
Name: serviceContainerName,
|
|
|
|
WorkingDir: ext.ToContainerPath(rc.Config.Workdir),
|
|
|
|
Image: spec.Image,
|
|
|
|
Username: username,
|
|
|
|
Password: password,
|
|
|
|
Env: mergedEnv,
|
|
|
|
Mounts: map[string]string{
|
|
|
|
// TODO merge volumes
|
|
|
|
name: ext.ToContainerPath(rc.Config.Workdir),
|
|
|
|
"act-toolcache": "/toolcache",
|
|
|
|
"act-actions": "/actions",
|
|
|
|
},
|
|
|
|
Binds: binds,
|
|
|
|
Stdout: logWriter,
|
|
|
|
Stderr: logWriter,
|
|
|
|
Privileged: rc.Config.Privileged,
|
|
|
|
UsernsMode: rc.Config.UsernsMode,
|
|
|
|
Platform: rc.Config.ContainerArchitecture,
|
|
|
|
AutoRemove: rc.Config.AutoRemove,
|
2023-04-19 21:53:57 +08:00
|
|
|
Options: spec.Options,
|
2023-04-19 11:23:28 +08:00
|
|
|
NetworkAliases: []string{name},
|
|
|
|
})
|
|
|
|
rc.ServiceContainers = append(rc.ServiceContainers, c)
|
|
|
|
}
|
|
|
|
|
2022-11-17 05:29:45 +08:00
|
|
|
rc.cleanUpJobContainer = func(ctx context.Context) error {
|
|
|
|
if rc.JobContainer != nil && !rc.Config.ReuseContainers {
|
|
|
|
return rc.JobContainer.Remove().
|
|
|
|
Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName(), false)).
|
|
|
|
Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName()+"-env", false))(ctx)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-24 07:01:25 +08:00
|
|
|
rc.JobContainer = container.NewContainer(&container.NewContainerInput{
|
2021-05-05 05:50:35 +08:00
|
|
|
Cmd: nil,
|
2022-11-18 16:09:51 +08:00
|
|
|
Entrypoint: []string{"/bin/sleep", fmt.Sprint(rc.Config.ContainerMaxLifetime.Round(time.Second).Seconds())},
|
2022-11-17 05:29:45 +08:00
|
|
|
WorkingDir: ext.ToContainerPath(rc.Config.Workdir),
|
2021-05-05 05:50:35 +08:00
|
|
|
Image: image,
|
2021-11-28 02:05:56 +08:00
|
|
|
Username: username,
|
|
|
|
Password: password,
|
2021-05-05 05:50:35 +08:00
|
|
|
Name: name,
|
|
|
|
Env: envList,
|
|
|
|
Mounts: mounts,
|
2022-11-18 16:09:51 +08:00
|
|
|
NetworkMode: rc.Config.ContainerNetworkMode,
|
2020-03-10 08:43:24 +08:00
|
|
|
Binds: binds,
|
|
|
|
Stdout: logWriter,
|
|
|
|
Stderr: logWriter,
|
2020-08-02 04:21:49 +08:00
|
|
|
Privileged: rc.Config.Privileged,
|
2021-02-28 00:31:25 +08:00
|
|
|
UsernsMode: rc.Config.UsernsMode,
|
2021-03-29 12:08:40 +08:00
|
|
|
Platform: rc.Config.ContainerArchitecture,
|
2022-10-07 06:09:43 +08:00
|
|
|
Options: rc.options(ctx),
|
2022-11-18 16:09:51 +08:00
|
|
|
AutoRemove: rc.Config.AutoRemove,
|
2020-02-24 07:01:25 +08:00
|
|
|
})
|
2022-11-17 05:29:45 +08:00
|
|
|
if rc.JobContainer == nil {
|
|
|
|
return errors.New("Failed to create job container")
|
|
|
|
}
|
2020-02-24 07:01:25 +08:00
|
|
|
|
2023-04-19 11:23:28 +08:00
|
|
|
networkName := fmt.Sprintf("%s-network", rc.jobContainerName())
|
2020-02-24 07:01:25 +08:00
|
|
|
return common.NewPipelineExecutor(
|
2023-04-19 11:23:28 +08:00
|
|
|
rc.pullServicesImages(rc.Config.ForcePull),
|
2020-02-24 07:01:25 +08:00
|
|
|
rc.JobContainer.Pull(rc.Config.ForcePull),
|
2023-04-19 11:23:28 +08:00
|
|
|
rc.stopServiceContainers(),
|
2020-06-18 23:21:55 +08:00
|
|
|
rc.stopJobContainer(),
|
2023-04-19 11:23:28 +08:00
|
|
|
func(ctx context.Context) error {
|
|
|
|
err := rc.removeNetwork(networkName)(ctx)
|
|
|
|
if errdefs.IsNotFound(err) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
},
|
|
|
|
rc.createNetwork(networkName),
|
|
|
|
rc.startServiceContainers(networkName),
|
2021-06-05 00:06:59 +08:00
|
|
|
rc.JobContainer.Create(rc.Config.ContainerCapAdd, rc.Config.ContainerCapDrop),
|
2020-02-24 07:01:25 +08:00
|
|
|
rc.JobContainer.Start(false),
|
2023-04-19 11:23:28 +08:00
|
|
|
rc.JobContainer.ConnectToNetwork(networkName),
|
2022-11-17 05:29:45 +08:00
|
|
|
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
|
2020-02-24 07:01:25 +08:00
|
|
|
Name: "workflow/event.json",
|
2023-02-16 23:34:51 +08:00
|
|
|
Mode: 0o644,
|
2020-02-24 07:01:25 +08:00
|
|
|
Body: rc.EventJSON,
|
2021-01-12 14:39:43 +08:00
|
|
|
}, &container.FileEntry{
|
|
|
|
Name: "workflow/envs.txt",
|
2023-02-16 23:34:51 +08:00
|
|
|
Mode: 0o666,
|
2021-05-06 21:30:12 +08:00
|
|
|
Body: "",
|
2020-02-24 07:01:25 +08:00
|
|
|
}),
|
|
|
|
)(ctx)
|
|
|
|
}
|
|
|
|
}
|
2021-08-11 03:40:20 +08:00
|
|
|
|
2023-04-19 11:23:28 +08:00
|
|
|
func (rc *RunContext) createNetwork(name string) common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
|
|
|
return container.NewDockerNetworkCreateExecutor(name)(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rc *RunContext) removeNetwork(name string) common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
|
|
|
return container.NewDockerNetworkRemoveExecutor(name)(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-11 03:40:20 +08:00
|
|
|
func (rc *RunContext) execJobContainer(cmd []string, env map[string]string, user, workdir string) common.Executor {
|
2020-02-24 07:01:25 +08:00
|
|
|
return func(ctx context.Context) error {
|
2021-08-11 03:40:20 +08:00
|
|
|
return rc.JobContainer.Exec(cmd, env, user, workdir)(ctx)
|
2020-02-24 07:01:25 +08:00
|
|
|
}
|
|
|
|
}
|
2020-06-18 23:21:55 +08:00
|
|
|
|
2023-02-04 21:35:13 +08:00
|
|
|
func (rc *RunContext) ApplyExtraPath(ctx context.Context, env *map[string]string) {
|
2022-12-09 19:16:15 +08:00
|
|
|
if rc.ExtraPath != nil && len(rc.ExtraPath) > 0 {
|
|
|
|
path := rc.JobContainer.GetPathVariableName()
|
|
|
|
if (*env)[path] == "" {
|
2023-02-04 21:35:13 +08:00
|
|
|
cenv := map[string]string{}
|
|
|
|
var cpath string
|
|
|
|
if err := rc.JobContainer.UpdateFromImageEnv(&cenv)(ctx); err == nil {
|
|
|
|
if p, ok := cenv[path]; ok {
|
|
|
|
cpath = p
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(cpath) == 0 {
|
|
|
|
cpath = rc.JobContainer.DefaultPathVariable()
|
|
|
|
}
|
|
|
|
(*env)[path] = cpath
|
2022-12-09 19:16:15 +08:00
|
|
|
}
|
|
|
|
(*env)[path] = rc.JobContainer.JoinPathVariable(append(rc.ExtraPath, (*env)[path])...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rc *RunContext) UpdateExtraPath(ctx context.Context, githubEnvPath string) error {
|
|
|
|
if common.Dryrun(ctx) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
pathTar, err := rc.JobContainer.GetContainerArchive(ctx, githubEnvPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer pathTar.Close()
|
|
|
|
|
|
|
|
reader := tar.NewReader(pathTar)
|
|
|
|
_, err = reader.Next()
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
s := bufio.NewScanner(reader)
|
|
|
|
for s.Scan() {
|
|
|
|
line := s.Text()
|
|
|
|
if len(line) > 0 {
|
|
|
|
rc.addPath(ctx, line)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-18 23:21:55 +08:00
|
|
|
// stopJobContainer removes the job container (if it exists) and its volume (if it exists) if !rc.Config.ReuseContainers
|
2020-02-24 07:01:25 +08:00
|
|
|
func (rc *RunContext) stopJobContainer() common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
2022-11-17 05:29:45 +08:00
|
|
|
if rc.cleanUpJobContainer != nil && !rc.Config.ReuseContainers {
|
|
|
|
return rc.cleanUpJobContainer(ctx)
|
2020-02-24 07:01:25 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-19 11:23:28 +08:00
|
|
|
func (rc *RunContext) pullServicesImages(forcePull bool) common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
|
|
|
execs := []common.Executor{}
|
|
|
|
for _, c := range rc.ServiceContainers {
|
|
|
|
execs = append(execs, c.Pull(forcePull))
|
|
|
|
}
|
|
|
|
return common.NewParallelExecutor(len(execs), execs...)(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rc *RunContext) startServiceContainers(networkName string) common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
|
|
|
execs := []common.Executor{}
|
|
|
|
for _, c := range rc.ServiceContainers {
|
|
|
|
execs = append(execs, common.NewPipelineExecutor(
|
|
|
|
c.Pull(false),
|
|
|
|
c.Create(rc.Config.ContainerCapAdd, rc.Config.ContainerCapDrop),
|
|
|
|
c.Start(false),
|
|
|
|
c.ConnectToNetwork(networkName),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
return common.NewParallelExecutor(len(execs), execs...)(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rc *RunContext) stopServiceContainers() common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
|
|
|
execs := []common.Executor{}
|
|
|
|
for _, c := range rc.ServiceContainers {
|
|
|
|
execs = append(execs, c.Remove())
|
|
|
|
}
|
|
|
|
return common.NewParallelExecutor(len(execs), execs...)(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-05 05:50:35 +08:00
|
|
|
// Prepare the mounts and binds for the worker
|
|
|
|
|
2020-02-25 02:56:49 +08:00
|
|
|
// ActionCacheDir is for rc
|
|
|
|
func (rc *RunContext) ActionCacheDir() string {
|
2020-02-24 14:34:48 +08:00
|
|
|
var xdgCache string
|
|
|
|
var ok bool
|
2021-04-05 23:51:13 +08:00
|
|
|
if xdgCache, ok = os.LookupEnv("XDG_CACHE_HOME"); !ok || xdgCache == "" {
|
|
|
|
if home, err := homedir.Dir(); err == nil {
|
|
|
|
xdgCache = filepath.Join(home, ".cache")
|
|
|
|
} else if xdgCache, err = filepath.Abs("."); err != nil {
|
|
|
|
log.Fatal(err)
|
2020-02-24 14:34:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return filepath.Join(xdgCache, "act")
|
|
|
|
}
|
|
|
|
|
2021-11-24 23:49:08 +08:00
|
|
|
// Interpolate outputs after a job is done
|
|
|
|
func (rc *RunContext) interpolateOutputs() common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
2022-06-17 23:55:21 +08:00
|
|
|
ee := rc.NewExpressionEvaluator(ctx)
|
2021-11-24 23:49:08 +08:00
|
|
|
for k, v := range rc.Run.Job().Outputs {
|
2022-06-17 23:55:21 +08:00
|
|
|
interpolated := ee.Interpolate(ctx, v)
|
2021-11-24 23:49:08 +08:00
|
|
|
if v != interpolated {
|
|
|
|
rc.Run.Job().Outputs[k] = interpolated
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-09 01:22:41 +08:00
|
|
|
func (rc *RunContext) startContainer() common.Executor {
|
2022-11-17 05:29:45 +08:00
|
|
|
return func(ctx context.Context) error {
|
2023-03-14 22:07:31 +08:00
|
|
|
if rc.IsHostEnv(ctx) {
|
2022-11-17 05:29:45 +08:00
|
|
|
return rc.startHostEnvironment()(ctx)
|
|
|
|
}
|
|
|
|
return rc.startJobContainer()(ctx)
|
|
|
|
}
|
2022-02-09 01:22:41 +08:00
|
|
|
}
|
2020-02-27 15:29:43 +08:00
|
|
|
|
2023-03-14 22:07:31 +08:00
|
|
|
func (rc *RunContext) IsHostEnv(ctx context.Context) bool {
|
|
|
|
image := rc.platformImage(ctx)
|
|
|
|
return strings.EqualFold(image, "-self-hosted")
|
|
|
|
}
|
|
|
|
|
2022-02-09 01:22:41 +08:00
|
|
|
func (rc *RunContext) stopContainer() common.Executor {
|
|
|
|
return rc.stopJobContainer()
|
|
|
|
}
|
2020-02-07 14:17:58 +08:00
|
|
|
|
2022-02-09 01:22:41 +08:00
|
|
|
func (rc *RunContext) closeContainer() common.Executor {
|
|
|
|
return func(ctx context.Context) error {
|
|
|
|
if rc.JobContainer != nil {
|
|
|
|
return rc.JobContainer.Close()(ctx)
|
2020-02-11 07:27:05 +08:00
|
|
|
}
|
2022-02-09 01:22:41 +08:00
|
|
|
return nil
|
2020-02-24 07:01:25 +08:00
|
|
|
}
|
2022-02-09 01:22:41 +08:00
|
|
|
}
|
2021-12-09 04:57:42 +08:00
|
|
|
|
2022-02-09 01:22:41 +08:00
|
|
|
func (rc *RunContext) matrix() map[string]interface{} {
|
|
|
|
return rc.Matrix
|
|
|
|
}
|
2021-12-09 04:57:42 +08:00
|
|
|
|
2022-02-09 01:22:41 +08:00
|
|
|
func (rc *RunContext) result(result string) {
|
|
|
|
rc.Run.Job().Result = result
|
|
|
|
}
|
2020-02-18 02:11:16 +08:00
|
|
|
|
2022-02-09 01:22:41 +08:00
|
|
|
func (rc *RunContext) steps() []*model.Step {
|
|
|
|
return rc.Run.Job().Steps
|
|
|
|
}
|
|
|
|
|
|
|
|
// Executor returns a pipeline executor for all the steps in the job
|
|
|
|
func (rc *RunContext) Executor() common.Executor {
|
2022-12-16 00:45:22 +08:00
|
|
|
var executor common.Executor
|
|
|
|
|
|
|
|
switch rc.Run.Job().Type() {
|
|
|
|
case model.JobTypeDefault:
|
|
|
|
executor = newJobExecutor(rc, &stepFactoryImpl{}, rc)
|
|
|
|
case model.JobTypeReusableWorkflowLocal:
|
|
|
|
executor = newLocalReusableWorkflowExecutor(rc)
|
|
|
|
case model.JobTypeReusableWorkflowRemote:
|
|
|
|
executor = newRemoteReusableWorkflowExecutor(rc)
|
|
|
|
}
|
|
|
|
|
2022-02-26 02:39:50 +08:00
|
|
|
return func(ctx context.Context) error {
|
2022-12-16 00:45:22 +08:00
|
|
|
res, err := rc.isEnabled(ctx)
|
2022-02-26 02:39:50 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-12-16 00:45:22 +08:00
|
|
|
if res {
|
|
|
|
return executor(ctx)
|
2022-02-26 02:39:50 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2020-02-24 07:01:25 +08:00
|
|
|
}
|
2020-02-18 02:11:16 +08:00
|
|
|
|
2022-06-17 23:55:21 +08:00
|
|
|
func (rc *RunContext) platformImage(ctx context.Context) string {
|
2020-03-17 05:58:10 +08:00
|
|
|
job := rc.Run.Job()
|
|
|
|
|
|
|
|
c := job.Container()
|
|
|
|
if c != nil {
|
2022-06-17 23:55:21 +08:00
|
|
|
return rc.ExprEval.Interpolate(ctx, c.Image)
|
2020-03-17 05:58:10 +08:00
|
|
|
}
|
|
|
|
|
2021-01-21 22:02:48 +08:00
|
|
|
if job.RunsOn() == nil {
|
2022-06-17 23:55:21 +08:00
|
|
|
common.Logger(ctx).Errorf("'runs-on' key not defined in %s", rc.String())
|
2021-01-21 22:02:48 +08:00
|
|
|
}
|
|
|
|
|
2022-11-22 16:39:19 +08:00
|
|
|
runsOn := job.RunsOn()
|
|
|
|
for i, v := range runsOn {
|
|
|
|
runsOn[i] = rc.ExprEval.Interpolate(ctx, v)
|
|
|
|
}
|
|
|
|
|
|
|
|
if pick := rc.Config.PlatformPicker; pick != nil {
|
|
|
|
if image := pick(runsOn); image != "" {
|
|
|
|
return image
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, runnerLabel := range runsOn {
|
|
|
|
image := rc.Config.Platforms[strings.ToLower(runnerLabel)]
|
2020-03-17 05:58:10 +08:00
|
|
|
if image != "" {
|
|
|
|
return image
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2022-10-07 06:09:43 +08:00
|
|
|
func (rc *RunContext) options(ctx context.Context) string {
|
2021-09-10 13:03:40 +08:00
|
|
|
job := rc.Run.Job()
|
|
|
|
c := job.Container()
|
|
|
|
if c == nil {
|
2022-12-06 23:58:47 +08:00
|
|
|
return rc.Config.ContainerOptions
|
2021-09-10 13:03:40 +08:00
|
|
|
}
|
|
|
|
|
2022-10-07 06:09:43 +08:00
|
|
|
return c.Options
|
2021-09-10 13:03:40 +08:00
|
|
|
}
|
|
|
|
|
2022-02-26 02:39:50 +08:00
|
|
|
func (rc *RunContext) isEnabled(ctx context.Context) (bool, error) {
|
2020-02-24 07:01:25 +08:00
|
|
|
job := rc.Run.Job()
|
2020-05-05 03:18:13 +08:00
|
|
|
l := common.Logger(ctx)
|
2022-06-17 23:55:21 +08:00
|
|
|
runJob, err := EvalBool(ctx, rc.ExprEval, job.If.Value, exprparser.DefaultStatusCheckSuccess)
|
2020-11-18 01:31:05 +08:00
|
|
|
if err != nil {
|
2022-02-26 02:39:50 +08:00
|
|
|
return false, fmt.Errorf(" \u274C Error in if-expression: \"if: %s\" (%s)", job.If.Value, err)
|
2020-11-18 01:31:05 +08:00
|
|
|
}
|
|
|
|
if !runJob {
|
2022-06-17 23:55:21 +08:00
|
|
|
l.WithField("jobResult", "skipped").Debugf("Skipping job '%s' due to '%s'", job.Name, job.If.Value)
|
2022-02-26 02:39:50 +08:00
|
|
|
return false, nil
|
2020-02-24 07:01:25 +08:00
|
|
|
}
|
2020-02-21 11:43:20 +08:00
|
|
|
|
2022-12-16 00:45:22 +08:00
|
|
|
if job.Type() != model.JobTypeDefault {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2022-06-17 23:55:21 +08:00
|
|
|
img := rc.platformImage(ctx)
|
2020-03-17 05:58:10 +08:00
|
|
|
if img == "" {
|
2021-01-21 22:02:48 +08:00
|
|
|
if job.RunsOn() == nil {
|
2022-06-17 23:55:21 +08:00
|
|
|
l.Errorf("'runs-on' key not defined in %s", rc.String())
|
2021-01-21 22:02:48 +08:00
|
|
|
}
|
|
|
|
|
2020-12-09 02:13:07 +08:00
|
|
|
for _, runnerLabel := range job.RunsOn() {
|
2022-06-17 23:55:21 +08:00
|
|
|
platformName := rc.ExprEval.Interpolate(ctx, runnerLabel)
|
2021-09-14 07:14:41 +08:00
|
|
|
l.Infof("\U0001F6A7 Skipping unsupported platform -- Try running with `-P %+v=...`", platformName)
|
2020-12-09 02:13:07 +08:00
|
|
|
}
|
2022-02-26 02:39:50 +08:00
|
|
|
return false, nil
|
2020-02-18 02:11:16 +08:00
|
|
|
}
|
2022-02-26 02:39:50 +08:00
|
|
|
return true, nil
|
2020-02-18 02:11:16 +08:00
|
|
|
}
|
|
|
|
|
2020-02-07 14:17:58 +08:00
|
|
|
func mergeMaps(maps ...map[string]string) map[string]string {
|
|
|
|
rtnMap := make(map[string]string)
|
|
|
|
for _, m := range maps {
|
|
|
|
for k, v := range m {
|
|
|
|
rtnMap[k] = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rtnMap
|
|
|
|
}
|
|
|
|
|
2022-11-24 14:45:32 +08:00
|
|
|
// deprecated: use createSimpleContainerName
|
2020-02-24 07:01:25 +08:00
|
|
|
func createContainerName(parts ...string) string {
|
2023-02-04 03:54:19 +08:00
|
|
|
name := strings.Join(parts, "-")
|
2020-02-24 07:01:25 +08:00
|
|
|
pattern := regexp.MustCompile("[^a-zA-Z0-9]")
|
2023-02-04 03:54:19 +08:00
|
|
|
name = pattern.ReplaceAllString(name, "-")
|
|
|
|
name = strings.ReplaceAll(name, "--", "-")
|
|
|
|
hash := sha256.Sum256([]byte(name))
|
|
|
|
|
|
|
|
// SHA256 is 64 hex characters. So trim name to 63 characters to make room for the hash and separator
|
|
|
|
trimmedName := strings.Trim(trimToLen(name, 63), "-")
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s-%x", trimmedName, hash)
|
2020-02-07 14:17:58 +08:00
|
|
|
}
|
|
|
|
|
2022-11-24 14:45:32 +08:00
|
|
|
func createSimpleContainerName(parts ...string) string {
|
|
|
|
pattern := regexp.MustCompile("[^a-zA-Z0-9-]")
|
|
|
|
name := make([]string, 0, len(parts))
|
|
|
|
for _, v := range parts {
|
|
|
|
v = pattern.ReplaceAllString(v, "-")
|
|
|
|
v = strings.Trim(v, "-")
|
|
|
|
for strings.Contains(v, "--") {
|
|
|
|
v = strings.ReplaceAll(v, "--", "-")
|
|
|
|
}
|
|
|
|
if v != "" {
|
|
|
|
name = append(name, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(name, "_")
|
|
|
|
}
|
|
|
|
|
2020-02-07 14:17:58 +08:00
|
|
|
func trimToLen(s string, l int) string {
|
2020-02-21 11:43:20 +08:00
|
|
|
if l < 0 {
|
|
|
|
l = 0
|
|
|
|
}
|
2020-02-07 14:17:58 +08:00
|
|
|
if len(s) > l {
|
|
|
|
return s[:l]
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
2020-02-14 16:41:20 +08:00
|
|
|
|
2021-12-23 03:52:09 +08:00
|
|
|
func (rc *RunContext) getJobContext() *model.JobContext {
|
2020-02-14 16:41:20 +08:00
|
|
|
jobStatus := "success"
|
|
|
|
for _, stepStatus := range rc.StepResults {
|
2021-12-23 03:52:09 +08:00
|
|
|
if stepStatus.Conclusion == model.StepStatusFailure {
|
2020-02-14 16:41:20 +08:00
|
|
|
jobStatus = "failure"
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2021-12-23 03:52:09 +08:00
|
|
|
return &model.JobContext{
|
2020-02-14 16:41:20 +08:00
|
|
|
Status: jobStatus,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-23 03:52:09 +08:00
|
|
|
func (rc *RunContext) getStepsContext() map[string]*model.StepResult {
|
2020-02-14 16:41:20 +08:00
|
|
|
return rc.StepResults
|
|
|
|
}
|
|
|
|
|
2023-04-19 15:22:56 +08:00
|
|
|
func (rc *RunContext) getVarsContext() map[string]string {
|
|
|
|
return rc.Config.Vars
|
|
|
|
}
|
|
|
|
|
2022-06-17 23:55:21 +08:00
|
|
|
func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext {
|
|
|
|
logger := common.Logger(ctx)
|
2021-12-23 03:52:09 +08:00
|
|
|
ghc := &model.GithubContext{
|
2021-05-07 04:02:29 +08:00
|
|
|
Event: make(map[string]interface{}),
|
|
|
|
Workflow: rc.Run.Workflow.Name,
|
|
|
|
RunID: rc.Config.Env["GITHUB_RUN_ID"],
|
|
|
|
RunNumber: rc.Config.Env["GITHUB_RUN_NUMBER"],
|
|
|
|
Actor: rc.Config.Actor,
|
|
|
|
EventName: rc.Config.EventName,
|
|
|
|
Action: rc.CurrentStep,
|
2022-05-12 03:06:05 +08:00
|
|
|
Token: rc.Config.Token,
|
2023-02-28 03:10:31 +08:00
|
|
|
Job: rc.Run.JobID,
|
2021-12-23 03:19:50 +08:00
|
|
|
ActionPath: rc.ActionPath,
|
2021-05-07 04:02:29 +08:00
|
|
|
RepositoryOwner: rc.Config.Env["GITHUB_REPOSITORY_OWNER"],
|
|
|
|
RetentionDays: rc.Config.Env["GITHUB_RETENTION_DAYS"],
|
|
|
|
RunnerPerflog: rc.Config.Env["RUNNER_PERFLOG"],
|
|
|
|
RunnerTrackingID: rc.Config.Env["RUNNER_TRACKING_ID"],
|
2023-02-04 03:35:49 +08:00
|
|
|
Repository: rc.Config.Env["GITHUB_REPOSITORY"],
|
|
|
|
Ref: rc.Config.Env["GITHUB_REF"],
|
|
|
|
Sha: rc.Config.Env["SHA_REF"],
|
|
|
|
RefName: rc.Config.Env["GITHUB_REF_NAME"],
|
|
|
|
RefType: rc.Config.Env["GITHUB_REF_TYPE"],
|
|
|
|
BaseRef: rc.Config.Env["GITHUB_BASE_REF"],
|
|
|
|
HeadRef: rc.Config.Env["GITHUB_HEAD_REF"],
|
|
|
|
Workspace: rc.Config.Env["GITHUB_WORKSPACE"],
|
2020-03-07 06:17:57 +08:00
|
|
|
}
|
2022-11-17 05:29:45 +08:00
|
|
|
if rc.JobContainer != nil {
|
|
|
|
ghc.EventPath = rc.JobContainer.GetActPath() + "/workflow/event.json"
|
|
|
|
ghc.Workspace = rc.JobContainer.ToContainerPath(rc.Config.Workdir)
|
|
|
|
}
|
2021-05-06 07:11:43 +08:00
|
|
|
|
2021-05-07 04:02:29 +08:00
|
|
|
if ghc.RunID == "" {
|
|
|
|
ghc.RunID = "1"
|
2020-09-23 05:13:29 +08:00
|
|
|
}
|
2021-05-06 07:11:43 +08:00
|
|
|
|
2021-05-07 04:02:29 +08:00
|
|
|
if ghc.RunNumber == "" {
|
|
|
|
ghc.RunNumber = "1"
|
2020-09-23 05:13:29 +08:00
|
|
|
}
|
2021-05-06 07:11:43 +08:00
|
|
|
|
2021-05-07 04:02:29 +08:00
|
|
|
if ghc.RetentionDays == "" {
|
|
|
|
ghc.RetentionDays = "0"
|
|
|
|
}
|
|
|
|
|
|
|
|
if ghc.RunnerPerflog == "" {
|
|
|
|
ghc.RunnerPerflog = "/dev/null"
|
2020-02-14 16:41:20 +08:00
|
|
|
}
|
|
|
|
|
2020-05-12 15:14:56 +08:00
|
|
|
// Backwards compatibility for configs that require
|
|
|
|
// a default rather than being run as a cmd
|
|
|
|
if ghc.Actor == "" {
|
|
|
|
ghc.Actor = "nektos/act"
|
|
|
|
}
|
|
|
|
|
2023-03-16 11:45:29 +08:00
|
|
|
{ // Adapt to Gitea
|
|
|
|
if preset := rc.Config.PresetGitHubContext; preset != nil {
|
|
|
|
ghc.Event = preset.Event
|
|
|
|
ghc.RunID = preset.RunID
|
|
|
|
ghc.RunNumber = preset.RunNumber
|
|
|
|
ghc.Actor = preset.Actor
|
|
|
|
ghc.Repository = preset.Repository
|
|
|
|
ghc.EventName = preset.EventName
|
|
|
|
ghc.Sha = preset.Sha
|
|
|
|
ghc.Ref = preset.Ref
|
|
|
|
ghc.RefName = preset.RefName
|
|
|
|
ghc.RefType = preset.RefType
|
|
|
|
ghc.HeadRef = preset.HeadRef
|
|
|
|
ghc.BaseRef = preset.BaseRef
|
|
|
|
ghc.Token = preset.Token
|
|
|
|
ghc.RepositoryOwner = preset.RepositoryOwner
|
|
|
|
ghc.RetentionDays = preset.RetentionDays
|
|
|
|
return ghc
|
2021-05-07 04:02:29 +08:00
|
|
|
}
|
2020-02-14 16:41:20 +08:00
|
|
|
}
|
|
|
|
|
2020-05-05 03:18:13 +08:00
|
|
|
if rc.EventJSON != "" {
|
2023-02-04 03:35:49 +08:00
|
|
|
err := json.Unmarshal([]byte(rc.EventJSON), &ghc.Event)
|
2020-05-05 03:18:13 +08:00
|
|
|
if err != nil {
|
2022-06-17 23:55:21 +08:00
|
|
|
logger.Errorf("Unable to Unmarshal event '%s': %v", rc.EventJSON, err)
|
2020-05-05 03:18:13 +08:00
|
|
|
}
|
2020-02-14 16:41:20 +08:00
|
|
|
}
|
2020-03-07 06:17:57 +08:00
|
|
|
|
2023-02-04 03:35:49 +08:00
|
|
|
ghc.SetBaseAndHeadRef()
|
|
|
|
repoPath := rc.Config.Workdir
|
|
|
|
ghc.SetRepositoryAndOwner(ctx, rc.Config.GitHubInstance, rc.Config.RemoteName, repoPath)
|
|
|
|
if ghc.Ref == "" {
|
|
|
|
ghc.SetRef(ctx, rc.Config.DefaultBranch, repoPath)
|
2020-03-07 06:17:57 +08:00
|
|
|
}
|
2023-02-04 03:35:49 +08:00
|
|
|
if ghc.Sha == "" {
|
|
|
|
ghc.SetSha(ctx, repoPath)
|
2022-05-08 22:23:19 +08:00
|
|
|
}
|
|
|
|
|
2023-02-04 03:35:49 +08:00
|
|
|
ghc.SetRefTypeAndName()
|
|
|
|
|
2020-02-14 16:41:20 +08:00
|
|
|
return ghc
|
|
|
|
}
|
|
|
|
|
2021-12-23 03:52:09 +08:00
|
|
|
func isLocalCheckout(ghc *model.GithubContext, step *model.Step) bool {
|
2021-05-10 23:12:57 +08:00
|
|
|
if step.Type() == model.StepTypeInvalid {
|
2021-05-05 05:50:35 +08:00
|
|
|
// This will be errored out by the executor later, we need this here to avoid a null panic though
|
|
|
|
return false
|
|
|
|
}
|
2020-03-10 08:45:42 +08:00
|
|
|
if step.Type() != model.StepTypeUsesActionRemote {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
remoteAction := newRemoteAction(step.Uses)
|
2021-05-10 23:12:57 +08:00
|
|
|
if remoteAction == nil {
|
|
|
|
// IsCheckout() will nil panic if we dont bail out early
|
|
|
|
return false
|
|
|
|
}
|
2020-03-10 08:45:42 +08:00
|
|
|
if !remoteAction.IsCheckout() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if repository, ok := step.With["repository"]; ok && repository != ghc.Repository {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if repository, ok := step.With["ref"]; ok && repository != ghc.Ref {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-03-07 06:17:57 +08:00
|
|
|
func nestedMapLookup(m map[string]interface{}, ks ...string) (rval interface{}) {
|
|
|
|
var ok bool
|
|
|
|
|
|
|
|
if len(ks) == 0 { // degenerate input
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if rval, ok = m[ks[0]]; !ok {
|
|
|
|
return nil
|
|
|
|
} else if len(ks) == 1 { // we've reached the final key
|
|
|
|
return rval
|
|
|
|
} else if m, ok = rval.(map[string]interface{}); !ok {
|
|
|
|
return nil
|
|
|
|
} else { // 1+ more keys
|
|
|
|
return nestedMapLookup(m, ks[1:]...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-07 05:58:16 +08:00
|
|
|
func (rc *RunContext) withGithubEnv(ctx context.Context, github *model.GithubContext, env map[string]string) map[string]string {
|
2020-09-28 23:22:42 +08:00
|
|
|
env["CI"] = "true"
|
2020-02-14 16:41:20 +08:00
|
|
|
env["GITHUB_WORKFLOW"] = github.Workflow
|
|
|
|
env["GITHUB_RUN_ID"] = github.RunID
|
|
|
|
env["GITHUB_RUN_NUMBER"] = github.RunNumber
|
|
|
|
env["GITHUB_ACTION"] = github.Action
|
2021-12-23 03:19:50 +08:00
|
|
|
env["GITHUB_ACTION_PATH"] = github.ActionPath
|
|
|
|
env["GITHUB_ACTION_REPOSITORY"] = github.ActionRepository
|
|
|
|
env["GITHUB_ACTION_REF"] = github.ActionRef
|
2020-02-25 02:56:49 +08:00
|
|
|
env["GITHUB_ACTIONS"] = "true"
|
2020-02-14 16:41:20 +08:00
|
|
|
env["GITHUB_ACTOR"] = github.Actor
|
|
|
|
env["GITHUB_REPOSITORY"] = github.Repository
|
|
|
|
env["GITHUB_EVENT_NAME"] = github.EventName
|
|
|
|
env["GITHUB_EVENT_PATH"] = github.EventPath
|
|
|
|
env["GITHUB_WORKSPACE"] = github.Workspace
|
|
|
|
env["GITHUB_SHA"] = github.Sha
|
|
|
|
env["GITHUB_REF"] = github.Ref
|
2022-05-08 22:23:19 +08:00
|
|
|
env["GITHUB_REF_NAME"] = github.RefName
|
|
|
|
env["GITHUB_REF_TYPE"] = github.RefType
|
2020-03-10 08:45:42 +08:00
|
|
|
env["GITHUB_TOKEN"] = github.Token
|
2023-02-28 03:10:31 +08:00
|
|
|
env["GITHUB_JOB"] = github.Job
|
2021-05-07 04:02:29 +08:00
|
|
|
env["GITHUB_REPOSITORY_OWNER"] = github.RepositoryOwner
|
|
|
|
env["GITHUB_RETENTION_DAYS"] = github.RetentionDays
|
|
|
|
env["RUNNER_PERFLOG"] = github.RunnerPerflog
|
|
|
|
env["RUNNER_TRACKING_ID"] = github.RunnerTrackingID
|
2023-02-04 03:35:49 +08:00
|
|
|
env["GITHUB_BASE_REF"] = github.BaseRef
|
|
|
|
env["GITHUB_HEAD_REF"] = github.HeadRef
|
|
|
|
|
|
|
|
defaultServerURL := "https://github.com"
|
|
|
|
defaultAPIURL := "https://api.github.com"
|
|
|
|
defaultGraphqlURL := "https://api.github.com/graphql"
|
|
|
|
|
2021-05-06 00:42:34 +08:00
|
|
|
if rc.Config.GitHubInstance != "github.com" {
|
2023-02-04 03:35:49 +08:00
|
|
|
defaultServerURL = fmt.Sprintf("https://%s", rc.Config.GitHubInstance)
|
|
|
|
defaultAPIURL = fmt.Sprintf("https://%s/api/v3", rc.Config.GitHubInstance)
|
|
|
|
defaultGraphqlURL = fmt.Sprintf("https://%s/api/graphql", rc.Config.GitHubInstance)
|
|
|
|
}
|
|
|
|
|
2023-03-16 11:45:29 +08:00
|
|
|
{ // Adapt to Gitea
|
|
|
|
instance := rc.Config.GitHubInstance
|
|
|
|
if !strings.HasPrefix(instance, "http://") &&
|
|
|
|
!strings.HasPrefix(instance, "https://") {
|
|
|
|
instance = "https://" + instance
|
2022-11-16 18:00:45 +08:00
|
|
|
}
|
2023-03-16 11:45:29 +08:00
|
|
|
defaultServerURL = instance
|
|
|
|
defaultAPIURL = instance + "/api/v1" // the version of Gitea is v1
|
|
|
|
defaultGraphqlURL = "" // Gitea doesn't support graphql
|
|
|
|
}
|
|
|
|
|
2023-02-04 03:35:49 +08:00
|
|
|
if env["GITHUB_SERVER_URL"] == "" {
|
|
|
|
env["GITHUB_SERVER_URL"] = defaultServerURL
|
|
|
|
}
|
|
|
|
|
|
|
|
if env["GITHUB_API_URL"] == "" {
|
|
|
|
env["GITHUB_API_URL"] = defaultAPIURL
|
|
|
|
}
|
|
|
|
|
|
|
|
if env["GITHUB_GRAPHQL_URL"] == "" {
|
|
|
|
env["GITHUB_GRAPHQL_URL"] = defaultGraphqlURL
|
2021-05-06 00:42:34 +08:00
|
|
|
}
|
2021-03-18 08:14:08 +08:00
|
|
|
|
2021-11-11 01:57:22 +08:00
|
|
|
if rc.Config.ArtifactServerPath != "" {
|
|
|
|
setActionRuntimeVars(rc, env)
|
|
|
|
}
|
|
|
|
|
2021-03-18 08:14:08 +08:00
|
|
|
job := rc.Run.Job()
|
|
|
|
if job.RunsOn() != nil {
|
|
|
|
for _, runnerLabel := range job.RunsOn() {
|
2022-06-17 23:55:21 +08:00
|
|
|
platformName := rc.ExprEval.Interpolate(ctx, runnerLabel)
|
2021-03-18 08:14:08 +08:00
|
|
|
if platformName != "" {
|
2021-03-29 12:46:09 +08:00
|
|
|
if platformName == "ubuntu-latest" {
|
|
|
|
// hardcode current ubuntu-latest since we have no way to check that 'on the fly'
|
|
|
|
env["ImageOS"] = "ubuntu20"
|
|
|
|
} else {
|
2021-08-01 23:39:39 +08:00
|
|
|
platformName = strings.SplitN(strings.Replace(platformName, `-`, ``, 1), `.`, 2)[0]
|
2021-03-29 12:46:09 +08:00
|
|
|
env["ImageOS"] = platformName
|
|
|
|
}
|
2021-03-18 08:14:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 16:41:20 +08:00
|
|
|
return env
|
|
|
|
}
|
2020-03-10 08:45:42 +08:00
|
|
|
|
2021-11-11 01:57:22 +08:00
|
|
|
func setActionRuntimeVars(rc *RunContext, env map[string]string) {
|
|
|
|
actionsRuntimeURL := os.Getenv("ACTIONS_RUNTIME_URL")
|
|
|
|
if actionsRuntimeURL == "" {
|
2023-01-16 22:12:20 +08:00
|
|
|
actionsRuntimeURL = fmt.Sprintf("http://%s:%s/", rc.Config.ArtifactServerAddr, rc.Config.ArtifactServerPort)
|
2021-11-11 01:57:22 +08:00
|
|
|
}
|
|
|
|
env["ACTIONS_RUNTIME_URL"] = actionsRuntimeURL
|
|
|
|
|
|
|
|
actionsRuntimeToken := os.Getenv("ACTIONS_RUNTIME_TOKEN")
|
|
|
|
if actionsRuntimeToken == "" {
|
|
|
|
actionsRuntimeToken = "token"
|
|
|
|
}
|
|
|
|
env["ACTIONS_RUNTIME_TOKEN"] = actionsRuntimeToken
|
|
|
|
}
|
|
|
|
|
2022-06-17 23:55:21 +08:00
|
|
|
func (rc *RunContext) handleCredentials(ctx context.Context) (username, password string, err error) {
|
2021-11-28 02:05:56 +08:00
|
|
|
// TODO: remove below 2 lines when we can release act with breaking changes
|
|
|
|
username = rc.Config.Secrets["DOCKER_USERNAME"]
|
|
|
|
password = rc.Config.Secrets["DOCKER_PASSWORD"]
|
|
|
|
|
|
|
|
container := rc.Run.Job().Container()
|
|
|
|
if container == nil || container.Credentials == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if container.Credentials != nil && len(container.Credentials) != 2 {
|
|
|
|
err = fmt.Errorf("invalid property count for key 'credentials:'")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-06-17 23:55:21 +08:00
|
|
|
ee := rc.NewExpressionEvaluator(ctx)
|
|
|
|
if username = ee.Interpolate(ctx, container.Credentials["username"]); username == "" {
|
2021-11-28 02:05:56 +08:00
|
|
|
err = fmt.Errorf("failed to interpolate container.credentials.username")
|
|
|
|
return
|
|
|
|
}
|
2022-06-17 23:55:21 +08:00
|
|
|
if password = ee.Interpolate(ctx, container.Credentials["password"]); password == "" {
|
2021-11-28 02:05:56 +08:00
|
|
|
err = fmt.Errorf("failed to interpolate container.credentials.password")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if container.Credentials["username"] == "" || container.Credentials["password"] == "" {
|
|
|
|
err = fmt.Errorf("container.credentials cannot be empty")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return username, password, err
|
|
|
|
}
|