feat: allow overriding of GITHUB_ env variables (#1582)

* allow overriding of GITHUB_ env variables

* bug fix for overriding env vars with empty string

* revert step.go

* refactor github_context to prevent lint failures. added more setters

* added ability to override github env variables

* handled base and head ref
This commit is contained in:
Shubh Bapna 2023-02-03 14:35:49 -05:00 committed by GitHub
parent c4b64ec1c1
commit ce168f9595
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 199 additions and 74 deletions

View file

@ -3,6 +3,7 @@ package model
import (
"context"
"fmt"
"strings"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/common/git"
@ -89,26 +90,22 @@ func withDefaultBranch(ctx context.Context, b string, event map[string]interface
var findGitRef = git.FindGitRef
var findGitRevision = git.FindGitRevision
func (ghc *GithubContext) SetRefAndSha(ctx context.Context, defaultBranch string, repoPath string) {
func (ghc *GithubContext) SetRef(ctx context.Context, defaultBranch string, 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 = fmt.Sprintf("refs/heads/%s", ghc.BaseRef)
ghc.Sha = asString(nestedMapLookup(ghc.Event, "pull_request", "base", "sha"))
case "pull_request", "pull_request_review", "pull_request_review_comment":
ghc.Ref = fmt.Sprintf("refs/pull/%.0f/merge", ghc.Event["number"])
case "deployment", "deployment_status":
ghc.Ref = asString(nestedMapLookup(ghc.Event, "deployment", "ref"))
ghc.Sha = asString(nestedMapLookup(ghc.Event, "deployment", "sha"))
case "release":
ghc.Ref = asString(nestedMapLookup(ghc.Event, "release", "tag_name"))
case "push", "create", "workflow_dispatch":
ghc.Ref = asString(ghc.Event["ref"])
if deleted, ok := ghc.Event["deleted"].(bool); ok && !deleted {
ghc.Sha = asString(ghc.Event["after"])
}
default:
defaultBranch := asString(nestedMapLookup(ghc.Event, "repository", "default_branch"))
if defaultBranch != "" {
@ -136,6 +133,23 @@ func (ghc *GithubContext) SetRefAndSha(ctx context.Context, defaultBranch string
ghc.Ref = fmt.Sprintf("refs/heads/%s", asString(nestedMapLookup(ghc.Event, "repository", "default_branch")))
}
}
}
func (ghc *GithubContext) SetSha(ctx context.Context, 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 = asString(nestedMapLookup(ghc.Event, "pull_request", "base", "sha"))
case "deployment", "deployment_status":
ghc.Sha = asString(nestedMapLookup(ghc.Event, "deployment", "sha"))
case "push", "create", "workflow_dispatch":
if deleted, ok := ghc.Event["deleted"].(bool); ok && !deleted {
ghc.Sha = asString(ghc.Event["after"])
}
}
if ghc.Sha == "" {
_, sha, err := findGitRevision(ctx, repoPath)
@ -146,3 +160,48 @@ func (ghc *GithubContext) SetRefAndSha(ctx context.Context, defaultBranch string
}
}
}
func (ghc *GithubContext) SetRepositoryAndOwner(ctx context.Context, githubInstance string, remoteName string, repoPath string) {
if ghc.Repository == "" {
repo, err := git.FindGithubRepo(ctx, repoPath, githubInstance, remoteName)
if err != nil {
common.Logger(ctx).Warningf("unable to get git repo: %v", err)
return
}
ghc.Repository = repo
}
ghc.RepositoryOwner = strings.Split(ghc.Repository, "/")[0]
}
func (ghc *GithubContext) SetRefTypeAndName() {
var refType, refName string
// https://docs.github.com/en/actions/learn-github-actions/environment-variables
if strings.HasPrefix(ghc.Ref, "refs/tags/") {
refType = "tag"
refName = ghc.Ref[len("refs/tags/"):]
} else if strings.HasPrefix(ghc.Ref, "refs/heads/") {
refType = "branch"
refName = ghc.Ref[len("refs/heads/"):]
}
if ghc.RefType == "" {
ghc.RefType = refType
}
if ghc.RefName == "" {
ghc.RefName = refName
}
}
func (ghc *GithubContext) SetBaseAndHeadRef() {
if ghc.EventName == "pull_request" || ghc.EventName == "pull_request_target" {
if ghc.BaseRef == "" {
ghc.BaseRef = asString(nestedMapLookup(ghc.Event, "pull_request", "base", "ref"))
}
if ghc.HeadRef == "" {
ghc.HeadRef = asString(nestedMapLookup(ghc.Event, "pull_request", "head", "ref"))
}
}
}

View file

@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/assert"
)
func TestSetRefAndSha(t *testing.T) {
func TestSetRef(t *testing.T) {
log.SetLevel(log.DebugLevel)
oldFindGitRef := findGitRef
@ -29,19 +29,11 @@ func TestSetRefAndSha(t *testing.T) {
eventName string
event map[string]interface{}
ref string
sha string
}{
{
eventName: "pull_request_target",
event: map[string]interface{}{
"pull_request": map[string]interface{}{
"base": map[string]interface{}{
"sha": "pr-base-sha",
},
},
},
ref: "refs/heads/master",
sha: "pr-base-sha",
event: map[string]interface{}{},
ref: "refs/heads/master",
},
{
eventName: "pull_request",
@ -49,18 +41,15 @@ func TestSetRefAndSha(t *testing.T) {
"number": 1234.,
},
ref: "refs/pull/1234/merge",
sha: "1234fakesha",
},
{
eventName: "deployment",
event: map[string]interface{}{
"deployment": map[string]interface{}{
"ref": "refs/heads/somebranch",
"sha": "deployment-sha",
},
},
ref: "refs/heads/somebranch",
sha: "deployment-sha",
},
{
eventName: "release",
@ -70,17 +59,13 @@ func TestSetRefAndSha(t *testing.T) {
},
},
ref: "v1.0.0",
sha: "1234fakesha",
},
{
eventName: "push",
event: map[string]interface{}{
"ref": "refs/heads/somebranch",
"after": "push-sha",
"deleted": false,
"ref": "refs/heads/somebranch",
},
ref: "refs/heads/somebranch",
sha: "push-sha",
},
{
eventName: "unknown",
@ -90,13 +75,11 @@ func TestSetRefAndSha(t *testing.T) {
},
},
ref: "refs/heads/main",
sha: "1234fakesha",
},
{
eventName: "no-event",
event: map[string]interface{}{},
ref: "refs/heads/master",
sha: "1234fakesha",
},
}
@ -108,10 +91,9 @@ func TestSetRefAndSha(t *testing.T) {
Event: table.event,
}
ghc.SetRefAndSha(context.Background(), "main", "/some/dir")
ghc.SetRef(context.Background(), "main", "/some/dir")
assert.Equal(t, table.ref, ghc.Ref)
assert.Equal(t, table.sha, ghc.Sha)
})
}
@ -125,9 +107,96 @@ func TestSetRefAndSha(t *testing.T) {
Event: map[string]interface{}{},
}
ghc.SetRefAndSha(context.Background(), "", "/some/dir")
ghc.SetRef(context.Background(), "", "/some/dir")
assert.Equal(t, "refs/heads/master", ghc.Ref)
assert.Equal(t, "1234fakesha", ghc.Sha)
})
}
func TestSetSha(t *testing.T) {
log.SetLevel(log.DebugLevel)
oldFindGitRef := findGitRef
oldFindGitRevision := findGitRevision
defer func() { findGitRef = oldFindGitRef }()
defer func() { findGitRevision = oldFindGitRevision }()
findGitRef = func(ctx context.Context, file string) (string, error) {
return "refs/heads/master", nil
}
findGitRevision = func(ctx context.Context, file string) (string, string, error) {
return "", "1234fakesha", nil
}
tables := []struct {
eventName string
event map[string]interface{}
sha string
}{
{
eventName: "pull_request_target",
event: map[string]interface{}{
"pull_request": map[string]interface{}{
"base": map[string]interface{}{
"sha": "pr-base-sha",
},
},
},
sha: "pr-base-sha",
},
{
eventName: "pull_request",
event: map[string]interface{}{
"number": 1234.,
},
sha: "1234fakesha",
},
{
eventName: "deployment",
event: map[string]interface{}{
"deployment": map[string]interface{}{
"sha": "deployment-sha",
},
},
sha: "deployment-sha",
},
{
eventName: "release",
event: map[string]interface{}{},
sha: "1234fakesha",
},
{
eventName: "push",
event: map[string]interface{}{
"after": "push-sha",
"deleted": false,
},
sha: "push-sha",
},
{
eventName: "unknown",
event: map[string]interface{}{},
sha: "1234fakesha",
},
{
eventName: "no-event",
event: map[string]interface{}{},
sha: "1234fakesha",
},
}
for _, table := range tables {
t.Run(table.eventName, func(t *testing.T) {
ghc := &GithubContext{
EventName: table.eventName,
BaseRef: "master",
Event: table.event,
}
ghc.SetSha(context.Background(), "/some/dir")
assert.Equal(t, table.sha, ghc.Sha)
})
}
}

View file

@ -21,7 +21,6 @@ import (
log "github.com/sirupsen/logrus"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/common/git"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/exprparser"
"github.com/nektos/act/pkg/model"
@ -571,6 +570,14 @@ func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext
RetentionDays: rc.Config.Env["GITHUB_RETENTION_DAYS"],
RunnerPerflog: rc.Config.Env["RUNNER_PERFLOG"],
RunnerTrackingID: rc.Config.Env["RUNNER_TRACKING_ID"],
Repository: rc.Config.Env["GITHUB_REPOSITORY"],
Ref: rc.Config.Env["GITHUB_REF"],
Sha: rc.Config.Env["SHA_REF"],
RefName: rc.Config.Env["GITHUB_REF_NAME"],
RefType: rc.Config.Env["GITHUB_REF_TYPE"],
BaseRef: rc.Config.Env["GITHUB_BASE_REF"],
HeadRef: rc.Config.Env["GITHUB_HEAD_REF"],
Workspace: rc.Config.Env["GITHUB_WORKSPACE"],
}
if rc.JobContainer != nil {
ghc.EventPath = rc.JobContainer.GetActPath() + "/workflow/event.json"
@ -599,39 +606,24 @@ func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext
ghc.Actor = "nektos/act"
}
repoPath := rc.Config.Workdir
repo, err := git.FindGithubRepo(ctx, repoPath, rc.Config.GitHubInstance, rc.Config.RemoteName)
if err != nil {
logger.Warningf("unable to get git repo: %v", err)
} else {
ghc.Repository = repo
if ghc.RepositoryOwner == "" {
ghc.RepositoryOwner = strings.Split(repo, "/")[0]
}
}
if rc.EventJSON != "" {
err = json.Unmarshal([]byte(rc.EventJSON), &ghc.Event)
err := json.Unmarshal([]byte(rc.EventJSON), &ghc.Event)
if err != nil {
logger.Errorf("Unable to Unmarshal event '%s': %v", rc.EventJSON, err)
}
}
if ghc.EventName == "pull_request" || ghc.EventName == "pull_request_target" {
ghc.BaseRef = asString(nestedMapLookup(ghc.Event, "pull_request", "base", "ref"))
ghc.HeadRef = asString(nestedMapLookup(ghc.Event, "pull_request", "head", "ref"))
ghc.SetBaseAndHeadRef()
repoPath := rc.Config.Workdir
ghc.SetRepositoryAndOwner(ctx, rc.Config.GitHubInstance, rc.Config.RemoteName, repoPath)
if ghc.Ref == "" {
ghc.SetRef(ctx, rc.Config.DefaultBranch, repoPath)
}
if ghc.Sha == "" {
ghc.SetSha(ctx, repoPath)
}
ghc.SetRefAndSha(ctx, rc.Config.DefaultBranch, repoPath)
// https://docs.github.com/en/actions/learn-github-actions/environment-variables
if strings.HasPrefix(ghc.Ref, "refs/tags/") {
ghc.RefType = "tag"
ghc.RefName = ghc.Ref[len("refs/tags/"):]
} else if strings.HasPrefix(ghc.Ref, "refs/heads/") {
ghc.RefType = "branch"
ghc.RefName = ghc.Ref[len("refs/heads/"):]
}
ghc.SetRefTypeAndName()
return ghc
}
@ -662,15 +654,6 @@ func isLocalCheckout(ghc *model.GithubContext, step *model.Step) bool {
return true
}
func asString(v interface{}) string {
if v == nil {
return ""
} else if s, ok := v.(string); ok {
return s
}
return ""
}
func nestedMapLookup(m map[string]interface{}, ks ...string) (rval interface{}) {
var ok bool
@ -709,20 +692,34 @@ func (rc *RunContext) withGithubEnv(ctx context.Context, github *model.GithubCon
env["GITHUB_REF_NAME"] = github.RefName
env["GITHUB_REF_TYPE"] = github.RefType
env["GITHUB_TOKEN"] = github.Token
env["GITHUB_SERVER_URL"] = "https://github.com"
env["GITHUB_API_URL"] = "https://api.github.com"
env["GITHUB_GRAPHQL_URL"] = "https://api.github.com/graphql"
env["GITHUB_BASE_REF"] = github.BaseRef
env["GITHUB_HEAD_REF"] = github.HeadRef
env["GITHUB_JOB"] = rc.JobName
env["GITHUB_REPOSITORY_OWNER"] = github.RepositoryOwner
env["GITHUB_RETENTION_DAYS"] = github.RetentionDays
env["RUNNER_PERFLOG"] = github.RunnerPerflog
env["RUNNER_TRACKING_ID"] = github.RunnerTrackingID
env["GITHUB_BASE_REF"] = github.BaseRef
env["GITHUB_HEAD_REF"] = github.HeadRef
defaultServerURL := "https://github.com"
defaultAPIURL := "https://api.github.com"
defaultGraphqlURL := "https://api.github.com/graphql"
if rc.Config.GitHubInstance != "github.com" {
env["GITHUB_SERVER_URL"] = fmt.Sprintf("https://%s", rc.Config.GitHubInstance)
env["GITHUB_API_URL"] = fmt.Sprintf("https://%s/api/v3", rc.Config.GitHubInstance)
env["GITHUB_GRAPHQL_URL"] = fmt.Sprintf("https://%s/api/graphql", rc.Config.GitHubInstance)
defaultServerURL = fmt.Sprintf("https://%s", rc.Config.GitHubInstance)
defaultAPIURL = fmt.Sprintf("https://%s/api/v3", rc.Config.GitHubInstance)
defaultGraphqlURL = fmt.Sprintf("https://%s/api/graphql", rc.Config.GitHubInstance)
}
if env["GITHUB_SERVER_URL"] == "" {
env["GITHUB_SERVER_URL"] = defaultServerURL
}
if env["GITHUB_API_URL"] == "" {
env["GITHUB_API_URL"] = defaultAPIURL
}
if env["GITHUB_GRAPHQL_URL"] == "" {
env["GITHUB_GRAPHQL_URL"] = defaultGraphqlURL
}
if rc.Config.ArtifactServerPath != "" {