Merge pull request #2253 from nwalters512/fmt-check
cli: Implement d2 fmt --check
This commit is contained in:
commit
f2bac02276
5 changed files with 56 additions and 4 deletions
|
|
@ -4,6 +4,7 @@
|
||||||
- Connections now support `link` [#1955](https://github.com/terrastruct/d2/pull/1955)
|
- Connections now support `link` [#1955](https://github.com/terrastruct/d2/pull/1955)
|
||||||
- Vars: vars in markdown blocks are substituted [#2218](https://github.com/terrastruct/d2/pull/2218)
|
- Vars: vars in markdown blocks are substituted [#2218](https://github.com/terrastruct/d2/pull/2218)
|
||||||
- Markdown: Github-flavored tables work in `md` blocks [#2221](https://github.com/terrastruct/d2/pull/2221)
|
- Markdown: Github-flavored tables work in `md` blocks [#2221](https://github.com/terrastruct/d2/pull/2221)
|
||||||
|
- `d2 fmt` now supports a `--check` flag [#2253](https://github.com/terrastruct/d2/pull/2253)
|
||||||
|
|
||||||
#### Improvements 🧹
|
#### Improvements 🧹
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,9 @@ In watch mode, images used in icons are cached for subsequent compilations. This
|
||||||
.It Fl -timeout Ar 120
|
.It Fl -timeout Ar 120
|
||||||
The maximum number of seconds that D2 runs for before timing out and exiting. When rendering a large diagram, it is recommended to increase this value
|
The maximum number of seconds that D2 runs for before timing out and exiting. When rendering a large diagram, it is recommended to increase this value
|
||||||
.Ns .
|
.Ns .
|
||||||
|
.It Fl -check Ar false
|
||||||
|
Check that the specified files are formatted correctly
|
||||||
|
.Ns .
|
||||||
.It Fl h , -help
|
.It Fl h , -help
|
||||||
Print usage information and exit
|
Print usage information and exit
|
||||||
.Ns .
|
.Ns .
|
||||||
|
|
@ -180,6 +183,8 @@ See --font-semibold flag.
|
||||||
See --animate-interval flag.
|
See --animate-interval flag.
|
||||||
.It Ev Sy D2_TIMEOUT
|
.It Ev Sy D2_TIMEOUT
|
||||||
See --timeout flag.
|
See --timeout flag.
|
||||||
|
.It Ev Sy D2_CHECK
|
||||||
|
See --check flag.
|
||||||
.El
|
.El
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Ev Sy DEBUG
|
.It Ev Sy DEBUG
|
||||||
|
|
|
||||||
24
d2cli/fmt.go
24
d2cli/fmt.go
|
|
@ -12,9 +12,10 @@ import (
|
||||||
|
|
||||||
"oss.terrastruct.com/d2/d2format"
|
"oss.terrastruct.com/d2/d2format"
|
||||||
"oss.terrastruct.com/d2/d2parser"
|
"oss.terrastruct.com/d2/d2parser"
|
||||||
|
"oss.terrastruct.com/d2/lib/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fmtCmd(ctx context.Context, ms *xmain.State) (err error) {
|
func fmtCmd(ctx context.Context, ms *xmain.State, check bool) (err error) {
|
||||||
defer xdefer.Errorf(&err, "failed to fmt")
|
defer xdefer.Errorf(&err, "failed to fmt")
|
||||||
|
|
||||||
ms.Opts = xmain.NewOpts(ms.Env, ms.Opts.Flags.Args()[1:])
|
ms.Opts = xmain.NewOpts(ms.Env, ms.Opts.Flags.Args()[1:])
|
||||||
|
|
@ -22,6 +23,8 @@ func fmtCmd(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
return xmain.UsageErrorf("fmt must be passed at least one file to be formatted")
|
return xmain.UsageErrorf("fmt must be passed at least one file to be formatted")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unformattedCount := 0
|
||||||
|
|
||||||
for _, inputPath := range ms.Opts.Args {
|
for _, inputPath := range ms.Opts.Args {
|
||||||
if inputPath != "-" {
|
if inputPath != "-" {
|
||||||
inputPath = ms.AbsPath(inputPath)
|
inputPath = ms.AbsPath(inputPath)
|
||||||
|
|
@ -43,10 +46,25 @@ func fmtCmd(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
|
|
||||||
output := []byte(d2format.Format(m))
|
output := []byte(d2format.Format(m))
|
||||||
if !bytes.Equal(output, input) {
|
if !bytes.Equal(output, input) {
|
||||||
if err := ms.WritePath(inputPath, output); err != nil {
|
if check {
|
||||||
return err
|
unformattedCount += 1
|
||||||
|
log.Warn(ctx, inputPath)
|
||||||
|
} else {
|
||||||
|
if err := ms.WritePath(inputPath, output); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if unformattedCount > 0 {
|
||||||
|
pluralFiles := "file"
|
||||||
|
if unformattedCount > 1 {
|
||||||
|
pluralFiles = "files"
|
||||||
|
}
|
||||||
|
|
||||||
|
return xmain.ExitErrorf(1, "found %d unformatted %s. Run d2 fmt to fix.", unformattedCount, pluralFiles)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,11 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
fontBoldFlag := ms.Opts.String("D2_FONT_BOLD", "font-bold", "", "", "path to .ttf file to use for the bold font. If none provided, Source Sans Pro Bold is used.")
|
fontBoldFlag := ms.Opts.String("D2_FONT_BOLD", "font-bold", "", "", "path to .ttf file to use for the bold font. If none provided, Source Sans Pro Bold is used.")
|
||||||
fontSemiboldFlag := ms.Opts.String("D2_FONT_SEMIBOLD", "font-semibold", "", "", "path to .ttf file to use for the semibold font. If none provided, Source Sans Pro Semibold is used.")
|
fontSemiboldFlag := ms.Opts.String("D2_FONT_SEMIBOLD", "font-semibold", "", "", "path to .ttf file to use for the semibold font. If none provided, Source Sans Pro Semibold is used.")
|
||||||
|
|
||||||
|
checkFlag, err := ms.Opts.Bool("D2_CHECK", "check", "", false, "check that the specified files are formatted correctly.")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
plugins, err := d2plugin.ListPlugins(ctx)
|
plugins, err := d2plugin.ListPlugins(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -153,7 +158,7 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
themesCmd(ctx, ms)
|
themesCmd(ctx, ms)
|
||||||
return nil
|
return nil
|
||||||
case "fmt":
|
case "fmt":
|
||||||
return fmtCmd(ctx, ms)
|
return fmtCmd(ctx, ms, *checkFlag)
|
||||||
case "version":
|
case "version":
|
||||||
if len(ms.Opts.Flags.Args()) > 1 {
|
if len(ms.Opts.Flags.Args()) > 1 {
|
||||||
return xmain.UsageErrorf("version subcommand accepts no arguments")
|
return xmain.UsageErrorf("version subcommand accepts no arguments")
|
||||||
|
|
|
||||||
|
|
@ -1005,6 +1005,29 @@ layers: {
|
||||||
assert.Equal(t, "x -> y\n", string(gotBar))
|
assert.Equal(t, "x -> y\n", string(gotBar))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "fmt-check-unformatted",
|
||||||
|
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||||
|
writeFile(t, dir, "foo.d2", `a ---> b`)
|
||||||
|
writeFile(t, dir, "bar.d2", `x ---> y`)
|
||||||
|
writeFile(t, dir, "baz.d2", "a -> z\n")
|
||||||
|
err := runTestMainPersist(t, ctx, dir, env, "fmt", "--check", "foo.d2", "bar.d2", "baz.d2")
|
||||||
|
assert.ErrorString(t, err, "failed to wait xmain test: e2etests-cli/d2: failed to fmt: exiting with code 1: found 2 unformatted files. Run d2 fmt to fix.")
|
||||||
|
gotFoo := readFile(t, dir, "foo.d2")
|
||||||
|
gotBar := readFile(t, dir, "bar.d2")
|
||||||
|
assert.Equal(t, "a ---> b", string(gotFoo))
|
||||||
|
assert.Equal(t, "x ---> y", string(gotBar))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fmt-check-formatted",
|
||||||
|
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||||
|
writeFile(t, dir, "foo.d2", "a -> b\n")
|
||||||
|
writeFile(t, dir, "bar.d2", "x -> y\n")
|
||||||
|
err := runTestMainPersist(t, ctx, dir, env, "fmt", "--check", "foo.d2", "bar.d2")
|
||||||
|
assert.Success(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "watch-regular",
|
name: "watch-regular",
|
||||||
serial: true,
|
serial: true,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue