mirror of
https://github.com/thegeeklab/wp-plugin-go.git
synced 2024-06-02 18:39:40 +02:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
07d29586c9 | ||
|
ec3b3263f8 | ||
|
dfbeaf935f | ||
e5e67d464c | |||
119641f63a | |||
23eca50904 | |||
6be7f2b898 | |||
|
e2bc944f1f | ||
085ee0d15a | |||
5e6b213c13 | |||
|
5ca8c9ac0e | ||
df36058fa9 | |||
|
c48fbf9bd7 | ||
d2c3493d68 | |||
211b38e908 | |||
|
3cb24ef473 | ||
830d37fa00 | |||
25469ebab3 | |||
7143086616 | |||
8ad911886e | |||
fc2102453c | |||
f381a5e6ba | |||
35072e3425 | |||
|
86776b673a | ||
|
b0a1901a24 | ||
|
d0c70f927c | ||
|
298d61949a | ||
|
bed6ac8b2b |
|
@ -23,7 +23,6 @@ linters:
|
|||
- errchkjson
|
||||
- errname
|
||||
- errorlint
|
||||
- execinquery
|
||||
- exhaustive
|
||||
- exportloopref
|
||||
- forcetypeassert
|
||||
|
@ -37,12 +36,12 @@ linters:
|
|||
- gocyclo
|
||||
- godot
|
||||
# - godox
|
||||
- goerr113
|
||||
- err113
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goheader
|
||||
- goimports
|
||||
- gomnd
|
||||
- mnd
|
||||
- gomoddirectives
|
||||
- gomodguard
|
||||
- goprintffuncname
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
|||
# renovate: datasource=github-releases depName=mvdan/gofumpt
|
||||
GOFUMPT_PACKAGE_VERSION := v0.6.0
|
||||
# renovate: datasource=github-releases depName=golangci/golangci-lint
|
||||
GOLANGCI_LINT_PACKAGE_VERSION := v1.56.2
|
||||
GOLANGCI_LINT_PACKAGE_VERSION := v1.59.0
|
||||
|
||||
GO ?= go
|
||||
PACKAGES ?= $(shell go list ./...)
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
wp_template "github.com/thegeeklab/wp-plugin-go/template"
|
||||
plugin_template "github.com/thegeeklab/wp-plugin-go/v3/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
@ -40,7 +40,7 @@ var templateFs embed.FS
|
|||
func ToMarkdown(app *cli.App) (string, error) {
|
||||
var w bytes.Buffer
|
||||
|
||||
tpls, err := template.New("cli").Funcs(wp_template.LoadFuncMap()).ParseFS(templateFs, "**/*.tmpl")
|
||||
tpls, err := template.New("cli").Funcs(plugin_template.LoadFuncMap()).ParseFS(templateFs, "**/*.tmpl")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
50
exec/command.go
Normal file
50
exec/command.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package exec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
// Cmd represents a command to be executed, with options to control its behavior.
|
||||
// The Cmd struct embeds the standard library's exec.Cmd, adding additional fields
|
||||
// to control the command's output and tracing.
|
||||
type Cmd struct {
|
||||
*exec.Cmd
|
||||
Trace bool // Print composed command before execution.
|
||||
TraceWriter io.Writer // Where to write the trace output.
|
||||
}
|
||||
|
||||
// Run runs the command and waits for it to complete.
|
||||
// If there is an error starting the command, it is returned.
|
||||
// Otherwise, the command is waited for and its exit status is returned.
|
||||
func (c *Cmd) Run() error {
|
||||
if c.Trace {
|
||||
fmt.Fprintf(c.TraceWriter, "+ %s\n", strings.Join(c.Args, " "))
|
||||
}
|
||||
|
||||
if err := c.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Wait()
|
||||
}
|
||||
|
||||
// Command creates a new Cmd with the given name and arguments. The Cmd is configured
|
||||
// with Trace set to true and TraceWriter set to os.Stdout. The Cmd's Env is set
|
||||
// to the current environment.
|
||||
func Command(name string, arg ...string) *Cmd {
|
||||
cmd := &Cmd{
|
||||
Cmd: execabs.Command(name, arg...),
|
||||
Trace: true,
|
||||
TraceWriter: os.Stdout,
|
||||
}
|
||||
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
return cmd
|
||||
}
|
103
exec/command_test.go
Normal file
103
exec/command_test.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
package exec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCmdRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cmd *Cmd
|
||||
wantErr bool
|
||||
wantStdout string
|
||||
wantStderr string
|
||||
wantTrace string
|
||||
}{
|
||||
{
|
||||
name: "trace enabled",
|
||||
cmd: &Cmd{
|
||||
Trace: true,
|
||||
Cmd: &exec.Cmd{
|
||||
Path: "/usr/bin/echo",
|
||||
Args: []string{"echo", "hello"},
|
||||
},
|
||||
},
|
||||
wantTrace: "+ echo hello\n",
|
||||
wantStdout: "hello\n",
|
||||
},
|
||||
{
|
||||
name: "trace disabled",
|
||||
cmd: &Cmd{
|
||||
Trace: false,
|
||||
Cmd: &exec.Cmd{
|
||||
Path: "/usr/bin/echo",
|
||||
Args: []string{"echo", "hello"},
|
||||
},
|
||||
},
|
||||
wantStdout: "hello\n",
|
||||
},
|
||||
{
|
||||
name: "custom env",
|
||||
cmd: &Cmd{
|
||||
Trace: true,
|
||||
Cmd: &exec.Cmd{
|
||||
Path: "/bin/sh",
|
||||
Args: []string{"sh", "-c", "echo $TEST"},
|
||||
Env: []string{"TEST=1"},
|
||||
},
|
||||
},
|
||||
wantTrace: "+ sh -c echo $TEST\n",
|
||||
wantStdout: "1\n",
|
||||
},
|
||||
{
|
||||
name: "custom stderr",
|
||||
cmd: &Cmd{
|
||||
Trace: true,
|
||||
Cmd: &exec.Cmd{
|
||||
Path: "/bin/sh",
|
||||
Args: []string{"sh", "-c", "echo error >&2"},
|
||||
Stderr: new(bytes.Buffer),
|
||||
},
|
||||
},
|
||||
wantTrace: "+ sh -c echo error >&2\n",
|
||||
wantStderr: "error\n",
|
||||
},
|
||||
{
|
||||
name: "error",
|
||||
cmd: &Cmd{
|
||||
Trace: true,
|
||||
Cmd: &exec.Cmd{
|
||||
Path: "/invalid/path",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
traceBuf := new(bytes.Buffer)
|
||||
stdoutBuf := new(bytes.Buffer)
|
||||
stderrBuf := new(bytes.Buffer)
|
||||
tt.cmd.TraceWriter = traceBuf
|
||||
tt.cmd.Stdout = stdoutBuf
|
||||
tt.cmd.Stderr = stderrBuf
|
||||
|
||||
err := tt.cmd.Run()
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.wantTrace, traceBuf.String())
|
||||
assert.Equal(t, tt.wantStdout, stdoutBuf.String())
|
||||
assert.Equal(t, tt.wantStderr, stderrBuf.String())
|
||||
})
|
||||
}
|
||||
}
|
54
file/dir.go
Normal file
54
file/dir.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// DeleteDir deletes the directory at the given path.
|
||||
// It returns nil if the deletion succeeds, or the deletion error otherwise.
|
||||
// If the directory does not exist, DeleteDir returns nil.
|
||||
func DeleteDir(path string) error {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// IsDir returns whether the given path is a directory. If the path does not exist, it returns (false, nil).
|
||||
// If there is an error checking the path, it returns (false, err).
|
||||
func IsDir(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
// IsDirEmpty checks if the directory at the given path is empty.
|
||||
// It returns true if the directory is empty, false if not empty, or an error if there was a problem checking it.
|
||||
func IsDirEmpty(path string) (bool, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Readdir(1)
|
||||
if err == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if errors.Is(err, io.EOF) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
69
file/dir_test.go
Normal file
69
file/dir_test.go
Normal file
|
@ -0,0 +1,69 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsDirEmpty(t *testing.T) {
|
||||
t.Run("empty directory", func(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("", "test")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
isEmpty, err := IsDirEmpty(dir)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !isEmpty {
|
||||
t.Error("expected directory to be empty")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("non-empty directory", func(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("", "test")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
file, err := os.CreateTemp(dir, "test")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp file: %v", err)
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
isEmpty, err := IsDirEmpty(dir)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if isEmpty {
|
||||
t.Error("expected directory to be non-empty")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("non-existent directory", func(t *testing.T) {
|
||||
dir := filepath.Join(os.TempDir(), "non-existent")
|
||||
|
||||
isEmpty, err := IsDirEmpty(dir)
|
||||
if err == nil {
|
||||
t.Error("expected an error for non-existent directory")
|
||||
}
|
||||
|
||||
if isEmpty {
|
||||
t.Error("expected directory to be non-empty")
|
||||
}
|
||||
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
29
file/file.go
29
file/file.go
|
@ -34,17 +34,6 @@ func ReadStringOrFile(input string) (string, bool, error) {
|
|||
return string(result), true, nil
|
||||
}
|
||||
|
||||
// DeleteDir deletes the directory at the given path.
|
||||
// It returns nil if the deletion succeeds, or the deletion error otherwise.
|
||||
// If the directory does not exist, DeleteDir returns nil.
|
||||
func DeleteDir(path string) error {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// ExpandFileList takes a list of file globs and expands them into a list
|
||||
// of matching file paths. It returns the expanded file list and any errors
|
||||
// from glob matching. This allows safely passing user input globs through to
|
||||
|
@ -65,3 +54,21 @@ func ExpandFileList(fileList []string) ([]string, error) {
|
|||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// WriteTmpFile creates a temporary file with the given name and content, and returns the path to the created file.
|
||||
func WriteTmpFile(name, content string) (string, error) {
|
||||
tmpfile, err := os.CreateTemp("", name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if _, err := tmpfile.Write([]byte(content)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := tmpfile.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tmpfile.Name(), nil
|
||||
}
|
||||
|
|
64
file/file_test.go
Normal file
64
file/file_test.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const helloWorld = "Hello, World!"
|
||||
|
||||
func TestWriteTmpFile(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fileName string
|
||||
content string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "write to temp file",
|
||||
fileName: "test.txt",
|
||||
content: helloWorld,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty file name",
|
||||
fileName: "",
|
||||
content: helloWorld,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty file content",
|
||||
fileName: "test.txt",
|
||||
content: "",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "create temp file error",
|
||||
fileName: filepath.Join(os.TempDir(), "non-existent", "test.txt"),
|
||||
content: helloWorld,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tmpFile, err := WriteTmpFile(tt.fileName, tt.content)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer os.Remove(tmpFile)
|
||||
|
||||
data, err := os.ReadFile(tmpFile)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.content, string(data))
|
||||
})
|
||||
}
|
||||
}
|
16
go.mod
16
go.mod
|
@ -1,4 +1,4 @@
|
|||
module github.com/thegeeklab/wp-plugin-go
|
||||
module github.com/thegeeklab/wp-plugin-go/v3
|
||||
|
||||
go 1.22
|
||||
|
||||
|
@ -6,15 +6,16 @@ require (
|
|||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/rs/zerolog v1.32.0
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/urfave/cli/v2 v2.27.1
|
||||
golang.org/x/net v0.22.0
|
||||
github.com/urfave/cli/v2 v2.27.2
|
||||
golang.org/x/net v0.25.0
|
||||
golang.org/x/sys v0.20.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/google/uuid v1.1.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
|
@ -27,8 +28,7 @@ require (
|
|||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
28
go.sum
28
go.sum
|
@ -6,8 +6,8 @@ github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYr
|
|||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -33,8 +33,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
|
||||
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
|
@ -46,23 +46,23 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
||||
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
|
||||
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
|
||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
|
||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -74,8 +74,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
|
|
|
@ -238,11 +238,11 @@ func prevFromContext(c *cli.Context) Commit {
|
|||
// line as the title, and the rest as the description. If there is no newline,
|
||||
// the entire message is returned as the title, and the description is empty.
|
||||
func splitMessage(message string) (string, string) {
|
||||
//nolint:gomnd
|
||||
//nolint:mnd
|
||||
switch parts := strings.SplitN(message, "\n", 2); len(parts) {
|
||||
case 1:
|
||||
return parts[0], ""
|
||||
//nolint:gomnd
|
||||
//nolint:mnd
|
||||
case 2:
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ func loggingFlags(category string) []cli.Flag {
|
|||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "log-level",
|
||||
Usage: "log level",
|
||||
EnvVars: []string{"CI_LOG_LEVEL"},
|
||||
Usage: "plugin log level",
|
||||
EnvVars: []string{"PLUGIN_LOG_LEVEL"},
|
||||
Value: "info",
|
||||
Category: category,
|
||||
},
|
||||
|
@ -36,7 +36,11 @@ func loggingFlags(category string) []cli.Flag {
|
|||
|
||||
// SetupConsoleLogger sets up the console logger.
|
||||
func SetupConsoleLogger(c *cli.Context) error {
|
||||
level := c.String("log-level")
|
||||
level := "info"
|
||||
|
||||
if c != nil {
|
||||
level = c.String("log-level")
|
||||
}
|
||||
|
||||
lvl, err := zerolog.ParseLevel(level)
|
||||
if err != nil {
|
||||
|
@ -51,7 +55,7 @@ func SetupConsoleLogger(c *cli.Context) error {
|
|||
|
||||
if zerolog.GlobalLevel() <= zerolog.DebugLevel {
|
||||
log.Logger = log.With().Caller().Logger()
|
||||
log.Log().Msgf("LogLevel = %s", zerolog.GlobalLevel().String())
|
||||
log.Info().Msgf("LogLevel = %s", zerolog.GlobalLevel().String())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/thegeeklab/wp-plugin-go/trace"
|
||||
plugin_trace "github.com/thegeeklab/wp-plugin-go/v3/trace"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
@ -45,8 +45,8 @@ type Network struct {
|
|||
//nolint:containedctx
|
||||
Context context.Context
|
||||
|
||||
/// Whether SSL verification is skipped
|
||||
SkipVerify bool
|
||||
/// Whether SSL verification is skipped or not.
|
||||
InsecureSkipVerify bool
|
||||
|
||||
// Client for making network requests.
|
||||
Client *http.Client
|
||||
|
@ -55,9 +55,9 @@ type Network struct {
|
|||
func networkFlags(category string) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "transport.skip-verify",
|
||||
Usage: "skip ssl verify",
|
||||
EnvVars: []string{"CI_SKIP_VERIFY"},
|
||||
Name: "transport.insecure-skip-verify",
|
||||
Usage: "skip SSL verification",
|
||||
EnvVars: []string{"PLUGIN_INSECURE_SKIP_VERIFY"},
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
|
@ -77,7 +77,7 @@ func networkFlags(category string) []cli.Flag {
|
|||
|
||||
func NetworkFromContext(ctx *cli.Context) Network {
|
||||
var (
|
||||
skip = ctx.Bool("transport.skip-verify")
|
||||
skipVerify = ctx.Bool("transport.insecure-skip-verify")
|
||||
defaultContext = context.Background()
|
||||
socks = ctx.String("transport.socks-proxy")
|
||||
socksoff = ctx.Bool("transport.socks-proxy-off")
|
||||
|
@ -90,7 +90,7 @@ func NetworkFromContext(ctx *cli.Context) Network {
|
|||
|
||||
tlsConfig := &tls.Config{
|
||||
RootCAs: certs,
|
||||
InsecureSkipVerify: skip, //nolint:gosec
|
||||
InsecureSkipVerify: skipVerify, //nolint:gosec
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
|
@ -126,7 +126,7 @@ func NetworkFromContext(ctx *cli.Context) Network {
|
|||
}
|
||||
|
||||
if zerolog.GlobalLevel() == zerolog.TraceLevel {
|
||||
defaultContext = trace.HTTP(defaultContext)
|
||||
defaultContext = plugin_trace.HTTP(defaultContext)
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
|
@ -134,8 +134,8 @@ func NetworkFromContext(ctx *cli.Context) Network {
|
|||
}
|
||||
|
||||
return Network{
|
||||
Context: defaultContext,
|
||||
SkipVerify: skip,
|
||||
Client: client,
|
||||
Context: defaultContext,
|
||||
InsecureSkipVerify: skipVerify,
|
||||
Client: client,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,37 @@ import (
|
|||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
//nolint:lll
|
||||
const appHelpTemplate = `NAME:
|
||||
{{template "helpNameTemplate" .}}
|
||||
|
||||
USAGE:
|
||||
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}{{if .Args}}[arguments...]{{end}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
|
||||
|
||||
VERSION:
|
||||
{{.Version}}{{end}}{{end}}{{if .Description}}
|
||||
|
||||
DESCRIPTION:
|
||||
{{template "descriptionTemplate" .}}{{end}}
|
||||
{{- if len .Authors}}
|
||||
|
||||
AUTHOR{{template "authorsTemplate" .}}{{end}}{{if .VisibleCommands}}
|
||||
|
||||
COMMANDS:{{template "visibleCommandCategoryTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
|
||||
|
||||
GLOBAL OPTIONS:{{range .VisibleFlagCategories}}{{if and .Name (ne .Name "Plugin Flags")}}{{continue}}{{end}}
|
||||
{{if .Name}}{{.Name}}
|
||||
|
||||
{{end}}{{$flglen := len .Flags}}{{range $i, $e := .Flags}}{{if eq (subtract $flglen $i) 1}}{{$e}}
|
||||
{{else}}{{$e}}
|
||||
{{end}}{{end}}{{end}}{{else if .VisibleFlags}}
|
||||
|
||||
GLOBAL OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .Copyright}}
|
||||
|
||||
COPYRIGHT:
|
||||
{{template "copyrightTemplate" .}}{{end}}
|
||||
`
|
||||
|
||||
// Options defines the options for the plugin.
|
||||
type Options struct {
|
||||
// Name of the plugin.
|
||||
|
@ -41,6 +72,8 @@ type Options struct {
|
|||
Flags []cli.Flag
|
||||
// Execute function of the plugin.
|
||||
Execute ExecuteFunc
|
||||
// Hide woodpecker system flags.
|
||||
HideWoodpeckerFlags bool
|
||||
}
|
||||
|
||||
// Plugin defines the plugin instance.
|
||||
|
@ -63,16 +96,23 @@ func New(opt Options) *Plugin {
|
|||
_ = godotenv.Overload("/run/woodpecker/env")
|
||||
}
|
||||
|
||||
_ = SetupConsoleLogger(nil)
|
||||
|
||||
app := &cli.App{
|
||||
Name: opt.Name,
|
||||
Usage: opt.Description,
|
||||
Version: opt.Version,
|
||||
Flags: append(opt.Flags, Flags()...),
|
||||
Before: SetupConsoleLogger,
|
||||
}
|
||||
|
||||
if opt.HideWoodpeckerFlags {
|
||||
app.CustomAppHelpTemplate = appHelpTemplate
|
||||
}
|
||||
|
||||
cli.VersionPrinter = func(c *cli.Context) {
|
||||
version := fmt.Sprintf("%s version=%s %s\n", c.App.Name, c.App.Version, opt.VersionMetadata)
|
||||
fmt.Print(strings.TrimSpace(version))
|
||||
fmt.Println(strings.TrimSpace(version))
|
||||
}
|
||||
|
||||
plugin := &Plugin{
|
||||
|
@ -85,10 +125,6 @@ func New(opt Options) *Plugin {
|
|||
}
|
||||
|
||||
func (p *Plugin) action(ctx *cli.Context) error {
|
||||
if err := SetupConsoleLogger(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Metadata = MetadataFromContext(ctx)
|
||||
p.Network = NetworkFromContext(ctx)
|
||||
p.Context = ctx
|
||||
|
|
|
@ -22,12 +22,12 @@ import (
|
|||
// format. Trailing or leading spaces or new-lines are not getting truncated. It
|
||||
// is able to read templates from remote paths, local files or directly from the
|
||||
// string.
|
||||
func Render(ctx context.Context, client http.Client, templateString string, payload interface{}) (string, error) {
|
||||
func Render(ctx context.Context, client http.Client, tmpl string, payload interface{}) (string, error) {
|
||||
var outString bytes.Buffer
|
||||
|
||||
tpl := new(template.Template).Funcs(LoadFuncMap())
|
||||
|
||||
templateURL, err := url.Parse(templateString)
|
||||
templateURL, err := url.Parse(tmpl)
|
||||
if err == nil {
|
||||
switch templateURL.Scheme {
|
||||
case "http", "https":
|
||||
|
@ -48,18 +48,18 @@ func Render(ctx context.Context, client http.Client, templateString string, payl
|
|||
return "", fmt.Errorf("failed to read: %w", err)
|
||||
}
|
||||
|
||||
templateString = string(out)
|
||||
tmpl = string(out)
|
||||
case "file":
|
||||
out, err := os.ReadFile(templateURL.Path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read: %w", err)
|
||||
}
|
||||
|
||||
templateString = string(out)
|
||||
tmpl = string(out)
|
||||
}
|
||||
}
|
||||
|
||||
tpl, err = tpl.Parse(templateString)
|
||||
tpl, err = tpl.Parse(tmpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -72,8 +72,8 @@ func Render(ctx context.Context, client http.Client, templateString string, payl
|
|||
// RenderTrim parses and executes a template, returning the results in string
|
||||
// format. The result is trimmed to remove left and right padding and newlines
|
||||
// that may be added unintentially in the template markup.
|
||||
func RenderTrim(ctx context.Context, client http.Client, template string, playload interface{}) (string, error) {
|
||||
out, err := Render(ctx, client, template, playload)
|
||||
func RenderTrim(ctx context.Context, client http.Client, tmpl string, playload interface{}) (string, error) {
|
||||
out, err := Render(ctx, client, tmpl, playload)
|
||||
|
||||
return strings.Trim(out, " \n"), err
|
||||
}
|
||||
|
|
|
@ -12,9 +12,6 @@ import (
|
|||
"fmt"
|
||||
"net/http/httptrace"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
@ -120,8 +117,3 @@ func HTTP(ctx context.Context) context.Context {
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Cmd prints the executed command to stdout.
|
||||
func Cmd(cmd *exec.Cmd) {
|
||||
fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ func splitWithEscaping(in, separator, escapeString string) []string {
|
|||
|
||||
out := strings.Split(in, separator)
|
||||
|
||||
//nolint:gomnd
|
||||
//nolint:mnd
|
||||
for i := len(out) - 2; i >= 0; i-- {
|
||||
if strings.HasSuffix(out[i], escapeString) {
|
||||
out[i] = out[i][:len(out[i])-len(escapeString)] + separator + out[i+1]
|
||||
|
|
15
util/user.go
Normal file
15
util/user.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package util
|
||||
|
||||
import "os/user"
|
||||
|
||||
// GetUserHomeDir returns the home directory path for the current user.
|
||||
// If the current user cannot be determined, it returns the default "/root" path.
|
||||
func GetUserHomeDir() string {
|
||||
home := "/root"
|
||||
|
||||
if currentUser, err := user.Current(); err == nil {
|
||||
home = currentUser.HomeDir
|
||||
}
|
||||
|
||||
return home
|
||||
}
|
Loading…
Reference in New Issue
Block a user