mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-08-13 22:41:54 +02:00
feat: support $/ prefix in action uses: (#1150)
Accepts GitHub's `$/` self-repository prefix in a step `uses:`. It resolves to the repository holding the file that wrote the `uses:`, at the ref being run, with no checkout. Inside a composite action that is the enclosing action, otherwise the workflow's own repo and commit. The action cache is keyed on the resolved reference for these, because the same `$/x` names a different action per enclosing repository. Related PR for job-level support: https://github.com/go-gitea/gitea/pull/38822 Reviewed-on: https://gitea.com/gitea/runner/pulls/1150 Reviewed-by: Zettat123 <[email protected]> Co-authored-by: silverwind <[email protected]>
This commit is contained in:
@@ -39,6 +39,9 @@ type stepActionRemote struct {
|
||||
|
||||
var stepActionRemoteNewCloneExecutor = git.NewGitCloneExecutor
|
||||
|
||||
// selfRepoPrefix introduces a self-repository reference: the action lives in the repo holding the file that wrote the `uses:`.
|
||||
const selfRepoPrefix = "$/"
|
||||
|
||||
func (sar *stepActionRemote) prepareActionExecutor() common.Executor {
|
||||
return func(ctx context.Context) error {
|
||||
if sar.remoteAction != nil && sar.action != nil {
|
||||
@@ -52,12 +55,16 @@ func (sar *stepActionRemote) prepareActionExecutor() common.Executor {
|
||||
// so we need to interpolate the expression value for uses first.
|
||||
sar.Step.Uses = sar.RunContext.NewExpressionEvaluator(ctx).Interpolate(ctx, sar.Step.Uses)
|
||||
|
||||
sar.remoteAction = newRemoteAction(sar.Step.Uses)
|
||||
github := sar.getGithubContext(ctx) // read before remoteAction is set, so `$/` resolves against the enclosing action
|
||||
if strings.HasPrefix(sar.Step.Uses, selfRepoPrefix) {
|
||||
sar.remoteAction = newSelfRepoAction(sar.Step.Uses, github)
|
||||
} else {
|
||||
sar.remoteAction = newRemoteAction(sar.Step.Uses)
|
||||
}
|
||||
if sar.remoteAction == nil {
|
||||
return fmt.Errorf("Expected format {org}/{repo}[/path]@ref. Actual '%s' Input string was not in a correct format", sar.Step.Uses)
|
||||
return fmt.Errorf("Expected format {org}/{repo}[/path]@ref or %s{path}. Actual '%s' Input string was not in a correct format", selfRepoPrefix, sar.Step.Uses)
|
||||
}
|
||||
|
||||
github := sar.getGithubContext(ctx)
|
||||
if sar.remoteAction.IsCheckout() && isLocalCheckout(github, sar.Step) && !sar.RunContext.Config.NoSkipCheckout {
|
||||
common.Logger(ctx).Debugf("Skipping local actions/checkout because workdir was already copied")
|
||||
return nil
|
||||
@@ -260,7 +267,12 @@ func (sar *stepActionRemote) revertToolkitOnFailure(exec common.Executor) common
|
||||
}
|
||||
|
||||
func (sar *stepActionRemote) actionDir() string {
|
||||
return fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), sar.Step.UsesHash())
|
||||
uses := sar.Step.Uses
|
||||
if strings.HasPrefix(uses, selfRepoPrefix) {
|
||||
// The same `$/x` names a different action per enclosing repo, so key the cache on what it resolved to.
|
||||
uses = sar.remoteAction.URL + "/" + sar.remoteAction.Reference()
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), model.UsesHash(uses))
|
||||
}
|
||||
|
||||
func (sar *stepActionRemote) getRunContext() *RunContext {
|
||||
@@ -390,6 +402,23 @@ func (ra *remoteAction) IsCheckout() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// newSelfRepoAction resolves `$/{path}` against the enclosing composite action, falling back to the workflow's own repo and commit.
|
||||
func newSelfRepoAction(action string, github *model.GithubContext) *remoteAction {
|
||||
subPath := strings.TrimLeft(strings.TrimPrefix(action, selfRepoPrefix), "/")
|
||||
if subPath == "" || strings.Contains(subPath, "@") || path.Clean("/"+subPath) != "/"+subPath { // rooted, so a leading ".." is rejected too
|
||||
return nil
|
||||
}
|
||||
repo, ref := github.ActionRepository, github.ActionRef
|
||||
if repo == "" || ref == "" {
|
||||
repo, ref = github.Repository, github.Sha
|
||||
}
|
||||
org, name, _ := strings.Cut(repo, "/")
|
||||
if org == "" || name == "" || ref == "" {
|
||||
return nil
|
||||
}
|
||||
return &remoteAction{URL: github.ServerURL, Org: org, Repo: name, Path: subPath, Ref: ref}
|
||||
}
|
||||
|
||||
func newRemoteAction(action string) *remoteAction {
|
||||
// support http(s)://host/owner/repo@v3
|
||||
for _, schema := range []string{"https://", "http://", "ssh://"} {
|
||||
|
||||
Reference in New Issue
Block a user