diff --git a/test/packaging/lint-once.test.ts b/test/packaging/lint-once.test.ts index 8972f5c..895bb6b 100644 --- a/test/packaging/lint-once.test.ts +++ b/test/packaging/lint-once.test.ts @@ -39,11 +39,12 @@ // one pass over literals, so a value that itself names another variable, a // value built by a make function (`$(shell ...)`, `$(addprefix ...)`), and the // body of a `define`/`endef` block are not expanded and not followed. A -// `docker build` resolves to the file named by `-f`, `-f=`, `--file` or -// `--file=`, wherever in the invocation that flag sits, and to `Dockerfile` -// when it names none; a Dockerfile chosen some other way — a bundled short -// flag cluster (`-qf `), a value this walk cannot expand to a literal — -// resolves to the default rather than to the real file. Within those edges, a +// `docker build` resolves to the file named by `-f`, `-f=`, `-f` with +// the value attached to the flag, `--file` or `--file=`, wherever in the +// invocation that flag sits, and to `Dockerfile` when it names none; a +// Dockerfile chosen some other way — a bundled short flag cluster +// (`-qf `), a value this walk cannot expand to a literal — resolves to +// the default rather than to the real file. Within those edges, a // prettier call is caught wherever it is added. // // Two entrypoints are walked, because they cover different graphs: `make check` @@ -437,16 +438,19 @@ const edgesOf = (line: string): string[] => { // it the count would miss the one invocation that is supposed to survive. // // Every spelling of the file flag is read, not just `-f `. Docker - // accepts `--file `, `--file=` and `-f=` for the same - // thing, and matching `-f ` alone resolved all of them to the default + // accepts `--file `, `--file=`, `-f=` and the value + // attached to the short flag as one token (`-f`) for the same thing, + // and matching `-f ` alone resolved all of them to the default // `Dockerfile` edge — so `docker build --file=Dockerfile.lint .` in a // recipe was followed into the wrong file, counted nothing, and reported // green. The flag is searched for anywhere in the invocation, as `-f` // already was, because a real build line wraps it in `--build-arg` and // other flags. A leading `\s` is required so that a longer flag ending in - // the same letters cannot supply the match. + // the same letters cannot supply the match, and the attached form is + // allowed only for the short flag, so that `--force-rm` — a long flag that + // merely starts with the same letters — still does not read as one. if (/\bdocker\s+build\b/.test(line)) { - const file = /\s(?:-f|--file)[=\s]+(\S+)/.exec(line); + const file = /\s(?:--file[=\s]+|-f=?\s*)(\S+)/.exec(line); edges.push(`docker:${file === null ? "Dockerfile" : file[1]}`); } @@ -1021,6 +1025,21 @@ describe("the resolver reads what the shell would run", () => { ]); }); + // The value may be attached to the short flag with no separator at all: + // `-fDockerfile.lint` is a single token, and the flag parser reads it as + // `-f` naming that file, exactly as `-f Dockerfile.lint` does. Requiring a + // separator sent it to the default `Dockerfile` edge instead — the same + // false green as the long spellings above, and one the header promised was + // followed: a second prettier pass added as `docker build + // -fDockerfile.lint .` was resolved into the wrong file, counted nothing, + // and left the build green. `-fFILE` is an ordinary thing for a human to + // write, so it is followed rather than merely documented as unfollowed. + it("follows a short file flag with its value attached", () => { + expect(edgesOf("docker build -fDockerfile.lint .")).toEqual([ + "docker:Dockerfile.lint", + ]); + }); + // The flag is found anywhere in the invocation rather than at a fixed // position, matching how `-f` was already read, since a real build line // carries `--build-arg` and friends around it.