publish-apk 0.0.1-alpha.13 → 0.0.1-alpha.15

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/README.md CHANGED
@@ -192,14 +192,16 @@ ANDROID_KEYSTORE_BASE64=... ANDROID_KEYSTORE_PASSWORD=... publish-apk keystore
192
192
 
193
193
  ### keystore-env(导出 Android keystore 的 CI 变量)
194
194
 
195
- 把一份 keystore 文件导出成 CI 可直接配置的四个变量:
195
+ 把一份 keystore 文件导出成 CI 可直接配置的变量。默认输出四个:
196
196
 
197
197
  | 变量 | 内容 |
198
198
  | --- | --- |
199
- | `ANDROID_KEYSTORE_BASE64` | keystore 文件的单行 BASE64 |
199
+ | `ANDROID_KEYSTORE_BASE64` | keystore 文件的单行 BASE64;加 `--no-base64` 可去掉 |
200
200
  | `ANDROID_KEYSTORE_PASSWORD` | keystore 明文口令 |
201
201
  | `ANDROID_KEY_ALIAS` | 私钥别名(不传 `--key-alias` 时由 keytool 自动识别) |
202
202
  | `ANDROID_KEY_PASSWORD` | 私钥明文口令(默认与 keystore 口令相同) |
203
+ | `ANDROID_KEYSTORE_FILE` | 可选;加 `--include-file` 输出 keystore 的绝对路径,给本地 `signing.env` 用 |
204
+
203
205
 
204
206
  ```bash
205
207
  # 默认 env 格式:KEY=value,一行一个,适合逐项复制到 CI 变量
@@ -210,11 +212,17 @@ ANDROID_KEYSTORE_PASSWORD=<口令> publish-apk keystore-env --file ./release.p12
210
212
 
211
213
  # JSON 格式
212
214
  ANDROID_KEYSTORE_PASSWORD=<口令> publish-apk keystore-env --file ./release.p12 --format json > keystore.json
215
+
216
+ # 生成可直接 source 的本地签名环境(要文件路径,不要 BASE64)
217
+ ANDROID_KEYSTORE_PASSWORD=<口令> publish-apk keystore-env --file ./release.p12 \
218
+ --format shell --include-file --no-base64 > .signing/android.env
213
219
  ```
214
220
 
215
221
  - 生成变量前会用 keytool 校验 keystore 口令、别名与私钥口令,校验失败不会输出变量。
216
222
  - `--key-alias` / `ANDROID_KEY_ALIAS` 不传时自动识别;`--key-password` / `ANDROID_KEY_PASSWORD`
217
223
  不传时使用 keystore 口令。
224
+ - `--include-file` 额外输出 `ANDROID_KEYSTORE_FILE`;`--no-base64` 去掉 `ANDROID_KEYSTORE_BASE64`。
225
+ 两者一起用适合生成 `.signing/android.env`,避免把整份 BASE64 再塞进本地环境。
218
226
  - `env` 格式不额外加引号,适合把 `=` 后面的值逐项复制到 CI 变量;`shell` 格式适合本地
219
227
  `source`;`json` 格式适合脚本解析。
220
228
  - **警告:输出包含明文口令**,不要写入日志、提交仓库或公开分享;`stdout` 只有变量,
@@ -480,7 +488,7 @@ HARMONY_CERTPATH_BASE64=... \
480
488
  HARMONY_PROFILE_BASE64=... \
481
489
  HARMONY_STORE_PASSWORD=<p12口令> \
482
490
  publish-apk huawei signing-material-env \
483
- --config ./build-profile.json5 --name default
491
+ --config ./build-profile.json5 --name default --require-all
484
492
  ```
485
493
 
486
494
  - 支持的 `HARMONY_*` 变量:
@@ -493,6 +501,8 @@ publish-apk huawei signing-material-env \
493
501
  - `HARMONY_*_OUT` 控制 BASE64 / 内容落盘位置
494
502
  - 先校验证书 / Profile / p12 内容;有口令时还会用 `keytool` 自检;全部通过后才写回。
495
503
  - 没有提供的变量保持原值;只替换提供的字段。
504
+ - `--require-all` 要求 store / cert / profile / 口令齐全,缺一项直接失败;CI 用这个开关保证
505
+ 不会拿半套材料继续打包。
496
506
  - 口令通过 `.p12` 同级 `material/` 加密;material 不存在时自动生成,`--new-material` 可重造。
497
507
  - 写回前备份到 `.signing/backup/`,写后回读校验。
498
508
  - 只给 `HARMONY_KEY_PASSWORD` 时还需要 `HARMONY_STORE_PASSWORD` 才能校验 / 加密。
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "publish-apk",
3
- "version": "0.0.1-alpha.13",
3
+ "version": "0.0.1-alpha.15",
4
4
  "description": "发布 华为 Android .apk、Harmony .app、Google Play Android .aab",
5
+ "homepage": "https://xuxiaowei.io",
5
6
  "keywords": [
6
7
  "huawei",
7
8
  "agc",
@@ -63,6 +63,8 @@ const OPTION_PRODUCT = '--product'
63
63
  const OPTION_WRITE = '--write'
64
64
  const OPTION_NEW_MATERIAL = '--new-material'
65
65
  const OPTION_NO_KEYTOOL = '--no-keytool'
66
+ /** signing-material-env:要求 store / cert / profile / 口令齐全 */
67
+ const OPTION_REQUIRE_ALL = '--require-all'
66
68
  const OPTION_VERBOSE = '--verbose'
67
69
 
68
70
  const SIGNING_OPTIONS = new Set([
@@ -119,8 +121,9 @@ const MATERIAL_ENV_OPTIONS = new Set([
119
121
  OPTION_PRODUCT,
120
122
  OPTION_NO_KEYTOOL,
121
123
  OPTION_NEW_MATERIAL,
124
+ OPTION_REQUIRE_ALL,
122
125
  ])
123
- const MATERIAL_ENV_FLAGS = new Set([OPTION_NO_KEYTOOL, OPTION_NEW_MATERIAL])
126
+ const MATERIAL_ENV_FLAGS = new Set([OPTION_NO_KEYTOOL, OPTION_NEW_MATERIAL, OPTION_REQUIRE_ALL])
124
127
 
125
128
  const ENV_STORE_FILE = 'HARMONY_STORE_FILE'
126
129
  const ENV_STORE_FILE_BASE64 = 'HARMONY_STORE_FILE_BASE64'
@@ -646,6 +649,7 @@ function renderSigningMaterialEnvHelp() {
646
649
  [`${OPTION_PRODUCT} <产品>`, `按 products[].name 找到它挂的 signingConfig(可用 ${ENV_PRODUCT} 补齐)`],
647
650
  [OPTION_NO_KEYTOOL, '跳过 keytool 口令自检(仍会校验证书 / Profile / p12 内容)'],
648
651
  [OPTION_NEW_MATERIAL, 'material 已存在也重造一套(旧的挪成 material.bak-<时间戳>)'],
652
+ [OPTION_REQUIRE_ALL, '要求 store / cert / profile / 口令齐全;缺一项直接失败(CI 用)'],
649
653
  ['-h, --help', '显示帮助信息'],
650
654
  ],
651
655
  },
@@ -1766,6 +1770,20 @@ export async function runHuaweiSigningMaterialEnv(argv, env) {
1766
1770
  const storePasswordEnv = readEnv(env, ENV_STORE_PASSWORD)
1767
1771
  const keyPasswordEnv = readEnv(env, ENV_KEY_PASSWORD)
1768
1772
 
1773
+ if (options.get(OPTION_REQUIRE_ALL) === true) {
1774
+ const missing = []
1775
+ if (storeValues.length === 0) missing.push(`${ENV_STORE_FILE} / ${ENV_STORE_FILE_BASE64}`)
1776
+ if (certValues.length === 0) missing.push(`${ENV_CERTPATH} / ${ENV_CERTPATH_BASE64}`)
1777
+ if (profileValues.length === 0) missing.push(`${ENV_PROFILE} / ${ENV_PROFILE_BASE64}`)
1778
+ if (storePasswordEnv === undefined) missing.push(ENV_STORE_PASSWORD)
1779
+ if (missing.length > 0) {
1780
+ throw new UsageError(
1781
+ `${OPTION_REQUIRE_ALL} 缺少:${missing.join('、')}`,
1782
+ renderSigningMaterialEnvHelp(),
1783
+ )
1784
+ }
1785
+ }
1786
+
1769
1787
  const configStoreFileValue = stringField(entry.text, 'storeFile')
1770
1788
  let storeFile =
1771
1789
  configStoreFileValue === undefined || configStoreFileValue.trim() === ''
package/src/keystore.js CHANGED
@@ -71,6 +71,10 @@ const OPTION_VALIDITY = '--validity'
71
71
  const OPTION_DNAME = '--dname'
72
72
  const OPTION_FORCE = '--force'
73
73
  const OPTION_FORMAT = '--format'
74
+ /** keystore-env:额外输出 ANDROID_KEYSTORE_FILE(绝对路径) */
75
+ const OPTION_INCLUDE_FILE = '--include-file'
76
+ /** keystore-env:不输出 ANDROID_KEYSTORE_BASE64 */
77
+ const OPTION_NO_BASE64 = '--no-base64'
74
78
 
75
79
  const KEYSTORE_OPTIONS = new Set([
76
80
  OPTION_FILE,
@@ -100,8 +104,10 @@ const ENV_OPTIONS = new Set([
100
104
  OPTION_KEY_ALIAS,
101
105
  OPTION_KEY_PASSWORD,
102
106
  OPTION_FORMAT,
107
+ OPTION_INCLUDE_FILE,
108
+ OPTION_NO_BASE64,
103
109
  ])
104
- const ENV_FLAGS = new Set()
110
+ const ENV_FLAGS = new Set([OPTION_INCLUDE_FILE, OPTION_NO_BASE64])
105
111
 
106
112
  /** 密钥库路径,等价于 --file(也可用 ANDROID_KEYSTORE 补) */
107
113
  const ENV_FILE = 'ANDROID_KEYSTORE_FILE'
@@ -884,6 +890,8 @@ function renderKeystoreEnvHelp() {
884
890
  `${OPTION_FORMAT} <env|shell|json>`,
885
891
  '输出格式,默认 env(KEY=value,一行一个);shell 输出 export KEY=...;json 输出对象',
886
892
  ],
893
+ [OPTION_INCLUDE_FILE, '额外输出 ANDROID_KEYSTORE_FILE(绝对路径)'],
894
+ [OPTION_NO_BASE64, '不输出 ANDROID_KEYSTORE_BASE64(本地 signing.env 用)'],
887
895
  ['-h, --help', '显示帮助信息'],
888
896
  ],
889
897
  },
@@ -902,7 +910,7 @@ function renderKeystoreEnvHelp() {
902
910
  entries: [
903
911
  [
904
912
  'stdout',
905
- 'ANDROID_KEYSTORE_BASE64 / ANDROID_KEYSTORE_PASSWORD / ANDROID_KEY_ALIAS / ANDROID_KEY_PASSWORD',
913
+ '默认 ANDROID_KEYSTORE_BASE64 / PASSWORD / ALIAS / KEY_PASSWORD;加 --include-file 输出 ANDROID_KEYSTORE_FILE,加 --no-base64 去掉 BASE64',
906
914
  ],
907
915
  ['stderr', '明文口令警告与错误信息'],
908
916
  ],
@@ -920,6 +928,7 @@ function renderKeystoreEnvHelp() {
920
928
  ` ${PROGRAM} ${ENV_COMMAND_NAME} --file ./release.p12`,
921
929
  ` ANDROID_KEYSTORE_PASSWORD=<口令> ${PROGRAM} ${ENV_COMMAND_NAME} --file ./release.p12 --format shell`,
922
930
  ` ${PROGRAM} ${ENV_COMMAND_NAME} --file ./release.p12 --format json > keystore.json`,
931
+ ` ${PROGRAM} ${ENV_COMMAND_NAME} --file ./release.p12 --format shell --include-file --no-base64 > signing.env`,
923
932
  '',
924
933
  '警告: 输出包含明文口令,请勿写入日志、提交仓库或公开分享',
925
934
  '说明: 生成前会用 keytool 校验 keystore 口令、别名与私钥口令',
@@ -929,13 +938,19 @@ function renderKeystoreEnvHelp() {
929
938
  })
930
939
  }
931
940
 
932
- function renderKeystoreEnvVariables(buffer, alias, storePassword, keyPassword, format, help) {
933
- const values = [
934
- ['ANDROID_KEYSTORE_BASE64', buffer.toString('base64')],
941
+ function renderKeystoreEnvVariables(absolute, buffer, alias, storePassword, keyPassword, format, options, help) {
942
+ const values = []
943
+ if (!options.get(OPTION_NO_BASE64)) {
944
+ values.push(['ANDROID_KEYSTORE_BASE64', buffer.toString('base64')])
945
+ }
946
+ if (options.get(OPTION_INCLUDE_FILE)) {
947
+ values.push(['ANDROID_KEYSTORE_FILE', absolute])
948
+ }
949
+ values.push(
935
950
  ['ANDROID_KEYSTORE_PASSWORD', storePassword],
936
951
  ['ANDROID_KEY_ALIAS', alias],
937
952
  ['ANDROID_KEY_PASSWORD', keyPassword],
938
- ]
953
+ )
939
954
  if (format === 'env') {
940
955
  return values.map(([name, value]) => `${name}=${value}`).join('\n')
941
956
  }
@@ -994,7 +1009,9 @@ async function runKeystoreEnv(argv, env) {
994
1009
  })
995
1010
  stderr('警告: 输出包含明文口令,请勿写入日志、提交仓库或公开分享')
996
1011
  stdout(
997
- renderKeystoreEnvVariables(buffer, info.alias, storePassword, keyPassword, format, renderKeystoreEnvHelp()),
1012
+ renderKeystoreEnvVariables(
1013
+ absolute, buffer, info.alias, storePassword, keyPassword, format, options, renderKeystoreEnvHelp(),
1014
+ ),
998
1015
  )
999
1016
  return EXIT_OK
1000
1017
  }