eoas 1.0.2 → 1.0.3
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/commands/generate-certs.d.ts +8 -0
- package/dist/commands/generate-certs.js +90 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.js +113 -0
- package/dist/commands/publish.d.ts +18 -0
- package/dist/commands/publish.js +249 -0
- package/dist/lib/assets.d.ts +19 -0
- package/dist/lib/assets.js +90 -0
- package/dist/lib/auth.d.ts +6 -0
- package/dist/lib/auth.js +57 -0
- package/dist/lib/expoConfig.d.ts +23 -0
- package/dist/lib/expoConfig.js +198 -0
- package/dist/lib/log.d.ts +40 -0
- package/dist/lib/log.js +101 -0
- package/dist/lib/ora.d.ts +9 -0
- package/dist/lib/ora.js +103 -0
- package/dist/lib/package.d.ts +1 -0
- package/dist/lib/package.js +9 -0
- package/dist/lib/prompts.d.ts +13 -0
- package/dist/lib/prompts.js +68 -0
- package/dist/lib/repo.d.ts +6 -0
- package/dist/lib/repo.js +48 -0
- package/dist/lib/runtimeVersion.d.ts +42 -0
- package/dist/lib/runtimeVersion.js +116 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +7 -0
- package/dist/lib/vcs/clients/git.d.ts +31 -0
- package/dist/lib/vcs/clients/git.js +322 -0
- package/dist/lib/vcs/clients/gitNoCommit.d.ts +8 -0
- package/dist/lib/vcs/clients/gitNoCommit.js +42 -0
- package/dist/lib/vcs/clients/noVcs.d.ts +7 -0
- package/dist/lib/vcs/clients/noVcs.js +22 -0
- package/dist/lib/vcs/git.d.ts +13 -0
- package/dist/lib/vcs/git.js +60 -0
- package/dist/lib/vcs/index.d.ts +2 -0
- package/dist/lib/vcs/index.js +26 -0
- package/dist/lib/vcs/local.d.ts +19 -0
- package/dist/lib/vcs/local.js +85 -0
- package/dist/lib/vcs/vcs.d.ts +25 -0
- package/dist/lib/vcs/vcs.js +61 -0
- package/dist/lib/workflow.d.ts +4 -0
- package/dist/lib/workflow.js +40 -0
- package/package.json +6 -2
- package/.eslintignore +0 -1
- package/.eslintrc.js +0 -73
- package/.prettierrc +0 -9
- package/src/commands/generate-certs.ts +0 -95
- package/src/commands/init.ts +0 -117
- package/src/commands/publish.ts +0 -277
- package/src/index.d.ts +0 -7
- package/src/lib/assets.ts +0 -118
- package/src/lib/auth.ts +0 -67
- package/src/lib/expoConfig.ts +0 -265
- package/src/lib/log.ts +0 -122
- package/src/lib/ora.ts +0 -113
- package/src/lib/package.ts +0 -6
- package/src/lib/prompts.ts +0 -97
- package/src/lib/repo.ts +0 -62
- package/src/lib/runtimeVersion.ts +0 -177
- package/src/lib/utils.ts +0 -3
- package/src/lib/vcs/README.md +0 -1
- package/src/lib/vcs/clients/git.ts +0 -390
- package/src/lib/vcs/clients/gitNoCommit.ts +0 -45
- package/src/lib/vcs/clients/noVcs.ts +0 -23
- package/src/lib/vcs/git.ts +0 -68
- package/src/lib/vcs/index.ts +0 -25
- package/src/lib/vcs/local.ts +0 -88
- package/src/lib/vcs/vcs.ts +0 -90
- package/src/lib/workflow.ts +0 -47
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare function getRootPath(): string;
|
|
2
|
+
/**
|
|
3
|
+
* Ignore wraps the 'ignore' package to support multiple .gitignore files
|
|
4
|
+
* in subdirectories.
|
|
5
|
+
*
|
|
6
|
+
* Inconsistencies with git behavior:
|
|
7
|
+
* - if parent .gitignore has ignore rule and child has exception to that rule,
|
|
8
|
+
* file will still be ignored,
|
|
9
|
+
* - node_modules is always ignored,
|
|
10
|
+
* - if .easignore exists, .gitignore files are not used.
|
|
11
|
+
*/
|
|
12
|
+
export declare class Ignore {
|
|
13
|
+
private readonly rootDir;
|
|
14
|
+
private ignoreMapping;
|
|
15
|
+
constructor(rootDir: string);
|
|
16
|
+
initIgnoreAsync(): Promise<void>;
|
|
17
|
+
ignores(relativePath: string): boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function makeShallowCopyAsync(src: string, dst: string): Promise<void>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeShallowCopyAsync = exports.Ignore = exports.getRootPath = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
|
|
6
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
7
|
+
const ignore_1 = tslib_1.__importDefault(require("ignore"));
|
|
8
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
9
|
+
const EASIGNORE_FILENAME = '.easignore';
|
|
10
|
+
const GITIGNORE_FILENAME = '.gitignore';
|
|
11
|
+
const DEFAULT_IGNORE = `
|
|
12
|
+
.git
|
|
13
|
+
node_modules
|
|
14
|
+
`;
|
|
15
|
+
function getRootPath() {
|
|
16
|
+
const rootPath = process.env.EAS_PROJECT_ROOT ?? process.cwd();
|
|
17
|
+
if (!path_1.default.isAbsolute(rootPath)) {
|
|
18
|
+
return path_1.default.resolve(process.cwd(), rootPath);
|
|
19
|
+
}
|
|
20
|
+
return rootPath;
|
|
21
|
+
}
|
|
22
|
+
exports.getRootPath = getRootPath;
|
|
23
|
+
/**
|
|
24
|
+
* Ignore wraps the 'ignore' package to support multiple .gitignore files
|
|
25
|
+
* in subdirectories.
|
|
26
|
+
*
|
|
27
|
+
* Inconsistencies with git behavior:
|
|
28
|
+
* - if parent .gitignore has ignore rule and child has exception to that rule,
|
|
29
|
+
* file will still be ignored,
|
|
30
|
+
* - node_modules is always ignored,
|
|
31
|
+
* - if .easignore exists, .gitignore files are not used.
|
|
32
|
+
*/
|
|
33
|
+
class Ignore {
|
|
34
|
+
rootDir;
|
|
35
|
+
ignoreMapping = [];
|
|
36
|
+
constructor(rootDir) {
|
|
37
|
+
this.rootDir = rootDir;
|
|
38
|
+
}
|
|
39
|
+
async initIgnoreAsync() {
|
|
40
|
+
const easIgnorePath = path_1.default.join(this.rootDir, EASIGNORE_FILENAME);
|
|
41
|
+
if (await fs_extra_1.default.pathExists(easIgnorePath)) {
|
|
42
|
+
this.ignoreMapping = [
|
|
43
|
+
['', (0, ignore_1.default)().add(DEFAULT_IGNORE)],
|
|
44
|
+
['', (0, ignore_1.default)().add(await fs_extra_1.default.readFile(easIgnorePath, 'utf-8'))],
|
|
45
|
+
];
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const ignoreFilePaths = (await (0, fast_glob_1.default)(`**/${GITIGNORE_FILENAME}`, {
|
|
49
|
+
cwd: this.rootDir,
|
|
50
|
+
ignore: ['node_modules'],
|
|
51
|
+
followSymbolicLinks: false,
|
|
52
|
+
}))
|
|
53
|
+
// ensure that parent dir is before child directories
|
|
54
|
+
.sort((a, b) => a.length - b.length && a.localeCompare(b));
|
|
55
|
+
const ignoreMapping = await Promise.all(ignoreFilePaths.map(async (filePath) => {
|
|
56
|
+
return [
|
|
57
|
+
filePath.slice(0, filePath.length - GITIGNORE_FILENAME.length),
|
|
58
|
+
(0, ignore_1.default)().add(await fs_extra_1.default.readFile(path_1.default.join(this.rootDir, filePath), 'utf-8')),
|
|
59
|
+
];
|
|
60
|
+
}));
|
|
61
|
+
this.ignoreMapping = [['', (0, ignore_1.default)().add(DEFAULT_IGNORE)], ...ignoreMapping];
|
|
62
|
+
}
|
|
63
|
+
ignores(relativePath) {
|
|
64
|
+
for (const [prefix, ignore] of this.ignoreMapping) {
|
|
65
|
+
if (relativePath.startsWith(prefix) && ignore.ignores(relativePath.slice(prefix.length))) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.Ignore = Ignore;
|
|
73
|
+
async function makeShallowCopyAsync(src, dst) {
|
|
74
|
+
const ignore = new Ignore(src);
|
|
75
|
+
await ignore.initIgnoreAsync();
|
|
76
|
+
await fs_extra_1.default.copy(src, dst, {
|
|
77
|
+
filter: (srcFilePath) => {
|
|
78
|
+
if (srcFilePath === src) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
return !ignore.ignores(path_1.default.relative(src, srcFilePath));
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
exports.makeShallowCopyAsync = makeShallowCopyAsync;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare abstract class Client {
|
|
2
|
+
abstract makeShallowCopyAsync(destinationPath: string): Promise<void>;
|
|
3
|
+
abstract getRootPathAsync(): Promise<string>;
|
|
4
|
+
ensureRepoExistsAsync(): Promise<void>;
|
|
5
|
+
isCommitRequiredAsync(): Promise<boolean>;
|
|
6
|
+
hasUncommittedChangesAsync(): Promise<boolean | undefined>;
|
|
7
|
+
commitAsync(_arg: {
|
|
8
|
+
commitMessage: string;
|
|
9
|
+
commitAllFiles?: boolean;
|
|
10
|
+
nonInteractive: boolean;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
trackFileAsync(_file: string): Promise<void>;
|
|
13
|
+
showDiffAsync(): Promise<void>;
|
|
14
|
+
/** (optional) print list of changed files */
|
|
15
|
+
showChangedFilesAsync(): Promise<void>;
|
|
16
|
+
getCommitHashAsync(): Promise<string | undefined>;
|
|
17
|
+
getBranchNameAsync(): Promise<string | null>;
|
|
18
|
+
getLastCommitMessageAsync(): Promise<string | null>;
|
|
19
|
+
isFileIgnoredAsync(_filePath: string): Promise<boolean>;
|
|
20
|
+
/**
|
|
21
|
+
* Whether this VCS client can get the last commit message.
|
|
22
|
+
* Used for EAS Update - implementation can be false for noVcs client.
|
|
23
|
+
*/
|
|
24
|
+
abstract canGetLastCommitMessage(): boolean;
|
|
25
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Client = void 0;
|
|
4
|
+
class Client {
|
|
5
|
+
// (optional) ensureRepoExistsAsync should verify whether repository exists and tooling is installed
|
|
6
|
+
// it's not required for minimal support, but lack of validation might cause the failure at a later stage.
|
|
7
|
+
async ensureRepoExistsAsync() { }
|
|
8
|
+
// (optional) checks whether commit is necessary before calling makeShallowCopyAsync
|
|
9
|
+
//
|
|
10
|
+
// If it's not implemented method `makeShallowCopyAsync` needs to be able to include uncommitted changes
|
|
11
|
+
// when creating copy
|
|
12
|
+
async isCommitRequiredAsync() {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
// (optional) hasUncommittedChangesAsync should check whether there are changes in local repository
|
|
16
|
+
async hasUncommittedChangesAsync() {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
// (optional) commitAsync commits changes
|
|
20
|
+
//
|
|
21
|
+
// - Should be implemented if hasUncommittedChangesAsync is implemented
|
|
22
|
+
// - If it's not implemented method `makeShallowCopyAsync` needs to be able to include uncommitted changes
|
|
23
|
+
// in project copy
|
|
24
|
+
async commitAsync(_arg) {
|
|
25
|
+
// it should not be called unless hasUncommittedChangesAsync is implemented
|
|
26
|
+
throw new Error('commitAsync is not implemented');
|
|
27
|
+
}
|
|
28
|
+
// (optional) mark file as tracked, if this method is called on file, the next call to
|
|
29
|
+
// `commitAsync({ commitAllFiles: false })` should commit that file
|
|
30
|
+
async trackFileAsync(_file) { }
|
|
31
|
+
// (optional) print diff of the changes that will be commited in the next call to
|
|
32
|
+
// `commitAsync({ commitAllFiles: false })`
|
|
33
|
+
async showDiffAsync() { }
|
|
34
|
+
/** (optional) print list of changed files */
|
|
35
|
+
async showChangedFilesAsync() { }
|
|
36
|
+
// (optional) returns hash of the last commit
|
|
37
|
+
// used for metadata - implementation can be safely skipped
|
|
38
|
+
async getCommitHashAsync() {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
// (optional) returns name of the current branch
|
|
42
|
+
// used for EAS Update - implementation can be safely skipped
|
|
43
|
+
async getBranchNameAsync() {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
// (optional) returns message of the last commit
|
|
47
|
+
// used for EAS Update - implementation can be safely skipped
|
|
48
|
+
async getLastCommitMessageAsync() {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
// (optional) checks if the file is ignored, an implementation should ensure
|
|
52
|
+
// that if file exists and `isFileIgnoredAsync` returns true, then that file
|
|
53
|
+
// should not be included in the project tarball.
|
|
54
|
+
//
|
|
55
|
+
// @param filePath has to be a relative normalized path pointing to a file
|
|
56
|
+
// located under the root of the repository
|
|
57
|
+
async isFileIgnoredAsync(_filePath) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.Client = Client;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Platform, Workflow } from '@expo/eas-build-job';
|
|
2
|
+
import { Client } from './vcs/vcs';
|
|
3
|
+
export declare function resolveWorkflowAsync(projectDir: string, platform: Platform, vcsClient: Client): Promise<Workflow>;
|
|
4
|
+
export declare function resolveWorkflowPerPlatformAsync(projectDir: string, vcsClient: Client): Promise<Record<Platform, Workflow>>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveWorkflowPerPlatformAsync = exports.resolveWorkflowAsync = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const config_plugins_1 = require("@expo/config-plugins");
|
|
6
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
7
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
9
|
+
async function resolveWorkflowAsync(projectDir, platform, vcsClient) {
|
|
10
|
+
let platformWorkflowMarkers;
|
|
11
|
+
try {
|
|
12
|
+
platformWorkflowMarkers =
|
|
13
|
+
platform === eas_build_job_1.Platform.ANDROID
|
|
14
|
+
? [
|
|
15
|
+
path_1.default.join(projectDir, 'android/app/build.gradle'),
|
|
16
|
+
await config_plugins_1.AndroidConfig.Paths.getAndroidManifestAsync(projectDir),
|
|
17
|
+
]
|
|
18
|
+
: [config_plugins_1.IOSConfig.Paths.getPBXProjectPath(projectDir)];
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return eas_build_job_1.Workflow.MANAGED;
|
|
22
|
+
}
|
|
23
|
+
const vcsRootPath = path_1.default.normalize(await vcsClient.getRootPathAsync());
|
|
24
|
+
for (const marker of platformWorkflowMarkers) {
|
|
25
|
+
if ((await fs_extra_1.default.pathExists(marker)) &&
|
|
26
|
+
!(await vcsClient.isFileIgnoredAsync(path_1.default.relative(vcsRootPath, marker)))) {
|
|
27
|
+
return eas_build_job_1.Workflow.GENERIC;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return eas_build_job_1.Workflow.MANAGED;
|
|
31
|
+
}
|
|
32
|
+
exports.resolveWorkflowAsync = resolveWorkflowAsync;
|
|
33
|
+
async function resolveWorkflowPerPlatformAsync(projectDir, vcsClient) {
|
|
34
|
+
const [android, ios] = await Promise.all([
|
|
35
|
+
resolveWorkflowAsync(projectDir, eas_build_job_1.Platform.ANDROID, vcsClient),
|
|
36
|
+
resolveWorkflowAsync(projectDir, eas_build_job_1.Platform.IOS, vcsClient),
|
|
37
|
+
]);
|
|
38
|
+
return { android, ios };
|
|
39
|
+
}
|
|
40
|
+
exports.resolveWorkflowPerPlatformAsync = resolveWorkflowPerPlatformAsync;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eoas",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsc --project tsconfig.json",
|
|
@@ -88,5 +88,9 @@
|
|
|
88
88
|
"commands": "./dist/commands",
|
|
89
89
|
"dirname": "eoas",
|
|
90
90
|
"topicSeparator": ":"
|
|
91
|
-
}
|
|
91
|
+
},
|
|
92
|
+
"files": [
|
|
93
|
+
"/bin",
|
|
94
|
+
"/dist"
|
|
95
|
+
]
|
|
92
96
|
}
|
package/.eslintignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
node_modules
|
package/.eslintrc.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
root: true,
|
|
3
|
-
extends: ['universe/node'],
|
|
4
|
-
plugins: ['node'],
|
|
5
|
-
ignorePatterns: ['bin/'],
|
|
6
|
-
rules: {
|
|
7
|
-
'no-console': 'warn',
|
|
8
|
-
'no-constant-condition': ['warn', { checkLoops: false }],
|
|
9
|
-
'sort-imports': [
|
|
10
|
-
'warn',
|
|
11
|
-
{
|
|
12
|
-
ignoreDeclarationSort: true,
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
curly: 'warn',
|
|
16
|
-
'import/no-cycle': 'error',
|
|
17
|
-
'import/no-extraneous-dependencies': [
|
|
18
|
-
'error',
|
|
19
|
-
{ devDependencies: ['**/__tests__/**/*', '**/__mocks__/**/*'] },
|
|
20
|
-
],
|
|
21
|
-
'import/no-relative-packages': 'error',
|
|
22
|
-
'no-restricted-imports': [
|
|
23
|
-
'error',
|
|
24
|
-
{
|
|
25
|
-
paths: [
|
|
26
|
-
{
|
|
27
|
-
name: 'lodash',
|
|
28
|
-
message: "Don't use lodash, it's heavy!",
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
'no-underscore-dangle': ['error', { allow: ['__typename'] }],
|
|
34
|
-
'node/no-sync': 'error',
|
|
35
|
-
},
|
|
36
|
-
overrides: [
|
|
37
|
-
{
|
|
38
|
-
files: ['*.ts', '*.d.ts'],
|
|
39
|
-
parserOptions: {
|
|
40
|
-
project: './tsconfig.json',
|
|
41
|
-
},
|
|
42
|
-
rules: {
|
|
43
|
-
'@typescript-eslint/explicit-function-return-type': [
|
|
44
|
-
'warn',
|
|
45
|
-
{
|
|
46
|
-
allowExpressions: true,
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
'@typescript-eslint/prefer-nullish-coalescing': ['warn', { ignorePrimitives: true }],
|
|
50
|
-
'@typescript-eslint/no-confusing-void-expression': 'warn',
|
|
51
|
-
'@typescript-eslint/await-thenable': 'error',
|
|
52
|
-
'@typescript-eslint/no-misused-promises': [
|
|
53
|
-
'error',
|
|
54
|
-
{
|
|
55
|
-
checksVoidReturn: false,
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
'@typescript-eslint/no-floating-promises': 'error',
|
|
59
|
-
'no-void': ['warn', { allowAsStatement: true }],
|
|
60
|
-
'no-return-await': 'off',
|
|
61
|
-
'@typescript-eslint/return-await': ['error', 'always'],
|
|
62
|
-
'@typescript-eslint/no-confusing-non-null-assertion': 'warn',
|
|
63
|
-
'@typescript-eslint/no-extra-non-null-assertion': 'warn',
|
|
64
|
-
'@typescript-eslint/prefer-as-const': 'warn',
|
|
65
|
-
'@typescript-eslint/prefer-includes': 'warn',
|
|
66
|
-
'@typescript-eslint/prefer-readonly': 'warn',
|
|
67
|
-
'@typescript-eslint/prefer-string-starts-ends-with': 'warn',
|
|
68
|
-
'@typescript-eslint/prefer-ts-expect-error': 'warn',
|
|
69
|
-
'@typescript-eslint/no-unnecessary-type-assertion': 'warn',
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
};
|
package/.prettierrc
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
convertCertificateToCertificatePEM,
|
|
3
|
-
convertKeyPairToPEM,
|
|
4
|
-
generateKeyPair,
|
|
5
|
-
generateSelfSignedCodeSigningCertificate,
|
|
6
|
-
} from '@expo/code-signing-certificates';
|
|
7
|
-
import { Command } from '@oclif/core';
|
|
8
|
-
import { ensureDirSync, writeFile } from 'fs-extra';
|
|
9
|
-
import path from 'path';
|
|
10
|
-
|
|
11
|
-
import Log from '../lib/log';
|
|
12
|
-
import { promptAsync } from '../lib/prompts';
|
|
13
|
-
|
|
14
|
-
export default class GenerateCerts extends Command {
|
|
15
|
-
static override args = {};
|
|
16
|
-
static override description = 'Generate private & public certificates for code signing';
|
|
17
|
-
static override examples = ['<%= config.bin %> <%= command.id %>'];
|
|
18
|
-
static override flags = {};
|
|
19
|
-
public async run(): Promise<void> {
|
|
20
|
-
const { certificateOutputDir } = await promptAsync({
|
|
21
|
-
message:
|
|
22
|
-
'In which directory would you like to store your code signing certificate (used by your expo app)?',
|
|
23
|
-
name: 'certificateOutputDir',
|
|
24
|
-
type: 'text',
|
|
25
|
-
initial: './keysStore',
|
|
26
|
-
validate: v => {
|
|
27
|
-
try {
|
|
28
|
-
// eslint-disable-next-line
|
|
29
|
-
ensureDirSync(path.join(process.cwd(), v));
|
|
30
|
-
return true;
|
|
31
|
-
} catch {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
const { keyOutputDir } = await promptAsync({
|
|
37
|
-
message:
|
|
38
|
-
'In which directory would you like to store your key pair (used by your OTA Server) ?. ⚠️ Those keysStore are sensitive and should be kept private.',
|
|
39
|
-
name: 'keyOutputDir',
|
|
40
|
-
type: 'text',
|
|
41
|
-
initial: './keysStore',
|
|
42
|
-
validate: v => {
|
|
43
|
-
try {
|
|
44
|
-
// eslint-disable-next-line
|
|
45
|
-
ensureDirSync(path.join(process.cwd(), v));
|
|
46
|
-
return true;
|
|
47
|
-
} catch {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
const { certificateCommonName } = await promptAsync({
|
|
53
|
-
message: 'Please enter your Organization name',
|
|
54
|
-
name: 'certificateCommonName',
|
|
55
|
-
type: 'text',
|
|
56
|
-
initial: 'Your Organization Name',
|
|
57
|
-
validate: v => {
|
|
58
|
-
return !!v;
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
const { certificateValidityDurationYears } = await promptAsync({
|
|
62
|
-
message: 'How many years should the certificate be valid for?',
|
|
63
|
-
name: 'certificateValidityDurationYears',
|
|
64
|
-
type: 'number',
|
|
65
|
-
initial: 10,
|
|
66
|
-
validate: v => {
|
|
67
|
-
return v > 0 && Number.isInteger(v);
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
const validityDurationYears = Math.floor(Number(certificateValidityDurationYears));
|
|
71
|
-
const certificateOutput = path.resolve(process.cwd(), certificateOutputDir);
|
|
72
|
-
const keyOutput = path.resolve(process.cwd(), keyOutputDir);
|
|
73
|
-
const validityNotBefore = new Date();
|
|
74
|
-
const validityNotAfter = new Date();
|
|
75
|
-
validityNotAfter.setFullYear(validityNotAfter.getFullYear() + validityDurationYears);
|
|
76
|
-
const keyPair = generateKeyPair();
|
|
77
|
-
const certificate = generateSelfSignedCodeSigningCertificate({
|
|
78
|
-
keyPair,
|
|
79
|
-
validityNotBefore,
|
|
80
|
-
validityNotAfter,
|
|
81
|
-
commonName: certificateCommonName,
|
|
82
|
-
});
|
|
83
|
-
const keyPairPEM = convertKeyPairToPEM(keyPair);
|
|
84
|
-
const certificatePEM = convertCertificateToCertificatePEM(certificate);
|
|
85
|
-
await Promise.all([
|
|
86
|
-
writeFile(path.join(keyOutput, 'public-key.pem'), keyPairPEM.publicKeyPEM),
|
|
87
|
-
writeFile(path.join(keyOutput, 'private-key.pem'), keyPairPEM.privateKeyPEM),
|
|
88
|
-
writeFile(path.join(certificateOutput, 'certificate.pem'), certificatePEM),
|
|
89
|
-
]);
|
|
90
|
-
Log.succeed(
|
|
91
|
-
`Generated public and private keys output in ${keyOutputDir}. Please follow the documentation to securely store them and do not commit them to your repository.`
|
|
92
|
-
);
|
|
93
|
-
Log.succeed(`Generated code signing certificate output in ${certificateOutputDir}.`);
|
|
94
|
-
}
|
|
95
|
-
}
|
package/src/commands/init.ts
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
createOrModifyExpoConfigAsync,
|
|
7
|
-
getExpoConfigUpdateUrl,
|
|
8
|
-
getPrivateExpoConfigAsync,
|
|
9
|
-
} from '../lib/expoConfig';
|
|
10
|
-
import Log from '../lib/log';
|
|
11
|
-
import { ora } from '../lib/ora';
|
|
12
|
-
import { isExpoInstalled } from '../lib/package';
|
|
13
|
-
import { confirmAsync, promptAsync } from '../lib/prompts';
|
|
14
|
-
import { isValidUpdateUrl } from '../lib/utils';
|
|
15
|
-
|
|
16
|
-
export default class Init extends Command {
|
|
17
|
-
static override args = {};
|
|
18
|
-
static override description = 'Configure your existing expo project with Expo Open OTA';
|
|
19
|
-
static override examples = ['<%= config.bin %> <%= command.id %>'];
|
|
20
|
-
static override flags = {};
|
|
21
|
-
public async run(): Promise<void> {
|
|
22
|
-
const projectDir = process.cwd();
|
|
23
|
-
const hasExpo = isExpoInstalled(projectDir);
|
|
24
|
-
if (!hasExpo) {
|
|
25
|
-
Log.error('Expo is not installed in this project. Please install Expo first.');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const config = await getPrivateExpoConfigAsync(projectDir);
|
|
29
|
-
if (!config) {
|
|
30
|
-
Log.error(
|
|
31
|
-
'Could not find Expo config in this project. Please make sure you have an Expo config.'
|
|
32
|
-
);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
const { updateUrl: promptedUrl } = await promptAsync({
|
|
36
|
-
message: 'Enter the URL of your update server (ex: https://customota.com)',
|
|
37
|
-
name: 'updateUrl',
|
|
38
|
-
type: 'text',
|
|
39
|
-
initial: getExpoConfigUpdateUrl(config),
|
|
40
|
-
validate: v => {
|
|
41
|
-
return !!v && isValidUpdateUrl(v);
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
let manifestEndpoint = `${promptedUrl}/manifest`;
|
|
45
|
-
const updateUrl = getExpoConfigUpdateUrl(config);
|
|
46
|
-
if (updateUrl && !updateUrl.includes('expo.dev')) {
|
|
47
|
-
const confirmed = await confirmAsync({
|
|
48
|
-
message: `Expo config already has an update URL set to ${updateUrl}. Do you want to replace it?`,
|
|
49
|
-
name: 'replace',
|
|
50
|
-
type: 'confirm',
|
|
51
|
-
});
|
|
52
|
-
if (!confirmed) {
|
|
53
|
-
manifestEndpoint = updateUrl;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const confirmed = await confirmAsync({
|
|
57
|
-
message: 'Do you have already generated your certificates and keysStore for code signing?',
|
|
58
|
-
name: 'certificates',
|
|
59
|
-
type: 'confirm',
|
|
60
|
-
});
|
|
61
|
-
if (!confirmed) {
|
|
62
|
-
Log.fail('You need to generate your certificates first by using npx eoas generate-keysStore');
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
const { codeSigningCertificatePath } = await promptAsync({
|
|
66
|
-
message: 'Enter the path to your code signing certificate (ex: ./keysStore/certificate.pem)',
|
|
67
|
-
name: 'codeSigningCertificatePath',
|
|
68
|
-
type: 'text',
|
|
69
|
-
initial: './keysStore/certificate.pem',
|
|
70
|
-
validate: v => {
|
|
71
|
-
try {
|
|
72
|
-
const fullPath = path.resolve(projectDir, v);
|
|
73
|
-
// eslint-disable-next-line
|
|
74
|
-
const fileExists = fs.existsSync(fullPath);
|
|
75
|
-
if (!fileExists) {
|
|
76
|
-
Log.newLine();
|
|
77
|
-
Log.error('File does not exist');
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
// eslint-disable-next-line
|
|
81
|
-
const key = fs.readFileSync(fullPath, 'utf8');
|
|
82
|
-
if (!key) {
|
|
83
|
-
Log.error('Empty key');
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
return true;
|
|
87
|
-
} catch {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
const newUpdateConfig = {
|
|
93
|
-
url: manifestEndpoint,
|
|
94
|
-
codeSigningMetadata: {
|
|
95
|
-
keyid: 'main',
|
|
96
|
-
alg: 'rsa-v1_5-sha256' as const,
|
|
97
|
-
},
|
|
98
|
-
codeSigningCertificate: codeSigningCertificatePath,
|
|
99
|
-
enabled: true,
|
|
100
|
-
requestHeaders: {
|
|
101
|
-
'expo-channel-name': 'process.env.RELEASE_CHANNEL',
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
const updateConfigSpinner = ora('Updating Expo config').start();
|
|
105
|
-
try {
|
|
106
|
-
await createOrModifyExpoConfigAsync(projectDir, {
|
|
107
|
-
updates: newUpdateConfig,
|
|
108
|
-
});
|
|
109
|
-
updateConfigSpinner.succeed(
|
|
110
|
-
'Expo config successfully updated do not forget to format the file with prettier or eslint'
|
|
111
|
-
);
|
|
112
|
-
} catch (e) {
|
|
113
|
-
updateConfigSpinner.fail('Failed to update Expo config');
|
|
114
|
-
Log.error(e);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|