Skip to content

Commit 27ad5ab

Browse files
authored
Add support for all GITHUB env vars (#46)
* Add support for repository and owner * Add note to use Repo method * Add support for all GITHUB_* env vars * Add tests and use booleans
1 parent cf611d2 commit 27ad5ab

File tree

2 files changed

+205
-38
lines changed

2 files changed

+205
-38
lines changed

actions.go

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -454,26 +454,85 @@ type GetenvFunc func(key string) string
454454

455455
// GitHubContext of current workflow.
456456
//
457-
// Replicated from https://github.com/actions/toolkit/blob/main/packages/github/src/context.ts
457+
// See: https://docs.github.com/en/actions/learn-github-actions/environment-variables
458458
type GitHubContext struct {
459-
EventPath string `env:"GITHUB_EVENT_PATH"`
460-
EventName string `env:"GITHUB_EVENT_NAME"`
461-
SHA string `env:"GITHUB_SHA"`
462-
Ref string `env:"GITHUB_REF"`
463-
Workflow string `env:"GITHUB_WORKFLOW"`
464-
Action string `env:"GITHUB_ACTION"`
465-
Actor string `env:"GITHUB_ACTOR"`
466-
Job string `env:"GITHUB_JOB"`
467-
RunNumber int64 `env:"GITHUB_RUN_NUMBER"`
468-
RunID int64 `env:"GITHUB_RUN_ID"`
469-
APIURL string `env:"GITHUB_API_URL,default=https://api.github.com"`
470-
ServerURL string `env:"GITHUB_SERVER_URL,default=https://github.com"`
471-
GraphqlURL string `env:"GITHUB_GRAPHQL_URL,default=https://api.github.com/graphql"`
459+
Action string `env:"GITHUB_ACTION"`
460+
ActionPath string `env:"GITHUB_ACTION_PATH"`
461+
ActionRepository string `env:"GITHUB_ACTION_REPOSITORY"`
462+
Actions bool `env:"GITHUB_ACTIONS"`
463+
Actor string `env:"GITHUB_ACTOR"`
464+
APIURL string `env:"GITHUB_API_URL,default=https://api.github.com"`
465+
BaseRef string `env:"GITHUB_BASE_REF"`
466+
Env string `env:"GITHUB_ENV"`
467+
EventName string `env:"GITHUB_EVENT_NAME"`
468+
EventPath string `env:"GITHUB_EVENT_PATH"`
469+
GraphqlURL string `env:"GITHUB_GRAPHQL_URL,default=https://api.github.com/graphql"`
470+
HeadRef string `env:"GITHUB_HEAD_REF"`
471+
Job string `env:"GITHUB_JOB"`
472+
Path string `env:"GITHUB_PATH"`
473+
Ref string `env:"GITHUB_REF"`
474+
RefName string `env:"GITHUB_REF_NAME"`
475+
RefProtected bool `env:"GITHUB_REF_PROTECTED"`
476+
RefType string `env:"GITHUB_REF_TYPE"`
477+
478+
// Repository is the owner and repository name. For example, octocat/Hello-World
479+
// It is not recommended to use this field to acquire the repository name
480+
// but to use the Repo method instead.
481+
Repository string `env:"GITHUB_REPOSITORY"`
482+
483+
// RepositoryOwner is the repository owner. For example, octocat
484+
// It is not recommended to use this field to acquire the repository owner
485+
// but to use the Repo method instead.
486+
RepositoryOwner string `env:"GITHUB_REPOSITORY_OWNER"`
487+
488+
RetentionDays int64 `env:"GITHUB_RETENTION_DAYS"`
489+
RunAttempt int64 `env:"GITHUB_RUN_ATTEMPT"`
490+
RunID int64 `env:"GITHUB_RUN_ID"`
491+
RunNumber int64 `env:"GITHUB_RUN_NUMBER"`
492+
ServerURL string `env:"GITHUB_SERVER_URL,default=https://github.com"`
493+
SHA string `env:"GITHUB_SHA"`
494+
StepSummary string `env:"GITHUB_STEP_SUMMARY"`
495+
Workflow string `env:"GITHUB_WORKFLOW"`
496+
Workspace string `env:"GITHUB_WORKSPACE"`
472497

473498
// Event is populated by parsing the file at EventPath, if it exists.
474499
Event map[string]any
475500
}
476501

502+
// Repo returns the username of the repository owner and repository name.
503+
func (c *GitHubContext) Repo() (string, string) {
504+
if c == nil {
505+
return "", ""
506+
}
507+
508+
// Based on https://github.com/actions/toolkit/blob/main/packages/github/src/context.ts
509+
if c.Repository != "" {
510+
parts := strings.SplitN(c.Repository, "/", 2)
511+
if len(parts) == 1 {
512+
return parts[0], ""
513+
}
514+
return parts[0], parts[1]
515+
}
516+
517+
// If c.Repository is empty attempt to get the repo from the Event data.
518+
var repoName string
519+
// NOTE: differs from context.ts. Fall back to GITHUB_REPOSITORY_OWNER
520+
ownerName := c.RepositoryOwner
521+
if c.Event != nil {
522+
if repo, ok := c.Event["repository"].(map[string]any); ok {
523+
if name, ok := repo["name"].(string); ok {
524+
repoName = name
525+
}
526+
if owner, ok := repo["owner"].(map[string]any); ok {
527+
if name, ok := owner["name"].(string); ok {
528+
ownerName = name
529+
}
530+
}
531+
}
532+
}
533+
return ownerName, repoName
534+
}
535+
477536
// Context returns the context of current action with the payload object
478537
// that triggered the workflow
479538
func (c *Action) Context() (*GitHubContext, error) {

actions_test.go

Lines changed: 132 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -631,32 +631,65 @@ func TestAction_Context(t *testing.T) {
631631
{
632632
name: "no_payload",
633633
env: map[string]string{
634-
"GITHUB_EVENT_NAME": "event_name",
635-
"GITHUB_SHA": "abcd1234",
636-
"GITHUB_REF": "main",
637-
"GITHUB_WORKFLOW": "test",
638-
"GITHUB_ACTION": "foo/bar@v0",
639-
"GITHUB_ACTOR": "sethvargo",
640-
"GITHUB_JOB": "12",
641-
"GITHUB_RUN_NUMBER": "34",
642-
"GITHUB_RUN_ID": "56",
643-
"GITHUB_API_URL": "https://foo.com",
644-
"GITHUB_SERVER_URL": "https://bar.com",
645-
"GITHUB_GRAPHQL_URL": "https://baz.com",
634+
"GITHUB_ACTION": "__repo-owner_name-of-action-repo",
635+
"GITHUB_ACTION_PATH": "/path/to/action",
636+
"GITHUB_ACTION_REPOSITORY": "repo-owner/name-of-action-repo",
637+
"GITHUB_ACTIONS": "true",
638+
"GITHUB_ACTOR": "sethvargo",
639+
"GITHUB_API_URL": "https://foo.com",
640+
"GITHUB_BASE_REF": "main",
641+
"GITHUB_ENV": "/path/to/env",
642+
"GITHUB_EVENT_NAME": "event_name",
643+
"GITHUB_HEAD_REF": "headbranch",
644+
"GITHUB_GRAPHQL_URL": "https://baz.com",
645+
"GITHUB_JOB": "12",
646+
"GITHUB_PATH": "/path/to/path",
647+
"GITHUB_REF": "refs/tags/v1.0",
648+
"GITHUB_REF_NAME": "v1.0",
649+
"GITHUB_REF_PROTECTED": "true",
650+
"GITHUB_REF_TYPE": "tag",
651+
"GITHUB_REPOSITORY": "sethvargo/baz",
652+
"GITHUB_REPOSITORY_OWNER": "sethvargo",
653+
"GITHUB_RETENTION_DAYS": "90",
654+
"GITHUB_RUN_ATTEMPT": "6",
655+
"GITHUB_RUN_ID": "56",
656+
"GITHUB_RUN_NUMBER": "34",
657+
"GITHUB_SERVER_URL": "https://bar.com",
658+
"GITHUB_SHA": "abcd1234",
659+
"GITHUB_STEP_SUMMARY": "/path/to/summary",
660+
"GITHUB_WORKFLOW": "test",
661+
"GITHUB_WORKSPACE": "/path/to/workspace",
646662
},
647663
exp: &GitHubContext{
648-
EventName: "event_name",
649-
SHA: "abcd1234",
650-
Ref: "main",
651-
Workflow: "test",
652-
Action: "foo/bar@v0",
653-
Actor: "sethvargo",
654-
Job: "12",
655-
RunNumber: 34,
656-
RunID: 56,
657-
APIURL: "https://foo.com",
658-
ServerURL: "https://bar.com",
659-
GraphqlURL: "https://baz.com",
664+
Action: "__repo-owner_name-of-action-repo",
665+
ActionPath: "/path/to/action",
666+
ActionRepository: "repo-owner/name-of-action-repo",
667+
Actions: true,
668+
Actor: "sethvargo",
669+
APIURL: "https://foo.com",
670+
BaseRef: "main",
671+
Env: "/path/to/env",
672+
EventName: "event_name",
673+
// NOTE: No EventPath
674+
GraphqlURL: "https://baz.com",
675+
Job: "12",
676+
HeadRef: "headbranch",
677+
Path: "/path/to/path",
678+
Ref: "refs/tags/v1.0",
679+
RefName: "v1.0",
680+
RefProtected: true,
681+
RefType: "tag",
682+
Repository: "sethvargo/baz",
683+
RepositoryOwner: "sethvargo",
684+
RetentionDays: 90,
685+
RunAttempt: 6,
686+
RunID: 56,
687+
RunNumber: 34,
688+
ServerURL: "https://bar.com",
689+
SHA: "abcd1234",
690+
StepSummary: "/path/to/summary",
691+
Workflow: "test",
692+
Workspace: "/path/to/workspace",
660693
},
661694
},
662695
{
@@ -700,6 +733,81 @@ func TestAction_Context(t *testing.T) {
700733
}
701734
}
702735

736+
func TestGitHubContext_Repo(t *testing.T) {
737+
t.Parallel()
738+
739+
cases := []struct {
740+
name string
741+
context *GitHubContext
742+
expOwner string
743+
expRepo string
744+
}{
745+
{
746+
name: "empty",
747+
context: &GitHubContext{},
748+
expOwner: "",
749+
expRepo: "",
750+
},
751+
{
752+
name: "GITHUB_REPOSITORY env",
753+
context: &GitHubContext{
754+
Repository: "sethvargo/foo",
755+
},
756+
expOwner: "sethvargo",
757+
expRepo: "foo",
758+
},
759+
{
760+
name: "event",
761+
context: &GitHubContext{
762+
Event: map[string]any{
763+
"repository": map[string]any{
764+
"name": "foo",
765+
"owner": map[string]any{
766+
"name": "sethvargo",
767+
},
768+
},
769+
},
770+
},
771+
expOwner: "sethvargo",
772+
expRepo: "foo",
773+
},
774+
{
775+
name: "event invalid type",
776+
context: &GitHubContext{
777+
Event: map[string]any{
778+
"repository": "sethvargo/foo",
779+
},
780+
},
781+
expOwner: "",
782+
expRepo: "",
783+
},
784+
{
785+
name: "owner fallback",
786+
context: &GitHubContext{
787+
RepositoryOwner: "sethvargo",
788+
},
789+
expOwner: "sethvargo",
790+
expRepo: "",
791+
},
792+
}
793+
794+
for _, tc := range cases {
795+
tc := tc
796+
797+
t.Run(tc.name, func(t *testing.T) {
798+
t.Parallel()
799+
800+
owner, repo := tc.context.Repo()
801+
if want, got := tc.expOwner, owner; want != got {
802+
t.Errorf("unexpected owner, want: %q, got: %q", want, got)
803+
}
804+
if want, got := tc.expRepo, repo; want != got {
805+
t.Errorf("unexpected repository, want: %q, got: %q", want, got)
806+
}
807+
})
808+
}
809+
}
810+
703811
// newFakeGetenvFunc returns a new GetenvFunc that is expected to be called with
704812
// the provided key. It returns the provided value if the call matches the
705813
// provided key. It reports an error on test t otherwise.

0 commit comments

Comments
 (0)