Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for getting the GitHub context #44

Merged
merged 4 commits into from May 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 63 additions & 0 deletions actions.go
Expand Up @@ -29,6 +29,8 @@ import (
"os"
"strings"
"time"

"github.com/sethvargo/go-envconfig"
)

var (
Expand Down Expand Up @@ -449,3 +451,64 @@ func (c *Action) Getenv(key string) string {
// GetenvFunc is an abstraction to make tests feasible for commands that
// interact with environment variables.
type GetenvFunc func(key string) string

// GitHubContext of current workflow.
//
// Replicated from https://github.com/actions/toolkit/blob/main/packages/github/src/context.ts
type GitHubContext struct {
EventPath string `env:"GITHUB_EVENT_PATH"`
EventName string `env:"GITHUB_EVENT_NAME"`
SHA string `env:"GITHUB_SHA"`
Ref string `env:"GITHUB_REF"`
Workflow string `env:"GITHUB_WORKFLOW"`
Action string `env:"GITHUB_ACTION"`
Actor string `env:"GITHUB_ACTOR"`
Job string `env:"GITHUB_JOB"`
RunNumber int64 `env:"GITHUB_RUN_NUMBER"`
RunID int64 `env:"GITHUB_RUN_ID"`
APIURL string `env:"GITHUB_API_URL,default=https://api.github.com"`
ServerURL string `env:"GITHUB_SERVER_URL,default=https://github.com"`
GraphqlURL string `env:"GITHUB_GRAPHQL_URL,default=https://api.github.com/graphql"`

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

// Context returns the context of current action with the payload object
// that triggered the workflow
func (c *Action) Context() (*GitHubContext, error) {
ctx := context.Background()
lookuper := &wrappedLookuper{f: c.getenv}

var githubContext GitHubContext
if err := envconfig.ProcessWith(ctx, &githubContext, lookuper); err != nil {
return nil, fmt.Errorf("could not process github context variables: %w", err)
}

if githubContext.EventPath != "" {
eventData, err := os.ReadFile(githubContext.EventPath)
if err != nil && !os.IsNotExist(err) {
return nil, fmt.Errorf("could not read event file: %w", err)
}
if eventData != nil {
if err := json.Unmarshal(eventData, &githubContext.Event); err != nil {
return nil, fmt.Errorf("failed to unmarshal event payload: %w", err)
}
}
}

return &githubContext, nil
}

// wrappedLookuper creates a lookuper that wraps a given getenv func.
type wrappedLookuper struct {
f GetenvFunc
}

// Lookup implements a custom lookuper.
func (w *wrappedLookuper) Lookup(key string) (string, bool) {
if v := w.f(key); v != "" {
return v, true
}
return "", false
}
4 changes: 4 additions & 0 deletions actions_root.go
Expand Up @@ -144,3 +144,7 @@ func WithFieldsMap(m map[string]string) *Action {
func GetIDToken(ctx context.Context, audience string) (string, error) {
return defaultAction.GetIDToken(ctx, audience)
}

func Context() (*GitHubContext, error) {
return defaultAction.Context()
}
109 changes: 109 additions & 0 deletions actions_test.go
Expand Up @@ -25,6 +25,8 @@ import (
"reflect"
"strings"
"testing"

"github.com/google/go-cmp/cmp"
)

func TestNew(t *testing.T) {
Expand Down Expand Up @@ -591,6 +593,113 @@ func TestAction_GetIDToken(t *testing.T) {
}
}

func TestAction_Context(t *testing.T) {
t.Parallel()

f, err := os.CreateTemp("", "")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
os.Remove(f.Name())
})

if _, err := f.Write([]byte(`{"foo": "bar"}`)); err != nil {
t.Fatal(err)
}
if err := f.Close(); err != nil {
t.Fatal(err)
}

eventPayloadPath := f.Name()

cases := []struct {
name string
env map[string]string
exp *GitHubContext
}{
{
name: "empty",
env: nil,
exp: &GitHubContext{
// Defaults
APIURL: "https://api.github.com",
ServerURL: "https://github.com",
GraphqlURL: "https://api.github.com/graphql",
},
},
{
name: "no_payload",
env: map[string]string{
"GITHUB_EVENT_NAME": "event_name",
"GITHUB_SHA": "abcd1234",
"GITHUB_REF": "main",
"GITHUB_WORKFLOW": "test",
"GITHUB_ACTION": "foo/bar@v0",
"GITHUB_ACTOR": "sethvargo",
"GITHUB_JOB": "12",
"GITHUB_RUN_NUMBER": "34",
"GITHUB_RUN_ID": "56",
"GITHUB_API_URL": "https://foo.com",
"GITHUB_SERVER_URL": "https://bar.com",
"GITHUB_GRAPHQL_URL": "https://baz.com",
},
exp: &GitHubContext{
EventName: "event_name",
SHA: "abcd1234",
Ref: "main",
Workflow: "test",
Action: "foo/bar@v0",
Actor: "sethvargo",
Job: "12",
RunNumber: 34,
RunID: 56,
APIURL: "https://foo.com",
ServerURL: "https://bar.com",
GraphqlURL: "https://baz.com",
},
},
{
name: "payload",
env: map[string]string{
"GITHUB_EVENT_PATH": eventPayloadPath,
},
exp: &GitHubContext{
EventPath: eventPayloadPath,

// Defaults
APIURL: "https://api.github.com",
ServerURL: "https://github.com",
GraphqlURL: "https://api.github.com/graphql",

Event: map[string]any{
"foo": "bar",
},
},
},
}

for _, tc := range cases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

a := New(WithGetenv(func(k string) string {
return tc.env[k]
}))
got, err := a.Context()
if err != nil {
t.Fatal(err)
}

if diff := cmp.Diff(tc.exp, got); diff != "" {
t.Fatalf("mismatch (-want, +got):\n%s", diff)
}
})
}
}

// newFakeGetenvFunc returns a new GetenvFunc that is expected to be called with
// the provided key. It returns the provided value if the call matches the
// provided key. It reports an error on test t otherwise.
Expand Down
5 changes: 5 additions & 0 deletions go.mod
Expand Up @@ -15,3 +15,8 @@
module github.com/sethvargo/go-githubactions

go 1.18

require (
github.com/google/go-cmp v0.4.1
github.com/sethvargo/go-envconfig v0.6.0
)
6 changes: 6 additions & 0 deletions go.sum
@@ -0,0 +1,6 @@
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/sethvargo/go-envconfig v0.6.0 h1:GxxdoeiNpWgGiVEphNFNObgMYRN/ZvI2dN7rBwadyss=
github.com/sethvargo/go-envconfig v0.6.0/go.mod h1:00S1FAhRUuTNJazWBWcJGvEHOM+NO6DhoRMAOX7FY5o=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=