Skip to content

Commit

Permalink
change printing ::set-output to writing to $GITHUB_OUTPUT
Browse files Browse the repository at this point in the history
  • Loading branch information
kang-makes committed Oct 16, 2024
1 parent 659c700 commit 97bff5b
Show file tree
Hide file tree
Showing 14 changed files with 287 additions and 89 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ on the default behavior.

### Bugfix
- Upgrade golang and project dependencies to the latest version
- Change use of deprecated print `::set-output` to write to `$GITHUB_OUTPUT` file

## v1.2.0 - 2024-08-09

Expand Down
40 changes: 40 additions & 0 deletions internal/testutil/gha_output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package testutil

import (
"io"
"os"
"path"
"testing"

"github.com/newrelic/release-toolkit/src/app/gha"
)

type GithubOutputWriter struct {
File *os.File
}

func NewGithubOutputWriter(t *testing.T) GithubOutputWriter {
t.Helper()

ghaOutputFileName := path.Join(t.TempDir(), "temporary_github_output_file")
t.Setenv(gha.GithubOutput, ghaOutputFileName)

ghaOutputFile, err := os.Create(ghaOutputFileName)
if err != nil {
t.Fatalf("Error creating temporary GHA output file for test: %v", err)
}

return GithubOutputWriter{
File: ghaOutputFile,
}
}

func (ghaOut GithubOutputWriter) Result(t *testing.T) string {
t.Helper()

actual, err := io.ReadAll(ghaOut.File)
if err != nil {
t.Fatalf("Unable to read temporary GHA output file: %v", err)
}
return string(actual)
}
5 changes: 4 additions & 1 deletion src/app/generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ type appendDepSrc func([]changelog.Source, git.TagsVersionGetter, git.CommitsGet
//
//nolint:gocyclo,cyclop
func Generate(cCtx *cli.Context) error {
gh := gha.NewFromCli(cCtx)
gh, err := gha.NewFromCli(cCtx)
if err != nil {
return fmt.Errorf("creating github client: %w", err)
}

yamlPath := cCtx.String(common.YAMLFlag)
chFile, err := os.Create(yamlPath)
Expand Down
30 changes: 18 additions & 12 deletions src/app/generate/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/newrelic/release-toolkit/internal/testutil"
"github.com/newrelic/release-toolkit/src/app"
"github.com/newrelic/release-toolkit/src/git"
)
Expand Down Expand Up @@ -37,18 +38,18 @@ This is a release note
//nolint:funlen,paralleltest,maintidx
func TestGenerate(t *testing.T) {
for _, tc := range []struct {
name string
commits []string
author string
md string
expected string
outputExpected string
args string
preCmdArgs string
name string
commits []string
author string
md string
expected string
expectedStdOutput string
expectedGHAOutput string
args string
preCmdArgs string
}{
{
name: "Empty_Changelog_gha",
args: "--exit-code=0",
preCmdArgs: "--gha=1",
md: strings.TrimSpace(`
# Changelog
Expand All @@ -61,7 +62,8 @@ This is based on blah blah blah
### Enhancements
- This is in the past and should not be included
`),
outputExpected: "::set-output name=empty-changelog::true\n",
expectedStdOutput: "",
expectedGHAOutput: "empty-changelog=true\n",
expected: strings.TrimSpace(`
notes: ""
changes: []
Expand Down Expand Up @@ -427,6 +429,7 @@ dependencies:
} {
//nolint:paralleltest
t.Run(tc.name, func(t *testing.T) {
ghaOutput := testutil.NewGithubOutputWriter(t)
tDir := repoWithCommits(t, tc.author, tc.commits...)
tc.expected = calculateHashes(t, tDir, tc.expected)

Expand Down Expand Up @@ -460,8 +463,11 @@ dependencies:
if diff := cmp.Diff(tc.expected, string(yaml)); diff != "" {
t.Fatalf("Output YAML is not as expected:\n%s", diff)
}
if actual := buf.String(); actual != tc.outputExpected {
t.Fatalf("Expected %q, app printed: %q", tc.outputExpected, actual)
if actual := buf.String(); actual != tc.expectedStdOutput {
t.Fatalf("Expected %q, app printed: %q", tc.expectedStdOutput, actual)
}
if actual := ghaOutput.Result(t); actual != tc.expectedGHAOutput {
t.Fatalf("Expected %q, GHA output: %q", tc.expectedStdOutput, actual)
}
})
}
Expand Down
39 changes: 31 additions & 8 deletions src/app/gha/gha.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,58 @@
package gha

import (
"errors"
"fmt"
"io"
"os"
"sync"

"github.com/newrelic/release-toolkit/src/app/common"
"github.com/urfave/cli/v2"
)

var ErrEmptyFileName = errors.New("filename is an empty string")

const (
GithubOutput = "GITHUB_OUTPUT"
)

// New creates a Github object that will print commands to the specified writer.
func New(writer io.Writer) Github {
return Github{w: writer}
}

// NewFromCli takes a cli.Context and looks for common.GHAFlag on it. If it is set, it returns a Github object that
// writes to the app's Writer. If it is not, it returns an empty Github object that does not write anything.
func NewFromCli(cCtx *cli.Context) Github {
if cCtx.Bool(common.GHAFlag) {
return New(cCtx.App.Writer)
func NewFromCli(cCtx *cli.Context) (Github, error) {
if !cCtx.Bool(common.GHAFlag) {
return New(io.Discard), nil
}

filename := os.Getenv(GithubOutput)

if filename == "" {
return Github{}, fmt.Errorf("invalid output file: %w", ErrEmptyFileName)
}

file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) //nolint:mnd,magicnumber
if err != nil {
return Github{}, fmt.Errorf("invalid output file: %w", err)
}

return New(io.Discard)
return New(file), nil
}

// Github is an object that output workflow commands.
type Github struct {
w io.Writer
w io.Writer
mu sync.Mutex
}

// SetOutput outputs the `set-output` command.
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter
func (g Github) SetOutput(name string, value interface{}) {
_, _ = fmt.Fprintf(g.w, "::set-output name=%s::%v\n", name, value)
// https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-output-parameter
func (g *Github) SetOutput(name string, value interface{}) {
g.mu.Lock()
_, _ = fmt.Fprintf(g.w, "%s=%v\n", name, value)
g.mu.Unlock()
}
72 changes: 72 additions & 0 deletions src/app/gha/gha_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package gha_test

import (
"strings"
"sync"
"testing"

"github.com/newrelic/release-toolkit/internal/testutil"
"github.com/newrelic/release-toolkit/src/app/gha"
)

//nolint:paralleltest
func TestGHA_FileIsEmptyByDefault(t *testing.T) {
ghaOutput := testutil.NewGithubOutputWriter(t)
if actual := ghaOutput.Result(t); actual != "" {
t.Fatalf("Expected GHA output is empty")
}
}

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

buf := &strings.Builder{}
buf.WriteString("not-empty=true\nanother-line=true\n")

gha := gha.New(buf)

gha.SetOutput("test", 1)
gha.SetOutput("test", "out")

expected := strings.TrimSpace(`
not-empty=true
another-line=true
test=1
test=out
`) + "\n"

if actual := buf.String(); actual != expected {
t.Fatalf("Expected:\n%s\n\ngot:\n%s", expected, actual)
}
}

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

buf := &strings.Builder{}
wg := sync.WaitGroup{}

gha := gha.New(buf)

for range 5 {
wg.Add(1)
go func() {
gha.SetOutput("test", 1)
wg.Done()
}()
}

expected := strings.TrimSpace(`
test=1
test=1
test=1
test=1
test=1
`) + "\n"

wg.Wait()

if actual := buf.String(); actual != expected {
t.Fatalf("Expected:\n%s\n\ngot:\n%s", expected, actual)
}
}
5 changes: 4 additions & 1 deletion src/app/isempty/isempty.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ var Cmd = &cli.Command{

// IsEmpty is a command function which loads a changelog.yaml file, and prints to stdout whether it is empty or not.
func IsEmpty(cCtx *cli.Context) error {
gh := gha.NewFromCli(cCtx)
gh, err := gha.NewFromCli(cCtx)
if err != nil {
return fmt.Errorf("creating github client: %w", err)
}

chPath := cCtx.String(common.YAMLFlag)
chFile, err := os.Open(chPath)
Expand Down
Loading

0 comments on commit 97bff5b

Please sign in to comment.