github.com/nektos/act@v0.2.83/pkg/model/github_context.go (about) 1 package model 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/nektos/act/pkg/common" 9 "github.com/nektos/act/pkg/common/git" 10 ) 11 12 type GithubContext struct { 13 Event map[string]interface{} `json:"event"` 14 EventPath string `json:"event_path"` 15 Workflow string `json:"workflow"` 16 RunAttempt string `json:"run_attempt"` 17 RunID string `json:"run_id"` 18 RunNumber string `json:"run_number"` 19 Actor string `json:"actor"` 20 Repository string `json:"repository"` 21 EventName string `json:"event_name"` 22 Sha string `json:"sha"` 23 Ref string `json:"ref"` 24 RefName string `json:"ref_name"` 25 RefType string `json:"ref_type"` 26 HeadRef string `json:"head_ref"` 27 BaseRef string `json:"base_ref"` 28 Token string `json:"token"` 29 Workspace string `json:"workspace"` 30 Action string `json:"action"` 31 ActionPath string `json:"action_path"` 32 ActionRef string `json:"action_ref"` 33 ActionRepository string `json:"action_repository"` 34 Job string `json:"job"` 35 JobName string `json:"job_name"` 36 RepositoryOwner string `json:"repository_owner"` 37 RetentionDays string `json:"retention_days"` 38 RunnerPerflog string `json:"runner_perflog"` 39 RunnerTrackingID string `json:"runner_tracking_id"` 40 ServerURL string `json:"server_url"` 41 APIURL string `json:"api_url"` 42 GraphQLURL string `json:"graphql_url"` 43 } 44 45 func asString(v interface{}) string { 46 if v == nil { 47 return "" 48 } else if s, ok := v.(string); ok { 49 return s 50 } 51 return "" 52 } 53 54 func nestedMapLookup(m map[string]interface{}, ks ...string) (rval interface{}) { 55 var ok bool 56 57 if len(ks) == 0 { // degenerate input 58 return nil 59 } 60 if rval, ok = m[ks[0]]; !ok { 61 return nil 62 } else if len(ks) == 1 { // we've reached the final key 63 return rval 64 } else if m, ok = rval.(map[string]interface{}); !ok { 65 return nil 66 } 67 // 1+ more keys 68 return nestedMapLookup(m, ks[1:]...) 69 } 70 71 func withDefaultBranch(ctx context.Context, b string, event map[string]interface{}) map[string]interface{} { 72 repoI, ok := event["repository"] 73 if !ok { 74 repoI = make(map[string]interface{}) 75 } 76 77 repo, ok := repoI.(map[string]interface{}) 78 if !ok { 79 common.Logger(ctx).Warnf("unable to set default branch to %v", b) 80 return event 81 } 82 83 // if the branch is already there return with no changes 84 if _, ok = repo["default_branch"]; ok { 85 return event 86 } 87 88 repo["default_branch"] = b 89 event["repository"] = repo 90 91 return event 92 } 93 94 var findGitRef = git.FindGitRef 95 var findGitRevision = git.FindGitRevision 96 97 func (ghc *GithubContext) SetRef(ctx context.Context, defaultBranch string, repoPath string) { 98 logger := common.Logger(ctx) 99 100 // https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows 101 // https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads 102 switch ghc.EventName { 103 case "pull_request_target": 104 ghc.Ref = fmt.Sprintf("refs/heads/%s", ghc.BaseRef) 105 case "pull_request", "pull_request_review", "pull_request_review_comment": 106 ghc.Ref = fmt.Sprintf("refs/pull/%.0f/merge", ghc.Event["number"]) 107 case "deployment", "deployment_status": 108 ghc.Ref = asString(nestedMapLookup(ghc.Event, "deployment", "ref")) 109 case "release": 110 ghc.Ref = fmt.Sprintf("refs/tags/%s", asString(nestedMapLookup(ghc.Event, "release", "tag_name"))) 111 case "push", "create", "workflow_dispatch": 112 ghc.Ref = asString(ghc.Event["ref"]) 113 default: 114 defaultBranch := asString(nestedMapLookup(ghc.Event, "repository", "default_branch")) 115 if defaultBranch != "" { 116 ghc.Ref = fmt.Sprintf("refs/heads/%s", defaultBranch) 117 } 118 } 119 120 if ghc.Ref == "" { 121 ref, err := findGitRef(ctx, repoPath) 122 if err != nil { 123 logger.Warningf("unable to get git ref: %v", err) 124 } else { 125 logger.Debugf("using github ref: %s", ref) 126 ghc.Ref = ref 127 } 128 129 // set the branch in the event data 130 if defaultBranch != "" { 131 ghc.Event = withDefaultBranch(ctx, defaultBranch, ghc.Event) 132 } else { 133 ghc.Event = withDefaultBranch(ctx, "master", ghc.Event) 134 } 135 136 if ghc.Ref == "" { 137 ghc.Ref = fmt.Sprintf("refs/heads/%s", asString(nestedMapLookup(ghc.Event, "repository", "default_branch"))) 138 } 139 } 140 } 141 142 func (ghc *GithubContext) SetSha(ctx context.Context, repoPath string) { 143 logger := common.Logger(ctx) 144 145 // https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows 146 // https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads 147 switch ghc.EventName { 148 case "pull_request_target": 149 ghc.Sha = asString(nestedMapLookup(ghc.Event, "pull_request", "base", "sha")) 150 case "deployment", "deployment_status": 151 ghc.Sha = asString(nestedMapLookup(ghc.Event, "deployment", "sha")) 152 case "push", "create", "workflow_dispatch": 153 if deleted, ok := ghc.Event["deleted"].(bool); ok && !deleted { 154 ghc.Sha = asString(ghc.Event["after"]) 155 } 156 } 157 158 if ghc.Sha == "" { 159 _, sha, err := findGitRevision(ctx, repoPath) 160 if err != nil { 161 logger.Warningf("unable to get git revision: %v", err) 162 } else { 163 ghc.Sha = sha 164 } 165 } 166 } 167 168 func (ghc *GithubContext) SetRepositoryAndOwner(ctx context.Context, githubInstance string, remoteName string, repoPath string) { 169 if ghc.Repository == "" { 170 repo, err := git.FindGithubRepo(ctx, repoPath, githubInstance, remoteName) 171 if err != nil { 172 common.Logger(ctx).Debugf("unable to get git repo (githubInstance: %v; remoteName: %v, repoPath: %v): %v", githubInstance, remoteName, repoPath, err) 173 // nektos/act is used as a default action, so why not a repo? 174 ghc.Repository = "nektos/act" 175 ghc.RepositoryOwner = strings.Split(ghc.Repository, "/")[0] 176 return 177 } 178 ghc.Repository = repo 179 } 180 ghc.RepositoryOwner = strings.Split(ghc.Repository, "/")[0] 181 } 182 183 func (ghc *GithubContext) SetRefTypeAndName() { 184 var refType, refName string 185 186 // https://docs.github.com/en/actions/learn-github-actions/environment-variables 187 if strings.HasPrefix(ghc.Ref, "refs/tags/") { 188 refType = "tag" 189 refName = ghc.Ref[len("refs/tags/"):] 190 } else if strings.HasPrefix(ghc.Ref, "refs/heads/") { 191 refType = "branch" 192 refName = ghc.Ref[len("refs/heads/"):] 193 } else if strings.HasPrefix(ghc.Ref, "refs/pull/") { 194 refType = "" 195 refName = ghc.Ref[len("refs/pull/"):] 196 } 197 198 if ghc.RefType == "" { 199 ghc.RefType = refType 200 } 201 202 if ghc.RefName == "" { 203 ghc.RefName = refName 204 } 205 } 206 207 func (ghc *GithubContext) SetBaseAndHeadRef() { 208 if ghc.EventName == "pull_request" || ghc.EventName == "pull_request_target" { 209 if ghc.BaseRef == "" { 210 ghc.BaseRef = asString(nestedMapLookup(ghc.Event, "pull_request", "base", "ref")) 211 } 212 213 if ghc.HeadRef == "" { 214 ghc.HeadRef = asString(nestedMapLookup(ghc.Event, "pull_request", "head", "ref")) 215 } 216 } 217 }