From 1240b904753eb6ae70b0d5ca3ed9e5d6428fab42 Mon Sep 17 00:00:00 2001 From: Nathan Sarang-Walters Date: Mon, 16 Dec 2024 15:09:31 -0800 Subject: [PATCH 1/6] Implement --check flag for fmt --- d2cli/fmt.go | 24 +++++++++++++++++++++--- d2cli/main.go | 7 ++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/d2cli/fmt.go b/d2cli/fmt.go index a2b8371589..61daf15ea0 100644 --- a/d2cli/fmt.go +++ b/d2cli/fmt.go @@ -12,9 +12,10 @@ import ( "oss.terrastruct.com/d2/d2format" "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") 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") } + unformattedCount := 0 + for _, inputPath := range ms.Opts.Args { if inputPath != "-" { inputPath = ms.AbsPath(inputPath) @@ -43,10 +46,25 @@ func fmtCmd(ctx context.Context, ms *xmain.State) (err error) { output := []byte(d2format.Format(m)) if !bytes.Equal(output, input) { - if err := ms.WritePath(inputPath, output); err != nil { - return err + if check { + 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 } diff --git a/d2cli/main.go b/d2cli/main.go index eeefd6ae91..0240e9d7ca 100644 --- a/d2cli/main.go +++ b/d2cli/main.go @@ -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.") 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) if err != nil { return err @@ -153,7 +158,7 @@ func Run(ctx context.Context, ms *xmain.State) (err error) { themesCmd(ctx, ms) return nil case "fmt": - return fmtCmd(ctx, ms) + return fmtCmd(ctx, ms, *checkFlag) case "version": if len(ms.Opts.Flags.Args()) > 1 { return xmain.UsageErrorf("version subcommand accepts no arguments") From e88e243d4c1f773af243bd54489fb2fe84426d04 Mon Sep 17 00:00:00 2001 From: Nathan Sarang-Walters Date: Mon, 16 Dec 2024 15:29:21 -0800 Subject: [PATCH 2/6] Add E2E test --- e2etests-cli/main_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/e2etests-cli/main_test.go b/e2etests-cli/main_test.go index 432d59aff5..ff764ac5e1 100644 --- a/e2etests-cli/main_test.go +++ b/e2etests-cli/main_test.go @@ -1005,6 +1005,19 @@ layers: { assert.Equal(t, "x -> y\n", string(gotBar)) }, }, + { + name: "fmt-check", + 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`) + err := runTestMainPersist(t, ctx, dir, env, "fmt", "--check", "foo.d2", "bar.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: "watch-regular", serial: true, From 6da8e9cfd5ece2609e88162d41bff3278c705780 Mon Sep 17 00:00:00 2001 From: Nathan Sarang-Walters Date: Mon, 16 Dec 2024 15:37:22 -0800 Subject: [PATCH 3/6] Update changelog --- ci/release/changelogs/next.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 302685f371..a6123c27f0 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -4,6 +4,7 @@ - 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) - Markdown: Github-flavored tables work in `md` blocks [#2221](https://github.com/terrastruct/d2/pull/2221) +- `d2 fm` now supports a `--check` flag [#2253](https://github.com/terrastruct/d2/pull/2253) #### Improvements 🧹 From cff7a8596db1b1d0c6ff599ae85038f0530c5b48 Mon Sep 17 00:00:00 2001 From: Nathan Sarang-Walters Date: Mon, 16 Dec 2024 15:40:12 -0800 Subject: [PATCH 4/6] Fix typo --- ci/release/changelogs/next.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index a6123c27f0..0226ca55df 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -4,7 +4,7 @@ - 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) - Markdown: Github-flavored tables work in `md` blocks [#2221](https://github.com/terrastruct/d2/pull/2221) -- `d2 fm` now supports a `--check` flag [#2253](https://github.com/terrastruct/d2/pull/2253) +- `d2 fmt` now supports a `--check` flag [#2253](https://github.com/terrastruct/d2/pull/2253) #### Improvements 🧹 From 48cba038db646bb76cc08ff3965ffcf880c6ccea Mon Sep 17 00:00:00 2001 From: Nathan Sarang-Walters Date: Mon, 16 Dec 2024 15:45:31 -0800 Subject: [PATCH 5/6] Update the manpage --- ci/release/template/man/d2.1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ci/release/template/man/d2.1 b/ci/release/template/man/d2.1 index 1a5ebee02e..42cead1790 100644 --- a/ci/release/template/man/d2.1 +++ b/ci/release/template/man/d2.1 @@ -125,6 +125,9 @@ In watch mode, images used in icons are cached for subsequent compilations. This .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 .Ns . +.It Fl -check Ar false +Check that the specified files are formatted correctly +.Ns . .It Fl h , -help Print usage information and exit .Ns . @@ -180,6 +183,8 @@ See --font-semibold flag. See --animate-interval flag. .It Ev Sy D2_TIMEOUT See --timeout flag. +.It Ev Sy D2_CHECK +See --check flag. .El .Bl -tag -width Ds .It Ev Sy DEBUG From 7cb58fc049bdb1cc03f9fcefc60a88bfc847a04b Mon Sep 17 00:00:00 2001 From: Nathan Sarang-Walters Date: Tue, 17 Dec 2024 09:45:50 -0800 Subject: [PATCH 6/6] Improve tests --- e2etests-cli/main_test.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/e2etests-cli/main_test.go b/e2etests-cli/main_test.go index ff764ac5e1..3c300b3374 100644 --- a/e2etests-cli/main_test.go +++ b/e2etests-cli/main_test.go @@ -1006,11 +1006,12 @@ layers: { }, }, { - name: "fmt-check", + 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`) - err := runTestMainPersist(t, ctx, dir, env, "fmt", "--check", "foo.d2", "bar.d2") + 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") @@ -1018,6 +1019,15 @@ layers: { 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", serial: true,