mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-10-29 11:26:31 +08:00
Without a docker daemon six `act/runner` tests failed instead of passing. A dry run still created and removed job networks, the job teardown dropped the dry-run flag along with every other context value, and the container mocks asked the daemon for the runner arch. This also speeds up the tests and CI without dropping assertions. Most of the time went to git and docker round trips, which are now pinned, batched or coalesced, and the dind and e2e steps cache or overlap more of their setup. On CI, `act/runner` went from 77s to 55s and `test-dind` from 108s to 55s. Locally, `act/runner` without docker went from 53s to 7s. Split out of https://gitea.com/gitea/runner/pulls/1348, which adds Windows CI on top. The go cache changes moved to https://gitea.com/gitea/runner/pulls/1350. Written by Claude Code. --------- Co-authored-by: bircni <bircni@icloud.com> Reviewed-on: https://gitea.com/gitea/runner/pulls/1349 Reviewed-by: bircni <bircni@icloud.com> Co-authored-by: silverwind <me@silverwind.io>
160 lines
5.4 KiB
Go
160 lines
5.4 KiB
Go
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
// Copyright 2021 The nektos/act Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
// Package ghcontext fills a model.GithubContext from the local git checkout.
|
|
// The pure data parts of the context live in the shared
|
|
// gitea.dev/actionslib/pkg/model package, only the helpers that need a
|
|
// git repository on disk are kept here.
|
|
package ghcontext
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
"gitea.com/gitea/runner/act/common"
|
|
"gitea.com/gitea/runner/act/common/git"
|
|
|
|
"gitea.dev/actionslib/pkg/model"
|
|
)
|
|
|
|
var (
|
|
findGitRef = git.FindGitRef
|
|
findGitRevision = git.FindGitRevision
|
|
findGithubRepo = git.FindGithubRepo
|
|
)
|
|
|
|
type pinnedKey struct{}
|
|
|
|
// WithPinnedCheckout keeps a run's sha, ref and repository fixed when HEAD moves, in pins unless ctx has some.
|
|
func WithPinnedCheckout(ctx context.Context, pins *sync.Map) context.Context {
|
|
if ctx.Value(pinnedKey{}) != nil {
|
|
return ctx
|
|
}
|
|
return context.WithValue(ctx, pinnedKey{}, pins)
|
|
}
|
|
|
|
func pinned(ctx context.Context, key string, lookup func() (string, error)) (string, error) {
|
|
cache, ok := ctx.Value(pinnedKey{}).(*sync.Map)
|
|
if !ok {
|
|
return lookup()
|
|
}
|
|
cached, _ := cache.LoadOrStore(key, sync.OnceValues(lookup))
|
|
lookupOnce, _ := cached.(func() (string, error))
|
|
return lookupOnce()
|
|
}
|
|
|
|
// SetRef resolves the ref of the context from its event payload, falling back
|
|
// to the ref checked out in repoPath.
|
|
func SetRef(ctx context.Context, ghc *model.GithubContext, repoPath string) {
|
|
logger := common.Logger(ctx)
|
|
|
|
// https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows
|
|
// https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads
|
|
switch ghc.EventName {
|
|
case "pull_request_target":
|
|
ghc.Ref = "refs/heads/" + ghc.BaseRef
|
|
case "pull_request", "pull_request_review", "pull_request_review_comment":
|
|
number := ghc.Event["number"]
|
|
if number == nil {
|
|
number = model.NestedMapLookup(ghc.Event, "pull_request", "number")
|
|
}
|
|
ghc.Ref = fmt.Sprintf("refs/pull/%.0f/merge", number)
|
|
if ghc.EventName == "pull_request" && ghc.Event["action"] == "closed" && model.NestedMapLookup(ghc.Event, "pull_request", "merged") == true {
|
|
ghc.Ref = "refs/heads/" + ghc.BaseRef
|
|
}
|
|
case "deployment", "deployment_status":
|
|
ghc.Ref = model.AsString(model.NestedMapLookup(ghc.Event, "deployment", "ref"))
|
|
case "release":
|
|
ghc.Ref = "refs/tags/" + model.AsString(model.NestedMapLookup(ghc.Event, "release", "tag_name"))
|
|
case "create":
|
|
ghc.Ref = model.AsString(ghc.Event["ref"])
|
|
if ghc.Ref != "" && !strings.HasPrefix(ghc.Ref, "refs/") {
|
|
switch model.AsString(ghc.Event["ref_type"]) {
|
|
case "branch":
|
|
ghc.Ref = "refs/heads/" + ghc.Ref
|
|
case "tag":
|
|
ghc.Ref = "refs/tags/" + ghc.Ref
|
|
}
|
|
}
|
|
case "push", "workflow_dispatch":
|
|
ghc.Ref = model.AsString(ghc.Event["ref"])
|
|
default:
|
|
defaultBranch := model.AsString(model.NestedMapLookup(ghc.Event, "repository", "default_branch"))
|
|
if defaultBranch != "" {
|
|
ghc.Ref = "refs/heads/" + defaultBranch
|
|
}
|
|
}
|
|
|
|
if ghc.Ref == "" {
|
|
ref, err := pinned(ctx, "ref:"+repoPath, func() (string, error) { return findGitRef(ctx, repoPath) })
|
|
if err != nil {
|
|
logger.Warnf("unable to get git ref: %v", err)
|
|
} else {
|
|
logger.Debugf("using github ref: %s", ref)
|
|
ghc.Ref = ref
|
|
}
|
|
|
|
repository, exists := ghc.Event["repository"]
|
|
if !exists {
|
|
repository = map[string]any{}
|
|
}
|
|
if repository, ok := repository.(map[string]any); !ok {
|
|
logger.Warn("unable to set default branch to master")
|
|
} else if _, exists := repository["default_branch"]; !exists {
|
|
repository["default_branch"] = "master"
|
|
ghc.Event["repository"] = repository
|
|
}
|
|
|
|
if ghc.Ref == "" {
|
|
ghc.Ref = "refs/heads/" + model.AsString(model.NestedMapLookup(ghc.Event, "repository", "default_branch"))
|
|
}
|
|
}
|
|
}
|
|
|
|
// SetSha resolves the commit of the context from its event payload, falling
|
|
// back to the revision checked out in repoPath.
|
|
func SetSha(ctx context.Context, ghc *model.GithubContext, repoPath string) {
|
|
logger := common.Logger(ctx)
|
|
|
|
// https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows
|
|
// https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads
|
|
switch ghc.EventName {
|
|
case "pull_request_target":
|
|
ghc.Sha = model.AsString(model.NestedMapLookup(ghc.Event, "pull_request", "base", "sha"))
|
|
case "deployment", "deployment_status":
|
|
ghc.Sha = model.AsString(model.NestedMapLookup(ghc.Event, "deployment", "sha"))
|
|
case "push", "create", "workflow_dispatch":
|
|
if deleted, ok := ghc.Event["deleted"].(bool); ok && !deleted {
|
|
ghc.Sha = model.AsString(ghc.Event["after"])
|
|
}
|
|
}
|
|
|
|
if ghc.Sha == "" {
|
|
sha, err := pinned(ctx, "sha:"+repoPath, func() (string, error) {
|
|
return findGitRevision(ctx, repoPath)
|
|
})
|
|
if err != nil {
|
|
logger.Warnf("unable to get git revision: %v", err)
|
|
} else {
|
|
ghc.Sha = sha
|
|
}
|
|
}
|
|
}
|
|
|
|
// SetRepositoryAndOwner resolves the repository of the context from the git
|
|
// remote in repoPath when it is not set yet, and derives its owner.
|
|
func SetRepositoryAndOwner(ctx context.Context, ghc *model.GithubContext, repoPath string) {
|
|
if ghc.Repository == "" {
|
|
repo, err := pinned(ctx, "repo:"+repoPath, func() (string, error) { return findGithubRepo(ctx, repoPath) })
|
|
if err != nil {
|
|
common.Logger(ctx).Warnf("unable to get git repo (repoPath: %v): %v", repoPath, err)
|
|
return
|
|
}
|
|
ghc.Repository = repo
|
|
}
|
|
ghc.RepositoryOwner, _, _ = strings.Cut(ghc.Repository, "/")
|
|
}
|