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