@webiny/cli 0.0.0-mt-2 → 0.0.0-unstable.5e7233243f
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 +625 -0
- package/README.md +1 -1
- package/bin.js +12 -10
- package/cli.js +1 -1
- package/commands/index.js +7 -0
- package/commands/run/index.js +9 -1
- package/commands/wcp/hooks.js +133 -0
- package/commands/wcp/index.js +8 -0
- package/commands/wcp/login.js +228 -0
- package/commands/wcp/logout.js +28 -0
- package/commands/wcp/project.js +202 -0
- package/commands/wcp/utils/getProjectEnvironment.js +120 -0
- package/commands/wcp/utils/getUser.js +100 -0
- package/commands/wcp/utils/getWcpPat.js +5 -0
- package/commands/wcp/utils/index.js +17 -0
- package/commands/wcp/utils/setProjectId.js +44 -0
- package/commands/wcp/utils/setWcpPat.js +5 -0
- package/commands/wcp/utils/sleep.js +1 -0
- package/commands/wcp/utils/updateUserLastActiveOn.js +28 -0
- package/commands/wcp/whoami.js +43 -0
- package/context.js +2 -2
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/package.json +16 -11
- package/types.d.ts +5 -41
- package/utils/createProjectApplicationWorkspace.js +16 -0
- package/utils/getApiProjectApplicationFolder.js +12 -0
- package/utils/getProjectApplication.js +31 -7
- package/utils/index.d.ts +1 -0
- package/utils/index.js +10 -1
- package/utils/log.js +15 -17
package/commands/run/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const camelCase = require("camelcase");
|
|
2
2
|
const findUp = require("find-up");
|
|
3
|
+
const path = require("path");
|
|
3
4
|
|
|
4
5
|
module.exports = {
|
|
5
6
|
type: "cli-command",
|
|
@@ -16,9 +17,16 @@ module.exports = {
|
|
|
16
17
|
},
|
|
17
18
|
async argv => {
|
|
18
19
|
const configFile = findUp.sync(["webiny.config.ts", "webiny.config.js"]);
|
|
19
|
-
|
|
20
|
+
let config = context.import(configFile);
|
|
20
21
|
|
|
21
22
|
const command = camelCase(argv.command);
|
|
23
|
+
if (typeof config === "function") {
|
|
24
|
+
config = config({
|
|
25
|
+
options: { ...argv, cwd: path.dirname(configFile) },
|
|
26
|
+
context
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
if (config.commands && typeof config.commands[command] === "function") {
|
|
23
31
|
return await config.commands[command]({ ...argv }, context);
|
|
24
32
|
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
const { encrypt, decrypt } = require("@webiny/wcp");
|
|
2
|
+
const { getUser, getProjectEnvironment, updateUserLastActiveOn } = require("./utils");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The two environment variables we set via these hooks are the following:
|
|
6
|
+
* - WCP_PROJECT_ENVIRONMENT - contains encrypted data about the deployed project environment
|
|
7
|
+
* - WCP_PROJECT_ENVIRONMENT_API_KEY - for easier access, we also set the API key
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* There are multiple ways the hooks below prepare the WCP-enabled project for deployment.
|
|
12
|
+
* 1. If `WCP_PROJECT_ENVIRONMENT` metadata env var is defined, we decrypt it, retrieve the
|
|
13
|
+
* API key from it, and assign it as the `WCP_PROJECT_ENVIRONMENT_API_KEY` env var.
|
|
14
|
+
* 2. If `WCP_PROJECT_ENVIRONMENT_API_KEY` env var is defined, then we use that as the
|
|
15
|
+
* project environment API key. We use that to load the project environment data
|
|
16
|
+
* and to also assign the `WCP_PROJECT_ENVIRONMENT` metadata env var.
|
|
17
|
+
* 3. If none of the above is defined, we retrieve (or create) the project environment,
|
|
18
|
+
* retrieve its API key and again assign it as `WCP_PROJECT_ENVIRONMENT_API_KEY` env var.
|
|
19
|
+
* As in 2), we also assign the `WCP_PROJECT_ENVIRONMENT` metadata env var.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
let projectEnvironment;
|
|
23
|
+
|
|
24
|
+
const getEnvironmentHookHandler = async (args, context) => {
|
|
25
|
+
// If the project isn't linked with WCP, do nothing.
|
|
26
|
+
const wcpProjectId = context.project.config.id || process.env.WCP_PROJECT_ID;
|
|
27
|
+
if (!wcpProjectId) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// For development purposes, we allow setting the WCP_PROJECT_ENVIRONMENT env var directly.
|
|
32
|
+
if (process.env.WCP_PROJECT_ENVIRONMENT) {
|
|
33
|
+
// If we have WCP_PROJECT_ENVIRONMENT env var, we set the WCP_PROJECT_ENVIRONMENT_API_KEY too.
|
|
34
|
+
const decryptedProjectEnvironment = decrypt(process.env.WCP_PROJECT_ENVIRONMENT);
|
|
35
|
+
process.env.WCP_PROJECT_ENVIRONMENT_API_KEY = decryptedProjectEnvironment.apiKey;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// The `id` has the orgId/projectId structure, for example `my-org-x/my-project-y`.
|
|
40
|
+
const [orgId, projectId] = wcpProjectId.split("/");
|
|
41
|
+
|
|
42
|
+
const apiKey = process.env.WCP_PROJECT_ENVIRONMENT_API_KEY;
|
|
43
|
+
|
|
44
|
+
let projectEnvironment;
|
|
45
|
+
if (apiKey) {
|
|
46
|
+
projectEnvironment = await getProjectEnvironment({ apiKey });
|
|
47
|
+
} else {
|
|
48
|
+
const isValidId = orgId && projectId;
|
|
49
|
+
if (!isValidId) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`It seems the project ID, specified in "webiny.project.ts" file, is invalid.`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// If there is no API key, that means we need to retrieve the currently logged-in user.
|
|
56
|
+
const user = await getUser();
|
|
57
|
+
const project = user.projects.find(item => item.id === projectId);
|
|
58
|
+
if (!project) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`It seems you don't belong to the current project or the current project has been deleted.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
projectEnvironment = await getProjectEnvironment({
|
|
65
|
+
orgId,
|
|
66
|
+
projectId,
|
|
67
|
+
userId: user.id,
|
|
68
|
+
environmentId: args.env
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (projectEnvironment.org.id !== orgId) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Cannot proceed with the deployment because the "${projectEnvironment.name}" project environment doesn't belong to the "${orgId}" organization. Please check your WCP project ID (currently set to "${wcpProjectId}").`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (projectEnvironment.project.id !== projectId) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Cannot proceed with the deployment because the "${projectEnvironment.name}" project environment doesn't belong to the "${wcpProjectId}" project. Please check your WCP project ID (currently set to "${wcpProjectId}").`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (projectEnvironment && projectEnvironment.status !== "enabled") {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Cannot proceed with the deployment because the "${projectEnvironment.name}" project environment has been disabled.`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Assign `WCP_PROJECT_ENVIRONMENT` and `WCP_PROJECT_ENVIRONMENT_API_KEY`
|
|
91
|
+
const wcpProjectEnvironment = {
|
|
92
|
+
id: projectEnvironment.id,
|
|
93
|
+
apiKey: projectEnvironment.apiKey,
|
|
94
|
+
org: { id: projectEnvironment.org.id },
|
|
95
|
+
project: { id: projectEnvironment.project.id }
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
process.env.WCP_PROJECT_ENVIRONMENT = encrypt(wcpProjectEnvironment);
|
|
99
|
+
process.env.WCP_PROJECT_ENVIRONMENT_API_KEY = projectEnvironment.apiKey;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const updateLastActiveOnHookHandler = async () => {
|
|
103
|
+
if (!projectEnvironment) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Is this a user environment? If so, let's update his "last active" field.
|
|
108
|
+
if (projectEnvironment.user) {
|
|
109
|
+
await updateUserLastActiveOn();
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Export hooks plugins for deploy and watch commands.
|
|
114
|
+
module.exports = () => [
|
|
115
|
+
// Deploy hook handlers.
|
|
116
|
+
{
|
|
117
|
+
type: "hook-before-deploy",
|
|
118
|
+
name: "hook-before-deploy-environment-get-environment",
|
|
119
|
+
hook: getEnvironmentHookHandler
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
type: "hook-before-deploy",
|
|
123
|
+
name: "hook-before-deploy-update-last-active-on",
|
|
124
|
+
hook: updateLastActiveOnHookHandler
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
// Watch hook handlers.
|
|
128
|
+
{
|
|
129
|
+
type: "hook-before-watch",
|
|
130
|
+
name: "hook-before-watch-environment-get-environment",
|
|
131
|
+
hook: getEnvironmentHookHandler
|
|
132
|
+
}
|
|
133
|
+
];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const { command: login } = require("./login");
|
|
2
|
+
const { command: logout } = require("./logout");
|
|
3
|
+
const { command: whoami } = require("./whoami");
|
|
4
|
+
const { command: project } = require("./project");
|
|
5
|
+
|
|
6
|
+
const hooks = require("./hooks");
|
|
7
|
+
|
|
8
|
+
module.exports = [login(), logout(), whoami(), project(), hooks()];
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
const open = require("open");
|
|
2
|
+
const { GraphQLClient } = require("graphql-request");
|
|
3
|
+
const { setProjectId, setWcpPat, sleep } = require("./utils");
|
|
4
|
+
const chalk = require("chalk");
|
|
5
|
+
const { getWcpGqlApiUrl, getWcpAppUrl } = require("@webiny/wcp");
|
|
6
|
+
|
|
7
|
+
// 120 retries * 2000ms interval = 4 minutes until the command returns an error.
|
|
8
|
+
const LOGIN_RETRIES_COUNT = 30;
|
|
9
|
+
const LOGIN_RETRIES_INTERVAL = 2000;
|
|
10
|
+
|
|
11
|
+
const USER_PAT_FIELDS = /* GraphQL */ `
|
|
12
|
+
fragment UserPatFields on UserPat {
|
|
13
|
+
name
|
|
14
|
+
meta
|
|
15
|
+
token
|
|
16
|
+
expiresOn
|
|
17
|
+
user {
|
|
18
|
+
email
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const GENERATE_USER_PAT = /* GraphQL */ `
|
|
24
|
+
mutation GenerateUserPat {
|
|
25
|
+
users {
|
|
26
|
+
generateUserPat
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const GET_USER_PAT = /* GraphQL */ `
|
|
32
|
+
${USER_PAT_FIELDS}
|
|
33
|
+
query GetUserPat($token: ID!) {
|
|
34
|
+
users {
|
|
35
|
+
getUserPat(token: $token) {
|
|
36
|
+
...UserPatFields
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const CREATE_USER_PAT = /* GraphQL */ `
|
|
43
|
+
${USER_PAT_FIELDS}
|
|
44
|
+
mutation CreateUserPat($expiresIn: Int, $token: ID, $data: CreateUserPatDataInput) {
|
|
45
|
+
users {
|
|
46
|
+
createUserPat(expiresIn: $expiresIn, token: $token, data: $data) {
|
|
47
|
+
...UserPatFields
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
module.exports.command = () => ({
|
|
54
|
+
type: "cli-command",
|
|
55
|
+
name: "cli-command-wcp-login",
|
|
56
|
+
create({ yargs, context }) {
|
|
57
|
+
yargs.command(
|
|
58
|
+
"login [pat]",
|
|
59
|
+
`Log in to the Webiny Control Panel`,
|
|
60
|
+
yargs => {
|
|
61
|
+
yargs.example("$0 login");
|
|
62
|
+
yargs.positional("pat", {
|
|
63
|
+
describe: `Personal access token (PAT)`,
|
|
64
|
+
type: "string"
|
|
65
|
+
});
|
|
66
|
+
yargs.option("debug", {
|
|
67
|
+
describe: `Turn on debug logs`,
|
|
68
|
+
type: "boolean"
|
|
69
|
+
});
|
|
70
|
+
yargs.option("debug-level", {
|
|
71
|
+
default: 1,
|
|
72
|
+
describe: `Set the debug logs verbosity level`,
|
|
73
|
+
type: "number"
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
async ({ debug, debugLevel, pat: patFromParams }) => {
|
|
77
|
+
const graphQLClient = new GraphQLClient(getWcpGqlApiUrl());
|
|
78
|
+
|
|
79
|
+
let pat;
|
|
80
|
+
|
|
81
|
+
if (patFromParams) {
|
|
82
|
+
try {
|
|
83
|
+
graphQLClient.setHeaders({ authorization: patFromParams });
|
|
84
|
+
pat = await graphQLClient
|
|
85
|
+
.request(GET_USER_PAT, { token: patFromParams })
|
|
86
|
+
.then(({ users }) => users.getUserPat);
|
|
87
|
+
|
|
88
|
+
// If we've received a PAT that has expiration, let's create a long-lived PAT.
|
|
89
|
+
// We don't want to have our users interrupted because of an expired PAT.
|
|
90
|
+
if (pat.expiresOn) {
|
|
91
|
+
pat = await graphQLClient
|
|
92
|
+
.request(CREATE_USER_PAT, { data: { meta: pat.meta } })
|
|
93
|
+
.then(({ users }) => users.createUserPat);
|
|
94
|
+
}
|
|
95
|
+
} catch (e) {
|
|
96
|
+
if (debug) {
|
|
97
|
+
context.debug(
|
|
98
|
+
`Could not use the provided ${context.debug.hl(
|
|
99
|
+
patFromParams
|
|
100
|
+
)} PAT because of the following error:`
|
|
101
|
+
);
|
|
102
|
+
console.debug(e);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
throw new Error(
|
|
106
|
+
`Invalid PAT received. Please try again or login manually via the ${context.error.hl(
|
|
107
|
+
"yarn webiny login"
|
|
108
|
+
)} command.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
const generatedPat = await graphQLClient
|
|
113
|
+
.request(GENERATE_USER_PAT)
|
|
114
|
+
.then(({ users }) => users.generateUserPat);
|
|
115
|
+
|
|
116
|
+
const queryParams = `pat=${generatedPat}&pat_name=${encodeURIComponent(
|
|
117
|
+
"Webiny CLI"
|
|
118
|
+
)}&ref=cli`;
|
|
119
|
+
const openUrl = `${getWcpAppUrl()}/login/cli?${queryParams}`;
|
|
120
|
+
|
|
121
|
+
debug && context.debug(`Opening ${context.debug.hl(openUrl)}...`);
|
|
122
|
+
await open(openUrl);
|
|
123
|
+
|
|
124
|
+
const graphql = {
|
|
125
|
+
variables: { token: generatedPat },
|
|
126
|
+
headers: {
|
|
127
|
+
Authorization: generatedPat
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
graphQLClient.setHeaders(graphql.headers);
|
|
132
|
+
|
|
133
|
+
let retries = 0;
|
|
134
|
+
const result = await new Promise(resolve => {
|
|
135
|
+
const interval = setInterval(async () => {
|
|
136
|
+
retries++;
|
|
137
|
+
if (retries > LOGIN_RETRIES_COUNT) {
|
|
138
|
+
clearInterval(interval);
|
|
139
|
+
resolve(null);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const pat = await graphQLClient
|
|
144
|
+
.request(GET_USER_PAT, graphql.variables)
|
|
145
|
+
.then(({ users }) => users.getUserPat);
|
|
146
|
+
|
|
147
|
+
clearInterval(interval);
|
|
148
|
+
resolve(pat);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
// Do nothing.
|
|
151
|
+
if (debug) {
|
|
152
|
+
context.debug(
|
|
153
|
+
`Could not login. Will try again in ${LOGIN_RETRIES_INTERVAL}ms.`
|
|
154
|
+
);
|
|
155
|
+
if (debugLevel > 1) {
|
|
156
|
+
context.debug("GraphQL Request: ");
|
|
157
|
+
console.log(JSON.stringify(graphql, null, 2));
|
|
158
|
+
}
|
|
159
|
+
if (debugLevel > 2) {
|
|
160
|
+
context.debug(e.message);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}, LOGIN_RETRIES_INTERVAL);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (!result) {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`Could not login. Did you complete the sign in / sign up process at ${getWcpAppUrl()}?`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
pat = result;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
setWcpPat(pat.token);
|
|
177
|
+
|
|
178
|
+
console.log(
|
|
179
|
+
`${chalk.green("✔")} You've successfully logged in to Webiny Control Panel.`
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
let projectInitialized = Boolean(
|
|
183
|
+
context.project.config.id || process.env.WCP_PROJECT_ID
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// If we have `orgId` and `projectId` in PAT's metadata, let's immediately link the project.
|
|
187
|
+
if (pat.meta && pat.meta.orgId && pat.meta.projectId) {
|
|
188
|
+
await sleep();
|
|
189
|
+
|
|
190
|
+
console.log();
|
|
191
|
+
|
|
192
|
+
const { orgId, projectId } = pat.meta;
|
|
193
|
+
|
|
194
|
+
const id = `${orgId}/${projectId}`;
|
|
195
|
+
console.log(`Project ${chalk.green(id)} detected. Linking...`);
|
|
196
|
+
|
|
197
|
+
await sleep();
|
|
198
|
+
|
|
199
|
+
await setProjectId({
|
|
200
|
+
project: context.project,
|
|
201
|
+
orgId,
|
|
202
|
+
projectId
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
console.log(`Project ${context.success.hl(id)} linked successfully.`);
|
|
206
|
+
projectInitialized = true;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
await sleep();
|
|
210
|
+
|
|
211
|
+
console.log();
|
|
212
|
+
console.log(chalk.bold("Next Steps"));
|
|
213
|
+
|
|
214
|
+
if (!projectInitialized) {
|
|
215
|
+
console.log(
|
|
216
|
+
`‣ link your project via the ${chalk.green(
|
|
217
|
+
"yarn webiny project link"
|
|
218
|
+
)} command`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
console.log(
|
|
223
|
+
`‣ deploy your project via the ${chalk.green("yarn webiny deploy")} command`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const { setWcpPat } = require("./utils");
|
|
2
|
+
|
|
3
|
+
module.exports.command = () => ({
|
|
4
|
+
type: "cli-command",
|
|
5
|
+
name: "cli-command-wcp-logout",
|
|
6
|
+
create({ yargs }) {
|
|
7
|
+
yargs.command(
|
|
8
|
+
"logout",
|
|
9
|
+
`Log out from the Webiny Control Panel`,
|
|
10
|
+
yargs => {
|
|
11
|
+
yargs.example("$0 logout");
|
|
12
|
+
yargs.option("debug", {
|
|
13
|
+
describe: `Turn on debug logs`,
|
|
14
|
+
type: "boolean"
|
|
15
|
+
});
|
|
16
|
+
yargs.option("debug-level", {
|
|
17
|
+
default: 1,
|
|
18
|
+
describe: `Set the debug logs verbosity level`,
|
|
19
|
+
type: "number"
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
async () => {
|
|
23
|
+
setWcpPat(null);
|
|
24
|
+
console.log(`You've successfully logged out from Webiny Control Panel.`);
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
const open = require("open");
|
|
2
|
+
const inquirer = require("inquirer");
|
|
3
|
+
const chalk = require("chalk");
|
|
4
|
+
const { getUser, WCP_APP_URL, setProjectId, sleep } = require("./utils");
|
|
5
|
+
|
|
6
|
+
module.exports.command = () => [
|
|
7
|
+
{
|
|
8
|
+
type: "cli-command",
|
|
9
|
+
name: "cli-command-wcp-project",
|
|
10
|
+
create({ yargs, context }) {
|
|
11
|
+
yargs.command(
|
|
12
|
+
["project <command>"],
|
|
13
|
+
`Webiny project-related commands`,
|
|
14
|
+
projectCommand => {
|
|
15
|
+
projectCommand.command(
|
|
16
|
+
"link",
|
|
17
|
+
`Link a Webiny project with Webiny Control Panel (WCP)`,
|
|
18
|
+
command => {
|
|
19
|
+
yargs.option("debug", {
|
|
20
|
+
describe: `Turn on debug logs`,
|
|
21
|
+
type: "boolean"
|
|
22
|
+
});
|
|
23
|
+
yargs.option("debug-level", {
|
|
24
|
+
default: 1,
|
|
25
|
+
describe: `Set the debug logs verbosity level`,
|
|
26
|
+
type: "number"
|
|
27
|
+
});
|
|
28
|
+
command.example("$0 project link");
|
|
29
|
+
},
|
|
30
|
+
() => handler({ context })
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
projectCommand.command(
|
|
34
|
+
"init",
|
|
35
|
+
`Initialize a Webiny project (deprecated, please use the link command instead)`,
|
|
36
|
+
command => {
|
|
37
|
+
yargs.option("debug", {
|
|
38
|
+
describe: `Turn on debug logs`,
|
|
39
|
+
type: "boolean"
|
|
40
|
+
});
|
|
41
|
+
yargs.option("debug-level", {
|
|
42
|
+
default: 1,
|
|
43
|
+
describe: `Set the debug logs verbosity level`,
|
|
44
|
+
type: "number"
|
|
45
|
+
});
|
|
46
|
+
command.example("$0 project init");
|
|
47
|
+
},
|
|
48
|
+
() => handler({ context })
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
const handler = async ({ context }) => {
|
|
57
|
+
// Check login.
|
|
58
|
+
const user = await getUser();
|
|
59
|
+
|
|
60
|
+
// User already linked a project?
|
|
61
|
+
const { id: orgProjectId } = context.project.config;
|
|
62
|
+
if (orgProjectId) {
|
|
63
|
+
const [, projectId] = orgProjectId.split("/");
|
|
64
|
+
const project = user.projects.find(item => item.id === projectId);
|
|
65
|
+
if (project) {
|
|
66
|
+
console.log(`Your ${chalk.green(orgProjectId)} project has already been linked.`);
|
|
67
|
+
|
|
68
|
+
const prompt = inquirer.createPromptModule();
|
|
69
|
+
const { proceed } = await prompt({
|
|
70
|
+
name: "proceed",
|
|
71
|
+
message: "Would you like to re-initialize it?",
|
|
72
|
+
type: "confirm",
|
|
73
|
+
default: false
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (!proceed) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Get user's organizations.
|
|
85
|
+
if (!user.orgs.length) {
|
|
86
|
+
console.log(
|
|
87
|
+
"It seems you're not part of any organization. Please log in to Webiny Control Panel and create one."
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const prompt = inquirer.createPromptModule();
|
|
91
|
+
const { proceed } = await prompt({
|
|
92
|
+
name: "proceed",
|
|
93
|
+
message: "Would you like to do that now?",
|
|
94
|
+
type: "confirm",
|
|
95
|
+
default: false
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (proceed) {
|
|
99
|
+
await open(WCP_APP_URL);
|
|
100
|
+
}
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let selectedOrg;
|
|
105
|
+
if (user.orgs.length === 1) {
|
|
106
|
+
selectedOrg = user.orgs[0];
|
|
107
|
+
} else {
|
|
108
|
+
console.log("It seems you're part of multiple organizations. ");
|
|
109
|
+
const choices = user.orgs.map(item => ({
|
|
110
|
+
name: item.name,
|
|
111
|
+
value: item
|
|
112
|
+
}));
|
|
113
|
+
|
|
114
|
+
const prompt = inquirer.createPromptModule();
|
|
115
|
+
selectedOrg = await prompt({
|
|
116
|
+
name: "org",
|
|
117
|
+
message: "Select organization:",
|
|
118
|
+
type: "list",
|
|
119
|
+
choices,
|
|
120
|
+
default: choices[0].value
|
|
121
|
+
}).then(result => result.org);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const orgProjects = user.projects.filter(item => item.org.id === selectedOrg.id);
|
|
125
|
+
|
|
126
|
+
// Get user's projects.
|
|
127
|
+
if (!orgProjects.length) {
|
|
128
|
+
console.log(
|
|
129
|
+
`It seems there are no projects created within the ${chalk.green(
|
|
130
|
+
selectedOrg.name
|
|
131
|
+
)} organization.`
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const prompt = inquirer.createPromptModule();
|
|
135
|
+
const { proceed } = await prompt({
|
|
136
|
+
name: "proceed",
|
|
137
|
+
message: "Would you like to create one now?",
|
|
138
|
+
type: "confirm",
|
|
139
|
+
default: false
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (proceed) {
|
|
143
|
+
await open(WCP_APP_URL);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let selectedProject;
|
|
149
|
+
if (orgProjects.length === 1) {
|
|
150
|
+
selectedProject = user.projects[0];
|
|
151
|
+
} else {
|
|
152
|
+
console.log(
|
|
153
|
+
`It seems there are multiple projects created within the ${chalk.green(
|
|
154
|
+
selectedOrg.name
|
|
155
|
+
)} organization.`
|
|
156
|
+
);
|
|
157
|
+
const choices = orgProjects.map(item => ({
|
|
158
|
+
name: item.name,
|
|
159
|
+
value: item
|
|
160
|
+
}));
|
|
161
|
+
const prompt = inquirer.createPromptModule();
|
|
162
|
+
selectedProject = await prompt({
|
|
163
|
+
name: "project",
|
|
164
|
+
message: "Select project:",
|
|
165
|
+
type: "list",
|
|
166
|
+
choices,
|
|
167
|
+
default: choices[0].value
|
|
168
|
+
}).then(result => result.project);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const orgId = selectedOrg.id,
|
|
172
|
+
projectId = selectedProject.id;
|
|
173
|
+
|
|
174
|
+
await sleep();
|
|
175
|
+
console.log();
|
|
176
|
+
|
|
177
|
+
console.log(`Initializing ${context.success.hl(selectedProject.name)} project...`);
|
|
178
|
+
|
|
179
|
+
await sleep();
|
|
180
|
+
|
|
181
|
+
// Assign the necessary IDs into root `webiny.project.ts` project file.
|
|
182
|
+
await setProjectId({
|
|
183
|
+
project: context.project,
|
|
184
|
+
orgId,
|
|
185
|
+
projectId
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
console.log(
|
|
189
|
+
`${chalk.green("✔")} Project ${context.success.hl(
|
|
190
|
+
selectedProject.name
|
|
191
|
+
)} linked successfully.`
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
await sleep();
|
|
195
|
+
|
|
196
|
+
console.log();
|
|
197
|
+
console.log(chalk.bold("Next Steps"));
|
|
198
|
+
|
|
199
|
+
console.log(`‣ deploy your project via the ${chalk.green("yarn webiny deploy")} command`);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
module.exports.handler = handler;
|