Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [BREAKING] make use of the new action cache #2509

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
1 change: 0 additions & 1 deletion cmd/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ type Input struct {
actionOfflineMode bool
logPrefixJobID bool
networkName string
useNewActionCache bool
localRepository []string
}

Expand Down
50 changes: 27 additions & 23 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ func Execute(ctx context.Context, version string) {
rootCmd.PersistentFlags().StringVarP(&input.actionCachePath, "action-cache-path", "", filepath.Join(CacheHomeDir, "act"), "Defines the path where the actions get cached and host workspaces created.")
rootCmd.PersistentFlags().BoolVarP(&input.actionOfflineMode, "action-offline-mode", "", false, "If action contents exists, it will not be fetch and pull again. If turn on this,will turn off force pull")
rootCmd.PersistentFlags().StringVarP(&input.networkName, "network", "", "host", "Sets a docker network name. Defaults to host.")
rootCmd.PersistentFlags().BoolVarP(&input.useNewActionCache, "use-new-action-cache", "", false, "Enable using the new Action Cache for storing Actions locally")
rootCmd.PersistentFlags().StringArrayVarP(&input.localRepository, "local-repository", "", []string{}, "Replaces the specified repository and ref with a local folder (e.g. https://github.com/test/test@v0=/home/act/test or test/test@v0=/home/act/test, the latter matches any hosts or protocols)")
rootCmd.SetArgs(args())

Expand Down Expand Up @@ -393,6 +392,16 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
vars := newSecrets(input.vars)
_ = readEnvs(input.Varfile(), vars)

log.Debugf("Cleaning up %s old action cache format", input.actionCachePath)
entries, _ := os.ReadDir(input.actionCachePath)
for _, entry := range entries {
if strings.Contains(entry.Name(), "@") {
fullPath := filepath.Join(input.actionCachePath, entry.Name())
log.Debugf("Removing %s", fullPath)
_ = os.RemoveAll(fullPath)
}
}

matrixes := parseMatrix(input.matrix)
log.Debugf("Evaluated matrix inclusions: %v", matrixes)

Expand Down Expand Up @@ -588,31 +597,26 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
Matrix: matrixes,
ContainerNetworkMode: docker_container.NetworkMode(input.networkName),
}
if input.useNewActionCache || len(input.localRepository) > 0 {
if input.actionOfflineMode {
config.ActionCache = &runner.GoGitActionCacheOfflineMode{
Parent: runner.GoGitActionCache{
Path: config.ActionCacheDir,
},
}
} else {
config.ActionCache = &runner.GoGitActionCache{
if input.actionOfflineMode {
config.ActionCache = &runner.GoGitActionCacheOfflineMode{
Parent: runner.GoGitActionCache{
Path: config.ActionCacheDir,
}
},
}
if len(input.localRepository) > 0 {
localRepositories := map[string]string{}
for _, l := range input.localRepository {
k, v, _ := strings.Cut(l, "=")
localRepositories[k] = v
}
config.ActionCache = &runner.LocalRepositoryCache{
Parent: config.ActionCache,
LocalRepositories: localRepositories,
CacheDirCache: map[string]string{},
}
}
if len(input.localRepository) > 0 {
localRepositories := map[string]string{}
for _, l := range input.localRepository {
k, v, _ := strings.Cut(l, "=")
localRepositories[k] = v
}
config.ActionCache = &runner.LocalRepositoryCache{
Parent: config.ActionCache,
LocalRepositories: localRepositories,
CacheDirCache: map[string]string{},
}
}

r, err := runner.New(config)
if err != nil {
return err
Expand Down Expand Up @@ -658,7 +662,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
func defaultImageSurvey(actrc string) error {
var answer string
confirmation := &survey.Select{
Message: "Please choose the default image you want to use with act:\n - Large size image: ca. 17GB download + 53.1GB storage, you will need 75GB of free disk space, snapshots of GitHub Hosted Runners without snap and pulled docker images\n - Medium size image: ~500MB, includes only necessary tools to bootstrap actions and aims to be compatible with most actions\n - Micro size image: <200MB, contains only NodeJS required to bootstrap actions, doesn't work with all actions\n\nDefault image and other options can be changed manually in " + configLocations()[0] + " (please refer to https://github.com/nektos/act#configuration for additional information about file structure)",
Message: "Please choose the default image you want to use with act:\n - Large size image: ca. 17GB download + 53.1GB storage, you will need 75GB of free disk space, snapshots of GitHub Hosted Runners without snap and pulled docker images\n - Medium size image: ~500MB, includes only necessary tools to bootstrap actions and aims to be compatible with most actions\n - Micro size image: <200MB, contains only NodeJS required to bootstrap actions, doesn't work with all actions\n\nDefault image and other options can be changed manually in " + configLocations()[0] + " (please refer to https://github.com/nektos/act#configuration for additional information about file structure)",
Help: "If you want to know why act asks you that, please go to https://github.com/nektos/act/issues/107",
Default: "Medium",
Options: []string{"Large", "Medium", "Micro"},
Expand Down
3 changes: 3 additions & 0 deletions pkg/container/docker_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,9 @@ func (cr *containerReference) waitForCommand(ctx context.Context, isTerminal boo
}

func (cr *containerReference) CopyTarStream(ctx context.Context, destPath string, tarStream io.Reader) error {
if common.Dryrun(ctx) {
return nil
}
// Mkdir
buf := &bytes.Buffer{}
tw := tar.NewWriter(buf)
Expand Down
7 changes: 5 additions & 2 deletions pkg/container/host_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@
}

func (e *HostEnvironment) CopyTarStream(ctx context.Context, destPath string, tarStream io.Reader) error {
if common.Dryrun(ctx) {
return nil
}

Check warning on line 67 in pkg/container/host_environment.go

View check run for this annotation

Codecov / codecov/patch

pkg/container/host_environment.go#L66-L67

Added lines #L66 - L67 were not covered by tests
if err := os.RemoveAll(destPath); err != nil {
return err
}
Expand Down Expand Up @@ -435,9 +438,9 @@

func goOsToActionOs(os string) string {
osMapper := map[string]string{
"linux": "Linux",
"linux": "Linux",
"windows": "Windows",
"darwin": "macOS",
"darwin": "macOS",
}
if os, ok := osMapper[os]; ok {
return os
Expand Down
47 changes: 20 additions & 27 deletions pkg/runner/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,13 @@
containerActionDirCopy += `/`
}

if rc.Config != nil && rc.Config.ActionCache != nil {
raction := step.(*stepActionRemote)
ta, err := rc.Config.ActionCache.GetTarArchive(ctx, raction.cacheDir, raction.resolvedSha, "")
if err != nil {
return err
}
defer ta.Close()
return rc.JobContainer.CopyTarStream(ctx, containerActionDirCopy, ta)
}

if err := removeGitIgnore(ctx, actionDir); err != nil {
raction := step.(*stepActionRemote)
ta, err := rc.getActionCache().GetTarArchive(ctx, raction.cacheDir, raction.resolvedSha, "")
if err != nil {
return err
}

return rc.JobContainer.CopyDir(containerActionDirCopy, actionDir+"/", rc.Config.UseGitIgnore)(ctx)
defer ta.Close()
return rc.JobContainer.CopyTarStream(ctx, containerActionDirCopy, ta)
}

func runActionImpl(step actionStep, actionDir string, remoteAction *remoteAction) common.Executor {
Expand Down Expand Up @@ -186,11 +178,11 @@

return rc.execJobContainer(containerArgs, *step.getEnv(), "", "")(ctx)
case model.ActionRunsUsingDocker:
location := actionLocation
if remoteAction == nil {
location = containerActionDir
actionDir = ""
actionPath = containerActionDir
}
return execAsDocker(ctx, step, actionName, location, remoteAction == nil, "entrypoint")
return execAsDocker(ctx, step, actionName, actionDir, actionPath, remoteAction == nil, "entrypoint")
case model.ActionRunsUsingComposite:
if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil {
return err
Expand Down Expand Up @@ -243,7 +235,7 @@
// TODO: break out parts of function to reduce complexicity
//
//nolint:gocyclo
func execAsDocker(ctx context.Context, step actionStep, actionName string, basedir string, localAction bool, entrypointType string) error {
func execAsDocker(ctx context.Context, step actionStep, actionName, basedir, subpath string, localAction bool, entrypointType string) error {
logger := common.Logger(ctx)
rc := step.getRunContext()
action := step.getActionModel()
Expand All @@ -260,7 +252,7 @@
image = fmt.Sprintf("%s-dockeraction:%s", regexp.MustCompile("[^a-zA-Z0-9]").ReplaceAllString(actionName, "-"), "latest")
image = fmt.Sprintf("act-%s", strings.TrimLeft(image, "-"))
image = strings.ToLower(image)
contextDir, fileName := filepath.Split(filepath.Join(basedir, action.Runs.Image))
contextDir, fileName := path.Split(path.Join(subpath, action.Runs.Image))

anyArchExists, err := container.ImageExistsLocally(ctx, image, "any")
if err != nil {
Expand Down Expand Up @@ -291,16 +283,16 @@
return err
}
defer buildContext.Close()
} else if rc.Config.ActionCache != nil {
} else {
rstep := step.(*stepActionRemote)
buildContext, err = rc.Config.ActionCache.GetTarArchive(ctx, rstep.cacheDir, rstep.resolvedSha, contextDir)
buildContext, err = rc.getActionCache().GetTarArchive(ctx, rstep.cacheDir, rstep.resolvedSha, contextDir)
if err != nil {
return err
}
defer buildContext.Close()
}
prepImage = container.NewDockerBuildExecutor(container.NewDockerBuildExecutorInput{
ContextDir: contextDir,
ContextDir: filepath.Join(basedir, contextDir),
Dockerfile: fileName,
ImageTag: image,
BuildContext: buildContext,
Expand All @@ -324,6 +316,7 @@
if len(entrypoint) == 0 {
if entrypointType == "pre-entrypoint" && action.Runs.PreEntrypoint != "" {
entrypoint, err = shellquote.Split(action.Runs.PreEntrypoint)

Check warning on line 319 in pkg/runner/action.go

View check run for this annotation

Codecov / codecov/patch

pkg/runner/action.go#L319

Added line #L319 was not covered by tests
if err != nil {
return err
}
Expand Down Expand Up @@ -557,11 +550,11 @@
return rc.execJobContainer(containerArgs, *step.getEnv(), "", "")(ctx)

case model.ActionRunsUsingDocker:
location := actionLocation
if remoteAction == nil {
location = containerActionDir
actionDir = ""
actionPath = containerActionDir

Check warning on line 555 in pkg/runner/action.go

View check run for this annotation

Codecov / codecov/patch

pkg/runner/action.go#L554-L555

Added lines #L554 - L555 were not covered by tests
}
return execAsDocker(ctx, step, actionName, location, remoteAction == nil, "pre-entrypoint")
return execAsDocker(ctx, step, actionName, actionDir, actionPath, remoteAction == nil, "pre-entrypoint")

Check warning on line 557 in pkg/runner/action.go

View check run for this annotation

Codecov / codecov/patch

pkg/runner/action.go#L557

Added line #L557 was not covered by tests

case model.ActionRunsUsingComposite:
if step.getCompositeSteps() == nil {
Expand Down Expand Up @@ -662,11 +655,11 @@
return rc.execJobContainer(containerArgs, *step.getEnv(), "", "")(ctx)

case model.ActionRunsUsingDocker:
location := actionLocation
if remoteAction == nil {
location = containerActionDir
actionDir = ""
actionPath = containerActionDir

Check warning on line 660 in pkg/runner/action.go

View check run for this annotation

Codecov / codecov/patch

pkg/runner/action.go#L659-L660

Added lines #L659 - L660 were not covered by tests
}
return execAsDocker(ctx, step, actionName, location, remoteAction == nil, "post-entrypoint")
return execAsDocker(ctx, step, actionName, actionDir, actionPath, remoteAction == nil, "post-entrypoint")

Check warning on line 662 in pkg/runner/action.go

View check run for this annotation

Codecov / codecov/patch

pkg/runner/action.go#L662

Added line #L662 was not covered by tests

case model.ActionRunsUsingComposite:
if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil {
Expand Down
6 changes: 5 additions & 1 deletion pkg/runner/action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,10 @@ func TestActionRunner(t *testing.T) {
ctx := context.Background()

cm := &containerMock{}
cm.On("CopyDir", "/var/run/act/actions/dir/", "dir/", false).Return(func(ctx context.Context) error { return nil })
cm.Mock.On("CopyTarStream", ctx, "/var/run/act/actions/dir/", mock.Anything).Return(nil)

cacheMock := &TestRepositoryCache{}
cacheMock.Mock.On("GetTarArchive", ctx, "", "", "").Return(io.NopCloser(io.MultiReader()))

envMatcher := mock.MatchedBy(func(env map[string]string) bool {
for k, v := range tt.expectedEnv {
Expand All @@ -241,6 +244,7 @@ func TestActionRunner(t *testing.T) {
cm.On("Exec", []string{"node", "/var/run/act/actions/dir/path"}, envMatcher, "", "").Return(func(ctx context.Context) error { return nil })

tt.step.getRunContext().JobContainer = cm
tt.step.getRunContext().Config.ActionCache = cacheMock

err := runActionImpl(tt.step, "dir", newRemoteAction("org/repo/path@ref"))(ctx)

Expand Down
9 changes: 9 additions & 0 deletions pkg/runner/container_mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,12 @@ func (cm *containerMock) GetContainerArchive(ctx context.Context, srcPath string
}
return args.Get(0).(io.ReadCloser), err
}

func (cm *containerMock) CopyTarStream(ctx context.Context, destPath string, tarStream io.Reader) error {
args := cm.Mock.Called(ctx, destPath, tarStream)
err, hasErr := args.Get(0).(error)
if !hasErr {
err = nil
}
return err
}
15 changes: 4 additions & 11 deletions pkg/runner/reusable_workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,20 @@ func newRemoteReusableWorkflowExecutor(rc *RunContext) common.Executor {
// instead we will just use {owner}-{repo}@{ref} as our target directory. This should also improve performance when we are using
// multiple reusable workflows from the same repository and ref since for each workflow we won't have to clone it again
filename := fmt.Sprintf("%s/%s@%s", remoteReusableWorkflow.Org, remoteReusableWorkflow.Repo, remoteReusableWorkflow.Ref)
workflowDir := fmt.Sprintf("%s/%s", rc.ActionCacheDir(), safeFilename(filename))

if rc.Config.ActionCache != nil {
return newActionCacheReusableWorkflowExecutor(rc, filename, remoteReusableWorkflow)
}

return common.NewPipelineExecutor(
newMutexExecutor(cloneIfRequired(rc, *remoteReusableWorkflow, workflowDir)),
newReusableWorkflowExecutor(rc, workflowDir, fmt.Sprintf("./.github/workflows/%s", remoteReusableWorkflow.Filename)),
)
return newActionCacheReusableWorkflowExecutor(rc, filename, remoteReusableWorkflow)
}

func newActionCacheReusableWorkflowExecutor(rc *RunContext, filename string, remoteReusableWorkflow *remoteReusableWorkflow) common.Executor {
return func(ctx context.Context) error {
ghctx := rc.getGithubContext(ctx)
remoteReusableWorkflow.URL = ghctx.ServerURL
sha, err := rc.Config.ActionCache.Fetch(ctx, filename, remoteReusableWorkflow.CloneURL(), remoteReusableWorkflow.Ref, ghctx.Token)
cache := rc.getActionCache()
sha, err := cache.Fetch(ctx, filename, remoteReusableWorkflow.CloneURL(), remoteReusableWorkflow.Ref, ghctx.Token)
if err != nil {
return err
}
archive, err := rc.Config.ActionCache.GetTarArchive(ctx, filename, sha, fmt.Sprintf(".github/workflows/%s", remoteReusableWorkflow.Filename))
archive, err := cache.GetTarArchive(ctx, filename, sha, fmt.Sprintf(".github/workflows/%s", remoteReusableWorkflow.Filename))
if err != nil {
return err
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/runner/run_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,15 @@ func (rc *RunContext) ActionCacheDir() string {
return filepath.Join(xdgCache, "act")
}

func (rc *RunContext) getActionCache() ActionCache {
if rc.Config.ActionCache == nil {
rc.Config.ActionCache = &GoGitActionCache{
Path: rc.ActionCacheDir(),
}
}
return rc.Config.ActionCache
}

// Interpolate outputs after a job is done
func (rc *RunContext) interpolateOutputs() common.Executor {
return func(ctx context.Context) error {
Expand Down
Loading
Loading