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  }