/ scripts / cargo-release.ts
cargo-release.ts
 1  #!/usr/bin/env -S deno run --allow-run
 2  
 3  import { defineCommand, runMain } from "npm:citty";
 4  import { runSyncLoroVersion } from "./sync-loro-version.ts";
 5  
 6  async function runCargoRelease(version: string): Promise<string> {
 7    const process = new Deno.Command("cargo", {
 8      args: ["release", "version", "--workspace", version],
 9    });
10    const output = await process.output();
11    return new TextDecoder().decode(output.stderr);
12  }
13  
14  function parseNoChangesCrates(output: string): string[] {
15    const lines = output.split("\n");
16    const noChangesCrates: string[] = [];
17  
18    for (const line of lines) {
19      if (line.includes("despite no changes made since tag")) {
20        const match = line.match(/updating ([^ ]+) to/);
21        if (match) {
22          noChangesCrates.push(match[1]);
23        }
24      }
25    }
26  
27    return noChangesCrates;
28  }
29  
30  function generateOptimizedCommand(
31    version: string,
32    excludedCrates: string[],
33  ): string {
34    const excludeFlags = excludedCrates.map((crate) => `--exclude ${crate}`).join(
35      " ",
36    );
37    return `cargo release version --workspace ${version} ${excludeFlags}`;
38  }
39  
40  function isValidVersion(version: string): boolean {
41    // Matches format like 1.2.3
42    return /^\d+\.\d+\.\d+$/.test(version);
43  }
44  
45  const main = defineCommand({
46    meta: {
47      name: "cargo-release",
48      version: "1.0.0",
49      description: "Bump version with optimized excludes",
50    },
51    args: {
52      version: {
53        type: "positional",
54        description: "Version to bump to (format: x.y.z)",
55        required: true,
56      },
57    },
58    async run({ args }) {
59      const version = args.version;
60      console.log(version);
61  
62      if (!isValidVersion(version)) {
63        throw new Error("Version must be in format x.y.z (e.g., 1.2.3)");
64      }
65  
66      runSyncLoroVersion(version);
67      const output = await runCargoRelease(version);
68      console.log("Original output:");
69      console.log(output);
70  
71      const noChangesCrates = parseNoChangesCrates(output);
72      const excludeFlags = noChangesCrates.map((crate) => `--exclude ${crate}`).join(
73        " ",
74      );
75      console.log("\n 1. Run command to bump version:");
76      console.log(generateOptimizedCommand(version, noChangesCrates));
77      console.log("2. Then Commit the changes");
78      console.log("3. Run command to publish:");
79      console.log(
80        `cargo release publish --workspace ${excludeFlags}`,
81      );
82      console.log("4. Tag:");
83      console.log(
84        `cargo release tag --workspace ${excludeFlags}`,
85      );
86      console.log("5. Push:");
87      console.log(
88        `git push --tags && git push`,
89      );
90    },
91  });
92  
93  runMain(main);