expo-release 2.3.1 → 2.3.2
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/dist/args.d.ts +14 -14
- package/dist/cli.js +25 -20
- package/dist/index.js +10 -11
- package/package.json +2 -2
- package/src/args.ts +28 -18
- package/src/cli.ts +23 -24
package/dist/args.d.ts
CHANGED
|
@@ -32,47 +32,47 @@ export declare const releaseFlags: z.ZodObject<{
|
|
|
32
32
|
profile: z.ZodString;
|
|
33
33
|
base: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
34
34
|
head: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
35
|
-
platform: z.ZodDefault<z.ZodEnum<{
|
|
35
|
+
platform: z.ZodDefault<z.ZodPreprocess<z.ZodEnum<{
|
|
36
36
|
android: "android";
|
|
37
37
|
ios: "ios";
|
|
38
|
-
}>>;
|
|
38
|
+
}>, unknown>>;
|
|
39
39
|
impactPaths: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<string[], string>>;
|
|
40
|
-
ignoreExpoImpact: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
|
|
40
|
+
ignoreExpoImpact: z.ZodPipe<z.ZodDefault<z.ZodPreprocess<z.ZodEnum<{
|
|
41
41
|
false: "false";
|
|
42
42
|
true: "true";
|
|
43
|
-
}>>, z.ZodTransform<boolean, "false" | "true">>;
|
|
44
|
-
operation: z.ZodDefault<z.ZodEnum<{
|
|
43
|
+
}>, unknown>>, z.ZodTransform<boolean, "false" | "true">>;
|
|
44
|
+
operation: z.ZodDefault<z.ZodPreprocess<z.ZodEnum<{
|
|
45
45
|
deploy: "deploy";
|
|
46
46
|
"force-native": "force-native";
|
|
47
47
|
republish: "republish";
|
|
48
48
|
"retry-ota": "retry-ota";
|
|
49
49
|
"rollback-embedded": "rollback-embedded";
|
|
50
|
-
}>>;
|
|
51
|
-
deployType: z.ZodDefault<z.ZodEnum<{
|
|
50
|
+
}>, unknown>>;
|
|
51
|
+
deployType: z.ZodDefault<z.ZodPreprocess<z.ZodEnum<{
|
|
52
52
|
native: "native";
|
|
53
53
|
none: "none";
|
|
54
54
|
ota: "ota";
|
|
55
|
-
}>>;
|
|
55
|
+
}>, unknown>>;
|
|
56
56
|
channel: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
57
57
|
environment: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
58
|
-
autoSubmit: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
|
|
58
|
+
autoSubmit: z.ZodPipe<z.ZodDefault<z.ZodPreprocess<z.ZodEnum<{
|
|
59
59
|
false: "false";
|
|
60
60
|
true: "true";
|
|
61
|
-
}>>, z.ZodTransform<boolean, "false" | "true">>;
|
|
61
|
+
}>, unknown>>, z.ZodTransform<boolean, "false" | "true">>;
|
|
62
62
|
preUpdate: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
63
63
|
postUpdate: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
64
64
|
updateExtraArgs: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
65
|
-
exportSourceMaps: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
|
|
65
|
+
exportSourceMaps: z.ZodPipe<z.ZodDefault<z.ZodPreprocess<z.ZodEnum<{
|
|
66
66
|
false: "false";
|
|
67
67
|
true: "true";
|
|
68
|
-
}>>, z.ZodTransform<boolean, "false" | "true">>;
|
|
68
|
+
}>, unknown>>, z.ZodTransform<boolean, "false" | "true">>;
|
|
69
69
|
group: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
70
70
|
runtimeVersion: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
71
71
|
message: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
72
72
|
fingerprint: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
73
|
-
dryRun: z.ZodBoolean
|
|
73
|
+
dryRun: z.ZodPreprocess<z.ZodBoolean, unknown>;
|
|
74
74
|
}, z.core.$strip>;
|
|
75
75
|
export type ReleaseFlags = z.output<typeof releaseFlags>;
|
|
76
|
-
export declare function toReleaseOptions(command: CommandName, { context: flags
|
|
76
|
+
export declare function toReleaseOptions(command: CommandName, { context: flags }: CommandContext<ReleaseFlags>): ReleaseOptions;
|
|
77
77
|
export declare function needsDecide(operation: Operation): boolean;
|
|
78
78
|
export declare function shouldIgnoreExpoImpact(options: Pick<ReleaseOptions, 'ignoreExpoImpact' | 'operation'>): boolean;
|
package/dist/cli.js
CHANGED
|
@@ -2,18 +2,23 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
CliUsageError,
|
|
7
|
+
defineCli,
|
|
8
|
+
defineCommand
|
|
9
|
+
} from "hanzio/cli";
|
|
6
10
|
|
|
7
11
|
// src/args.ts
|
|
8
12
|
import { z } from "zod";
|
|
9
13
|
var DEFAULT_IMPACT_PATHS = ["apps/expo/"];
|
|
10
14
|
var text = (env) => z.string().transform((value) => value.trim() || undefined).optional().meta({ env: `EXPO_RELEASE_${env}` });
|
|
11
|
-
var
|
|
15
|
+
var trimmed = (schema) => z.preprocess((value) => typeof value === "string" ? value.trim() : value, schema);
|
|
16
|
+
var trueFalse = (env, fallback) => trimmed(z.enum(["true", "false"])).default(fallback).transform((value) => value === "true").meta({ env: `EXPO_RELEASE_${env}` });
|
|
12
17
|
var releaseFlags = z.object({
|
|
13
18
|
profile: z.string().trim().min(1).meta({ env: "EXPO_RELEASE_PROFILE" }).describe("EAS build profile, also the default update channel"),
|
|
14
|
-
base: text("BASE").describe("Git base SHA for the impact diff
|
|
15
|
-
head: text("HEAD").describe("Git head SHA for the impact diff
|
|
16
|
-
platform: z.enum(["ios", "android"]).default("ios").meta({ env: "EXPO_RELEASE_PLATFORM" }).describe("Native platform"),
|
|
19
|
+
base: text("BASE").meta({ env: ["EXPO_RELEASE_BASE", "GITHUB_EVENT_BEFORE"] }).describe("Git base SHA for the impact diff"),
|
|
20
|
+
head: text("HEAD").meta({ env: ["EXPO_RELEASE_HEAD", "GITHUB_SHA"] }).describe("Git head SHA for the impact diff"),
|
|
21
|
+
platform: trimmed(z.enum(["ios", "android"])).default("ios").meta({ env: "EXPO_RELEASE_PLATFORM" }).describe("Native platform"),
|
|
17
22
|
impactPaths: z.string().default(DEFAULT_IMPACT_PATHS.join(",")).transform((value, ctx) => {
|
|
18
23
|
const paths = value.split(",").map((path) => path.trim()).filter(Boolean);
|
|
19
24
|
if (paths.length === 0)
|
|
@@ -24,14 +29,14 @@ var releaseFlags = z.object({
|
|
|
24
29
|
return paths;
|
|
25
30
|
}).meta({ env: "EXPO_RELEASE_IMPACT_PATHS" }).describe("Comma-separated repo-root paths that count as an Expo change"),
|
|
26
31
|
ignoreExpoImpact: trueFalse("IGNORE_EXPO_IMPACT", "false").describe("Check the fingerprint even when no impact path changed"),
|
|
27
|
-
operation: z.enum([
|
|
32
|
+
operation: trimmed(z.enum([
|
|
28
33
|
"deploy",
|
|
29
34
|
"force-native",
|
|
30
35
|
"retry-ota",
|
|
31
36
|
"republish",
|
|
32
37
|
"rollback-embedded"
|
|
33
|
-
]).default("deploy").meta({ env: "EXPO_RELEASE_OPERATION" }).describe("What to run"),
|
|
34
|
-
deployType: z.enum(["none", "ota", "native"]).default("none").meta({ env: "EXPO_RELEASE_DEPLOY_TYPE" }).describe("Decision type for operate"),
|
|
38
|
+
])).default("deploy").meta({ env: "EXPO_RELEASE_OPERATION" }).describe("What to run"),
|
|
39
|
+
deployType: trimmed(z.enum(["none", "ota", "native"])).default("none").meta({ env: "EXPO_RELEASE_DEPLOY_TYPE" }).describe("Decision type for operate"),
|
|
35
40
|
channel: text("CHANNEL").describe("EAS Update channel (default: the profile)"),
|
|
36
41
|
environment: text("ENVIRONMENT").describe("EAS environment for eas update (required for Expo SDK 55+)"),
|
|
37
42
|
autoSubmit: trueFalse("AUTO_SUBMIT", "true").describe("Pass --auto-submit on native builds"),
|
|
@@ -43,7 +48,7 @@ var releaseFlags = z.object({
|
|
|
43
48
|
runtimeVersion: text("RUNTIME_VERSION").describe("Runtime version for rollback-embedded (default: the fingerprint)"),
|
|
44
49
|
message: text("MESSAGE").describe("Override the eas update message"),
|
|
45
50
|
fingerprint: text("FINGERPRINT").describe("Fingerprint hash to use instead of generating one"),
|
|
46
|
-
dryRun: z.boolean().meta({ env: "EXPO_RELEASE_DRY_RUN" }).describe("Print mutating EAS commands without running them")
|
|
51
|
+
dryRun: z.preprocess((value) => typeof value === "string" && /^\s*(true|false)\s*$/.test(value) ? value.trim() === "true" : value, z.boolean()).meta({ env: "EXPO_RELEASE_DRY_RUN" }).describe("Print mutating EAS commands without running them")
|
|
47
52
|
}).superRefine((flags, ctx) => {
|
|
48
53
|
if (flags.operation === "republish" && !flags.group)
|
|
49
54
|
ctx.addIssue({
|
|
@@ -52,12 +57,10 @@ var releaseFlags = z.object({
|
|
|
52
57
|
message: "required by --operation republish"
|
|
53
58
|
});
|
|
54
59
|
});
|
|
55
|
-
function toReleaseOptions(command, { context: flags
|
|
60
|
+
function toReleaseOptions(command, { context: flags }) {
|
|
56
61
|
return {
|
|
57
62
|
...flags,
|
|
58
63
|
command,
|
|
59
|
-
base: flags.base ?? env.GITHUB_EVENT_BEFORE,
|
|
60
|
-
head: flags.head ?? env.GITHUB_SHA,
|
|
61
64
|
channel: flags.channel ?? flags.profile
|
|
62
65
|
};
|
|
63
66
|
}
|
|
@@ -568,12 +571,20 @@ async function operate(options, decision, ctx) {
|
|
|
568
571
|
ctx.stdout.write(`${result}
|
|
569
572
|
`);
|
|
570
573
|
}
|
|
571
|
-
var COMMANDS = ["release", "decide", "operate"];
|
|
572
574
|
var cli = defineCli({
|
|
573
575
|
name: "expo-release",
|
|
574
576
|
description: "Fingerprint-driven Expo EAS release: OTA update or native store build",
|
|
575
577
|
globals: releaseFlags,
|
|
576
578
|
context: (flags) => flags,
|
|
579
|
+
defaultCommand: (env) => env.EXPO_RELEASE_COMMAND?.trim() || undefined,
|
|
580
|
+
onError: (error, io) => {
|
|
581
|
+
if (error instanceof CliUsageError && error.kind === "missing-command" && process.argv.length <= 2) {
|
|
582
|
+
io.stdout.write(error.help);
|
|
583
|
+
return 0;
|
|
584
|
+
}
|
|
585
|
+
const code = io.print();
|
|
586
|
+
return code === 2 ? 1 : code;
|
|
587
|
+
},
|
|
577
588
|
commands: {
|
|
578
589
|
release: defineCommand({
|
|
579
590
|
description: "Run decide, then operate on its decision",
|
|
@@ -597,10 +608,4 @@ var cli = defineCli({
|
|
|
597
608
|
})
|
|
598
609
|
}
|
|
599
610
|
});
|
|
600
|
-
|
|
601
|
-
var argv = process.argv.slice(2);
|
|
602
|
-
if (!argv.some((arg) => COMMANDS.includes(arg))) {
|
|
603
|
-
argv = env.EXPO_RELEASE_COMMAND ? [env.EXPO_RELEASE_COMMAND, ...argv] : argv.length === 0 ? ["--help"] : argv;
|
|
604
|
-
}
|
|
605
|
-
var code = await cli.run(argv, { env });
|
|
606
|
-
process.exitCode = code === 2 ? 1 : code;
|
|
611
|
+
process.exitCode = await cli.run();
|
package/dist/index.js
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
var DEFAULT_IMPACT_PATHS = ["apps/expo/"];
|
|
5
5
|
var text = (env) => z.string().transform((value) => value.trim() || undefined).optional().meta({ env: `EXPO_RELEASE_${env}` });
|
|
6
|
-
var
|
|
6
|
+
var trimmed = (schema) => z.preprocess((value) => typeof value === "string" ? value.trim() : value, schema);
|
|
7
|
+
var trueFalse = (env, fallback) => trimmed(z.enum(["true", "false"])).default(fallback).transform((value) => value === "true").meta({ env: `EXPO_RELEASE_${env}` });
|
|
7
8
|
var releaseFlags = z.object({
|
|
8
9
|
profile: z.string().trim().min(1).meta({ env: "EXPO_RELEASE_PROFILE" }).describe("EAS build profile, also the default update channel"),
|
|
9
|
-
base: text("BASE").describe("Git base SHA for the impact diff
|
|
10
|
-
head: text("HEAD").describe("Git head SHA for the impact diff
|
|
11
|
-
platform: z.enum(["ios", "android"]).default("ios").meta({ env: "EXPO_RELEASE_PLATFORM" }).describe("Native platform"),
|
|
10
|
+
base: text("BASE").meta({ env: ["EXPO_RELEASE_BASE", "GITHUB_EVENT_BEFORE"] }).describe("Git base SHA for the impact diff"),
|
|
11
|
+
head: text("HEAD").meta({ env: ["EXPO_RELEASE_HEAD", "GITHUB_SHA"] }).describe("Git head SHA for the impact diff"),
|
|
12
|
+
platform: trimmed(z.enum(["ios", "android"])).default("ios").meta({ env: "EXPO_RELEASE_PLATFORM" }).describe("Native platform"),
|
|
12
13
|
impactPaths: z.string().default(DEFAULT_IMPACT_PATHS.join(",")).transform((value, ctx) => {
|
|
13
14
|
const paths = value.split(",").map((path) => path.trim()).filter(Boolean);
|
|
14
15
|
if (paths.length === 0)
|
|
@@ -19,14 +20,14 @@ var releaseFlags = z.object({
|
|
|
19
20
|
return paths;
|
|
20
21
|
}).meta({ env: "EXPO_RELEASE_IMPACT_PATHS" }).describe("Comma-separated repo-root paths that count as an Expo change"),
|
|
21
22
|
ignoreExpoImpact: trueFalse("IGNORE_EXPO_IMPACT", "false").describe("Check the fingerprint even when no impact path changed"),
|
|
22
|
-
operation: z.enum([
|
|
23
|
+
operation: trimmed(z.enum([
|
|
23
24
|
"deploy",
|
|
24
25
|
"force-native",
|
|
25
26
|
"retry-ota",
|
|
26
27
|
"republish",
|
|
27
28
|
"rollback-embedded"
|
|
28
|
-
]).default("deploy").meta({ env: "EXPO_RELEASE_OPERATION" }).describe("What to run"),
|
|
29
|
-
deployType: z.enum(["none", "ota", "native"]).default("none").meta({ env: "EXPO_RELEASE_DEPLOY_TYPE" }).describe("Decision type for operate"),
|
|
29
|
+
])).default("deploy").meta({ env: "EXPO_RELEASE_OPERATION" }).describe("What to run"),
|
|
30
|
+
deployType: trimmed(z.enum(["none", "ota", "native"])).default("none").meta({ env: "EXPO_RELEASE_DEPLOY_TYPE" }).describe("Decision type for operate"),
|
|
30
31
|
channel: text("CHANNEL").describe("EAS Update channel (default: the profile)"),
|
|
31
32
|
environment: text("ENVIRONMENT").describe("EAS environment for eas update (required for Expo SDK 55+)"),
|
|
32
33
|
autoSubmit: trueFalse("AUTO_SUBMIT", "true").describe("Pass --auto-submit on native builds"),
|
|
@@ -38,7 +39,7 @@ var releaseFlags = z.object({
|
|
|
38
39
|
runtimeVersion: text("RUNTIME_VERSION").describe("Runtime version for rollback-embedded (default: the fingerprint)"),
|
|
39
40
|
message: text("MESSAGE").describe("Override the eas update message"),
|
|
40
41
|
fingerprint: text("FINGERPRINT").describe("Fingerprint hash to use instead of generating one"),
|
|
41
|
-
dryRun: z.boolean().meta({ env: "EXPO_RELEASE_DRY_RUN" }).describe("Print mutating EAS commands without running them")
|
|
42
|
+
dryRun: z.preprocess((value) => typeof value === "string" && /^\s*(true|false)\s*$/.test(value) ? value.trim() === "true" : value, z.boolean()).meta({ env: "EXPO_RELEASE_DRY_RUN" }).describe("Print mutating EAS commands without running them")
|
|
42
43
|
}).superRefine((flags, ctx) => {
|
|
43
44
|
if (flags.operation === "republish" && !flags.group)
|
|
44
45
|
ctx.addIssue({
|
|
@@ -47,12 +48,10 @@ var releaseFlags = z.object({
|
|
|
47
48
|
message: "required by --operation republish"
|
|
48
49
|
});
|
|
49
50
|
});
|
|
50
|
-
function toReleaseOptions(command, { context: flags
|
|
51
|
+
function toReleaseOptions(command, { context: flags }) {
|
|
51
52
|
return {
|
|
52
53
|
...flags,
|
|
53
54
|
command,
|
|
54
|
-
base: flags.base ?? env.GITHUB_EVENT_BEFORE,
|
|
55
|
-
head: flags.head ?? env.GITHUB_SHA,
|
|
56
55
|
channel: flags.channel ?? flags.profile
|
|
57
56
|
};
|
|
58
57
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-release",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"description": "Fingerprint-driven Expo EAS release: OTA update or native store build, plus app runtime helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"verify:package": "node scripts/verify-package.mjs"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"hanzio": "^3.
|
|
61
|
+
"hanzio": "^3.3.0",
|
|
62
62
|
"zod": "^4.3.6"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
package/src/args.ts
CHANGED
|
@@ -48,10 +48,16 @@ const text = (env: string) =>
|
|
|
48
48
|
.optional()
|
|
49
49
|
.meta({ env: `EXPO_RELEASE_${env}` })
|
|
50
50
|
|
|
51
|
+
// hanzio/cli skips blank env values but keeps padding (`platform: |` in YAML adds a newline).
|
|
52
|
+
const trimmed = <T extends z.ZodType>(schema: T) =>
|
|
53
|
+
z.preprocess(
|
|
54
|
+
(value) => (typeof value === 'string' ? value.trim() : value),
|
|
55
|
+
schema
|
|
56
|
+
)
|
|
57
|
+
|
|
51
58
|
// `--auto-submit false` takes a value, so these are not boolean switches.
|
|
52
59
|
const trueFalse = (env: string, fallback: 'true' | 'false') =>
|
|
53
|
-
z
|
|
54
|
-
.enum(['true', 'false'])
|
|
60
|
+
trimmed(z.enum(['true', 'false']))
|
|
55
61
|
.default(fallback)
|
|
56
62
|
.transform((value) => value === 'true')
|
|
57
63
|
.meta({ env: `EXPO_RELEASE_${env}` })
|
|
@@ -64,14 +70,13 @@ export const releaseFlags = z
|
|
|
64
70
|
.min(1)
|
|
65
71
|
.meta({ env: 'EXPO_RELEASE_PROFILE' })
|
|
66
72
|
.describe('EAS build profile, also the default update channel'),
|
|
67
|
-
base: text('BASE')
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
head: text('HEAD')
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
platform: z
|
|
74
|
-
.enum(['ios', 'android'])
|
|
73
|
+
base: text('BASE')
|
|
74
|
+
.meta({ env: ['EXPO_RELEASE_BASE', 'GITHUB_EVENT_BEFORE'] })
|
|
75
|
+
.describe('Git base SHA for the impact diff'),
|
|
76
|
+
head: text('HEAD')
|
|
77
|
+
.meta({ env: ['EXPO_RELEASE_HEAD', 'GITHUB_SHA'] })
|
|
78
|
+
.describe('Git head SHA for the impact diff'),
|
|
79
|
+
platform: trimmed(z.enum(['ios', 'android']))
|
|
75
80
|
.default('ios')
|
|
76
81
|
.meta({ env: 'EXPO_RELEASE_PLATFORM' })
|
|
77
82
|
.describe('Native platform'),
|
|
@@ -95,19 +100,19 @@ export const releaseFlags = z
|
|
|
95
100
|
ignoreExpoImpact: trueFalse('IGNORE_EXPO_IMPACT', 'false').describe(
|
|
96
101
|
'Check the fingerprint even when no impact path changed'
|
|
97
102
|
),
|
|
98
|
-
operation:
|
|
99
|
-
.enum([
|
|
103
|
+
operation: trimmed(
|
|
104
|
+
z.enum([
|
|
100
105
|
'deploy',
|
|
101
106
|
'force-native',
|
|
102
107
|
'retry-ota',
|
|
103
108
|
'republish',
|
|
104
109
|
'rollback-embedded'
|
|
105
110
|
])
|
|
111
|
+
)
|
|
106
112
|
.default('deploy')
|
|
107
113
|
.meta({ env: 'EXPO_RELEASE_OPERATION' })
|
|
108
114
|
.describe('What to run'),
|
|
109
|
-
deployType: z
|
|
110
|
-
.enum(['none', 'ota', 'native'])
|
|
115
|
+
deployType: trimmed(z.enum(['none', 'ota', 'native']))
|
|
111
116
|
.default('none')
|
|
112
117
|
.meta({ env: 'EXPO_RELEASE_DEPLOY_TYPE' })
|
|
113
118
|
.describe('Decision type for operate'),
|
|
@@ -141,7 +146,14 @@ export const releaseFlags = z
|
|
|
141
146
|
'Fingerprint hash to use instead of generating one'
|
|
142
147
|
),
|
|
143
148
|
dryRun: z
|
|
144
|
-
.
|
|
149
|
+
.preprocess(
|
|
150
|
+
// hanzio/cli makes booleans of exact `true`/`false`; this takes padded ones too.
|
|
151
|
+
(value) =>
|
|
152
|
+
typeof value === 'string' && /^\s*(true|false)\s*$/.test(value)
|
|
153
|
+
? value.trim() === 'true'
|
|
154
|
+
: value,
|
|
155
|
+
z.boolean()
|
|
156
|
+
)
|
|
145
157
|
.meta({ env: 'EXPO_RELEASE_DRY_RUN' })
|
|
146
158
|
.describe('Print mutating EAS commands without running them')
|
|
147
159
|
})
|
|
@@ -158,13 +170,11 @@ export type ReleaseFlags = z.output<typeof releaseFlags>
|
|
|
158
170
|
|
|
159
171
|
export function toReleaseOptions(
|
|
160
172
|
command: CommandName,
|
|
161
|
-
{ context: flags
|
|
173
|
+
{ context: flags }: CommandContext<ReleaseFlags>
|
|
162
174
|
): ReleaseOptions {
|
|
163
175
|
return {
|
|
164
176
|
...flags,
|
|
165
177
|
command,
|
|
166
|
-
base: flags.base ?? env.GITHUB_EVENT_BEFORE,
|
|
167
|
-
head: flags.head ?? env.GITHUB_SHA,
|
|
168
178
|
channel: flags.channel ?? flags.profile
|
|
169
179
|
}
|
|
170
180
|
}
|
package/src/cli.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import { type CommandContext, defineCli, defineCommand } from 'hanzio/cli'
|
|
4
3
|
import {
|
|
5
|
-
|
|
4
|
+
CliUsageError,
|
|
5
|
+
type CommandContext,
|
|
6
|
+
defineCli,
|
|
7
|
+
defineCommand
|
|
8
|
+
} from 'hanzio/cli'
|
|
9
|
+
import {
|
|
6
10
|
needsDecide,
|
|
7
11
|
type ReleaseFlags,
|
|
8
12
|
type ReleaseOptions,
|
|
@@ -76,8 +80,6 @@ async function operate(
|
|
|
76
80
|
ctx.stdout.write(`${result}\n`)
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
const COMMANDS: CommandName[] = ['release', 'decide', 'operate']
|
|
80
|
-
|
|
81
83
|
const cli = defineCli({
|
|
82
84
|
name: 'expo-release',
|
|
83
85
|
description:
|
|
@@ -85,6 +87,22 @@ const cli = defineCli({
|
|
|
85
87
|
// All three commands take the same flags, before or after the command name.
|
|
86
88
|
globals: releaseFlags,
|
|
87
89
|
context: (flags) => flags,
|
|
90
|
+
// The composite action names the command in EXPO_RELEASE_COMMAND and passes no argv.
|
|
91
|
+
defaultCommand: (env) => env.EXPO_RELEASE_COMMAND?.trim() || undefined,
|
|
92
|
+
onError: (error, io) => {
|
|
93
|
+
// With no arguments at all, print help and exit 0.
|
|
94
|
+
if (
|
|
95
|
+
error instanceof CliUsageError &&
|
|
96
|
+
error.kind === 'missing-command' &&
|
|
97
|
+
process.argv.length <= 2
|
|
98
|
+
) {
|
|
99
|
+
io.stdout.write(error.help)
|
|
100
|
+
return 0
|
|
101
|
+
}
|
|
102
|
+
// Bad arguments exit 1, as before hanzio/cli, which uses 2.
|
|
103
|
+
const code = io.print()
|
|
104
|
+
return code === 2 ? 1 : code
|
|
105
|
+
},
|
|
88
106
|
commands: {
|
|
89
107
|
release: defineCommand({
|
|
90
108
|
description: 'Run decide, then operate on its decision',
|
|
@@ -112,23 +130,4 @@ const cli = defineCli({
|
|
|
112
130
|
}
|
|
113
131
|
})
|
|
114
132
|
|
|
115
|
-
|
|
116
|
-
const env = Object.fromEntries(
|
|
117
|
-
Object.entries(process.env).flatMap(([name, value]) =>
|
|
118
|
-
value?.trim() ? [[name, value.trim()]] : []
|
|
119
|
-
)
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
let argv = process.argv.slice(2)
|
|
123
|
-
if (!argv.some((arg) => COMMANDS.includes(arg as CommandName))) {
|
|
124
|
-
// The composite action names the command in EXPO_RELEASE_COMMAND and passes no argv.
|
|
125
|
-
argv = env.EXPO_RELEASE_COMMAND
|
|
126
|
-
? [env.EXPO_RELEASE_COMMAND, ...argv]
|
|
127
|
-
: argv.length === 0
|
|
128
|
-
? ['--help']
|
|
129
|
-
: argv
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const code = await cli.run(argv, { env })
|
|
133
|
-
// Bad arguments exit 1, as before hanzio/cli, which uses 2.
|
|
134
|
-
process.exitCode = code === 2 ? 1 : code
|
|
133
|
+
process.exitCode = await cli.run()
|