Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: matty-rose/gha-docs
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.12.1
Choose a base ref
...
head repository: matty-rose/gha-docs
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.13.0
Choose a head ref
  • 2 commits
  • 10 files changed
  • 1 contributor

Commits on Nov 14, 2021

  1. feat: add option to inject docs into existing file

    Signed-off-by: Matthew Rose <[email protected]>
    matty-rose committed Nov 14, 2021
    Copy the full SHA
    bb0860f View commit details
  2. test: add injection tests

    Signed-off-by: Matthew Rose <[email protected]>
    matty-rose committed Nov 14, 2021
    Copy the full SHA
    ac28626 View commit details
16 changes: 15 additions & 1 deletion cmd/generate.go
Original file line number Diff line number Diff line change
@@ -36,6 +36,9 @@ var format string
// Output file flag
var outputFile string

// Inject flag
var inject bool

// generateCmd represents the generate command
var generateCmd = &cobra.Command{
Use: "generate [PATH]",
@@ -55,7 +58,11 @@ var generateCmd = &cobra.Command{

content := g.Generate(action)

err = writer.Write(content, outputFile)
err = writer.Write(writer.WriteInputs{
Content: content,
OutputFile: outputFile,
Inject: inject,
})
return err
},
}
@@ -75,5 +82,12 @@ func init() {
"",
"File to write generated documentation to.",
)
generateCmd.PersistentFlags().BoolVarP(
&inject,
"inject",
"i",
false,
"Set flag to inject generated documentation between markers. Ignored if not writing to a file. Defaults to false.",
)
rootCmd.AddCommand(generateCmd)
}
2 changes: 2 additions & 0 deletions pkg/writer/testdata/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name: "test"
description: "test"
Empty file added pkg/writer/testdata/empty.md
Empty file.
4 changes: 4 additions & 0 deletions pkg/writer/testdata/end_before_begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!-- END GHA DOCS -->
something blah blah
<!-- BEGIN GHA DOCS -->
testdata
5 changes: 5 additions & 0 deletions pkg/writer/testdata/existing_and_markers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
something already existing
<!-- BEGIN GHA DOCS -->
something that will be overwritten
<!-- END GHA DOCS -->
something else not overwritten
3 changes: 3 additions & 0 deletions pkg/writer/testdata/no_begin_marker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
something blah blah
testdata
<!-- END GHA DOCS -->
3 changes: 3 additions & 0 deletions pkg/writer/testdata/no_end_marker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
something blah blah
<!-- BEGIN GHA DOCS -->
testdata
2 changes: 2 additions & 0 deletions pkg/writer/testdata/only_markers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!-- BEGIN GHA DOCS -->
<!-- END GHA DOCS -->
71 changes: 53 additions & 18 deletions pkg/writer/writer.go
Original file line number Diff line number Diff line change
@@ -25,52 +25,87 @@ import (
"fmt"
"io"
"os"
"strings"

"github.com/pkg/errors"
)

const (
BeginInjection string = "<!-- BEGIN GHA DOCS -->"
EndInjection string = "<!-- END GHA DOCS -->"
)

type stdoutWriter struct{}

func (sw stdoutWriter) Write(content []byte) (int, error) {
return os.Stdout.Write(content)
}

type fileWriter struct {
file string
file string
inject bool
}

func (fw fileWriter) Write(content []byte) (n int, err error) {
f, err := os.OpenFile(fw.file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return 0, errors.Wrap(err, fmt.Sprintf("couldn't open file: %s", fw.file))
func (fw fileWriter) Write(content []byte) (int, error) {
if !fw.inject {
return fw.writeFile(content)
}

existingFileContent, err := os.ReadFile(fw.file)
if err != nil || len(existingFileContent) == 0 {
// Even if inject flag is passed, if file doesn't exist OR is empty, then write as per normal.
return fw.writeFile(content)
}

return fw.injectContent(string(existingFileContent), string(content))
}

func (fw fileWriter) injectContent(existing, newContent string) (int, error) {
beginIdx := strings.Index(existing, BeginInjection)
endIdx := strings.Index(existing, EndInjection)

if beginIdx == -1 {
return 0, errors.New(fmt.Sprintf("missing begin injection marker: %s", BeginInjection))
}

if endIdx == -1 {
return 0, errors.New(fmt.Sprintf("missing end injection marker: %s", EndInjection))
}

if endIdx < beginIdx {
return 0, errors.New("end injection marker is before begin injection marker")
}

defer func() {
cerr := f.Close()
if err == nil {
err = cerr
}
}()
injectedContent := existing[:beginIdx+len(BeginInjection)] + "\n" + newContent + existing[endIdx:]

n, err = f.Write(content)
return fw.writeFile([]byte(injectedContent))
}

func (fw fileWriter) writeFile(content []byte) (int, error) {
err := os.WriteFile(fw.file, []byte(content), 0644)
if err != nil {
return 0, errors.Wrap(err, fmt.Sprintf("couldn't write to file: %s", fw.file))
}

// Uses named return values
return
return len(content), err
}

type WriteInputs struct {
Content string
OutputFile string
Inject bool
}

func Write(content string, outputFile string) error {
func Write(inputs WriteInputs) error {
var w io.Writer

if outputFile != "" {
w = fileWriter{outputFile}
if inputs.OutputFile != "" {
w = fileWriter{inputs.OutputFile, inputs.Inject}
} else {
w = stdoutWriter{}
}

_, err := io.WriteString(w, content)
_, err := io.WriteString(w, inputs.Content)

return err
}
57 changes: 55 additions & 2 deletions pkg/writer/writer_test.go
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ package writer_test

import (
"bytes"
"fmt"
"io"
"os"
"testing"
@@ -57,7 +58,7 @@ func TestStdoutWriter(t *testing.T) {
outC <- buf.String()
}()

writer.Write(tc, "")
writer.Write(writer.WriteInputs{Content: tc, OutputFile: "", Inject: false})

// back to normal state
w.Close()
@@ -78,7 +79,7 @@ func TestFileWriter(t *testing.T) {
shenanigans`}

for _, tc := range testCases {
writer.Write(tc, testFile)
writer.Write(writer.WriteInputs{Content: tc, OutputFile: testFile, Inject: false})

got, err := os.ReadFile(testFile)
if err != nil {
@@ -88,3 +89,55 @@ func TestFileWriter(t *testing.T) {
assert.Equal(t, tc, string(got))
}
}

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

content := "dummy\n"

testCases := []struct {
outputFile string
expectedContent string
}{
{"./testdata/non_existent.md", "dummy\n"},
{"./testdata/empty.md", "dummy\n"},
{"./testdata/only_markers.md", fmt.Sprintf("%s\ndummy\n%s\n", writer.BeginInjection, writer.EndInjection)},
{"./testdata/existing_and_markers.md",
fmt.Sprintf(
"something already existing\n%s\ndummy\n%s\nsomething else not overwritten\n",
writer.BeginInjection,
writer.EndInjection,
),
},
}

for _, tc := range testCases {
writer.Write(writer.WriteInputs{Content: content, OutputFile: tc.outputFile, Inject: true})

got, err := os.ReadFile(tc.outputFile)
if err != nil {
t.Fatal(err)
}

assert.Equal(t, tc.expectedContent, string(got))
}
}

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

testCases := []struct {
outputFile string
expectedErrMsg string
}{
{"./testdata/no_begin_marker.md", "missing begin injection marker"},
{"./testdata/no_end_marker.md", "missing end injection marker"},
{"./testdata/end_before_begin.md", "end injection marker is before begin"},
}

for _, tc := range testCases {
err := writer.Write(writer.WriteInputs{Content: "dummy", OutputFile: tc.outputFile, Inject: true})
assert.Error(t, err)
assert.Contains(t, err.Error(), tc.expectedErrMsg)
}
}