Skip to content

Commit

Permalink
fix: defer plan creation until clone is done
Browse files Browse the repository at this point in the history
We need wait for the full clone (and only clone once)
before we start to plan the execution for a remote workflow
  • Loading branch information
KnisterPeter authored and github-actions committed Jan 2, 2023
1 parent 7bd6bd3 commit 8b03f6e
Showing 1 changed file with 48 additions and 20 deletions.
68 changes: 48 additions & 20 deletions pkg/runner/reusable_workflow.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package runner

import (
"context"
"errors"
"fmt"
"io/fs"
"os"
"path"
"regexp"
"strings"
"sync"

"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/common/git"
Expand All @@ -22,39 +27,62 @@ func newRemoteReusableWorkflowExecutor(rc *RunContext) common.Executor {
if remoteReusableWorkflow == nil {
return common.NewErrorExecutor(fmt.Errorf("expected format {owner}/{repo}/.github/workflows/{filename}@{ref}. Actual '%s' Input string was not in a correct format", uses))
}

remoteReusableWorkflow.URL = rc.Config.GitHubInstance

// todo: really use rc.ActionCacheDir()?
workflowDir := fmt.Sprintf("%s/%s", rc.ActionCacheDir(), strings.ReplaceAll(uses, "/", "-"))

gitClone := git.NewGitCloneExecutor(git.NewGitCloneExecutorInput{
URL: remoteReusableWorkflow.CloneURL(),
Ref: remoteReusableWorkflow.Ref,
Dir: workflowDir,
Token: rc.Config.Token,
})

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

func newReusableWorkflowExecutor(rc *RunContext, directory string, workflow string) common.Executor {
planner, err := model.NewWorkflowPlanner(path.Join(directory, workflow), true)
if err != nil {
return common.NewErrorExecutor(err)
}
var (
executorLock sync.Mutex
)

plan := planner.PlanEvent("workflow_call")
func newMutexExecutor(executor common.Executor) common.Executor {
return func(ctx context.Context) error {
executorLock.Lock()
defer executorLock.Unlock()

runner, err := NewReusableWorkflowRunner(rc)
if err != nil {
return common.NewErrorExecutor(err)
return executor(ctx)
}
}

return runner.NewPlanExecutor(plan)
func cloneIfRequired(rc *RunContext, remoteReusableWorkflow remoteReusableWorkflow, targetDirectory string) common.Executor {
return common.NewConditionalExecutor(
func(ctx context.Context) bool {
_, err := os.Stat(targetDirectory)
notExists := errors.Is(err, fs.ErrNotExist)
return notExists
},
git.NewGitCloneExecutor(git.NewGitCloneExecutorInput{
URL: remoteReusableWorkflow.CloneURL(),
Ref: remoteReusableWorkflow.Ref,
Dir: targetDirectory,
Token: rc.Config.Token,
}),
nil,
)
}

func newReusableWorkflowExecutor(rc *RunContext, directory string, workflow string) common.Executor {
return func(ctx context.Context) error {
planner, err := model.NewWorkflowPlanner(path.Join(directory, workflow), true)
if err != nil {
return err
}

plan := planner.PlanEvent("workflow_call")

runner, err := NewReusableWorkflowRunner(rc)
if err != nil {
return err
}

return runner.NewPlanExecutor(plan)(ctx)
}
}

func NewReusableWorkflowRunner(rc *RunContext) (Runner, error) {
Expand Down

0 comments on commit 8b03f6e

Please sign in to comment.