Skip to content

Commit

Permalink
feat: improve publish workflow (#27)
Browse files Browse the repository at this point in the history
* feat: don't validate publish arguments

* feat: use local deno binary if env provided

* chore: exclude test from windows
  • Loading branch information
marvinhagemeister authored Feb 29, 2024
1 parent 49dd483 commit fb580a0
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 81 deletions.
165 changes: 93 additions & 72 deletions src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,21 @@ ${
"Prepare the package for publishing performing all checks and validations without uploading.",
],
["--allow-slow-types", "Allow publishing with slow types."],
[
"--provenance",
"From CI/CD system, publicly links the package to where it was built and published from.",
],
])
}
Environment variables:
${
prettyPrintRow([
["JSR_URL", "Use a different registry URL for the publish command."],
[
"DENO_BIN_PATH",
"Use specified Deno binary instead of local downloaded one.",
],
])
}
`);
Expand All @@ -106,85 +114,98 @@ if (args.length === 0) {
printHelp();
process.exit(0);
} else {
const options = parseArgs({
args,
allowPositionals: true,
options: {
"save-prod": { type: "boolean", default: true, short: "P" },
"save-dev": { type: "boolean", default: false, short: "D" },
"save-optional": { type: "boolean", default: false, short: "O" },
"dry-run": { type: "boolean", default: false },
"allow-slow-types": { type: "boolean", default: false },
token: { type: "string" },
npm: { type: "boolean", default: false },
yarn: { type: "boolean", default: false },
pnpm: { type: "boolean", default: false },
bun: { type: "boolean", default: false },
debug: { type: "boolean", default: false },
help: { type: "boolean", default: false, short: "h" },
version: { type: "boolean", default: false, short: "v" },
},
});

if (options.values.debug || process.env.DEBUG) {
setDebug(true);
}

if (options.values.help) {
printHelp();
process.exit(0);
} else if (options.values.version) {
const version = JSON.parse(
fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8"),
).version as string;
console.log(version);
process.exit(0);
} else if (options.positionals.length === 0) {
printHelp();
process.exit(0);
}

const pkgManagerName: PkgManagerName | null = options.values.pnpm
? "pnpm"
: options.values.yarn
? "yarn"
: options.values.bun
? "bun"
: null;

const cmd = options.positionals[0];
if (cmd === "i" || cmd === "install" || cmd === "add") {
run(async () => {
const packages = getPackages(options.positionals);
await install(packages, {
mode: options.values["save-dev"]
? "dev"
: options.values["save-optional"]
? "optional"
: "prod",
pkgManagerName,
});
});
} else if (cmd === "r" || cmd === "uninstall" || cmd === "remove") {
run(async () => {
const packages = getPackages(options.positionals);
await remove(packages, { pkgManagerName });
});
} else if (cmd === "publish") {
const cmd = args[0];
// Bypass cli argument validation for publish command. The underlying
// `deno publish` cli is under active development and args may change
// frequently.
if (
cmd === "publish" &&
!args.some((arg) =>
arg === "-h" || arg === "--help" || arg === "--version" || arg === "-v"
)
) {
const binFolder = path.join(__dirname, "..", ".download");
run(() =>
publish(process.cwd(), {
binFolder,
dryRun: options.values["dry-run"] ?? false,
allowSlowTypes: options.values["allow-slow-types"] ?? false,
token: options.values.token,
publishArgs: args.slice(1),
})
);
} else {
console.error(kl.red(`Unknown command: ${cmd}`));
console.log();
printHelp();
process.exit(1);
const options = parseArgs({
args,
allowPositionals: true,
options: {
"save-prod": { type: "boolean", default: true, short: "P" },
"save-dev": { type: "boolean", default: false, short: "D" },
"save-optional": { type: "boolean", default: false, short: "O" },
"dry-run": { type: "boolean", default: false },
"allow-slow-types": { type: "boolean", default: false },
token: { type: "string" },
config: { type: "string", short: "c" },
"no-config": { type: "boolean" },
check: { type: "string" },
"no-check": { type: "string" },
quiet: { type: "boolean", short: "q" },
npm: { type: "boolean", default: false },
yarn: { type: "boolean", default: false },
pnpm: { type: "boolean", default: false },
bun: { type: "boolean", default: false },
debug: { type: "boolean", default: false },
help: { type: "boolean", default: false, short: "h" },
version: { type: "boolean", default: false, short: "v" },
},
});

if (options.values.debug || process.env.DEBUG) {
setDebug(true);
}

if (options.values.help) {
printHelp();
process.exit(0);
} else if (options.values.version) {
const version = JSON.parse(
fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8"),
).version as string;
console.log(version);
process.exit(0);
} else if (options.positionals.length === 0) {
printHelp();
process.exit(0);
}

const pkgManagerName: PkgManagerName | null = options.values.pnpm
? "pnpm"
: options.values.yarn
? "yarn"
: options.values.bun
? "bun"
: null;

if (cmd === "i" || cmd === "install" || cmd === "add") {
run(async () => {
const packages = getPackages(options.positionals);
await install(packages, {
mode: options.values["save-dev"]
? "dev"
: options.values["save-optional"]
? "optional"
: "prod",
pkgManagerName,
});
});
} else if (cmd === "r" || cmd === "uninstall" || cmd === "remove") {
run(async () => {
const packages = getPackages(options.positionals);
await remove(packages, { pkgManagerName });
});
} else {
console.error(kl.red(`Unknown command: ${cmd}`));
console.log();
printHelp();
process.exit(1);
}
}
}

Expand Down
22 changes: 13 additions & 9 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,14 @@ export async function remove(packages: JsrPackage[], options: BaseOptions) {

export interface PublishOptions {
binFolder: string;
dryRun: boolean;
allowSlowTypes: boolean;
token: string | undefined;
publishArgs: string[];
}

export async function publish(cwd: string, options: PublishOptions) {
async function getOrDownloadBinPath(binFolder: string) {
const info = await getDenoDownloadUrl();

const binPath = path.join(
options.binFolder,
binFolder,
info.version,
// Ensure each binary has their own folder to avoid overwriting it
// in case jsr gets added to a project as a dependency where
Expand All @@ -120,7 +118,7 @@ export async function publish(cwd: string, options: PublishOptions) {
// Clear folder first to get rid of old download artifacts
// to avoid taking up lots of disk space.
try {
await fs.promises.rm(options.binFolder, { recursive: true });
await fs.promises.rm(binFolder, { recursive: true });
} catch (err) {
if (!(err instanceof Error) || (err as any).code !== "ENOENT") {
throw err;
Expand All @@ -130,14 +128,20 @@ export async function publish(cwd: string, options: PublishOptions) {
await downloadDeno(binPath, info);
}

return binPath;
}

export async function publish(cwd: string, options: PublishOptions) {
const binPath = process.env.DENO_BIN_PATH ??
await getOrDownloadBinPath(options.binFolder);

// Ready to publish now!
const args = [
"publish",
"--unstable-bare-node-builtins",
"--unstable-sloppy-imports",
"--no-check",
...options.publishArgs,
];
if (options.dryRun) args.push("--dry-run");
if (options.allowSlowTypes) args.push("--allow-slow-types");
if (options.token) args.push("--token", options.token);
await exec(binPath, args, cwd);
}
26 changes: 26 additions & 0 deletions test/commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,30 @@ describe("publish", () => {
await runJsr(["publish", "--dry-run", "--token", "dummy-token"], dir);
});
}).timeout(600000);

// Windows doesn't support #!/usr/bin/env
if (process.platform !== "win32") {
it("use deno binary from DENO_BIN_PATH when set", async () => {
await runInTempDir(async (dir) => {
await fs.promises.writeFile(
path.join(dir, "mod.ts"),
"export const value = 42;",
"utf-8",
);

// TODO: Change this once deno supports jsr.json
await writeJson<DenoJson>(path.join(dir, "deno.json"), {
name: "@deno/jsr-cli-test",
version: "1.0.0",
exports: {
".": "./mod.ts",
},
});

await runJsr(["publish", "--dry-run", "--non-existant-option"], dir, {
DENO_BIN_PATH: path.join(__dirname, "fixtures", "dummy.js"),
});
});
});
}
});
2 changes: 2 additions & 0 deletions test/fixtures/dummy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
console.log("it works");

0 comments on commit fb580a0

Please sign in to comment.