rnbuilder 0.6.70 → 0.6.72
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 +46 -13
- package/lib/commands/build.js +5 -5
- package/lib/commands/setup-gcp.d.ts +8 -0
- package/lib/commands/setup-gcp.js +26 -0
- package/lib/utils/setup/android.d.ts +1 -2
- package/lib/utils/setup/android.js +29 -21
- package/lib/utils/setup/client.js +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/setup_gcp_impersonation.sh +128 -0
package/README.md
CHANGED
|
@@ -10,10 +10,28 @@ React Native builder tool
|
|
|
10
10
|
|
|
11
11
|
<!-- toc -->
|
|
12
12
|
* [rnbuilder](#rnbuilder)
|
|
13
|
+
* [Setup](#setup)
|
|
13
14
|
* [Usage](#usage)
|
|
14
15
|
* [Commands](#commands)
|
|
15
16
|
<!-- tocstop -->
|
|
16
17
|
|
|
18
|
+
# Setup
|
|
19
|
+
|
|
20
|
+
## Google Play Store (Android)
|
|
21
|
+
|
|
22
|
+
Builds are uploaded to Google Play using **GCP service account impersonation** — no private key files stored on disk.
|
|
23
|
+
|
|
24
|
+
Run once per machine:
|
|
25
|
+
|
|
26
|
+
```sh-session
|
|
27
|
+
$ rnbuilder setup-gcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Each client `.env` must set `GOOGLE_APPLICATION_CREDENTIALS` pointing to the SA's ADC file.
|
|
31
|
+
Google Play Console limits one service account to 10 developer accounts — use multiple SAs for more clients.
|
|
32
|
+
|
|
33
|
+
See [docs/gcp-service-account-impersonation.md](docs/gcp-service-account-impersonation.md) for full setup, adding new service accounts, client mapping, and troubleshooting.
|
|
34
|
+
|
|
17
35
|
# Usage
|
|
18
36
|
|
|
19
37
|
<!-- usage -->
|
|
@@ -22,7 +40,7 @@ $ npm install -g rnbuilder
|
|
|
22
40
|
$ rnbuilder COMMAND
|
|
23
41
|
running command...
|
|
24
42
|
$ rnbuilder (-v|--version|version)
|
|
25
|
-
rnbuilder/0.6.
|
|
43
|
+
rnbuilder/0.6.72 darwin-arm64 node-v24.13.0
|
|
26
44
|
$ rnbuilder --help [COMMAND]
|
|
27
45
|
USAGE
|
|
28
46
|
$ rnbuilder COMMAND
|
|
@@ -44,6 +62,7 @@ USAGE
|
|
|
44
62
|
* [`rnbuilder onesignal [BUILD]`](#rnbuilder-onesignal-build)
|
|
45
63
|
* [`rnbuilder reject-review [REJECT-REVIEW]`](#rnbuilder-reject-review-reject-review)
|
|
46
64
|
* [`rnbuilder setup [SETUP]`](#rnbuilder-setup-setup)
|
|
65
|
+
* [`rnbuilder setup-gcp`](#rnbuilder-setup-gcp)
|
|
47
66
|
* [`rnbuilder submit-review [SUBMIT-REVIEW]`](#rnbuilder-submit-review-submit-review)
|
|
48
67
|
* [`rnbuilder sync-udids [BUILD]`](#rnbuilder-sync-udids-build)
|
|
49
68
|
|
|
@@ -79,7 +98,7 @@ EXAMPLE
|
|
|
79
98
|
hello world from ./src/build.ts!
|
|
80
99
|
```
|
|
81
100
|
|
|
82
|
-
_See code: [src/commands/build.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
101
|
+
_See code: [src/commands/build.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/build.ts)_
|
|
83
102
|
|
|
84
103
|
## `rnbuilder check-version [MATCH-CHECK]`
|
|
85
104
|
|
|
@@ -98,7 +117,7 @@ EXAMPLE
|
|
|
98
117
|
Nuke certificates ./src/match-check.ts!
|
|
99
118
|
```
|
|
100
119
|
|
|
101
|
-
_See code: [src/commands/check-version.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
120
|
+
_See code: [src/commands/check-version.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/check-version.ts)_
|
|
102
121
|
|
|
103
122
|
## `rnbuilder codepush [BUILD]`
|
|
104
123
|
|
|
@@ -117,7 +136,7 @@ EXAMPLE
|
|
|
117
136
|
Push changes to existing apps ./src/firebase-sync-udids.ts!
|
|
118
137
|
```
|
|
119
138
|
|
|
120
|
-
_See code: [src/commands/codepush.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
139
|
+
_See code: [src/commands/codepush.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/codepush.ts)_
|
|
121
140
|
|
|
122
141
|
## `rnbuilder google-key [MATCH-CHECK]`
|
|
123
142
|
|
|
@@ -136,7 +155,7 @@ EXAMPLE
|
|
|
136
155
|
Nuke certificates ./src/match-check.ts!
|
|
137
156
|
```
|
|
138
157
|
|
|
139
|
-
_See code: [src/commands/google-key.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
158
|
+
_See code: [src/commands/google-key.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/google-key.ts)_
|
|
140
159
|
|
|
141
160
|
## `rnbuilder help [COMMAND]`
|
|
142
161
|
|
|
@@ -168,7 +187,7 @@ EXAMPLE
|
|
|
168
187
|
initialize environment for first run from ./src/initialize.ts!
|
|
169
188
|
```
|
|
170
189
|
|
|
171
|
-
_See code: [src/commands/initialize.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
190
|
+
_See code: [src/commands/initialize.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/initialize.ts)_
|
|
172
191
|
|
|
173
192
|
## `rnbuilder match-check [MATCH-CHECK]`
|
|
174
193
|
|
|
@@ -187,7 +206,7 @@ EXAMPLE
|
|
|
187
206
|
Check match certificates ./src/match-check.ts!
|
|
188
207
|
```
|
|
189
208
|
|
|
190
|
-
_See code: [src/commands/match-check.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
209
|
+
_See code: [src/commands/match-check.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/match-check.ts)_
|
|
191
210
|
|
|
192
211
|
## `rnbuilder match-nuke [BUILD]`
|
|
193
212
|
|
|
@@ -206,7 +225,7 @@ EXAMPLE
|
|
|
206
225
|
Nuke certificates ./src/match-nuke.ts!
|
|
207
226
|
```
|
|
208
227
|
|
|
209
|
-
_See code: [src/commands/match-nuke.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
228
|
+
_See code: [src/commands/match-nuke.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/match-nuke.ts)_
|
|
210
229
|
|
|
211
230
|
## `rnbuilder onesignal [BUILD]`
|
|
212
231
|
|
|
@@ -228,7 +247,7 @@ EXAMPLE
|
|
|
228
247
|
Create and upload push certificate to One Signal from ./src/commands/onesignal.ts!
|
|
229
248
|
```
|
|
230
249
|
|
|
231
|
-
_See code: [src/commands/onesignal.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
250
|
+
_See code: [src/commands/onesignal.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/onesignal.ts)_
|
|
232
251
|
|
|
233
252
|
## `rnbuilder reject-review [REJECT-REVIEW]`
|
|
234
253
|
|
|
@@ -246,7 +265,7 @@ EXAMPLE
|
|
|
246
265
|
$ rnbuilder reject-review
|
|
247
266
|
```
|
|
248
267
|
|
|
249
|
-
_See code: [src/commands/reject-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
268
|
+
_See code: [src/commands/reject-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/reject-review.ts)_
|
|
250
269
|
|
|
251
270
|
## `rnbuilder setup [SETUP]`
|
|
252
271
|
|
|
@@ -264,7 +283,21 @@ EXAMPLE
|
|
|
264
283
|
hello world from ./src/setup.ts!
|
|
265
284
|
```
|
|
266
285
|
|
|
267
|
-
_See code: [src/commands/setup.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
286
|
+
_See code: [src/commands/setup.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/setup.ts)_
|
|
287
|
+
|
|
288
|
+
## `rnbuilder setup-gcp`
|
|
289
|
+
|
|
290
|
+
Setup GCP service account impersonation
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
USAGE
|
|
294
|
+
$ rnbuilder setup-gcp
|
|
295
|
+
|
|
296
|
+
OPTIONS
|
|
297
|
+
-h, --help show CLI help
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
_See code: [src/commands/setup-gcp.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/setup-gcp.ts)_
|
|
268
301
|
|
|
269
302
|
## `rnbuilder submit-review [SUBMIT-REVIEW]`
|
|
270
303
|
|
|
@@ -283,7 +316,7 @@ EXAMPLE
|
|
|
283
316
|
Push changes to existing apps ./src/firebase-sync-udids.ts!
|
|
284
317
|
```
|
|
285
318
|
|
|
286
|
-
_See code: [src/commands/submit-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
319
|
+
_See code: [src/commands/submit-review.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/submit-review.ts)_
|
|
287
320
|
|
|
288
321
|
## `rnbuilder sync-udids [BUILD]`
|
|
289
322
|
|
|
@@ -302,5 +335,5 @@ EXAMPLE
|
|
|
302
335
|
Sync device UDIDs from firebase from ./src/firebase-sync-udids.ts!
|
|
303
336
|
```
|
|
304
337
|
|
|
305
|
-
_See code: [src/commands/sync-udids.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.
|
|
338
|
+
_See code: [src/commands/sync-udids.ts](https://github.com/r0b0t3d/rnbuilder/blob/v0.6.72/src/commands/sync-udids.ts)_
|
|
306
339
|
<!-- commandsstop -->
|
package/lib/commands/build.js
CHANGED
|
@@ -246,15 +246,15 @@ class Build extends command_1.Command {
|
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
248
|
shell.exec('git pull');
|
|
249
|
-
shell.exec('bundle update --bundler');
|
|
250
|
-
shell.exec('bundle install');
|
|
251
|
-
// Clean fastlane builds
|
|
252
|
-
shell.exec('rm -rf fastlane/builds');
|
|
253
|
-
shell.exec('rm ios/.xcode.env.local');
|
|
254
249
|
if (flags.cleanup) {
|
|
250
|
+
// Clean fastlane builds
|
|
251
|
+
shell.exec('rm -rf fastlane/builds');
|
|
252
|
+
shell.exec('rm ios/.xcode.env.local');
|
|
255
253
|
shell.exec('rm -rf android/.gradle android/build android/app/build android/app/.cxx node_modules');
|
|
256
254
|
}
|
|
257
255
|
if (flags.install) {
|
|
256
|
+
shell.exec('bundle update --bundler');
|
|
257
|
+
shell.exec('bundle install');
|
|
258
258
|
const installCmd = shell.test('-f', 'bun.lockb') || shell.test('-f', 'bun.lock')
|
|
259
259
|
? 'bun install'
|
|
260
260
|
: shell.test('-f', 'pnpm-lock.yaml')
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const command_1 = require("@oclif/command");
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const common_1 = require("../utils/common");
|
|
7
|
+
class SetupGcp extends command_1.Command {
|
|
8
|
+
async run() {
|
|
9
|
+
var _a, _b, _c, _d, _e;
|
|
10
|
+
const configs = common_1.getFastlaneConfigs();
|
|
11
|
+
const gcp = (_a = configs.gcp) !== null && _a !== void 0 ? _a : {};
|
|
12
|
+
const scriptPath = path.join(__dirname, '../../scripts/setup_gcp_impersonation.sh');
|
|
13
|
+
const result = child_process_1.spawnSync('bash', [scriptPath], {
|
|
14
|
+
stdio: 'inherit',
|
|
15
|
+
env: Object.assign(Object.assign({}, process.env), { GCP_PROJECT_ID: (_b = gcp.projectId) !== null && _b !== void 0 ? _b : '', GCP_USER_EMAIL: (_c = gcp.userEmail) !== null && _c !== void 0 ? _c : '', GCP_SERVICE_ACCOUNTS: ((_d = gcp.serviceAccounts) !== null && _d !== void 0 ? _d : []).join(',') }),
|
|
16
|
+
});
|
|
17
|
+
if (result.status !== 0) {
|
|
18
|
+
this.exit((_e = result.status) !== null && _e !== void 0 ? _e : 1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.default = SetupGcp;
|
|
23
|
+
SetupGcp.description = 'Setup GCP service account impersonation';
|
|
24
|
+
SetupGcp.flags = {
|
|
25
|
+
help: command_1.flags.help({ char: 'h' }),
|
|
26
|
+
};
|
|
@@ -3,49 +3,57 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.addProductFlavor = void 0;
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
|
-
function insertIntoProductFlavors(gradle,
|
|
7
|
-
|
|
6
|
+
function insertIntoProductFlavors(gradle, client) {
|
|
7
|
+
var _a;
|
|
8
8
|
const blockStart = gradle.indexOf('productFlavors {');
|
|
9
9
|
if (blockStart === -1) {
|
|
10
|
-
// No productFlavors block — append one inside android {}
|
|
11
10
|
const androidEnd = gradle.lastIndexOf('}');
|
|
12
11
|
return (gradle.slice(0, androidEnd) +
|
|
13
|
-
`\n productFlavors {\n${
|
|
12
|
+
`\n productFlavors {\n ${client}\n }\n` +
|
|
14
13
|
gradle.slice(androidEnd));
|
|
15
14
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let
|
|
19
|
-
|
|
15
|
+
const bracePos = gradle.indexOf('{', blockStart) + 1;
|
|
16
|
+
// Find closing brace of productFlavors block
|
|
17
|
+
let depth = 1;
|
|
18
|
+
let i = bracePos;
|
|
19
|
+
while (i < gradle.length && depth > 0) {
|
|
20
20
|
if (gradle[i] === '{')
|
|
21
21
|
depth++;
|
|
22
|
-
else if (gradle[i] === '}')
|
|
22
|
+
else if (gradle[i] === '}')
|
|
23
23
|
depth--;
|
|
24
|
-
if (depth === 0)
|
|
25
|
-
break;
|
|
26
|
-
}
|
|
27
24
|
i++;
|
|
28
25
|
}
|
|
29
|
-
|
|
26
|
+
const blockEnd = i - 1;
|
|
27
|
+
const blockContent = gradle.slice(bracePos, blockEnd);
|
|
28
|
+
const lines = blockContent.split('\n');
|
|
29
|
+
// Detect indentation from existing flavor lines
|
|
30
|
+
const existingLine = lines.find(l => /^\s+\w+\s*$/.test(l));
|
|
31
|
+
const indent = existingLine ? ((_a = existingLine.match(/^(\s+)/)) !== null && _a !== void 0 ? _a : ['', ' '])[1] : ' ';
|
|
32
|
+
// Find insertion point to maintain alphabetical order
|
|
33
|
+
let insertAt = lines.length - 1; // default: before last empty/closing line
|
|
34
|
+
for (let li = 0; li < lines.length; li++) {
|
|
35
|
+
const name = lines[li].trim();
|
|
36
|
+
if (/^\w+$/.test(name) && name.localeCompare(client) > 0) {
|
|
37
|
+
insertAt = li;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
lines.splice(insertAt, 0, `${indent}${client}`);
|
|
42
|
+
return gradle.slice(0, bracePos) + lines.join('\n') + gradle.slice(blockEnd);
|
|
30
43
|
}
|
|
31
|
-
function addProductFlavor({ client,
|
|
44
|
+
function addProductFlavor({ client, }) {
|
|
32
45
|
const gradlePath = path.join(process.cwd(), 'android/app/build.gradle');
|
|
33
46
|
if (!fs.existsSync(gradlePath)) {
|
|
34
47
|
console.warn(`build.gradle not found at ${gradlePath} — skipping`);
|
|
35
48
|
return;
|
|
36
49
|
}
|
|
37
50
|
const gradle = fs.readFileSync(gradlePath, 'utf-8');
|
|
38
|
-
|
|
39
|
-
const flavorRegex = new RegExp(`\\b${client}\\s*\\{`);
|
|
51
|
+
const flavorRegex = new RegExp(`^\\s+${client}\\s*$`, 'm');
|
|
40
52
|
if (flavorRegex.test(gradle)) {
|
|
41
53
|
console.log(`Flavor "${client}" already exists in build.gradle — skipping`);
|
|
42
54
|
return;
|
|
43
55
|
}
|
|
44
|
-
const
|
|
45
|
-
` dimension "default"\n` +
|
|
46
|
-
` applicationId "${applicationId}"\n` +
|
|
47
|
-
` }`;
|
|
48
|
-
const updated = insertIntoProductFlavors(gradle, flavorBlock);
|
|
56
|
+
const updated = insertIntoProductFlavors(gradle, client);
|
|
49
57
|
fs.writeFileSync(gradlePath, updated, 'utf-8');
|
|
50
58
|
console.log(`Added flavor "${client}" to android/app/build.gradle`);
|
|
51
59
|
}
|
|
@@ -24,7 +24,7 @@ exports.createClientConfig = async (client) => {
|
|
|
24
24
|
default: `com.edular.${client}`,
|
|
25
25
|
},
|
|
26
26
|
]);
|
|
27
|
-
android_1.addProductFlavor({ client
|
|
27
|
+
android_1.addProductFlavor({ client });
|
|
28
28
|
ios_scheme_1.createXcodeScheme({ client, bundleId });
|
|
29
29
|
return { appName, bundleId, applicationId };
|
|
30
30
|
};
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.6.
|
|
1
|
+
{"version":"0.6.72","commands":{"build":{"id":"build","description":"Build react native apps","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder build\nhello world from ./src/build.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Set client that you want to build app"},"target":{"name":"target","type":"option","char":"t","description":"Set the build target: android, ios or both","options":["android","ios","android,ios"]},"env":{"name":"env","type":"option","char":"e","description":"Set the environment: prod, staging, dev"},"branch":{"name":"branch","type":"option","char":"b","description":"Set the source branch used to build the app"},"version":{"name":"version","type":"option","char":"v","description":"Set the version number for this build"},"installr":{"name":"installr","type":"option","char":"i","description":"If enabled, the build will be uploaded to installR"},"distribute":{"name":"distribute","type":"option","char":"d","description":"Specify where to distribute app"},"firebase":{"name":"firebase","type":"boolean","char":"f","description":"If enabled, the build will be uploaded to firebase","allowNo":false},"testersIos":{"name":"testersIos","type":"option","char":"t","description":"Tester ids for iOS distribution"},"testersAndroid":{"name":"testersAndroid","type":"option","char":"u","description":"Tester ids for Android distribution"},"gitReset":{"name":"gitReset","type":"boolean","char":"g","description":"Do git reset when building","allowNo":false},"cleanup":{"name":"cleanup","type":"boolean","char":"s","description":"Do cleanup when building","allowNo":false},"groupsIos":{"name":"groupsIos","type":"option","description":"Groups ids for iOS distribution"},"groupsAndroid":{"name":"groupsAndroid","type":"option","description":"Groups ids for Android distribution"},"skipCheckVersion":{"name":"skipCheckVersion","type":"boolean","description":"Skip checking current version on stores","allowNo":false},"install":{"name":"install","type":"boolean","char":"n","description":"Install dependencies before building","allowNo":false}},"args":[{"name":"build"}]},"check-version":{"id":"check-version","description":"Check live versions","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder check-version\n Nuke certificates ./src/match-check.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"match-check"}]},"codepush":{"id":"codepush","description":"Push changes to existing apps","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder codepush\n Push changes to existing apps ./src/firebase-sync-udids.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to push update"}},"args":[{"name":"build"}]},"google-key":{"id":"google-key","description":"Nuke certificates","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder match-check\n Nuke certificates ./src/match-check.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"match-check"}]},"initialize":{"id":"initialize","description":"Initialize the environment for first run","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder initialize\ninitialize environment for first run from ./src/initialize.ts!\n"],"flags":{},"args":[]},"match-check":{"id":"match-check","description":"Check match certificates","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder match-check\n Check match certificates ./src/match-check.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to check match certificates"}},"args":[{"name":"match-check"}]},"match-nuke":{"id":"match-nuke","description":"Nuke certificates","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder match-nuke\n Nuke certificates ./src/match-nuke.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"build"}]},"onesignal":{"id":"onesignal","description":"Create and upload push cerfiticate to One Signal","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder onesignal\n Create and upload push certificate to One Signal from ./src/commands/onesignal.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"},"auth_token":{"name":"auth_token","type":"option","description":"Auth token for OneSignal"},"android_token":{"name":"android_token","type":"option"},"android_gcm_sender_id":{"name":"android_gcm_sender_id","type":"option"}},"args":[{"name":"build"}]},"reject-review":{"id":"reject-review","description":"Reject current App Store review version (In Review or Pending Developer Release)","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder reject-review\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client to reject App Store review version"}},"args":[{"name":"reject-review"}]},"setup-gcp":{"id":"setup-gcp","description":"Setup GCP service account impersonation","pluginName":"rnbuilder","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"setup":{"id":"setup","description":"Setup new client","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder build\nhello world from ./src/setup.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[{"name":"setup"}]},"submit-review":{"id":"submit-review","description":"Submit ios for review","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder submit-review\n Push changes to existing apps ./src/firebase-sync-udids.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to push update"}},"args":[{"name":"submit-review"}]},"sync-udids":{"id":"sync-udids","description":"Sync device UDIDs from firebase","pluginName":"rnbuilder","pluginType":"core","aliases":[],"examples":["$ rnbuilder sync-udids\n Sync device UDIDs from firebase from ./src/firebase-sync-udids.ts!\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"client":{"name":"client","type":"option","char":"c","description":"Select client that you want to sync udids"}},"args":[{"name":"build"}]}}}
|
package/package.json
CHANGED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
if ! command -v gcloud >/dev/null 2>&1; then
|
|
5
|
+
echo "gcloud is not installed. Install Google Cloud SDK first."
|
|
6
|
+
exit 1
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
if ! command -v python3 >/dev/null 2>&1; then
|
|
10
|
+
echo "python3 is required but not found."
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
echo "Available projects:"
|
|
15
|
+
gcloud projects list --format="table(projectId,name)" 2>/dev/null || echo " (could not list projects)"
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
DEFAULT_PROJECT_ID="${GCP_PROJECT_ID:-edular-19fe4}"
|
|
19
|
+
read -rp "Enter Google Cloud project ID [$DEFAULT_PROJECT_ID]: " PROJECT_ID
|
|
20
|
+
PROJECT_ID="${PROJECT_ID:-$DEFAULT_PROJECT_ID}"
|
|
21
|
+
|
|
22
|
+
DEFAULT_USER_EMAIL="${GCP_USER_EMAIL:-klassapp2013@gmail.com}"
|
|
23
|
+
read -rp "Enter your Google account email [$DEFAULT_USER_EMAIL]: " USER_EMAIL
|
|
24
|
+
USER_EMAIL="${USER_EMAIL:-$DEFAULT_USER_EMAIL}"
|
|
25
|
+
|
|
26
|
+
gcloud config set project "$PROJECT_ID"
|
|
27
|
+
|
|
28
|
+
echo ""
|
|
29
|
+
echo "Logging into gcloud as $USER_EMAIL..."
|
|
30
|
+
gcloud auth login "$USER_EMAIL"
|
|
31
|
+
|
|
32
|
+
echo ""
|
|
33
|
+
echo "Creating base ADC (user credentials, no impersonation)..."
|
|
34
|
+
gcloud auth application-default login
|
|
35
|
+
|
|
36
|
+
BASE_ADC="$HOME/.config/gcloud/application_default_credentials.json"
|
|
37
|
+
ADC_DIR="$HOME/.config/gcloud"
|
|
38
|
+
|
|
39
|
+
# Generate an impersonated ADC file for a service account.
|
|
40
|
+
# Reuses the base user credentials — no extra gcloud login needed.
|
|
41
|
+
generate_sa_adc() {
|
|
42
|
+
local sa_email="$1"
|
|
43
|
+
local sa_slug
|
|
44
|
+
sa_slug=$(printf '%s' "$sa_email" | cut -d'@' -f1 | tr -cs '[:alnum:]' '_' | sed 's/_*$//')
|
|
45
|
+
local output="$ADC_DIR/adc_${sa_slug}.json"
|
|
46
|
+
|
|
47
|
+
echo ""
|
|
48
|
+
echo "Granting roles/iam.serviceAccountTokenCreator to $USER_EMAIL for $sa_email..."
|
|
49
|
+
# Unset gcloud impersonation so the grant runs as the user, not as an SA
|
|
50
|
+
gcloud config unset auth/impersonate_service_account 2>/dev/null || true
|
|
51
|
+
gcloud iam service-accounts add-iam-policy-binding \
|
|
52
|
+
"$sa_email" \
|
|
53
|
+
--role="roles/iam.serviceAccountTokenCreator" \
|
|
54
|
+
--member="user:$USER_EMAIL" \
|
|
55
|
+
--project="$PROJECT_ID"
|
|
56
|
+
|
|
57
|
+
python3 - "$BASE_ADC" "$sa_email" "$output" <<'PYEOF'
|
|
58
|
+
import json, sys
|
|
59
|
+
|
|
60
|
+
base_path, sa_email, output_path = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
61
|
+
|
|
62
|
+
with open(base_path) as f:
|
|
63
|
+
base = json.load(f)
|
|
64
|
+
|
|
65
|
+
# If base is already an impersonated ADC, extract its source_credentials.
|
|
66
|
+
# Otherwise use base directly as the source (authorized_user).
|
|
67
|
+
src = base.get("source_credentials", base)
|
|
68
|
+
|
|
69
|
+
adc = {
|
|
70
|
+
"delegates": [],
|
|
71
|
+
"service_account_impersonation_url": (
|
|
72
|
+
"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/"
|
|
73
|
+
f"{sa_email}:generateAccessToken"
|
|
74
|
+
),
|
|
75
|
+
"source_credentials": src,
|
|
76
|
+
"type": "impersonated_service_account",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
with open(output_path, "w") as f:
|
|
80
|
+
json.dump(adc, f, indent=2)
|
|
81
|
+
|
|
82
|
+
print(f"Created: {output_path}")
|
|
83
|
+
print(f"Add to client .env:")
|
|
84
|
+
print(f" GOOGLE_APPLICATION_CREDENTIALS={output_path}")
|
|
85
|
+
PYEOF
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Service accounts from repo's fastlane/configs.json (gcp.serviceAccounts), if provided.
|
|
89
|
+
if [ -n "${GCP_SERVICE_ACCOUNTS:-}" ]; then
|
|
90
|
+
echo ""
|
|
91
|
+
echo "Service accounts from fastlane/configs.json:"
|
|
92
|
+
IFS=',' read -ra CONFIG_SAS <<< "$GCP_SERVICE_ACCOUNTS"
|
|
93
|
+
for sa in "${CONFIG_SAS[@]}"; do
|
|
94
|
+
echo " - $sa"
|
|
95
|
+
done
|
|
96
|
+
for sa in "${CONFIG_SAS[@]}"; do
|
|
97
|
+
generate_sa_adc "$sa"
|
|
98
|
+
done
|
|
99
|
+
else
|
|
100
|
+
read -rp "Enter service account email [fastlane@edular-19fe4.iam.gserviceaccount.com]: " SERVICE_ACCOUNT_EMAIL
|
|
101
|
+
SERVICE_ACCOUNT_EMAIL="${SERVICE_ACCOUNT_EMAIL:-fastlane@edular-19fe4.iam.gserviceaccount.com}"
|
|
102
|
+
generate_sa_adc "$SERVICE_ACCOUNT_EMAIL"
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# Additional service accounts
|
|
106
|
+
while true; do
|
|
107
|
+
echo ""
|
|
108
|
+
read -rp "Add another service account? (y/N): " ADD_MORE
|
|
109
|
+
case "${ADD_MORE:-N}" in
|
|
110
|
+
[Yy]*)
|
|
111
|
+
read -rp "Enter service account email: " EXTRA_SA
|
|
112
|
+
if [ -n "${EXTRA_SA:-}" ]; then
|
|
113
|
+
generate_sa_adc "$EXTRA_SA"
|
|
114
|
+
fi
|
|
115
|
+
;;
|
|
116
|
+
*) break ;;
|
|
117
|
+
esac
|
|
118
|
+
done
|
|
119
|
+
|
|
120
|
+
echo ""
|
|
121
|
+
echo "Done."
|
|
122
|
+
echo ""
|
|
123
|
+
echo "To test a service account token:"
|
|
124
|
+
echo " gcloud auth print-access-token --impersonate-service-account=<SA_EMAIL>"
|
|
125
|
+
echo ""
|
|
126
|
+
echo "ADC files are in: $ADC_DIR/adc_*.json"
|
|
127
|
+
echo "Each client .env needs:"
|
|
128
|
+
echo " GOOGLE_APPLICATION_CREDENTIALS=<path to their SA's adc file>"
|