Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): default entrypoints #4412

Merged
merged 52 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
af30eef
introduce default entrypoints to wing cli
garysassano Sep 21, 2023
aefffd1
fix tests in `run.test.ts`
garysassano Sep 23, 2023
332da26
update cli docs
garysassano Sep 23, 2023
5265bdc
fix glob version
garysassano Sep 23, 2023
cf91309
improve code readability
garysassano Sep 23, 2023
ed950a2
expand all `wing test` entrypoints
garysassano Sep 25, 2023
c58e7bc
optimize code
garysassano Sep 25, 2023
8bd52c0
Update apps/wing/src/cli.ts
garysassano Sep 25, 2023
1af56e0
change error description
garysassano Sep 25, 2023
d8f9817
change `wing test` default entrypoints
garysassano Sep 25, 2023
b1feb62
restore `wing run`
garysassano Sep 26, 2023
983781b
add default entrypoint for `wing compile`
garysassano Sep 26, 2023
fc56c8c
fix `wing test` and `wing compile` default entrypoints
garysassano Sep 26, 2023
e0340fe
Update docs/docs/06-tools/01-cli.md
garysassano Sep 26, 2023
52478c9
fix Docosaurus notes
garysassano Sep 26, 2023
5e23d19
Update docs/docs/06-tools/01-cli.md
garysassano Sep 26, 2023
5e70a8f
reorder CompileOptions for cleaner look
garysassano Sep 26, 2023
dd4249b
update CLI docs for default entrypoints
garysassano Sep 26, 2023
bdebf45
update glob version
garysassano Sep 27, 2023
38514e0
update `wing it` tests
garysassano Sep 28, 2023
489f4f7
Merge branch 'main' into garysassano/cli-default-entrypoints
garysassano Sep 28, 2023
825b83b
update `wing compile` tests
garysassano Sep 28, 2023
2b08ec5
update dependencies
garysassano Sep 28, 2023
57a67d0
Merge branch 'main' into garysassano/cli-default-entrypoints
monadabot Sep 28, 2023
9b11f44
chore: self mutation (e2e-2of2.diff)
monadabot Sep 28, 2023
7167f48
Update apps/wing/package.json
garysassano Sep 29, 2023
b9c4d7a
Remove `*.test.w` as default entrypoint for `wing it` and `wing compile`
garysassano Sep 29, 2023
793da05
align `wing test` to docs
garysassano Sep 29, 2023
6834402
improve test names
garysassano Sep 29, 2023
2e0b6a2
fix compile plugins
garysassano Sep 30, 2023
12d2f71
Merge branch 'main' into garysassano/cli-default-entrypoints
monadabot Sep 30, 2023
bdbad19
chore: self mutation (e2e-2of2.diff)
monadabot Sep 30, 2023
cdbec74
Update apps/wing/src/commands/test.ts
garysassano Oct 1, 2023
ad669a1
Update docs/docs/06-tools/01-cli.md
garysassano Oct 1, 2023
93f797c
Update docs/docs/06-tools/01-cli.md
garysassano Oct 1, 2023
2751620
Update docs/docs/06-tools/01-cli.md
garysassano Oct 1, 2023
46c84f8
Update docs/docs/06-tools/01-cli.md
garysassano Oct 1, 2023
e6a1f02
Merge branch 'main' into garysassano/cli-default-entrypoints
garysassano Oct 3, 2023
11723a6
move `wing test` default entrypoint logic
garysassano Oct 4, 2023
26b25d1
Merge branch 'main' into garysassano/cli-default-entrypoints
garysassano Oct 4, 2023
1ef7f5c
fix duplicated imports
garysassano Oct 4, 2023
23adadf
move glob import
garysassano Oct 4, 2023
2be2e12
switch error message brackets
garysassano Oct 4, 2023
262582b
Merge branch 'main' into garysassano/cli-default-entrypoints
monadabot Oct 4, 2023
edcf225
chore: self mutation (build.diff)
monadabot Oct 4, 2023
526d406
handle windows paths
garysassano Oct 4, 2023
1ce5b95
replace globs only on windows
garysassano Oct 4, 2023
d77a7c3
make compile error more helpful
garysassano Oct 7, 2023
354b73a
make run error more helpful
garysassano Oct 7, 2023
88d6998
Merge branch 'main' into garysassano/cli-default-entrypoints
garysassano Oct 7, 2023
5b3759a
update run tests
garysassano Oct 7, 2023
d17b211
Merge branch 'main' into garysassano/cli-default-entrypoints
MarkMcCulloh Oct 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/wing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"commander": "^10.0.1",
"compare-versions": "^5.0.3",
"debug": "^4.3.4",
"glob": "^10.3.10",
"nanoid": "^3.3.6",
"open": "^8.4.2",
"ora": "^5.4.1",
Expand Down
5 changes: 2 additions & 3 deletions apps/wing/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { collectCommandAnalytics } from "./analytics/collect";
import { optionallyDisplayDisclaimer } from "./analytics/disclaimer";
import { exportAnalytics } from "./analytics/export";
import { currentPackage } from "./util";

export const PACKAGE_VERSION = currentPackage.version;
let analyticsExportFile: Promise<string | undefined>;

Expand Down Expand Up @@ -133,7 +132,7 @@ async function main() {
program
.command("compile")
.description("Compiles a Wing program")
.argument("<entrypoint>", "program .w entrypoint")
.argument("[entrypoint]", "program .w entrypoint")
.addOption(
new Option("-t, --target <target>", "Target platform")
.choices(["tf-aws", "tf-azure", "tf-gcp", "sim", "awscdk"])
Expand All @@ -150,7 +149,7 @@ async function main() {
.description(
"Compiles a Wing program and runs all functions with the word 'test' or start with 'test:' in their resource identifiers"
)
.argument("<entrypoint...>", "all entrypoints to test")
.argument("[entrypoint...]", "all files to test (globs are supported)")
.addOption(
new Option("-t, --target <target>", "Target platform")
.choices(["tf-aws", "tf-azure", "tf-gcp", "sim", "awscdk"])
Expand Down
35 changes: 34 additions & 1 deletion apps/wing/src/commands/compile.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { readdir, stat, writeFile } from "fs/promises";
import { writeFileSync } from "fs";
import { readdir, stat, writeFile, mkdtemp } from "fs/promises";
import { tmpdir } from "os";
import { join, resolve } from "path";
import { Target } from "@winglang/compiler";
import { describe, test, expect } from "vitest";
Expand Down Expand Up @@ -40,6 +42,37 @@ describe(
expect(files).toEqual([".wing", "connections.json", "simulator.json", "tree.json"]);
});

test("should be able to compile to default target sim", async () => {
const outDir = await compile(exampleFilePath, {
targetDir: `${await generateTmpDir()}/target`,
});

const stats = await stat(outDir);
expect(stats.isDirectory()).toBeTruthy();
const files = (await readdir(outDir)).sort();
expect(files.length).toBeGreaterThan(0);
expect(files).toEqual([".wing", "connections.json", "simulator.json", "tree.json"]);
});

test("should be able to compile the only entrypoint file in current directory", async () => {
const outDir = await mkdtemp(join(tmpdir(), "-wing-compile-test"));
const prevdir = process.cwd();

try {
process.chdir(outDir);
writeFileSync("main.w", "bring cloud;");
await compile();

const stats = await stat(outDir);
expect(stats.isDirectory()).toBeTruthy();
const files = (await readdir(outDir)).sort();
expect(files.length).toBeGreaterThan(0);
expect(files).toEqual(["main.w", "target"]);
} finally {
process.chdir(prevdir);
}
});

test("should error if a nonexistent file is compiled", async () => {
return expect(compile("non-existent-file.w", { target: Target.SIM })).rejects.toThrowError(
/Source file cannot be found/
Expand Down
27 changes: 20 additions & 7 deletions apps/wing/src/commands/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as wingCompiler from "@winglang/compiler";
import chalk from "chalk";
import { CHARS_ASCII, emitDiagnostic, File, Label } from "codespan-wasm";
import debug from "debug";
import { glob } from "glob";

// increase the stack trace limit to 50, useful for debugging Rust panics
// (not setting the limit too high in case of infinite recursion)
Expand All @@ -17,19 +18,23 @@ const log = debug("wing:compile");
* This is passed from Commander to the `compile` function.
*/
export interface CompileOptions {
readonly target: wingCompiler.Target;
readonly plugins?: string[];
readonly rootId?: string;
readonly plugins?: string[];
/**
* Whether to run the compiler in `wing test` mode. This may create multiple
* copies of the application resources in order to run tests in parallel.
* The target to compile to
* @default wingCompiler.Target.SIM
*/
readonly testing?: boolean;
readonly target?: wingCompiler.Target;
/**
* The location to save the compilation output
* @default "./target"
*/
readonly targetDir?: string;
/**
* Whether to run the compiler in `wing test` mode. This may create multiple
* copies of the application resources in order to run tests in parallel.
*/
readonly testing?: boolean;
}

/**
Expand All @@ -38,14 +43,22 @@ export interface CompileOptions {
* @param options Compile options.
* @returns the output directory
*/
export async function compile(entrypoint: string, options: CompileOptions): Promise<string> {
export async function compile(entrypoint?: string, options?: CompileOptions): Promise<string> {
if (!entrypoint) {
const wingFiles = await glob("{main,*.main}.w");
if (wingFiles.length !== 1) {
throw new Error("Please specify which file you want to compile");
garysassano marked this conversation as resolved.
Show resolved Hide resolved
}
entrypoint = wingFiles[0];
}

const coloring = chalk.supportsColor ? chalk.supportsColor.hasBasic : false;
try {
return await wingCompiler.compile(entrypoint, {
...options,
log,
color: coloring,
targetDir: options.targetDir,
target: options?.target || wingCompiler.Target.SIM,
});
} catch (error) {
if (error instanceof wingCompiler.CompileError) {
Expand Down
74 changes: 51 additions & 23 deletions apps/wing/src/commands/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ vi.mock("@wingconsole/app", () => {
};
});

test("wing it runs the only .w file", async () => {
test("wing it runs the only entrypoint file named main.w", async () => {
const workdir = await mkdtemp(join(tmpdir(), "-wing-it-test"));
const prevdir = process.cwd();
try {
process.chdir(workdir);

writeFileSync("foo.w", "bring cloud;");
writeFileSync("main.w", "bring cloud;");

await run();
expect(createConsoleApp).toBeCalledWith({
wingfile: resolve("foo.w"),
wingfile: resolve("main.w"),
requestedPort: 3000,
hostUtils: expect.anything(),
requireAcceptTerms: false,
Expand All @@ -40,37 +40,65 @@ test("wing it runs the only .w file", async () => {
}
});

test("wing it with no file throws error for a directory with more than 1 .w file", async () => {
test("wing it runs the only entrypoint file ending with .main.w", async () => {
const workdir = await mkdtemp(join(tmpdir(), "-wing-it-test"));
const prevdir = process.cwd();
try {
process.chdir(workdir);

writeFileSync("foo.w", "bring cloud;");
writeFileSync("bar.w", "bring cloud;");
writeFileSync("foo.main.w", "bring cloud;");

await run();
expect(createConsoleApp).toBeCalledWith({
wingfile: resolve("foo.main.w"),
requestedPort: 3000,
hostUtils: expect.anything(),
requireAcceptTerms: false,
});
expect(open).toBeCalledWith("http://localhost:3000/");
} finally {
process.chdir(prevdir);
}
});

test("wing it doesn't run the only entrypoint file ending with .test.w", async () => {
const workdir = await mkdtemp(join(tmpdir(), "-wing-it-test"));
const prevdir = process.cwd();
try {
process.chdir(workdir);

writeFileSync("foo.test.w", "bring cloud;");

await expect(run).rejects.toThrow("Please specify which file you want to run");
} finally {
process.chdir(prevdir);
}
});

test("wing it with a file runs", async () => {
test("wing it throws error for a directory with a non-entrypoint file", async () => {
const workdir = await mkdtemp(join(tmpdir(), "-wing-it-test"));
const prevdir = process.cwd();
try {
process.chdir(workdir);

writeFileSync("foo.w", "bring cloud;");

await run("foo.w");
expect(createConsoleApp).toBeCalledWith({
wingfile: resolve("foo.w"),
requestedPort: 3000,
hostUtils: expect.anything(),
requireAcceptTerms: false,
});
expect(open).toBeCalledWith("http://localhost:3000/");
await expect(run).rejects.toThrow("Please specify which file you want to run");
} finally {
process.chdir(prevdir);
}
});

test("wing it throws error for a directory with more than one entrypoint file", async () => {
const workdir = await mkdtemp(join(tmpdir(), "-wing-it-test"));
const prevdir = process.cwd();
try {
process.chdir(workdir);

writeFileSync("main.w", "bring cloud;");
writeFileSync("foo.main.w", "bring cloud;");

await expect(run).rejects.toThrow("Please specify which file you want to run");
} finally {
process.chdir(prevdir);
}
Expand All @@ -79,7 +107,7 @@ test("wing it with a file runs", async () => {
test("wing it with a nested file runs", async () => {
const workdir = await mkdtemp(join(tmpdir(), "-wing-it-test"));
const subdir = join(workdir, "subdir");
const filePath = join(subdir, "foo.w");
const filePath = join(subdir, "foo.main.w");
const prevdir = process.cwd();
try {
process.chdir(workdir);
Expand All @@ -106,9 +134,9 @@ test("wing it with an invalid file throws exception", async () => {
try {
process.chdir(workdir);

writeFileSync("foo.w", "bring cloud;");
writeFileSync("foo.main.w", "bring cloud;");

await expect(run("bar.w")).rejects.toThrow("bar.w doesn't exist");
await expect(run("bar.main.w")).rejects.toThrow("bar.main.w doesn't exist");
} finally {
process.chdir(prevdir);
}
Expand All @@ -120,11 +148,11 @@ test("wing it with a custom port runs", async () => {
try {
process.chdir(workdir);

writeFileSync("foo.w", "bring cloud;");
writeFileSync("foo.main.w", "bring cloud;");

await run("foo.w", { port: "5000" });
await run("foo.main.w", { port: "5000" });
expect(createConsoleApp).toBeCalledWith({
wingfile: resolve("foo.w"),
wingfile: resolve("foo.main.w"),
requestedPort: 5000,
hostUtils: expect.anything(),
requireAcceptTerms: false,
Expand All @@ -141,10 +169,10 @@ test("wing it throws when invalid port number is used", async () => {
try {
process.chdir(workdir);

writeFileSync("foo.w", "bring cloud;");
writeFileSync("foo.main.w", "bring cloud;");

await expect(async () => {
await run("foo.w", { port: "not a number" });
await run("foo.main.w", { port: "not a number" });
}).rejects.toThrowError('"not a number" is not a number');
} finally {
process.chdir(prevdir);
Expand Down
5 changes: 3 additions & 2 deletions apps/wing/src/commands/run.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { readdirSync, existsSync } from "fs";
import { existsSync } from "fs";
import { resolve } from "path";
import { createConsoleApp } from "@wingconsole/app";
import { debug } from "debug";
import { glob } from "glob";
import open from "open";
import { parseNumericString } from "../util";

Expand Down Expand Up @@ -35,7 +36,7 @@ export async function run(entrypoint?: string, options?: RunOptions) {
const openBrowser = options?.open ?? true;

if (!entrypoint) {
const wingFiles = readdirSync(".").filter((item) => item.endsWith(".w"));
const wingFiles = await glob("{main,*.main}.w");
if (wingFiles.length !== 1) {
throw new Error("Please specify which file you want to run");
}
Expand Down
20 changes: 19 additions & 1 deletion apps/wing/src/commands/test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as cp from "child_process";
import { readFile, rm, rmSync } from "fs";
import * as os from "os";
import { basename, resolve, sep } from "path";
import { promisify } from "util";
import { Target } from "@winglang/compiler";
import { std, simulator } from "@winglang/sdk";
import chalk from "chalk";
import debug from "debug";
import { glob } from "glob";
import { nanoid } from "nanoid";
import { compile, CompileOptions } from "./compile";
import { generateTmpDir, withSpinner } from "../util";
Expand All @@ -29,6 +31,22 @@ export interface TestOptions extends CompileOptions {
}

export async function test(entrypoints: string[], options: TestOptions): Promise<number> {
let patterns;

if (entrypoints.length === 0) {
patterns = ["*.test.w"];
} else {
patterns =
os.platform() === "win32"
? entrypoints.map((entrypoint) => entrypoint.replace(/\\/g, "/"))
: entrypoints;
}

const expandedEntrypoints = await glob(patterns);
if (expandedEntrypoints.length === 0) {
throw new Error(`No matching files found for patterns: [${patterns.join(", ")}]`);
}

const startTime = Date.now();
const results: { testName: string; results: std.TestResult[] }[] = [];
const testFile = async (entrypoint: string) => {
Expand All @@ -44,7 +62,7 @@ export async function test(entrypoints: string[], options: TestOptions): Promise
});
}
};
await Promise.all(entrypoints.map(testFile));
await Promise.all(expandedEntrypoints.map(testFile));
printResults(results, Date.now() - startTime);

// if we have any failures, exit with 1
Expand Down
Loading
Loading