Move more functionality into internal/build/build.go

and use make targets in CI, pass flag spec YAML through yq

includes result of running `make v2approve`
This commit is contained in:
Dan Buch 2022-09-11 12:43:29 -04:00
parent 8e3fa067e0
commit 8cc0a9c5da
Signed by: meatballhat
GPG Key ID: A12F782281063434
5 changed files with 343 additions and 172 deletions

View File

@ -1,5 +1,4 @@
name: Run Tests
on:
push:
branches:
@ -12,10 +11,8 @@ on:
branches:
- main
- v3-dev-main
permissions:
contents: read
jobs:
test:
strategy:
@ -25,45 +22,26 @@ jobs:
name: ${{ matrix.os }} @ Go ${{ matrix.go }}
runs-on: ${{ matrix.os }}
steps:
- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v3
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go }}
- name: Set PATH
run: echo "${GITHUB_WORKSPACE}/.local/bin" >>"${GITHUB_PATH}"
- name: install goimports
if: matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest'
run: GOBIN=${PWD}/.local/bin go install golang.org/x/tools/cmd/goimports@latest
- name: Checkout Code
uses: actions/checkout@v3
- name: goimports check
if: matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest'
run: test -z $(goimports -l .)
- name: vet
run: go run internal/build/build.go vet
- name: test with urfave_cli_no_docs tag
run: go run internal/build/build.go -tags urfave_cli_no_docs test
- name: test
run: go run internal/build/build.go test
- name: test urfave-cli-genflags
run: make -C cmd/urfave-cli-genflags
- name: check-binary-size
run: go run internal/build/build.go check-binary-size
- name: check-binary-size with tags (informational only)
run: go run internal/build/build.go -tags urfave_cli_no_docs check-binary-size
- name: Upload coverage to Codecov
if: success() && matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest'
run: echo "${GITHUB_WORKSPACE}/.local/bin" | tee -a "${GITHUB_PATH}" >/dev/null
- if: matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest'
run: make ensure-goimports
- uses: actions/checkout@v3
- if: matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest'
run: make lint
- run: make vet
- run: make tag-test
- run: make test
- run: make -C cmd/urfave-cli-genflags
- run: make check-binary-size
- run: make tag-check-binary-size
- run: make yamlfmt
- run: make diffcheck
- run: make v2diff
- if: success() && matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
@ -73,36 +51,18 @@ jobs:
name: test-docs
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v3
- uses: actions/setup-go@v3
with:
go-version: 1.19.x
- name: Use Node.js 16
uses: actions/setup-node@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
- name: Set PATH
run: echo "${GITHUB_WORKSPACE}/.local/bin" >>"${GITHUB_PATH}"
- name: Checkout Code
uses: actions/checkout@v3
- name: Install Dependencies
run: |
mkdir -p "${GITHUB_WORKSPACE}/.local/bin"
curl -fsSL -o "${GITHUB_WORKSPACE}/.local/bin/gfmrun" "https://github.com/urfave/gfmrun/releases/download/v1.3.0/gfmrun-$(go env GOOS)-$(go env GOARCH)-v1.3.0"
chmod +x "${GITHUB_WORKSPACE}/.local/bin/gfmrun"
- name: gfmrun
run: go run internal/build/build.go gfmrun --walk docs/v3/
- name: diff check
run: |
git diff --exit-code
git diff --cached --exit-code
run: echo "${GITHUB_WORKSPACE}/.local/bin" | tee -a "${GITHUB_PATH}" >/dev/null
- uses: actions/checkout@v3
- run: make ensure-gfmrun
- run: make gfmrun
- run: make diffcheck
publish:
permissions:
contents: write
@ -114,18 +74,11 @@ jobs:
needs: [test-docs]
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup mkdocs
run: |
pip install -U pip
pip install -r mkdocs-requirements.txt
git remote rm origin
git remote add origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/urfave/cli.git
- name: Publish Docs
run: |
mkdocs gh-deploy --force
- run: make ci-ensure-mkdocs
- run: make set-mkdocs-remote
env:
MKDOCS_REMOTE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: make deploy-mkdocs

View File

@ -4,8 +4,10 @@
# are very important so that maintainers and contributors can focus their
# attention on files that are primarily Go.
GO_RUN_BUILD := go run internal/build/build.go
.PHONY: all
all: generate vet tag-test test check-binary-size tag-check-binary-size gfmrun v2diff
all: generate vet tag-test test check-binary-size tag-check-binary-size gfmrun yamlfmt v2diff
# NOTE: this is a special catch-all rule to run any of the commands
# defined in internal/build/build.go with optional arguments passed
@ -13,28 +15,28 @@ all: generate vet tag-test test check-binary-size tag-check-binary-size gfmrun v
#
# $ make test GFLAGS='--packages cli'
%:
go run internal/build/build.go $(GFLAGS) $* $(FLAGS)
$(GO_RUN_BUILD) $(GFLAGS) $* $(FLAGS)
.PHONY: tag-test
tag-test:
go run internal/build/build.go -tags urfave_cli_no_docs test
$(GO_RUN_BUILD) -tags urfave_cli_no_docs test
.PHONY: tag-check-binary-size
tag-check-binary-size:
go run internal/build/build.go -tags urfave_cli_no_docs check-binary-size
$(GO_RUN_BUILD) -tags urfave_cli_no_docs check-binary-size
.PHONY: gfmrun
gfmrun:
go run internal/build/build.go gfmrun docs/v2/manual.md
$(GO_RUN_BUILD) gfmrun --walk docs/v2/
.PHONY: ci-ensure-mkdocs
ci-ensure-mkdocs:
$(GO_RUN_BUILD) ensure-mkdocs --upgrade-pip
.PHONY: docs
docs:
mkdocs build
.PHONY: docs-deps
docs-deps:
pip install -r mkdocs-requirements.txt
.PHONY: serve-docs
serve-docs:
mkdocs serve

View File

@ -107,7 +107,7 @@ following `make` targets may be used if desired:
```sh
# install documentation dependencies with `pip`
make docs-deps
make ensure-mkdocs
```
```sh

View File

@ -3,13 +3,13 @@
# `Spec` type that maps to this file structure.
flag_types:
bool:
bool:
no_default_text: true
struct_fields:
- name: Count
- name: Count
type: int
pointer: true
float64:
float64:
Float64Slice:
value_pointer: true
skip_interfaces:
@ -34,7 +34,7 @@ flag_types:
struct_fields:
- name: Base
type: int
UintSlice:
UintSlice:
value_pointer: true
skip_interfaces:
- fmt.Stringer
@ -42,10 +42,10 @@ flag_types:
struct_fields:
- name: Base
type: int
Uint64Slice:
Uint64Slice:
value_pointer: true
skip_interfaces:
- fmt.Stringer
- fmt.Stringer
string:
struct_fields:
- name: TakesFile
@ -57,12 +57,12 @@ flag_types:
struct_fields:
- name: TakesFile
type: bool
time.Duration:
time.Duration:
Timestamp:
value_pointer: true
struct_fields:
- name: Layout
type: string
- name: Layout
type: string
- name: Timezone
type: "*time.Location"
Generic:

View File

@ -5,12 +5,17 @@ package main
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"log"
"math"
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"github.com/urfave/cli/v3"
@ -21,6 +26,8 @@ const (
goodNewsEmoji = "✨"
checksPassedEmoji = "✅"
gfmrunVersion = "v1.3.0"
v2diffWarning = `
# The unified diff above indicates that the public API surface area
# has changed. If you feel that the changes are acceptable and adhere
@ -45,63 +52,108 @@ func main() {
log.Fatal(err)
}
app := cli.NewApp()
app.Name = "builder"
app.Usage = "Generates a new urfave/cli build!"
app.Commands = cli.Commands{
{
Name: "vet",
Action: VetActionFunc,
},
{
Name: "test",
Action: TestActionFunc,
},
{
Name: "gfmrun",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "walk",
Value: false,
Usage: "Walk the specified directory and perform validation on all markdown files",
app := &cli.App{
Name: "builder",
Usage: "Do a thing for urfave/cli! (maybe build?)",
Commands: cli.Commands{
{
Name: "vet",
Action: topRunAction("go", "vet", "./..."),
},
{
Name: "test",
Action: TestActionFunc,
},
{
Name: "gfmrun",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "walk",
Value: false,
Usage: "Walk the specified directory and perform validation on all markdown files",
},
},
Action: GfmrunActionFunc,
},
{
Name: "check-binary-size",
Action: checkBinarySizeActionFunc,
},
{
Name: "generate",
Action: GenerateActionFunc,
},
{
Name: "yamlfmt",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "strict", Value: false, Usage: "require presence of yq"},
},
Action: YAMLFmtActionFunc,
},
{
Name: "diffcheck",
Action: DiffCheckActionFunc,
},
{
Name: "ensure-goimports",
Action: EnsureGoimportsActionFunc,
},
{
Name: "ensure-gfmrun",
Action: EnsureGfmrunActionFunc,
},
{
Name: "ensure-mkdocs",
Action: EnsureMkdocsActionFunc,
Flags: []cli.Flag{
&cli.BoolFlag{Name: "upgrade-pip"},
},
},
Action: GfmrunActionFunc,
},
{
Name: "check-binary-size",
Action: checkBinarySizeActionFunc,
},
{
Name: "generate",
Action: GenerateActionFunc,
},
{
Name: "v2diff",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "color", Value: false},
{
Name: "set-mkdocs-remote",
Action: SetMkdocsRemoteActionFunc,
Flags: []cli.Flag{
&cli.StringFlag{Name: "github-token", Required: true},
},
},
{
Name: "deploy-mkdocs",
Action: topRunAction("mkdocs", "gh-deploy", "--force"),
},
{
Name: "lint",
Action: LintActionFunc,
},
{
Name: "v2diff",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "color", Value: false},
},
Action: V2Diff,
},
{
Name: "v2approve",
Action: topRunAction(
"cp",
"-v",
"godoc-current.txt",
filepath.Join("testdata", "godoc-v2.x.txt"),
),
},
Action: V2Diff,
},
{
Name: "v2approve",
Action: V2Approve,
},
}
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "tags",
Usage: "set build tags",
},
&cli.PathFlag{
Name: "top",
Value: top,
},
&cli.StringSliceFlag{
Name: "packages",
Value: cli.NewStringSlice("cli", "altsrc", "internal/build"),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "tags",
Usage: "set build tags",
},
&cli.PathFlag{
Name: "top",
Value: top,
},
&cli.StringSliceFlag{
Name: "packages",
Value: cli.NewStringSlice("cli", "altsrc", "internal/build"),
},
},
}
@ -120,6 +172,14 @@ func sh(exe string, args ...string) (string, error) {
return string(outBytes), err
}
func topRunAction(arg string, args ...string) cli.ActionFunc {
return func(cCtx *cli.Context) error {
os.Chdir(cCtx.Path("top"))
return runCmd(arg, args...)
}
}
func runCmd(arg string, args ...string) error {
cmd := exec.Command(arg, args...)
@ -131,6 +191,43 @@ func runCmd(arg string, args ...string) error {
return cmd.Run()
}
func downloadFile(src, dest string, dirPerm, perm os.FileMode) error {
req, err := http.NewRequest(http.MethodGet, src, nil)
if err != nil {
return err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
return fmt.Errorf("download response %[1]v", resp.StatusCode)
}
if err := os.MkdirAll(filepath.Dir(dest), dirPerm); err != nil {
return err
}
out, err := os.Create(dest)
if err != nil {
return err
}
if _, err := io.Copy(out, resp.Body); err != nil {
return err
}
if err := out.Close(); err != nil {
return err
}
return os.Chmod(dest, perm)
}
func VetActionFunc(cCtx *cli.Context) error {
return runCmd("go", "vet", cCtx.Path("top")+"/...")
}
@ -145,15 +242,20 @@ func TestActionFunc(c *cli.Context) error {
packageName = fmt.Sprintf("github.com/urfave/cli/v3/%s", pkg)
}
if err := runCmd(
"go", "test",
"-tags", tags,
args := []string{"test"}
if tags != "" {
args = append(args, []string{"-tags", tags}...)
}
args = append(args, []string{
"-v",
"--coverprofile", pkg+".coverprofile",
"--coverprofile", pkg + ".coverprofile",
"--covermode", "count",
"--cover", packageName,
packageName,
); err != nil {
}...)
if err := runCmd("go", args...); err != nil {
return err
}
}
@ -411,6 +513,125 @@ func GenerateActionFunc(cCtx *cli.Context) error {
return runCmd("go", "generate", cCtx.Path("top")+"/...")
}
func YAMLFmtActionFunc(cCtx *cli.Context) error {
yqBin, err := exec.LookPath("yq")
if err != nil {
if !cCtx.Bool("strict") {
fmt.Fprintln(cCtx.App.ErrWriter, "# ---> no yq found; skipping")
return nil
}
return err
}
os.Chdir(cCtx.Path("top"))
return runCmd(yqBin, "eval", "--inplace", "flag-spec.yaml")
}
func DiffCheckActionFunc(cCtx *cli.Context) error {
os.Chdir(cCtx.Path("top"))
if err := runCmd("git", "diff", "--exit-code"); err != nil {
return err
}
return runCmd("git", "diff", "--cached", "--exit-code")
}
func EnsureGoimportsActionFunc(cCtx *cli.Context) error {
top := cCtx.Path("top")
os.Chdir(top)
if err := runCmd(
"goimports",
"-d",
filepath.Join(top, "internal/build/build.go"),
); err == nil {
return nil
}
os.Setenv("GOBIN", filepath.Join(top, ".local/bin"))
return runCmd("go", "install", "golang.org/x/tools/cmd/goimports@latest")
}
func EnsureGfmrunActionFunc(cCtx *cli.Context) error {
top := cCtx.Path("top")
gfmrunExe := filepath.Join(top, ".local/bin/gfmrun")
os.Chdir(top)
if v, err := sh(gfmrunExe, "--version"); err == nil && strings.TrimSpace(v) == gfmrunVersion {
return nil
}
gfmrunURL, err := url.Parse(
fmt.Sprintf(
"https://github.com/urfave/gfmrun/releases/download/%[1]s/gfmrun-%[2]s-%[3]s-%[1]s",
gfmrunVersion, runtime.GOOS, runtime.GOARCH,
),
)
if err != nil {
return err
}
return downloadFile(gfmrunURL.String(), gfmrunExe, 0755, 0755)
}
func EnsureMkdocsActionFunc(cCtx *cli.Context) error {
os.Chdir(cCtx.Path("top"))
if err := runCmd("mkdocs", "--version"); err == nil {
return nil
}
if cCtx.Bool("upgrade-pip") {
if err := runCmd("pip", "install", "-U", "pip"); err != nil {
return err
}
}
return runCmd("pip", "install", "-r", "mkdocs-requirements.txt")
}
func SetMkdocsRemoteActionFunc(cCtx *cli.Context) error {
ghToken := strings.TrimSpace(cCtx.String("github-token"))
if ghToken == "" {
return errors.New("empty github token")
}
os.Chdir(cCtx.Path("top"))
if err := runCmd("git", "remote", "rm", "origin"); err != nil {
return err
}
return runCmd(
"git", "remote", "add", "origin",
fmt.Sprintf("https://x-access-token:%[1]s@github.com/urfave/cli.git", ghToken),
)
}
func LintActionFunc(cCtx *cli.Context) error {
top := cCtx.Path("top")
os.Chdir(top)
out, err := sh(filepath.Join(top, ".local/bin/goimports"), "-l", ".")
if err != nil {
return err
}
if strings.TrimSpace(out) != "" {
fmt.Fprintln(cCtx.App.ErrWriter, "# ---> goimports -l is non-empty:")
fmt.Fprintln(cCtx.App.ErrWriter, out)
return errors.New("goimports needed")
}
return nil
}
func V2Diff(cCtx *cli.Context) error {
os.Chdir(cCtx.Path("top"))
@ -439,34 +660,29 @@ func V2Diff(cCtx *cli.Context) error {
return err
}
func V2Approve(cCtx *cli.Context) error {
top := cCtx.Path("top")
func getSize(sourcePath, builtPath, tags string) (int64, error) {
args := []string{"build"}
return runCmd(
"cp",
"-v",
filepath.Join(top, "godoc-current.txt"),
filepath.Join(top, "testdata", "godoc-v2.x.txt"),
)
}
if tags != "" {
args = append(args, []string{"-tags", tags}...)
}
func getSize(sourcePath string, builtPath string, tags string) (size int64, err error) {
// build example binary
err = runCmd("go", "build", "-tags", tags, "-o", builtPath, "-ldflags", "-s -w", sourcePath)
if err != nil {
args = append(args, []string{
"-o", builtPath,
"-ldflags", "-s -w",
sourcePath,
}...)
if err := runCmd("go", args...); err != nil {
fmt.Println("issue getting size for example binary")
return 0, err
}
// get file info
fileInfo, err := os.Stat(builtPath)
if err != nil {
fmt.Println("issue getting size for example binary")
return 0, err
}
// size!
size = fileInfo.Size()
return size, nil
return fileInfo.Size(), nil
}