@expo-up/cli 0.1.0 → 0.1.2-next.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.
- package/CHANGELOG.md +17 -0
- package/README.md +161 -0
- package/dist/index.js +3 -4
- package/package.json +6 -2
- package/src/index.tsx +3 -1
- package/src/release-utils.test.ts +3 -1
- package/src/release.tsx +2 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @expo-up/cli
|
|
2
|
+
|
|
3
|
+
## 0.1.2-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 37a6319: chore: patch release across core, server, and cli
|
|
8
|
+
- Updated dependencies [37a6319]
|
|
9
|
+
- @expo-up/core@0.1.2-next.0
|
|
10
|
+
|
|
11
|
+
## 0.1.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 7115c93: chore: patch release across core, server, and cli
|
|
16
|
+
- Updated dependencies [7115c93]
|
|
17
|
+
- @expo-up/core@0.1.1
|
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# @expo-up/cli
|
|
2
|
+
|
|
3
|
+
CLI package for managing self-hosted Expo OTA workflows.
|
|
4
|
+
|
|
5
|
+
> Current storage target is GitHub Repository storage.
|
|
6
|
+
> Additional providers (AWS S3, Firebase Storage, Google Cloud Storage, Azure Blob Storage, etc.) are planned.
|
|
7
|
+
|
|
8
|
+
## Responsibilities
|
|
9
|
+
|
|
10
|
+
- Authenticate against GitHub for storage access.
|
|
11
|
+
- Export and release update bundles to storage.
|
|
12
|
+
- Inspect and manage build history.
|
|
13
|
+
- Roll back channels to embedded/previous builds.
|
|
14
|
+
- Bootstrap Expo code signing (generate/configure).
|
|
15
|
+
|
|
16
|
+
## Global Option
|
|
17
|
+
|
|
18
|
+
- `--debug`: enable verbose logs for API calls, release diffing, and error context.
|
|
19
|
+
|
|
20
|
+
## Command Reference
|
|
21
|
+
|
|
22
|
+
### `expo-up login`
|
|
23
|
+
|
|
24
|
+
Authenticate and store local token/config for subsequent commands.
|
|
25
|
+
|
|
26
|
+
### `expo-up logout`
|
|
27
|
+
|
|
28
|
+
Clear locally stored token/config session.
|
|
29
|
+
|
|
30
|
+
### `expo-up whoami`
|
|
31
|
+
|
|
32
|
+
Print resolved project context:
|
|
33
|
+
- projectId from Expo config
|
|
34
|
+
- active channel
|
|
35
|
+
- server URL
|
|
36
|
+
- auth state (masked token)
|
|
37
|
+
|
|
38
|
+
### `expo-up set-channel <name>`
|
|
39
|
+
|
|
40
|
+
Persist default channel used by release/history/rollback when `--channel` is not passed.
|
|
41
|
+
Default channel is `main`.
|
|
42
|
+
|
|
43
|
+
Example:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
expo-up set-channel main
|
|
47
|
+
expo-up set-channel staging
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### `expo-up list-channels`
|
|
51
|
+
|
|
52
|
+
List available channels from the storage repository.
|
|
53
|
+
|
|
54
|
+
### `expo-up release`
|
|
55
|
+
|
|
56
|
+
Build and upload a new OTA build for a channel/runtime.
|
|
57
|
+
|
|
58
|
+
Options:
|
|
59
|
+
- `--platform <ios|android|all>` default: `all`
|
|
60
|
+
- `--channel <name>` optional channel override
|
|
61
|
+
- channel defaults to `main` when no saved/override channel is provided
|
|
62
|
+
|
|
63
|
+
Behavior:
|
|
64
|
+
1. Runs `expo export`.
|
|
65
|
+
2. Reads local `dist/metadata.json`.
|
|
66
|
+
3. Compares sorted metadata hash against latest remote build in the channel.
|
|
67
|
+
4. Skips upload if no changes.
|
|
68
|
+
5. Uploads new build and advances channel ref if changed.
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
expo-up release --platform all --channel main
|
|
74
|
+
expo-up --debug release --platform ios --channel feat/new-home
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `expo-up history`
|
|
78
|
+
|
|
79
|
+
Show release/rollback timeline for a channel.
|
|
80
|
+
|
|
81
|
+
Options:
|
|
82
|
+
- `--channel <name>` optional channel override
|
|
83
|
+
- `--delete <buildIds...>` non-interactive delete mode (CI friendly)
|
|
84
|
+
- `--yes` skip confirmation for delete mode
|
|
85
|
+
- `--no-interactive-delete` disable TUI selection mode
|
|
86
|
+
- channel defaults to `main` when no saved/override channel is provided
|
|
87
|
+
|
|
88
|
+
Examples:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
expo-up history --channel main
|
|
92
|
+
expo-up history --channel main --delete 10 11 --yes
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `expo-up rollback`
|
|
96
|
+
|
|
97
|
+
Rollback channel to previous build or embedded app update.
|
|
98
|
+
|
|
99
|
+
Options:
|
|
100
|
+
- `--channel <name>` optional channel override
|
|
101
|
+
- `--to <buildId>` rollback target build
|
|
102
|
+
- `--embedded` rollback to embedded/native update
|
|
103
|
+
- channel defaults to `main` when no saved/override channel is provided
|
|
104
|
+
|
|
105
|
+
Examples:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
expo-up rollback --channel main --to 10
|
|
109
|
+
expo-up rollback --channel main --embedded
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `expo-up codesigning:generate`
|
|
113
|
+
|
|
114
|
+
Generate keypair/certificate and update Expo config for signed updates.
|
|
115
|
+
|
|
116
|
+
Key options:
|
|
117
|
+
- `--organization <name>`
|
|
118
|
+
- `--certificate-validity-duration-years <years>`
|
|
119
|
+
- `--key-id <id>` default: `main`
|
|
120
|
+
- `--project-root <path>`
|
|
121
|
+
- `--key-output-directory <path>` default: `codesigning-keys`
|
|
122
|
+
- `--certificate-output-directory <path>` default: `certs`
|
|
123
|
+
- `--force`
|
|
124
|
+
|
|
125
|
+
### `expo-up codesigning:configure`
|
|
126
|
+
|
|
127
|
+
Configure existing signing materials into Expo config.
|
|
128
|
+
|
|
129
|
+
## Local Development
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
bun install
|
|
133
|
+
bun run build
|
|
134
|
+
bun run test
|
|
135
|
+
bun run check-types
|
|
136
|
+
bun run lint
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## End-to-End Test With Example Apps
|
|
140
|
+
|
|
141
|
+
1. Start server app:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
cd ../../apps/example-hono-cf-worker
|
|
145
|
+
bun run dev
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
2. Use CLI from Expo app root:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
cd ../example-expo-app
|
|
152
|
+
bunx expo-up whoami
|
|
153
|
+
bunx expo-up release --channel main --platform all
|
|
154
|
+
bunx expo-up history --channel main
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
3. In mobile app, press `Fetch update` and verify logs/status.
|
|
158
|
+
|
|
159
|
+
## Package
|
|
160
|
+
|
|
161
|
+
Published as `@expo-up/cli`.
|
package/dist/index.js
CHANGED
|
@@ -77252,7 +77252,7 @@ var require_source_map_support = __commonJS((exports, module) => {
|
|
|
77252
77252
|
|
|
77253
77253
|
// ../../node_modules/.bun/typescript@5.9.2/node_modules/typescript/lib/typescript.js
|
|
77254
77254
|
var require_typescript4 = __commonJS((exports, module) => {
|
|
77255
|
-
var __dirname = "/
|
|
77255
|
+
var __dirname = "/home/runner/work/expo-up/expo-up/node_modules/.bun/typescript@5.9.2/node_modules/typescript/lib", __filename = "/home/runner/work/expo-up/expo-up/node_modules/.bun/typescript@5.9.2/node_modules/typescript/lib/typescript.js";
|
|
77256
77256
|
/*! *****************************************************************************
|
|
77257
77257
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
77258
77258
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
@@ -261315,7 +261315,7 @@ var require_dist3 = __commonJS((exports, module) => {
|
|
|
261315
261315
|
|
|
261316
261316
|
// ../../node_modules/.bun/xcode@3.0.1/node_modules/xcode/lib/pbxProject.js
|
|
261317
261317
|
var require_pbxProject = __commonJS((exports, module) => {
|
|
261318
|
-
var __dirname = "/
|
|
261318
|
+
var __dirname = "/home/runner/work/expo-up/expo-up/node_modules/.bun/xcode@3.0.1/node_modules/xcode/lib";
|
|
261319
261319
|
var util = __require("util");
|
|
261320
261320
|
var f = util.format;
|
|
261321
261321
|
var EventEmitter = __require("events").EventEmitter;
|
|
@@ -291301,7 +291301,6 @@ config(en_default());
|
|
|
291301
291301
|
var DEFAULT_CHANNEL = "main";
|
|
291302
291302
|
var INIT_CHANNEL = "__INIT__";
|
|
291303
291303
|
var EMBEDDED_ROLLBACK_TARGET = "EMBEDDED";
|
|
291304
|
-
var DEFAULT_EXPO_UP_BASE_PATH = "/api/expo-up";
|
|
291305
291304
|
// ../core/src/project.ts
|
|
291306
291305
|
function isRecord(value2) {
|
|
291307
291306
|
return typeof value2 === "object" && value2 !== null;
|
|
@@ -291360,7 +291359,7 @@ async function resolveRollbackTarget(input) {
|
|
|
291360
291359
|
throw new Error(`Rollback chain exceeded max depth (${maxDepth}).`);
|
|
291361
291360
|
}
|
|
291362
291361
|
// ../core/src/url.ts
|
|
291363
|
-
function parseExpoUpUpdatesUrl(rawUpdatesUrl, basePath =
|
|
291362
|
+
function parseExpoUpUpdatesUrl(rawUpdatesUrl, basePath = "/api/expo-up") {
|
|
291364
291363
|
if (!rawUpdatesUrl) {
|
|
291365
291364
|
return { serverUrl: "", projectId: "" };
|
|
291366
291365
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo-up/cli",
|
|
3
|
-
"version": "0.1.0",
|
|
3
|
+
"version": "0.1.2-next.0",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/glncy/expo-up"
|
|
8
|
+
},
|
|
5
9
|
"bin": {
|
|
6
|
-
"expo-up": "
|
|
10
|
+
"expo-up": "dist/index.js"
|
|
7
11
|
},
|
|
8
12
|
"scripts": {
|
|
9
13
|
"build": "bun build ./src/index.tsx --outdir ./dist --target node --external react --external ink --external ink-spinner --external figlet",
|
package/src/index.tsx
CHANGED
|
@@ -306,7 +306,9 @@ program
|
|
|
306
306
|
|
|
307
307
|
program
|
|
308
308
|
.command("codesigning:configure")
|
|
309
|
-
.description(
|
|
309
|
+
.description(
|
|
310
|
+
"Configure Expo config codeSigning fields from existing cert/key",
|
|
311
|
+
)
|
|
310
312
|
.option(
|
|
311
313
|
"-p, --project-root <path>",
|
|
312
314
|
"Expo app root containing app.json or app.config.* (defaults to auto-detect)",
|
|
@@ -193,7 +193,9 @@ describe("createSortedMetadataHash", () => {
|
|
|
193
193
|
},
|
|
194
194
|
};
|
|
195
195
|
|
|
196
|
-
expect(createSortedMetadataHash(first)).toBe(
|
|
196
|
+
expect(createSortedMetadataHash(first)).toBe(
|
|
197
|
+
createSortedMetadataHash(second),
|
|
198
|
+
);
|
|
197
199
|
});
|
|
198
200
|
|
|
199
201
|
it("changes when metadata content changes", () => {
|
package/src/release.tsx
CHANGED
|
@@ -146,7 +146,8 @@ export const Release: React.FC<ReleaseProps> = ({
|
|
|
146
146
|
|
|
147
147
|
const metadata = readJsonFile<unknown>(metadataPath);
|
|
148
148
|
const sortedMetadataHash = createSortedMetadataHash(metadata);
|
|
149
|
-
if (debug)
|
|
149
|
+
if (debug)
|
|
150
|
+
appendDebug(`Local sorted metadata hash: ${sortedMetadataHash}`);
|
|
150
151
|
|
|
151
152
|
const appConfig = getConfig(process.cwd());
|
|
152
153
|
fs.writeFileSync(
|