cache dir for remote actions

This commit is contained in:
Casey Lee 2020-02-23 22:34:48 -08:00
parent 94591c58d7
commit 88041afb87
No known key found for this signature in database
GPG key ID: 1899120ECD0A1784
5 changed files with 76 additions and 111 deletions

View file

@ -171,7 +171,7 @@ func (cr *containerReference) remove() common.Executor {
Force: true,
})
if err != nil {
return errors.WithStack(err)
logger.Error(errors.WithStack(err))
}
logger.Debugf("Removed container: %v", cr.id)

View file

@ -1,52 +0,0 @@
package container
import (
"bytes"
"context"
"io/ioutil"
"testing"
"github.com/nektos/act/pkg/common"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
)
type rawFormatter struct{}
func (f *rawFormatter) Format(entry *logrus.Entry) ([]byte, error) {
return []byte(entry.Message), nil
}
func TestNewDockerRunExecutor(t *testing.T) {
if testing.Short() {
t.Skip("skipping slower test")
}
noopLogger := logrus.New()
noopLogger.SetOutput(ioutil.Discard)
buf := &bytes.Buffer{}
logger := logrus.New()
logger.SetOutput(buf)
logger.SetFormatter(&rawFormatter{})
ctx := common.WithLogger(context.Background(), logger)
runner := NewDockerRunExecutor(NewDockerRunExecutorInput{
Image: "hello-world",
Stdout: buf,
})
puller := NewDockerPullExecutor(NewDockerPullExecutorInput{
Image: "hello-world",
})
pipeline := common.NewPipelineExecutor(puller, runner)
err := pipeline(ctx)
assert.NoError(t, err)
actual := buf.String()
assert.Contains(t, actual, `docker pull hello-world`)
assert.Contains(t, actual, `docker run image=hello-world entrypoint=[] cmd=[]`)
assert.Contains(t, actual, `Hello from Docker!`)
}

View file

@ -38,6 +38,7 @@ func (sc *StepContext) NewExpressionEvaluator() ExpressionEvaluator {
vm := sc.RunContext.newVM()
configers := []func(*otto.Otto){
sc.vmEnv(),
sc.vmInputs(),
}
for _, configer := range configers {
configer(vm)
@ -241,6 +242,16 @@ func (sc *StepContext) vmEnv() func(*otto.Otto) {
}
}
func (sc *StepContext) vmInputs() func(*otto.Otto) {
inputs := make(map[string]string)
for k, v := range sc.Step.With {
inputs[k] = v
}
return func(vm *otto.Otto) {
_ = vm.Set("inputs", inputs)
}
}
func (rc *RunContext) vmJob() func(*otto.Otto) {
job := rc.getJobContext()

View file

@ -45,7 +45,7 @@ func (rc *RunContext) GetEnv() map[string]string {
}
func (rc *RunContext) jobContainerName() string {
return createContainerName(filepath.Base(rc.Config.Workdir), rc.Run.String())
return createContainerName("act", rc.Run.String())
}
func (rc *RunContext) startJobContainer() common.Executor {
@ -74,7 +74,7 @@ func (rc *RunContext) startJobContainer() common.Executor {
rc.JobContainer = container.NewContainer(&container.NewContainerInput{
Cmd: nil,
Entrypoint: []string{"/bin/cat"},
Entrypoint: []string{"/usr/bin/tail", "-f", "/dev/null"},
WorkingDir: "/github/workspace",
Image: image,
Name: name,
@ -83,6 +83,7 @@ func (rc *RunContext) startJobContainer() common.Executor {
},
Binds: []string{
fmt.Sprintf("%s:%s", rc.Config.Workdir, "/github/workspace"),
fmt.Sprintf("%s:%s", rc.ActionDir(), "/github/home/.act"),
fmt.Sprintf("%s:%s", "/var/run/docker.sock", "/var/run/docker.sock"),
},
Stdout: logWriter,
@ -98,10 +99,6 @@ func (rc *RunContext) startJobContainer() common.Executor {
Name: "workflow/event.json",
Mode: 644,
Body: rc.EventJSON,
}, &container.FileEntry{
Name: "home/.actions/.keep",
Mode: 644,
Body: "",
}),
)(ctx)
}
@ -121,6 +118,18 @@ func (rc *RunContext) stopJobContainer() common.Executor {
}
}
// ActionDir is for rc
func (rc *RunContext) ActionDir() string {
var xdgCache string
var ok bool
if xdgCache, ok = os.LookupEnv("XDG_CACHE_HOME"); !ok {
if home, ok := os.LookupEnv("HOME"); ok {
xdgCache = fmt.Sprintf("%s/.cache", home)
}
}
return filepath.Join(xdgCache, "act")
}
// Executor returns a pipeline executor for all the steps in the job
func (rc *RunContext) Executor() common.Executor {
steps := make([]common.Executor, 0)
@ -210,10 +219,14 @@ func createContainerName(parts ...string) string {
name := make([]string, 0)
pattern := regexp.MustCompile("[^a-zA-Z0-9]")
partLen := (30 / len(parts)) - 1
for _, part := range parts {
name = append(name, trimToLen(pattern.ReplaceAllString(part, "-"), partLen))
for i, part := range parts {
if i == len(parts)-1 {
name = append(name, pattern.ReplaceAllString(part, "-"))
} else {
name = append(name, trimToLen(pattern.ReplaceAllString(part, "-"), partLen))
}
}
return strings.Join(name, "-")
return trimToLen(strings.Trim(strings.Join(name, "-"), "-"), 30)
}
func trimToLen(s string, l int) string {

View file

@ -49,54 +49,37 @@ func (sc *StepContext) Executor() common.Executor {
)
case model.StepTypeUsesActionLocal:
actionDir := filepath.Join(rc.Config.Workdir, step.Uses)
return common.NewPipelineExecutor(
sc.setupEnv(),
sc.setupAction(),
sc.runAction(),
sc.setupAction(actionDir),
sc.runAction(actionDir),
)
case model.StepTypeUsesActionRemote:
remoteAction := newRemoteAction(step.Uses)
if remoteAction.Org == "actions" && remoteAction.Repo == "checkout" {
return func(ctx context.Context) error {
common.Logger(ctx).Debugf("Skipping actions/checkout")
return nil
}
}
actionDir := rc.ActionDir()
return common.NewPipelineExecutor(
common.NewGitCloneExecutor(common.NewGitCloneExecutorInput{
URL: remoteAction.CloneURL(),
Ref: remoteAction.Ref,
Dir: actionDir,
}),
sc.setupEnv(),
sc.setupAction(actionDir),
sc.runAction(actionDir),
)
/*
case model.StepTypeUsesActionRemote:
remoteAction := newRemoteAction(step.Uses)
if remoteAction.Org == "actions" && remoteAction.Repo == "checkout" {
return func(ctx context.Context) error {
common.Logger(ctx).Debugf("Skipping actions/checkout")
return nil
}
}
cloneDir, err := ioutil.TempDir(rc.Tempdir, remoteAction.Repo)
if err != nil {
return common.NewErrorExecutor(err)
}
return common.NewPipelineExecutor(
common.NewGitCloneExecutor(common.NewGitCloneExecutorInput{
URL: remoteAction.CloneURL(),
Ref: remoteAction.Ref,
Dir: cloneDir,
}),
sc.setupEnv(),
sc.setupAction(),
applyWith(containerSpec, step),
rc.pullImage(containerSpec),
rc.runContainer(containerSpec),
)
*/
}
return common.NewErrorExecutor(fmt.Errorf("Unable to determine how to run job:%s step:%+v", rc.Run, step))
}
func applyWith(containerSpec *model.ContainerSpec, step *model.Step) common.Executor {
return func(ctx context.Context) error {
if entrypoint, ok := step.With["entrypoint"]; ok {
containerSpec.Entrypoint = entrypoint
}
if args, ok := step.With["args"]; ok {
containerSpec.Args = args
}
return nil
}
}
func (sc *StepContext) setupEnv() common.Executor {
rc := sc.RunContext
job := rc.Run.Job()
@ -160,6 +143,13 @@ func (sc *StepContext) newStepContainer(ctx context.Context, image string, cmd [
for k, v := range sc.Env {
envList = append(envList, fmt.Sprintf("%s=%s", k, v))
}
stepEE := sc.NewExpressionEvaluator()
for i, v := range cmd {
cmd[i] = stepEE.Interpolate(v)
}
for i, v := range entrypoint {
entrypoint[i] = stepEE.Interpolate(v)
}
stepContainer := container.NewContainer(&container.NewContainerInput{
Cmd: cmd,
Entrypoint: entrypoint,
@ -184,8 +174,8 @@ func (sc *StepContext) runUsesContainer() common.Executor {
step := sc.Step
return func(ctx context.Context) error {
image := strings.TrimPrefix(step.Uses, "docker://")
cmd := strings.Fields(rc.ExprEval.Interpolate(step.With["args"]))
entrypoint := strings.Fields(rc.ExprEval.Interpolate(step.With["entrypoint"]))
cmd := strings.Fields(step.With["args"])
entrypoint := strings.Fields(step.With["entrypoint"])
stepContainer := sc.newStepContainer(ctx, image, cmd, entrypoint)
return common.NewPipelineExecutor(
@ -199,10 +189,7 @@ func (sc *StepContext) runUsesContainer() common.Executor {
}
}
func (sc *StepContext) setupAction() common.Executor {
rc := sc.RunContext
step := sc.Step
actionDir := filepath.Join(rc.Config.Workdir, step.Uses)
func (sc *StepContext) setupAction(actionDir string) common.Executor {
return func(ctx context.Context) error {
f, err := os.Open(filepath.Join(actionDir, "action.yml"))
if os.IsNotExist(err) {
@ -220,7 +207,7 @@ func (sc *StepContext) setupAction() common.Executor {
}
}
func (sc *StepContext) runAction() common.Executor {
func (sc *StepContext) runAction(actionDir string) common.Executor {
rc := sc.RunContext
step := sc.Step
return func(ctx context.Context) error {
@ -236,7 +223,13 @@ func (sc *StepContext) runAction() common.Executor {
switch action.Runs.Using {
case model.ActionRunsUsingNode12:
return rc.execJobContainer([]string{"node", action.Runs.Main}, sc.Env)(ctx)
basePath := "."
if strings.HasPrefix(actionDir, rc.Config.Workdir) {
basePath = fmt.Sprintf("/github/workspace/%s", strings.TrimPrefix(actionDir, rc.Config.Workdir))
} else if strings.HasPrefix(actionDir, rc.ActionDir()) {
basePath = fmt.Sprintf("/github/home/.act/%s", strings.TrimPrefix(actionDir, rc.ActionDir()))
}
return rc.execJobContainer([]string{"node", fmt.Sprintf("%s/%s", basePath, action.Runs.Main)}, sc.Env)(ctx)
case model.ActionRunsUsingDocker:
var prepImage common.Executor
var image string
@ -245,7 +238,7 @@ func (sc *StepContext) runAction() common.Executor {
} else {
image = fmt.Sprintf("%s:%s", regexp.MustCompile("[^a-zA-Z0-9]").ReplaceAllString(step.Uses, "-"), "latest")
image = strings.TrimLeft(image, "-")
contextDir := filepath.Join(rc.Config.Workdir, step.Uses, action.Runs.Main)
contextDir := filepath.Join(actionDir, action.Runs.Main)
prepImage = container.NewDockerBuildExecutor(container.NewDockerBuildExecutorInput{
ContextDir: contextDir,
ImageTag: image,