@aptos-labs/aptos-cli 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +109 -0
  2. package/dist/aptos.js +7 -2
  3. package/dist/aptos.js.map +1 -1
  4. package/dist/examples/examples.test.js +69 -0
  5. package/dist/examples/examples.test.js.map +1 -0
  6. package/dist/tasks/install.js +82 -31
  7. package/dist/tasks/install.js.map +1 -1
  8. package/dist/tasks/install.test.js +227 -0
  9. package/dist/tasks/install.test.js.map +1 -0
  10. package/dist/tasks/run.js +13 -8
  11. package/dist/tasks/run.js.map +1 -1
  12. package/dist/tasks/run.test.js +92 -0
  13. package/dist/tasks/run.test.js.map +1 -0
  14. package/dist/tasks/update.js +55 -20
  15. package/dist/tasks/update.js.map +1 -1
  16. package/dist/utils/brewOperations.js +30 -4
  17. package/dist/utils/brewOperations.js.map +1 -1
  18. package/dist/utils/brewOperations.test.js +83 -0
  19. package/dist/utils/brewOperations.test.js.map +1 -0
  20. package/dist/utils/consts.js.map +1 -1
  21. package/dist/utils/execSyncShell.js +6 -2
  22. package/dist/utils/execSyncShell.js.map +1 -1
  23. package/dist/utils/executableIsAvailable.js +12 -0
  24. package/dist/utils/executableIsAvailable.js.map +1 -0
  25. package/dist/utils/getLocalBinPath.js +76 -20
  26. package/dist/utils/getLocalBinPath.js.map +1 -1
  27. package/dist/utils/getUserOs.js +92 -6
  28. package/dist/utils/getUserOs.js.map +1 -1
  29. package/dist/utils/getUserOs.test.js +143 -0
  30. package/dist/utils/getUserOs.test.js.map +1 -0
  31. package/dist/utils/ghOperations.js +81 -6
  32. package/dist/utils/ghOperations.js.map +1 -1
  33. package/dist/utils/ghOperations.test.js +217 -0
  34. package/dist/utils/ghOperations.test.js.map +1 -0
  35. package/dist/utils/parseCommandOptions.js +4 -4
  36. package/dist/utils/parseCommandOptions.js.map +1 -1
  37. package/dist/utils/windowsPackageManagers.js +100 -0
  38. package/dist/utils/windowsPackageManagers.js.map +1 -0
  39. package/dist/utils/windowsPackageManagers.test.js +169 -0
  40. package/dist/utils/windowsPackageManagers.test.js.map +1 -0
  41. package/package.json +22 -11
  42. package/bin/.gitkeep +0 -0
  43. package/bin/aptos.ts +0 -44
  44. package/bin/tasks/install.ts +0 -55
  45. package/bin/tasks/run.ts +0 -27
  46. package/bin/tasks/update.ts +0 -41
  47. package/bin/utils/aptosExecutableIsAvailable.ts +0 -14
  48. package/bin/utils/brewOperations.ts +0 -12
  49. package/bin/utils/consts.ts +0 -3
  50. package/bin/utils/execSyncShell.ts +0 -8
  51. package/bin/utils/getLocalBinPath.ts +0 -28
  52. package/bin/utils/getUserOs.ts +0 -18
  53. package/bin/utils/ghOperations.ts +0 -20
  54. package/bin/utils/handleHelpOptions.ts +0 -38
  55. package/bin/utils/parseCommandOptions.ts +0 -28
  56. package/bin/utils/versions.ts +0 -9
  57. package/dist/aptos.d.ts +0 -2
  58. package/dist/tasks/install.d.ts +0 -1
  59. package/dist/tasks/run.d.ts +0 -1
  60. package/dist/tasks/update.d.ts +0 -1
  61. package/dist/utils/aptosExecutableIsAvailable.d.ts +0 -1
  62. package/dist/utils/aptosExecutableIsAvailable.js +0 -11
  63. package/dist/utils/aptosExecutableIsAvailable.js.map +0 -1
  64. package/dist/utils/brewOperations.d.ts +0 -1
  65. package/dist/utils/consts.d.ts +0 -2
  66. package/dist/utils/execSyncShell.d.ts +0 -1
  67. package/dist/utils/getLocalBinPath.d.ts +0 -1
  68. package/dist/utils/getUserOs.d.ts +0 -1
  69. package/dist/utils/ghOperations.d.ts +0 -1
  70. package/dist/utils/handleHelpOptions.d.ts +0 -2
  71. package/dist/utils/handleHelpOptions.js +0 -16
  72. package/dist/utils/handleHelpOptions.js.map +0 -1
  73. package/dist/utils/parseCommandOptions.d.ts +0 -5
  74. package/dist/utils/versions.d.ts +0 -1
  75. package/dist/utils/versions.js +0 -6
  76. package/dist/utils/versions.js.map +0 -1
package/README.md CHANGED
@@ -42,6 +42,28 @@ If you already have the Aptos CLI binary installed on your system, you can speci
42
42
  npx aptos --binary-path /path/to/aptos <command>
43
43
  ```
44
44
 
45
+ ### Installing a Specific Version
46
+
47
+ You can install a specific version of the Aptos CLI by setting the `APTOS_CLI_VERSION` environment variable:
48
+
49
+ ```bash
50
+ # Install version 4.5.0
51
+ APTOS_CLI_VERSION=4.5.0 npx aptos --install
52
+
53
+ # Or with the v prefix
54
+ APTOS_CLI_VERSION=v4.5.0 npx aptos --install
55
+ ```
56
+
57
+ When `APTOS_CLI_VERSION` is set:
58
+ - The specified version is downloaded directly from GitHub releases (package managers are bypassed)
59
+ - The version is validated to ensure it exists before downloading
60
+ - This works for both `--install` and `--update` commands
61
+
62
+ This is useful for:
63
+ - Pinning to a known working version
64
+ - Testing against specific CLI versions
65
+ - Reproducible builds in CI/CD pipelines
66
+
45
67
  ## Updating the Aptos CLI
46
68
 
47
69
  To update the Aptos CLI, you can run the following command within your project environment:
@@ -73,3 +95,90 @@ To build the project:
73
95
  ```bash
74
96
  npm run build
75
97
  ```
98
+
99
+ ## Building Move Artifacts in CI/CD
100
+
101
+ The Aptos CLI can be used in CI/CD pipelines to build Move packages and generate deployment payloads. This is useful for automated deployments and multi-step workflows.
102
+
103
+ ### Example: Building Publish Payload
104
+
105
+ ```yaml
106
+ # In your GitHub Actions workflow
107
+
108
+ # Prerequisites: Set up Node.js first
109
+ - name: Setup Node.js
110
+ uses: actions/setup-node@v4
111
+ with:
112
+ node-version: "20"
113
+
114
+ - name: Install Aptos CLI npm package
115
+ run: npm install @aptos-labs/aptos-cli
116
+
117
+ - name: Install Aptos CLI
118
+ run: npx aptos --install
119
+
120
+ - name: Build Move package
121
+ working-directory: your-move-project
122
+ run: |
123
+ ~/.local/bin/aptos move compile \
124
+ --named-addresses your_module=0x1 \
125
+ --save-metadata
126
+
127
+ - name: Generate publish payload
128
+ working-directory: your-move-project
129
+ run: |
130
+ ~/.local/bin/aptos move build-publish-payload \
131
+ --named-addresses your_module=0x1 \
132
+ --json-output-file publish-payload.json \
133
+ --assume-yes
134
+
135
+ - name: Upload artifact for later steps
136
+ uses: actions/upload-artifact@v4
137
+ with:
138
+ name: move-artifacts
139
+ path: your-move-project/publish-payload.json
140
+ ```
141
+
142
+ ### Example: Building Upgrade Payload (Object Code Deployment)
143
+
144
+ For upgrading existing object-deployed contracts:
145
+
146
+ ```yaml
147
+ - name: Generate upgrade payload
148
+ working-directory: your-move-project
149
+ run: |
150
+ ~/.local/bin/aptos move build-upgrade-payload \
151
+ --named-addresses your_module=0x1 \
152
+ --object-address 0xYOUR_OBJECT_ADDRESS \
153
+ --json-output-file upgrade-payload.json \
154
+ --assume-yes
155
+ ```
156
+
157
+ ### Using Artifacts in Subsequent Jobs
158
+
159
+ ```yaml
160
+ jobs:
161
+ build:
162
+ runs-on: ubuntu-latest
163
+ steps:
164
+ # ... build steps above ...
165
+ - uses: actions/upload-artifact@v4
166
+ with:
167
+ name: move-artifacts
168
+ path: your-move-project/publish-payload.json
169
+
170
+ deploy:
171
+ needs: build
172
+ runs-on: ubuntu-latest
173
+ steps:
174
+ - uses: actions/download-artifact@v4
175
+ with:
176
+ name: move-artifacts
177
+
178
+ - name: Use the payload
179
+ run: |
180
+ # The payload JSON can be used for deployment
181
+ cat publish-payload.json
182
+ ```
183
+
184
+ See the [build-move-artifacts.yaml](.github/workflows/build-move-artifacts.yaml) workflow for a complete working example.
package/dist/aptos.js CHANGED
@@ -1,20 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import { program } from "commander";
3
- import { parseCommandOptions } from "./utils/parseCommandOptions.js";
4
3
  import { runCLI } from "./tasks/run.js";
4
+ import { parseCommandOptions } from "./utils/parseCommandOptions.js";
5
5
  program
6
6
  .name("aptos")
7
7
  .helpOption(false)
8
8
  .option("-i, --install", "install the latest version of the CLI")
9
9
  .option("-u, --update", "update the CLI to the latest version")
10
10
  .option("-b, --binary-path <path>", "path to an existing Aptos CLI binary")
11
- .allowUnknownOption();
11
+ .option("-d, --direct-download", "skip package managers and download directly from GitHub")
12
+ .allowUnknownOption()
13
+ .allowExcessArguments(true);
12
14
  program.parse(process.argv);
13
15
  const main = async () => {
14
16
  const options = {
15
17
  install: program.opts().install,
16
18
  update: program.opts().update,
17
19
  binaryPath: program.opts().binaryPath,
20
+ directDownload: program.opts().directDownload ||
21
+ process.env.APTOS_DIRECT_DOWNLOAD === "1" ||
22
+ process.env.APTOS_DIRECT_DOWNLOAD === "true",
18
23
  };
19
24
  const unknownOptions = program.args;
20
25
  if (process.argv.includes("--help")) {
package/dist/aptos.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"aptos.js","sourceRoot":"","sources":["../bin/aptos.ts"],"names":[],"mappings":";AAWA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,UAAU,CAAC,KAAK,CAAC;KACjB,MAAM,CAAC,eAAe,EAAE,uCAAuC,CAAC;KAChE,MAAM,CAAC,cAAc,EAAE,sCAAsC,CAAC;KAC9D,MAAM,CAAC,0BAA0B,EAAE,sCAAsC,CAAC;KAC1E,kBAAkB,EAAE,CAAC;AAExB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5B,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;IACtB,MAAM,OAAO,GAAG;QACd,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO;QAC/B,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM;QAC7B,UAAU,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,UAAU;KACtC,CAAC;IACF,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAGpC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAEpC,OAAO,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AACrD,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
1
+ {"version":3,"file":"aptos.js","sourceRoot":"","sources":["../bin/aptos.ts"],"names":[],"mappings":";AAkBA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,UAAU,CAAC,KAAK,CAAC;KACjB,MAAM,CAAC,eAAe,EAAE,uCAAuC,CAAC;KAChE,MAAM,CAAC,cAAc,EAAE,sCAAsC,CAAC;KAC9D,MAAM,CAAC,0BAA0B,EAAE,sCAAsC,CAAC;KAC1E,MAAM,CACL,uBAAuB,EACvB,yDAAyD,CAC1D;KACA,kBAAkB,EAAE;KACpB,oBAAoB,CAAC,IAAI,CAAC,CAAC;AAE9B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5B,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;IACtB,MAAM,OAAO,GAAG;QACd,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO;QAC/B,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM;QAC7B,UAAU,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,UAAU;QACrC,cAAc,EACZ,OAAO,CAAC,IAAI,EAAE,CAAC,cAAc;YAC7B,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,GAAG;YACzC,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,MAAM;KAC/C,CAAC;IACF,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAGpC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAEpC,OAAO,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AACrD,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC","sourcesContent":["#!/usr/bin/env node\n\n// Installation priorities by platform:\n//\n// macOS:\n// 1. Homebrew (if available) - builds for native CPU architecture\n// 2. Direct download from GitHub releases\n//\n// Windows:\n// 1. winget (if available)\n// 2. Chocolatey (if available)\n// 3. Direct download from GitHub releases\n//\n// Linux:\n// - Direct download from GitHub releases (with Ubuntu version detection)\n//\n// Use --direct-download or set APTOS_DIRECT_DOWNLOAD=1 to skip package managers.\n\nimport { program } from \"commander\";\nimport { runCLI } from \"./tasks/run.js\";\nimport { parseCommandOptions } from \"./utils/parseCommandOptions.js\";\n\nprogram\n .name(\"aptos\")\n .helpOption(false)\n .option(\"-i, --install\", \"install the latest version of the CLI\")\n .option(\"-u, --update\", \"update the CLI to the latest version\")\n .option(\"-b, --binary-path <path>\", \"path to an existing Aptos CLI binary\")\n .option(\n \"-d, --direct-download\",\n \"skip package managers and download directly from GitHub\",\n )\n .allowUnknownOption()\n .allowExcessArguments(true);\n\nprogram.parse(process.argv);\n\nconst main = async () => {\n const options = {\n install: program.opts().install,\n update: program.opts().update,\n binaryPath: program.opts().binaryPath,\n directDownload:\n program.opts().directDownload ||\n process.env.APTOS_DIRECT_DOWNLOAD === \"1\" ||\n process.env.APTOS_DIRECT_DOWNLOAD === \"true\",\n };\n const unknownOptions = program.args;\n\n // Manually check for `--help` and handle the CLI `--help`\n if (process.argv.includes(\"--help\")) {\n // Forward to the CLI\n return runCLI(unknownOptions, options.binaryPath);\n }\n\n await parseCommandOptions(options, unknownOptions);\n};\n\nmain().catch(console.error);\n"]}
@@ -0,0 +1,69 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { describe, expect, it } from "vitest";
4
+ const WORKSPACE_ROOT = join(__dirname, "../..");
5
+ const EXAMPLES_DIR = join(WORKSPACE_ROOT, "examples");
6
+ const HELLO_BLOCKCHAIN_DIR = join(EXAMPLES_DIR, "hello_blockchain");
7
+ describe("Example Move Projects", () => {
8
+ describe("hello_blockchain example", () => {
9
+ it("should have Move.toml configuration file", () => {
10
+ const moveTomlPath = join(HELLO_BLOCKCHAIN_DIR, "Move.toml");
11
+ expect(existsSync(moveTomlPath)).toBe(true);
12
+ const content = readFileSync(moveTomlPath, "utf-8");
13
+ expect(content).toContain("[package]");
14
+ expect(content).toContain('name = "HelloBlockchain"');
15
+ expect(content).toContain("[addresses]");
16
+ expect(content).toContain("hello_blockchain");
17
+ expect(content).toContain("[dependencies.AptosFramework]");
18
+ });
19
+ it("should have source files", () => {
20
+ const sourcesDir = join(HELLO_BLOCKCHAIN_DIR, "sources");
21
+ expect(existsSync(sourcesDir)).toBe(true);
22
+ const messageMovePath = join(sourcesDir, "message.move");
23
+ expect(existsSync(messageMovePath)).toBe(true);
24
+ });
25
+ it("should have valid Move module structure", () => {
26
+ const messageMovePath = join(HELLO_BLOCKCHAIN_DIR, "sources/message.move");
27
+ const content = readFileSync(messageMovePath, "utf-8");
28
+ expect(content).toContain("module hello_blockchain::message");
29
+ expect(content).toContain("public entry fun");
30
+ expect(content).toContain("has key");
31
+ expect(content).toContain("#[test");
32
+ });
33
+ });
34
+ });
35
+ describe("Build Move Artifacts Workflow", () => {
36
+ const workflowPath = join(WORKSPACE_ROOT, ".github/workflows/build-move-artifacts.yaml");
37
+ it("should have the workflow file", () => {
38
+ expect(existsSync(workflowPath)).toBe(true);
39
+ });
40
+ it("should contain required workflow configuration", () => {
41
+ const content = readFileSync(workflowPath, "utf-8");
42
+ expect(content).toContain("name: Build Move Artifacts");
43
+ expect(content).toContain("on:");
44
+ expect(content).toContain("jobs:");
45
+ expect(content).toContain("Install Aptos CLI");
46
+ expect(content).toContain("--install");
47
+ expect(content).toContain("Build Move package");
48
+ expect(content).toContain("move compile");
49
+ expect(content).toContain("--named-addresses");
50
+ expect(content).toContain("--save-metadata");
51
+ expect(content).toContain("Generate publish payload");
52
+ expect(content).toContain("build-publish-payload");
53
+ expect(content).toContain("--json-output-file");
54
+ expect(content).toContain("Upload build artifacts");
55
+ expect(content).toContain("actions/upload-artifact");
56
+ });
57
+ it("should have artifact download job for downstream usage", () => {
58
+ const content = readFileSync(workflowPath, "utf-8");
59
+ expect(content).toContain("use-artifacts");
60
+ expect(content).toContain("needs: build-artifacts");
61
+ expect(content).toContain("actions/download-artifact");
62
+ });
63
+ it("should demonstrate upgrade payload generation", () => {
64
+ const content = readFileSync(workflowPath, "utf-8");
65
+ expect(content).toContain("build-upgrade-payload");
66
+ expect(content).toContain("--object-address");
67
+ });
68
+ });
69
+ //# sourceMappingURL=examples.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"examples.test.js","sourceRoot":"","sources":["../../bin/examples/examples.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { describe, expect, it } from \"vitest\";\n\nconst WORKSPACE_ROOT = join(__dirname, \"../..\");\nconst EXAMPLES_DIR = join(WORKSPACE_ROOT, \"examples\");\nconst HELLO_BLOCKCHAIN_DIR = join(EXAMPLES_DIR, \"hello_blockchain\");\n\ndescribe(\"Example Move Projects\", () => {\n describe(\"hello_blockchain example\", () => {\n it(\"should have Move.toml configuration file\", () => {\n const moveTomlPath = join(HELLO_BLOCKCHAIN_DIR, \"Move.toml\");\n expect(existsSync(moveTomlPath)).toBe(true);\n\n const content = readFileSync(moveTomlPath, \"utf-8\");\n expect(content).toContain(\"[package]\");\n expect(content).toContain('name = \"HelloBlockchain\"');\n expect(content).toContain(\"[addresses]\");\n expect(content).toContain(\"hello_blockchain\");\n expect(content).toContain(\"[dependencies.AptosFramework]\");\n });\n\n it(\"should have source files\", () => {\n const sourcesDir = join(HELLO_BLOCKCHAIN_DIR, \"sources\");\n expect(existsSync(sourcesDir)).toBe(true);\n\n const messageMovePath = join(sourcesDir, \"message.move\");\n expect(existsSync(messageMovePath)).toBe(true);\n });\n\n it(\"should have valid Move module structure\", () => {\n const messageMovePath = join(\n HELLO_BLOCKCHAIN_DIR,\n \"sources/message.move\",\n );\n const content = readFileSync(messageMovePath, \"utf-8\");\n\n // Verify module declaration\n expect(content).toContain(\"module hello_blockchain::message\");\n\n // Verify it has required components for a deployable module\n expect(content).toContain(\"public entry fun\");\n expect(content).toContain(\"has key\");\n\n // Verify it has a test\n expect(content).toContain(\"#[test\");\n });\n });\n});\n\ndescribe(\"Build Move Artifacts Workflow\", () => {\n const workflowPath = join(\n WORKSPACE_ROOT,\n \".github/workflows/build-move-artifacts.yaml\",\n );\n\n it(\"should have the workflow file\", () => {\n expect(existsSync(workflowPath)).toBe(true);\n });\n\n it(\"should contain required workflow configuration\", () => {\n const content = readFileSync(workflowPath, \"utf-8\");\n\n // Verify workflow structure\n expect(content).toContain(\"name: Build Move Artifacts\");\n expect(content).toContain(\"on:\");\n expect(content).toContain(\"jobs:\");\n\n // Verify it installs the CLI\n expect(content).toContain(\"Install Aptos CLI\");\n expect(content).toContain(\"--install\");\n\n // Verify it builds Move package\n expect(content).toContain(\"Build Move package\");\n expect(content).toContain(\"move compile\");\n expect(content).toContain(\"--named-addresses\");\n expect(content).toContain(\"--save-metadata\");\n\n // Verify it generates publish payload\n expect(content).toContain(\"Generate publish payload\");\n expect(content).toContain(\"build-publish-payload\");\n expect(content).toContain(\"--json-output-file\");\n\n // Verify artifact upload step\n expect(content).toContain(\"Upload build artifacts\");\n expect(content).toContain(\"actions/upload-artifact\");\n });\n\n it(\"should have artifact download job for downstream usage\", () => {\n const content = readFileSync(workflowPath, \"utf-8\");\n\n // Verify there's a job that uses artifacts\n expect(content).toContain(\"use-artifacts\");\n expect(content).toContain(\"needs: build-artifacts\");\n expect(content).toContain(\"actions/download-artifact\");\n });\n\n it(\"should demonstrate upgrade payload generation\", () => {\n const content = readFileSync(workflowPath, \"utf-8\");\n\n // Verify upgrade payload example is present\n expect(content).toContain(\"build-upgrade-payload\");\n expect(content).toContain(\"--object-address\");\n });\n});\n"]}
@@ -1,42 +1,93 @@
1
- import { execSync } from "child_process";
2
- import { existsSync } from "fs";
1
+ import { execSync } from "node:child_process";
2
+ import { chmodSync, existsSync, mkdirSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { installViaBrew, isBrewAvailable, isInstalledViaBrew, } from "../utils/brewOperations.js";
3
6
  import { GH_CLI_DOWNLOAD_URL, PNAME } from "../utils/consts.js";
4
- import { execSyncShell } from "../utils/execSyncShell.js";
5
- import { getCurrentOpenSSLVersion } from "../utils/versions.js";
6
- import { getOS } from "../utils/getUserOs.js";
7
- import { getLocalBinPath } from "../utils/getLocalBinPath.js";
8
- import { getLatestVersionGh } from "../utils/ghOperations.js";
9
- export const installCli = async () => {
10
- const path = getLocalBinPath();
11
- if (existsSync(path)) {
7
+ import { getBinDir, getLocalBinPath, invalidateBinPathCache, } from "../utils/getLocalBinPath.js";
8
+ import { getOS, getTargetPlatform } from "../utils/getUserOs.js";
9
+ import { getCliVersion, hasUserSpecifiedVersion, } from "../utils/ghOperations.js";
10
+ import { installViaChoco, installViaWinget, isChocoAvailable, isInstalledViaChoco, isInstalledViaWinget, isWingetAvailable, } from "../utils/windowsPackageManagers.js";
11
+ export const installCli = async (directDownload = false) => {
12
+ invalidateBinPathCache();
13
+ const os = getOS();
14
+ const useDirectDownload = directDownload || hasUserSpecifiedVersion();
15
+ if (useDirectDownload && hasUserSpecifiedVersion()) {
16
+ console.log(`Using specified version from APTOS_CLI_VERSION: ${process.env.APTOS_CLI_VERSION}`);
17
+ }
18
+ if (!useDirectDownload) {
19
+ if (os === "MacOS" && isBrewAvailable()) {
20
+ if (isInstalledViaBrew()) {
21
+ console.log("Aptos CLI is already installed via Homebrew");
22
+ return;
23
+ }
24
+ installViaBrew();
25
+ return;
26
+ }
27
+ if (os === "Windows") {
28
+ if (isWingetAvailable()) {
29
+ if (isInstalledViaWinget()) {
30
+ console.log("Aptos CLI is already installed via winget");
31
+ return;
32
+ }
33
+ installViaWinget();
34
+ return;
35
+ }
36
+ if (isChocoAvailable()) {
37
+ if (isInstalledViaChoco()) {
38
+ console.log("Aptos CLI is already installed via Chocolatey");
39
+ return;
40
+ }
41
+ installViaChoco();
42
+ return;
43
+ }
44
+ }
45
+ }
46
+ const binaryPath = getLocalBinPath();
47
+ if (existsSync(binaryPath)) {
12
48
  console.log("Aptos CLI is already installed");
13
49
  return;
14
50
  }
15
- const latestCLIVersion = await getLatestVersionGh();
16
- console.log(`Downloading aptos CLI version ${latestCLIVersion}`);
17
- const os = getOS();
18
- if (os === "Windows") {
19
- const url = `${GH_CLI_DOWNLOAD_URL}/${PNAME}-v${latestCLIVersion}/${PNAME}-${latestCLIVersion}-${os}-x86_64.zip`;
20
- execSync(`powershell -Command "if (!(Test-Path -Path 'C:\\tmp')) { New-Item -ItemType Directory -Path 'C:\\tmp' } ; Invoke-RestMethod -Uri ${url} -OutFile C:\\tmp\\aptos.zip; Expand-Archive -Path C:\\tmp\\aptos.zip -DestinationPath C:\\tmp -Force; Move-Item -Path C:\\tmp\\aptos.exe -Destination \"${path}\""`);
21
- }
22
- else if (os === "MacOS") {
23
- execSyncShell("brew install aptos", { encoding: "utf8" });
51
+ const binDir = getBinDir();
52
+ if (!existsSync(binDir)) {
53
+ mkdirSync(binDir, { recursive: true });
24
54
  }
25
- else {
26
- let osVersion = "x86_64";
27
- let opensSslVersion = "1.0.0";
28
- try {
29
- opensSslVersion = getCurrentOpenSSLVersion();
55
+ const targetPlatform = getTargetPlatform();
56
+ const version = await getCliVersion(targetPlatform);
57
+ console.log(`Downloading Aptos CLI version ${version} for ${targetPlatform}...`);
58
+ const url = `${GH_CLI_DOWNLOAD_URL}/${PNAME}-v${version}/${PNAME}-${version}-${targetPlatform}.zip`;
59
+ const tempDir = tmpdir();
60
+ try {
61
+ if (os === "Windows") {
62
+ const zipPath = join(tempDir, "aptos-cli.zip");
63
+ execSync(`powershell -Command "` +
64
+ `Invoke-WebRequest -Uri '${url}' -OutFile '${zipPath}'; ` +
65
+ `Expand-Archive -Path '${zipPath}' -DestinationPath '${binDir}' -Force; ` +
66
+ `Remove-Item -Path '${zipPath}' -Force"`, { stdio: "inherit" });
30
67
  }
31
- catch (error) {
32
- console.log("Could not determine OpenSSL version, assuming older version (1.x.x)");
68
+ else {
69
+ const zipPath = join(tempDir, "aptos-cli.zip");
70
+ execSync(`curl -L -o "${zipPath}" "${url}"`, { stdio: "inherit" });
71
+ execSync(`unzip -o -q "${zipPath}" -d "${tempDir}"`, {
72
+ stdio: "inherit",
73
+ });
74
+ const extractedBinary = join(tempDir, "aptos");
75
+ execSync(`mv "${extractedBinary}" "${binaryPath}"`, { stdio: "inherit" });
76
+ chmodSync(binaryPath, 0o755);
77
+ try {
78
+ execSync(`rm -f "${zipPath}"`, { stdio: "ignore" });
79
+ }
80
+ catch {
81
+ }
33
82
  }
34
- if (opensSslVersion.startsWith("3.")) {
35
- osVersion = "22.04-x86_64";
83
+ console.log(`Aptos CLI installed successfully to ${binaryPath}`);
84
+ if (os !== "Windows") {
85
+ console.log(`\nMake sure ${binDir} is in your PATH. You can add it by running:`);
86
+ console.log(` export PATH="${binDir}:$PATH"`);
36
87
  }
37
- console.log(`Downloading CLI binary ${os}-${osVersion}`);
38
- const url = `${GH_CLI_DOWNLOAD_URL}/${PNAME}-v${latestCLIVersion}/${PNAME}-${latestCLIVersion}-${os}-${osVersion}.zip`;
39
- execSync(`curl -L -o /tmp/aptos.zip ${url}; unzip -o -q /tmp/aptos.zip -d /tmp; mv /tmp/aptos ${path};`);
88
+ }
89
+ catch (error) {
90
+ throw new Error(`Failed to install Aptos CLI: ${error instanceof Error ? error.message : String(error)}`);
40
91
  }
41
92
  };
42
93
  //# sourceMappingURL=install.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../../bin/tasks/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAEhC,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAG9D,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE;IACnC,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,kBAAkB,EAAE,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,iCAAiC,gBAAgB,EAAE,CAAC,CAAC;IACjE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IAEnB,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,GAAG,mBAAmB,IAAI,KAAK,KAAK,gBAAgB,IAAI,KAAK,IAAI,gBAAgB,IAAI,EAAE,aAAa,CAAC;QAEjH,QAAQ,CACN,oIAAoI,GAAG,4JAA4J,IAAI,KAAK,CAC7S,CAAC;IACJ,CAAC;SAAM,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;QAE1B,aAAa,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5D,CAAC;SAAM,CAAC;QAGN,IAAI,SAAS,GAAG,QAAQ,CAAC;QACzB,IAAI,eAAe,GAAG,OAAO,CAAC;QAC9B,IAAI,CAAC;YACH,eAAe,GAAG,wBAAwB,EAAE,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CACT,qEAAqE,CACtE,CAAC;QACJ,CAAC;QAED,IAAI,eAAe,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,SAAS,GAAG,cAAc,CAAC;QAC7B,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,0BAA0B,EAAE,IAAI,SAAS,EAAE,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,GAAG,mBAAmB,IAAI,KAAK,KAAK,gBAAgB,IAAI,KAAK,IAAI,gBAAgB,IAAI,EAAE,IAAI,SAAS,MAAM,CAAC;QAEvH,QAAQ,CACN,6BAA6B,GAAG,uDAAuD,IAAI,GAAG,CAC/F,CAAC;IACJ,CAAC;AACH,CAAC,CAAC"}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../bin/tasks/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EACL,SAAS,EACT,eAAe,EACf,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EACL,aAAa,EACb,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,oCAAoC,CAAC;AAwB5C,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAC7B,iBAA0B,KAAK,EAChB,EAAE;IACjB,sBAAsB,EAAE,CAAC;IACzB,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IAInB,MAAM,iBAAiB,GAAG,cAAc,IAAI,uBAAuB,EAAE,CAAC;IAEtE,IAAI,iBAAiB,IAAI,uBAAuB,EAAE,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CACT,mDAAmD,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CACnF,CAAC;IACJ,CAAC;IAGD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEvB,IAAI,EAAE,KAAK,OAAO,IAAI,eAAe,EAAE,EAAE,CAAC;YACxC,IAAI,kBAAkB,EAAE,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;gBAC3D,OAAO;YACT,CAAC;YACD,cAAc,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QAGD,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,IAAI,iBAAiB,EAAE,EAAE,CAAC;gBACxB,IAAI,oBAAoB,EAAE,EAAE,CAAC;oBAC3B,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;oBACzD,OAAO;gBACT,CAAC;gBACD,gBAAgB,EAAE,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,IAAI,gBAAgB,EAAE,EAAE,CAAC;gBACvB,IAAI,mBAAmB,EAAE,EAAE,CAAC;oBAC1B,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;oBAC7D,OAAO;gBACT,CAAC;gBACD,eAAe,EAAE,CAAC;gBAClB,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;IAGD,MAAM,UAAU,GAAG,eAAe,EAAE,CAAC;IACrC,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAGD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IAGD,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAC;IAG3C,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,cAAc,CAAC,CAAC;IAEpD,OAAO,CAAC,GAAG,CACT,iCAAiC,OAAO,QAAQ,cAAc,KAAK,CACpE,CAAC;IAGF,MAAM,GAAG,GAAG,GAAG,mBAAmB,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,IAAI,OAAO,IAAI,cAAc,MAAM,CAAC;IAEpG,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC;IAEzB,IAAI,CAAC;QACH,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YAErB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;YAC/C,QAAQ,CACN,uBAAuB;gBACrB,2BAA2B,GAAG,eAAe,OAAO,KAAK;gBACzD,yBAAyB,OAAO,uBAAuB,MAAM,YAAY;gBACzE,sBAAsB,OAAO,WAAW,EAC1C,EAAE,KAAK,EAAE,SAAS,EAAE,CACrB,CAAC;QACJ,CAAC;aAAM,CAAC;YAEN,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;YAG/C,QAAQ,CAAC,eAAe,OAAO,MAAM,GAAG,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YAGnE,QAAQ,CAAC,gBAAgB,OAAO,SAAS,OAAO,GAAG,EAAE;gBACnD,KAAK,EAAE,SAAS;aACjB,CAAC,CAAC;YAGH,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC/C,QAAQ,CAAC,OAAO,eAAe,MAAM,UAAU,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YAG1E,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAG7B,IAAI,CAAC;gBACH,QAAQ,CAAC,UAAU,OAAO,GAAG,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YACtD,CAAC;YAAC,MAAM,CAAC;YAET,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,uCAAuC,UAAU,EAAE,CAAC,CAAC;QAGjE,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CACT,eAAe,MAAM,8CAA8C,CACpE,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,SAAS,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,gCAAgC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACzF,CAAC;IACJ,CAAC;AACH,CAAC,CAAC","sourcesContent":["import { execSync } from \"node:child_process\";\nimport { chmodSync, existsSync, mkdirSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n installViaBrew,\n isBrewAvailable,\n isInstalledViaBrew,\n} from \"../utils/brewOperations.js\";\nimport { GH_CLI_DOWNLOAD_URL, PNAME } from \"../utils/consts.js\";\nimport {\n getBinDir,\n getLocalBinPath,\n invalidateBinPathCache,\n} from \"../utils/getLocalBinPath.js\";\nimport { getOS, getTargetPlatform } from \"../utils/getUserOs.js\";\nimport {\n getCliVersion,\n hasUserSpecifiedVersion,\n} from \"../utils/ghOperations.js\";\nimport {\n installViaChoco,\n installViaWinget,\n isChocoAvailable,\n isInstalledViaChoco,\n isInstalledViaWinget,\n isWingetAvailable,\n} from \"../utils/windowsPackageManagers.js\";\n\n/**\n * Install the Aptos CLI.\n *\n * Installation priority:\n *\n * macOS:\n * 1. Homebrew (if available)\n * 2. Direct download from GitHub releases\n *\n * Windows:\n * 1. winget (if available)\n * 2. Chocolatey (if available)\n * 3. Direct download from GitHub releases\n *\n * Linux:\n * - Direct download from GitHub releases\n *\n * Note: When APTOS_CLI_VERSION is set, package managers are skipped and the\n * specified version is downloaded directly from GitHub releases.\n *\n * @param directDownload - If true, skip package managers and download directly\n */\nexport const installCli = async (\n directDownload: boolean = false,\n): Promise<void> => {\n invalidateBinPathCache();\n const os = getOS();\n\n // If a specific version is requested, force direct download\n // Package managers don't support installing specific versions\n const useDirectDownload = directDownload || hasUserSpecifiedVersion();\n\n if (useDirectDownload && hasUserSpecifiedVersion()) {\n console.log(\n `Using specified version from APTOS_CLI_VERSION: ${process.env.APTOS_CLI_VERSION}`,\n );\n }\n\n // Skip package managers if directDownload is set or specific version requested\n if (!useDirectDownload) {\n // On macOS, prefer Homebrew if available\n if (os === \"MacOS\" && isBrewAvailable()) {\n if (isInstalledViaBrew()) {\n console.log(\"Aptos CLI is already installed via Homebrew\");\n return;\n }\n installViaBrew();\n return;\n }\n\n // On Windows, prefer winget, then Chocolatey\n if (os === \"Windows\") {\n if (isWingetAvailable()) {\n if (isInstalledViaWinget()) {\n console.log(\"Aptos CLI is already installed via winget\");\n return;\n }\n installViaWinget();\n return;\n }\n\n if (isChocoAvailable()) {\n if (isInstalledViaChoco()) {\n console.log(\"Aptos CLI is already installed via Chocolatey\");\n return;\n }\n installViaChoco();\n return;\n }\n }\n }\n\n // Direct download installation\n const binaryPath = getLocalBinPath();\n if (existsSync(binaryPath)) {\n console.log(\"Aptos CLI is already installed\");\n return;\n }\n\n // Ensure the bin directory exists\n const binDir = getBinDir();\n if (!existsSync(binDir)) {\n mkdirSync(binDir, { recursive: true });\n }\n\n // Get target platform first for version validation\n const targetPlatform = getTargetPlatform();\n\n // Get the version to install (user-specified or latest)\n const version = await getCliVersion(targetPlatform);\n\n console.log(\n `Downloading Aptos CLI version ${version} for ${targetPlatform}...`,\n );\n\n // Build download URL matching official release artifact naming\n const url = `${GH_CLI_DOWNLOAD_URL}/${PNAME}-v${version}/${PNAME}-${version}-${targetPlatform}.zip`;\n\n const tempDir = tmpdir();\n\n try {\n if (os === \"Windows\") {\n // Windows installation using PowerShell\n const zipPath = join(tempDir, \"aptos-cli.zip\");\n execSync(\n `powershell -Command \"` +\n `Invoke-WebRequest -Uri '${url}' -OutFile '${zipPath}'; ` +\n `Expand-Archive -Path '${zipPath}' -DestinationPath '${binDir}' -Force; ` +\n `Remove-Item -Path '${zipPath}' -Force\"`,\n { stdio: \"inherit\" },\n );\n } else {\n // macOS (without Homebrew) and Linux installation using curl/unzip\n const zipPath = join(tempDir, \"aptos-cli.zip\");\n\n // Download\n execSync(`curl -L -o \"${zipPath}\" \"${url}\"`, { stdio: \"inherit\" });\n\n // Extract\n execSync(`unzip -o -q \"${zipPath}\" -d \"${tempDir}\"`, {\n stdio: \"inherit\",\n });\n\n // Move binary to bin directory\n const extractedBinary = join(tempDir, \"aptos\");\n execSync(`mv \"${extractedBinary}\" \"${binaryPath}\"`, { stdio: \"inherit\" });\n\n // Set executable permissions\n chmodSync(binaryPath, 0o755);\n\n // Clean up\n try {\n execSync(`rm -f \"${zipPath}\"`, { stdio: \"ignore\" });\n } catch {\n // Ignore cleanup errors\n }\n }\n\n console.log(`Aptos CLI installed successfully to ${binaryPath}`);\n\n // Remind user about PATH if needed\n if (os !== \"Windows\") {\n console.log(\n `\\nMake sure ${binDir} is in your PATH. You can add it by running:`,\n );\n console.log(` export PATH=\"${binDir}:$PATH\"`);\n }\n } catch (error) {\n throw new Error(\n `Failed to install Aptos CLI: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n};\n"]}
@@ -0,0 +1,227 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ vi.mock("child_process", () => ({
3
+ execSync: vi.fn(),
4
+ }));
5
+ vi.mock("fs", () => ({
6
+ existsSync: vi.fn(),
7
+ chmodSync: vi.fn(),
8
+ mkdirSync: vi.fn(),
9
+ }));
10
+ vi.mock("os", () => ({
11
+ tmpdir: () => "/tmp",
12
+ homedir: () => "/home/user",
13
+ platform: vi.fn(() => "linux"),
14
+ arch: vi.fn(() => "x64"),
15
+ }));
16
+ vi.mock("../utils/getUserOs.js", () => ({
17
+ getOS: vi.fn(),
18
+ getTargetPlatform: vi.fn(),
19
+ }));
20
+ vi.mock("../utils/getLocalBinPath.js", () => ({
21
+ getLocalBinPath: vi.fn(),
22
+ getBinDir: vi.fn(),
23
+ invalidateBinPathCache: vi.fn(),
24
+ }));
25
+ vi.mock("../utils/ghOperations.js", () => ({
26
+ getCliVersion: vi.fn(),
27
+ hasUserSpecifiedVersion: vi.fn(),
28
+ }));
29
+ vi.mock("../utils/brewOperations.js", () => ({
30
+ isBrewAvailable: vi.fn(),
31
+ isInstalledViaBrew: vi.fn(),
32
+ installViaBrew: vi.fn(),
33
+ }));
34
+ vi.mock("../utils/windowsPackageManagers.js", () => ({
35
+ isWingetAvailable: vi.fn(),
36
+ isChocoAvailable: vi.fn(),
37
+ isInstalledViaWinget: vi.fn(),
38
+ isInstalledViaChoco: vi.fn(),
39
+ installViaWinget: vi.fn(),
40
+ installViaChoco: vi.fn(),
41
+ }));
42
+ import { execSync } from "node:child_process";
43
+ import { existsSync, mkdirSync } from "node:fs";
44
+ import { installViaBrew, isBrewAvailable, isInstalledViaBrew, } from "../utils/brewOperations.js";
45
+ import { getBinDir, getLocalBinPath } from "../utils/getLocalBinPath.js";
46
+ import { getOS, getTargetPlatform } from "../utils/getUserOs.js";
47
+ import { getCliVersion, hasUserSpecifiedVersion, } from "../utils/ghOperations.js";
48
+ import { installViaChoco, installViaWinget, isChocoAvailable, isInstalledViaChoco, isInstalledViaWinget, isWingetAvailable, } from "../utils/windowsPackageManagers.js";
49
+ import { installCli } from "./install.js";
50
+ describe("install", () => {
51
+ beforeEach(() => {
52
+ vi.clearAllMocks();
53
+ vi.mocked(getLocalBinPath).mockReturnValue("/home/user/.local/bin/aptos");
54
+ vi.mocked(getBinDir).mockReturnValue("/home/user/.local/bin");
55
+ vi.mocked(getCliVersion).mockResolvedValue("1.0.0");
56
+ vi.mocked(hasUserSpecifiedVersion).mockReturnValue(false);
57
+ vi.mocked(getTargetPlatform).mockReturnValue("Linux-x86_64");
58
+ });
59
+ afterEach(() => {
60
+ vi.restoreAllMocks();
61
+ });
62
+ describe("macOS with Homebrew", () => {
63
+ beforeEach(() => {
64
+ vi.mocked(getOS).mockReturnValue("MacOS");
65
+ vi.mocked(isBrewAvailable).mockReturnValue(true);
66
+ });
67
+ it("should use Homebrew when available", async () => {
68
+ vi.mocked(isInstalledViaBrew).mockReturnValue(false);
69
+ await installCli();
70
+ expect(installViaBrew).toHaveBeenCalled();
71
+ expect(execSync).not.toHaveBeenCalled();
72
+ });
73
+ it("should skip if already installed via Homebrew", async () => {
74
+ vi.mocked(isInstalledViaBrew).mockReturnValue(true);
75
+ await installCli();
76
+ expect(installViaBrew).not.toHaveBeenCalled();
77
+ });
78
+ it("should skip Homebrew when directDownload is true", async () => {
79
+ vi.mocked(isInstalledViaBrew).mockReturnValue(false);
80
+ vi.mocked(existsSync).mockReturnValue(false);
81
+ vi.mocked(execSync).mockReturnValue(Buffer.from(""));
82
+ vi.mocked(getTargetPlatform).mockReturnValue("macos-x86_64");
83
+ await installCli(true);
84
+ expect(installViaBrew).not.toHaveBeenCalled();
85
+ expect(execSync).toHaveBeenCalled();
86
+ });
87
+ });
88
+ describe("Windows with winget", () => {
89
+ beforeEach(() => {
90
+ vi.mocked(getOS).mockReturnValue("Windows");
91
+ vi.mocked(isBrewAvailable).mockReturnValue(false);
92
+ vi.mocked(isWingetAvailable).mockReturnValue(true);
93
+ vi.mocked(isChocoAvailable).mockReturnValue(false);
94
+ });
95
+ it("should use winget when available", async () => {
96
+ vi.mocked(isInstalledViaWinget).mockReturnValue(false);
97
+ await installCli();
98
+ expect(installViaWinget).toHaveBeenCalled();
99
+ expect(installViaChoco).not.toHaveBeenCalled();
100
+ });
101
+ it("should skip if already installed via winget", async () => {
102
+ vi.mocked(isInstalledViaWinget).mockReturnValue(true);
103
+ await installCli();
104
+ expect(installViaWinget).not.toHaveBeenCalled();
105
+ });
106
+ });
107
+ describe("Windows with Chocolatey", () => {
108
+ beforeEach(() => {
109
+ vi.mocked(getOS).mockReturnValue("Windows");
110
+ vi.mocked(isBrewAvailable).mockReturnValue(false);
111
+ vi.mocked(isWingetAvailable).mockReturnValue(false);
112
+ vi.mocked(isChocoAvailable).mockReturnValue(true);
113
+ });
114
+ it("should use Chocolatey when winget is not available", async () => {
115
+ vi.mocked(isInstalledViaChoco).mockReturnValue(false);
116
+ await installCli();
117
+ expect(installViaChoco).toHaveBeenCalled();
118
+ expect(installViaWinget).not.toHaveBeenCalled();
119
+ });
120
+ it("should skip if already installed via Chocolatey", async () => {
121
+ vi.mocked(isInstalledViaChoco).mockReturnValue(true);
122
+ await installCli();
123
+ expect(installViaChoco).not.toHaveBeenCalled();
124
+ });
125
+ });
126
+ describe("Windows direct download", () => {
127
+ beforeEach(() => {
128
+ vi.mocked(getOS).mockReturnValue("Windows");
129
+ vi.mocked(isBrewAvailable).mockReturnValue(false);
130
+ vi.mocked(isWingetAvailable).mockReturnValue(false);
131
+ vi.mocked(isChocoAvailable).mockReturnValue(false);
132
+ vi.mocked(existsSync).mockReturnValue(false);
133
+ vi.mocked(getTargetPlatform).mockReturnValue("Windows-x86_64");
134
+ });
135
+ it("should download directly when no package manager available", async () => {
136
+ vi.mocked(execSync).mockReturnValue(Buffer.from(""));
137
+ await installCli();
138
+ expect(installViaWinget).not.toHaveBeenCalled();
139
+ expect(installViaChoco).not.toHaveBeenCalled();
140
+ expect(execSync).toHaveBeenCalledWith(expect.stringContaining("powershell"), expect.any(Object));
141
+ });
142
+ it("should skip package managers when directDownload is true", async () => {
143
+ vi.mocked(isWingetAvailable).mockReturnValue(true);
144
+ vi.mocked(isChocoAvailable).mockReturnValue(true);
145
+ vi.mocked(execSync).mockReturnValue(Buffer.from(""));
146
+ await installCli(true);
147
+ expect(installViaWinget).not.toHaveBeenCalled();
148
+ expect(installViaChoco).not.toHaveBeenCalled();
149
+ expect(execSync).toHaveBeenCalled();
150
+ });
151
+ });
152
+ describe("Linux direct download", () => {
153
+ beforeEach(() => {
154
+ vi.mocked(getOS).mockReturnValue("Linux");
155
+ vi.mocked(isBrewAvailable).mockReturnValue(false);
156
+ vi.mocked(existsSync).mockReturnValue(false);
157
+ vi.mocked(getTargetPlatform).mockReturnValue("Ubuntu-22.04-x86_64");
158
+ });
159
+ it("should download directly on Linux", async () => {
160
+ vi.mocked(execSync).mockReturnValue(Buffer.from(""));
161
+ await installCli();
162
+ expect(execSync).toHaveBeenCalledWith(expect.stringContaining("curl"), expect.any(Object));
163
+ });
164
+ it("should create bin directory if it doesn't exist", async () => {
165
+ vi.mocked(existsSync).mockImplementation((path) => {
166
+ if (path === "/home/user/.local/bin")
167
+ return false;
168
+ return false;
169
+ });
170
+ vi.mocked(execSync).mockReturnValue(Buffer.from(""));
171
+ await installCli();
172
+ expect(mkdirSync).toHaveBeenCalledWith("/home/user/.local/bin", {
173
+ recursive: true,
174
+ });
175
+ });
176
+ });
177
+ describe("already installed", () => {
178
+ it("should skip if binary already exists", async () => {
179
+ vi.mocked(getOS).mockReturnValue("Linux");
180
+ vi.mocked(isBrewAvailable).mockReturnValue(false);
181
+ vi.mocked(existsSync).mockReturnValue(true);
182
+ await installCli();
183
+ expect(execSync).not.toHaveBeenCalled();
184
+ expect(getCliVersion).not.toHaveBeenCalled();
185
+ });
186
+ });
187
+ describe("specific version via APTOS_CLI_VERSION", () => {
188
+ beforeEach(() => {
189
+ vi.mocked(hasUserSpecifiedVersion).mockReturnValue(true);
190
+ vi.mocked(getCliVersion).mockResolvedValue("4.5.0");
191
+ });
192
+ it("should skip package managers when specific version is set", async () => {
193
+ vi.mocked(getOS).mockReturnValue("MacOS");
194
+ vi.mocked(isBrewAvailable).mockReturnValue(true);
195
+ vi.mocked(isInstalledViaBrew).mockReturnValue(false);
196
+ vi.mocked(existsSync).mockReturnValue(false);
197
+ vi.mocked(execSync).mockReturnValue(Buffer.from(""));
198
+ vi.mocked(getTargetPlatform).mockReturnValue("macos-x86_64");
199
+ await installCli();
200
+ expect(installViaBrew).not.toHaveBeenCalled();
201
+ expect(execSync).toHaveBeenCalled();
202
+ });
203
+ it("should skip winget when specific version is set on Windows", async () => {
204
+ vi.mocked(getOS).mockReturnValue("Windows");
205
+ vi.mocked(isBrewAvailable).mockReturnValue(false);
206
+ vi.mocked(isWingetAvailable).mockReturnValue(true);
207
+ vi.mocked(isChocoAvailable).mockReturnValue(true);
208
+ vi.mocked(existsSync).mockReturnValue(false);
209
+ vi.mocked(execSync).mockReturnValue(Buffer.from(""));
210
+ vi.mocked(getTargetPlatform).mockReturnValue("Windows-x86_64");
211
+ await installCli();
212
+ expect(installViaWinget).not.toHaveBeenCalled();
213
+ expect(installViaChoco).not.toHaveBeenCalled();
214
+ expect(execSync).toHaveBeenCalled();
215
+ });
216
+ it("should use specific version in download URL", async () => {
217
+ vi.mocked(getOS).mockReturnValue("Linux");
218
+ vi.mocked(isBrewAvailable).mockReturnValue(false);
219
+ vi.mocked(existsSync).mockReturnValue(false);
220
+ vi.mocked(execSync).mockReturnValue(Buffer.from(""));
221
+ vi.mocked(getTargetPlatform).mockReturnValue("Ubuntu-22.04-x86_64");
222
+ await installCli();
223
+ expect(execSync).toHaveBeenCalledWith(expect.stringContaining("4.5.0"), expect.any(Object));
224
+ });
225
+ });
226
+ });
227
+ //# sourceMappingURL=install.test.js.map