Selaa lähdekoodia

Adds initial structure for description templates

arianagiroux 2 viikkoa sitten
vanhempi
sitoutus
55b63c6bae
2 muutettua tiedostoa jossa 166 lisäystä ja 1 poistoa
  1. 119 1
      io.go
  2. 47 0
      io_test.go

+ 119 - 1
io.go

@@ -26,12 +26,17 @@ package issues
 
 import (
 	"errors"
+	"fmt"
+	"math/rand"
 	"os"
+	"os/exec"
 	"path/filepath"
+	"strings"
+	"time"
 )
 
 // converts file from []string to string, reports errors
-func readPath(path string) (output string, err error) {
+func readPath(path string) (output string, err error) { // TODO DEPRECATE
 	content, err := os.ReadFile(path)
 
 	if err != nil {
@@ -45,6 +50,119 @@ func readPath(path string) (output string, err error) {
 	return output, nil
 }
 
+// The quote string used to generate a template description
+type Template string
+
+var DescriptionTemplate = Template(`# Please provide a short, one line description.
+
+# Include any additional comments here.
+# -----------
+# Note: Lines beginning with "#" are automatically ignored.
+# Note: It is recommended to leave a blank line after the short description.`)
+
+// generates template description files
+func GenerateTemplate(t Template, path string) error {
+	err := os.WriteFile(path, []byte(DescriptionTemplate), 0755)
+	return err
+}
+
+// parses template description files, removing any lines beginning with #
+//
+// Note: the function deletes the template file upon completion.
+func ReadTemplate(path string) (lines []string, err error) {
+	data, err := os.ReadFile(path)
+	if err != nil {
+		return []string{}, err
+	}
+	sdata := string(data)
+	slines := strings.SplitSeq(sdata, "\n")
+
+	for line := range slines {
+		if len(string(line)) > 0 {
+			if string(line[0]) != "#" {
+				lines = append(lines, line)
+			}
+		} else {
+			lines = append(lines, line)
+		}
+	}
+
+	return lines, err
+}
+
+// InvokeEditor invokes a preconfigured editor, and reports the output and any errors.
+func InvokeEditor(path string) error {
+	// determine editor
+	//	1. Git config
+	//	2. $EDITOR
+	//	3. Panic?
+
+	// execute editor
+	cmd := exec.Command("vim", path)
+	cmd.Stdin = os.Stdin   // capture data
+	cmd.Stdout = os.Stdout // capture data
+	cmd.Stderr = os.Stderr // capture data
+
+	// wait for cmd and error out if err
+	if err := cmd.Run(); err != nil {
+		return fmt.Errorf("editor execution failed: %w", err)
+	}
+	return nil
+}
+
+// EditTemplate wraps GenerateTemplate and ReadTemplate, providing
+// both with a tempfile. EditTemplate then reports the content of the tempfile
+// after any modifications made by the editFunc callback and any encountered
+// errors.
+//
+// Note: A pre-built editor function is provided. See InvokeEditor for more.
+func EditTemplate(t Template, editFunc func(path string) error) (data []string, err error) {
+	// note: wraps writeText
+
+	var seededRand = rand.New(
+		rand.NewSource(time.Now().UnixNano()))
+
+	makeID := func(length int) string {
+		var charset = "abcdefghijklmnopqrstuvwxyz" +
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+		b := make([]byte, length)
+		for i := range b {
+			b[i] = charset[seededRand.Intn(len(charset))]
+		}
+		return string(b)
+	}
+
+	// get get temp file
+	tempfile, err := os.CreateTemp("", makeID(8))
+	if err != nil {
+		return []string{}, nil
+	}
+
+	cleanup := func() {
+		err = os.Remove(tempfile.Name())
+		if err != nil {
+			panic(err)
+		}
+	}
+	defer cleanup()
+
+	err = GenerateTemplate(DescriptionTemplate, tempfile.Name())
+	if err != nil {
+		return []string{}, nil
+	}
+
+	// invoke editor
+	err = editFunc(tempfile.Name())
+	if err != nil {
+		return []string{}, nil
+	}
+
+	// get data
+	result, err := ReadTemplate(tempfile.Name())
+
+	return result, err
+}
+
 // Reports true when the specified path conforms to the minimum Poorman spec
 func IsIssue(path string) bool {
 	files, err := os.ReadDir(path)

+ 47 - 0
io_test.go

@@ -3,6 +3,7 @@ package issues
 import (
 	"os"
 	"testing"
+	"time"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -143,3 +144,49 @@ func Test_WriteIssue_creates_variadic_fields(t *testing.T) {
 	err = os.RemoveAll(testIssue.Path)
 	assert.Nil(t, err)
 }
+
+func Test_Generate_and_Read_Template(t *testing.T) {
+	testPath := "tests/desc1"
+
+	// clean up path
+	err := os.RemoveAll(testPath)
+	assert.Nil(t, err)
+
+	err = GenerateTemplate(DescriptionTemplate, testPath)
+	assert.Nil(t, err)
+
+	lines, err := ReadTemplate(testPath)
+	assert.Nil(t, err)
+	assert.Equal(t, 1, len(lines))
+
+	// clean up path
+	err = os.RemoveAll(testPath)
+	assert.Nil(t, err)
+}
+
+func Test_EditTemplate(t *testing.T) {
+	testEditFunc := func(path string) error {
+		d := []string{
+			"title\n",
+			"# ignore\n",
+			"\n",
+			"# ignore\n",
+			"description\n",
+			"# ignore\n",
+			"# ignore\n",
+			"# ignore\n",
+		}
+		send := ""
+		for _, v := range d {
+			send = send + v
+		}
+		err := os.WriteFile(path, []byte(send), 0755)
+		time.Sleep(5 * time.Millisecond)
+		return err
+	}
+
+	data, err := EditTemplate(DescriptionTemplate, testEditFunc)
+	assert.Nil(t, err)
+	assert.IsType(t, []string{}, data)
+	assert.Equal(t, 4, len(data), data)
+}