netlify-cli 27.12.1 → 27.13.0
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/agents/agents-stop.js +2 -2
- package/dist/commands/base-command.js +7 -3
- package/dist/commands/deploy/deploy.js +29 -41
- package/dist/commands/sites/sites-create.js +3 -2
- package/dist/utils/team.d.ts +1 -0
- package/dist/utils/team.js +10 -5
- package/dist/utils/telemetry/report-error.js +2 -3
- package/dist/utils/telemetry/telemetry.js +9 -5
- package/dist/utils/telemetry/utils.d.ts +1 -0
- package/dist/utils/telemetry/utils.js +4 -0
- package/package.json +3 -3
|
@@ -38,8 +38,8 @@ export const agentsStop = async (id, options, command) => {
|
|
|
38
38
|
}
|
|
39
39
|
// Stop the agent task
|
|
40
40
|
const stopSpinnerInstance = startSpinner({ text: 'Stopping agent task...' });
|
|
41
|
-
const response = await fetch(`${apiOpts.scheme ?? 'https'}://${apiOpts.host ?? api.host}/api/v1/agent_runners/${id}`, {
|
|
42
|
-
method: '
|
|
41
|
+
const response = await fetch(`${apiOpts.scheme ?? 'https'}://${apiOpts.host ?? api.host}/api/v1/agent_runners/${id}/stop`, {
|
|
42
|
+
method: 'POST',
|
|
43
43
|
headers: {
|
|
44
44
|
Authorization: `Bearer ${api.accessToken ?? ''}`,
|
|
45
45
|
'User-Agent': apiOpts.userAgent,
|
|
@@ -234,6 +234,8 @@ export default class BaseCommand extends Command {
|
|
|
234
234
|
const getCommands = (command) => {
|
|
235
235
|
const parentCommand = this.name() === 'netlify' ? command : command.parent;
|
|
236
236
|
return (parentCommand?.commands
|
|
237
|
+
// subcommands nested with `.command()` rather than named `parent:child`, e.g. `database connect`
|
|
238
|
+
.concat(this.name() === 'netlify' ? [] : command.commands)
|
|
237
239
|
.filter((cmd) => {
|
|
238
240
|
if (cmd._hidden)
|
|
239
241
|
return false;
|
|
@@ -242,11 +244,13 @@ export default class BaseCommand extends Command {
|
|
|
242
244
|
// don't include subcommands on the main page
|
|
243
245
|
return !cmd.name().includes(':');
|
|
244
246
|
}
|
|
245
|
-
return cmd.name().startsWith(`${command.name()}:`);
|
|
247
|
+
return cmd.name().startsWith(`${command.name()}:`) || cmd.parent === command;
|
|
246
248
|
})
|
|
247
249
|
.sort((a, b) => a.name().localeCompare(b.name())) || []);
|
|
248
250
|
};
|
|
249
|
-
|
|
251
|
+
/** nested subcommands are shown by their full path, e.g. `database migrations apply` */
|
|
252
|
+
const getCommandTerm = (cmd) => cmd.parent && cmd.parent.name() !== 'netlify' ? `${getCommandTerm(cmd.parent)} ${cmd.name()}` : cmd.name();
|
|
253
|
+
help.longestSubcommandTermLength = (command) => getCommands(command).reduce((max, cmd) => Math.max(max, getCommandTerm(cmd).length), 0);
|
|
250
254
|
/** override the longestOptionTermLength to react on hide options flag */
|
|
251
255
|
help.longestOptionTermLength = (command, helper) => (!command.noBaseOptions &&
|
|
252
256
|
helper.visibleOptions(command).reduce((max, option) => Math.max(max, helper.optionTerm(option).length), 0)) ||
|
|
@@ -313,7 +317,7 @@ export default class BaseCommand extends Command {
|
|
|
313
317
|
'',
|
|
314
318
|
];
|
|
315
319
|
}
|
|
316
|
-
const commandList = getCommands(command).map((cmd) => formatItem(cmd
|
|
320
|
+
const commandList = getCommands(command).map((cmd) => formatItem(getCommandTerm(cmd), helper.subcommandDescription(cmd).split('\n')[0], true));
|
|
317
321
|
if (commandList.length !== 0) {
|
|
318
322
|
output = [...output, chalk.bold('COMMANDS'), formatHelpList(commandList), ''];
|
|
319
323
|
}
|
|
@@ -72,7 +72,7 @@ const getDeployFolder = async ({ command, config, options, site, siteData, }) =>
|
|
|
72
72
|
? resolve(command.jsWorkspaceRoot || site.root, options.dir)
|
|
73
73
|
: resolve(command.workingDir, options.dir);
|
|
74
74
|
}
|
|
75
|
-
else if (config
|
|
75
|
+
else if (config.build.publish) {
|
|
76
76
|
deployFolder = resolve(site.root, config.build.publish);
|
|
77
77
|
}
|
|
78
78
|
else if (siteData?.build_settings?.dir) {
|
|
@@ -252,10 +252,7 @@ const generateDeployCommand = (options, availableTeams, command) => {
|
|
|
252
252
|
return parts.join(' ');
|
|
253
253
|
};
|
|
254
254
|
const prepareProductionDeploy = async ({ api, siteData, options, command, }) => {
|
|
255
|
-
if (
|
|
256
|
-
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- FIXME: a non-object `published_deploy` must not count as locked
|
|
257
|
-
siteData.published_deploy !== null &&
|
|
258
|
-
siteData.published_deploy.locked) {
|
|
255
|
+
if (siteData.published_deploy?.locked) {
|
|
259
256
|
log(`\n${NETLIFYDEVERR} Deployments are "locked" for production context of this project\n`);
|
|
260
257
|
const overrideCommand = generateDeployCommand({ ...options, prodIfUnlocked: true, prod: false }, [], command);
|
|
261
258
|
if (!isInteractive()) {
|
|
@@ -275,6 +272,19 @@ const prepareProductionDeploy = async ({ api, siteData, options, command, }) =>
|
|
|
275
272
|
log(`\n${NETLIFYDEVLOG} "Auto publishing" has been enabled for production context\n`);
|
|
276
273
|
}
|
|
277
274
|
};
|
|
275
|
+
const createDeploy = async ({ alias, api, command, deployToProduction, options, siteData, siteId, }) => {
|
|
276
|
+
if (deployToProduction) {
|
|
277
|
+
await prepareProductionDeploy({ siteData, api, options, command });
|
|
278
|
+
}
|
|
279
|
+
const draft = options.draft || (!deployToProduction && !alias);
|
|
280
|
+
const createDeployBody = {
|
|
281
|
+
draft,
|
|
282
|
+
branch: alias,
|
|
283
|
+
include_upload_url: options.uploadSourceZip,
|
|
284
|
+
...getDeploySourceFields(),
|
|
285
|
+
};
|
|
286
|
+
return (await api.createSiteDeploy({ siteId, title: options.message, body: createDeployBody }));
|
|
287
|
+
};
|
|
278
288
|
const hasErrorMessage = (actual, expected) => {
|
|
279
289
|
if (typeof actual === 'string') {
|
|
280
290
|
return actual.includes(expected);
|
|
@@ -372,7 +382,7 @@ const uploadDeployBlobs = async ({ cachedConfig, deployId, options, packagePath,
|
|
|
372
382
|
phase: 'stop',
|
|
373
383
|
});
|
|
374
384
|
};
|
|
375
|
-
const runDeploy = async ({ alias, api, command, config, deployFolder, deployTimeout, deployToProduction, functionsConfig, functionsFolder, options, packagePath, silent, site, siteData, siteId, skipFunctionsCache,
|
|
385
|
+
const runDeploy = async ({ alias, api, command, config, deployFolder, deployTimeout, deployToProduction, functionsConfig, functionsFolder, options, packagePath, silent, site, siteData, siteId, skipFunctionsCache, deployId: existingDeployId, }) => {
|
|
376
386
|
let results;
|
|
377
387
|
let deployId = existingDeployId;
|
|
378
388
|
let uploadSourceZipResult;
|
|
@@ -380,21 +390,15 @@ const runDeploy = async ({ alias, api, command, config, deployFolder, deployTime
|
|
|
380
390
|
// We won't have a deploy ID if we run the command with `--no-build`.
|
|
381
391
|
// In this case, we must create the deploy.
|
|
382
392
|
if (!deployId) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
include_upload_url: options.uploadSourceZip,
|
|
391
|
-
...getDeploySourceFields(),
|
|
392
|
-
};
|
|
393
|
-
const createDeployResponse = (await api.createSiteDeploy({
|
|
393
|
+
const createDeployResponse = await createDeploy({
|
|
394
|
+
alias,
|
|
395
|
+
api,
|
|
396
|
+
command,
|
|
397
|
+
deployToProduction,
|
|
398
|
+
options,
|
|
399
|
+
siteData,
|
|
394
400
|
siteId,
|
|
395
|
-
|
|
396
|
-
body: createDeployBody,
|
|
397
|
-
}));
|
|
401
|
+
});
|
|
398
402
|
deployId = createDeployResponse.id;
|
|
399
403
|
if (options.uploadSourceZip &&
|
|
400
404
|
createDeployResponse.source_zip_upload_url &&
|
|
@@ -458,7 +462,7 @@ const runDeploy = async ({ alias, api, command, config, deployFolder, deployTime
|
|
|
458
462
|
workingDir: command.workingDir,
|
|
459
463
|
manifestPath: manifestPath ?? undefined,
|
|
460
464
|
packagePath,
|
|
461
|
-
serverEnabled: Boolean(siteData
|
|
465
|
+
serverEnabled: Boolean(siteData.feature_flags?.netlify_build_server_standalone),
|
|
462
466
|
serverManifestPath: serverManifestPath ?? undefined,
|
|
463
467
|
skipFunctionsCache,
|
|
464
468
|
siteRoot: site.root,
|
|
@@ -708,7 +712,6 @@ const prepAndRunDeploy = async ({ api, command, config, deployToProduction, opti
|
|
|
708
712
|
siteData,
|
|
709
713
|
siteId,
|
|
710
714
|
skipFunctionsCache: options.skipFunctionsCache,
|
|
711
|
-
title: options.message,
|
|
712
715
|
deployId,
|
|
713
716
|
});
|
|
714
717
|
return results;
|
|
@@ -831,7 +834,7 @@ const anonymousDeploy = async (options, command) => {
|
|
|
831
834
|
}
|
|
832
835
|
};
|
|
833
836
|
const checkForFunctions = async () => {
|
|
834
|
-
const functionsFolder = getFunctionsFolder({ config, options, site,
|
|
837
|
+
const functionsFolder = getFunctionsFolder({ config, options, site, workingDir });
|
|
835
838
|
const internalFunctionsDir = await getInternalFunctionsDir({ base: site.root });
|
|
836
839
|
const frameworksFunctionsDir = command.netlify.frameworksAPIPaths.functions.path;
|
|
837
840
|
const hasFunctions = (await dirHasFiles(functionsFolder)) ||
|
|
@@ -861,10 +864,9 @@ const anonymousDeploy = async (options, command) => {
|
|
|
861
864
|
}
|
|
862
865
|
const deployFolder = await getDeployFolder({
|
|
863
866
|
command,
|
|
864
|
-
config
|
|
867
|
+
config,
|
|
865
868
|
options,
|
|
866
869
|
site,
|
|
867
|
-
siteData: {},
|
|
868
870
|
});
|
|
869
871
|
await validateDeployFolder(deployFolder);
|
|
870
872
|
const edgeFunctionsDistPath = await getEdgeFunctionsDistPathIfExists(workingDir);
|
|
@@ -983,22 +985,8 @@ export const deploy = async (options, command) => {
|
|
|
983
985
|
const deployToProduction = !options.draft && (options.prod || (options.prodIfUnlocked && !(siteData.published_deploy?.locked ?? false)));
|
|
984
986
|
let results = {};
|
|
985
987
|
if (options.build) {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
}
|
|
989
|
-
const draft = options.draft || (!deployToProduction && !alias);
|
|
990
|
-
const createDeployBody = {
|
|
991
|
-
draft,
|
|
992
|
-
branch: alias,
|
|
993
|
-
include_upload_url: options.uploadSourceZip,
|
|
994
|
-
...getDeploySourceFields(),
|
|
995
|
-
};
|
|
996
|
-
const deployMetadata = (await api.createSiteDeploy({
|
|
997
|
-
siteId,
|
|
998
|
-
title: options.message,
|
|
999
|
-
body: createDeployBody,
|
|
1000
|
-
}));
|
|
1001
|
-
const deployId = deployMetadata.id || '';
|
|
988
|
+
const deployMetadata = await createDeploy({ alias, api, command, deployToProduction, options, siteData, siteId });
|
|
989
|
+
const deployId = deployMetadata.id;
|
|
1002
990
|
const skewProtectionToken = deployMetadata.skew_protection_token;
|
|
1003
991
|
let sourceZipFileName;
|
|
1004
992
|
if (options.uploadSourceZip &&
|
|
@@ -5,7 +5,7 @@ import { chalk, logAndThrowError, log, logJson, warn } from '../../utils/command
|
|
|
5
5
|
import getRepoData from '../../utils/get-repo-data.js';
|
|
6
6
|
import { configureRepo } from '../../utils/init/config.js';
|
|
7
7
|
import { isInteractive } from '../../utils/scripted-commands.js';
|
|
8
|
-
import { resolveTeamForNonInteractive } from '../../utils/team.js';
|
|
8
|
+
import { requireTeams, resolveTeamForNonInteractive } from '../../utils/team.js';
|
|
9
9
|
import { track } from '../../utils/telemetry/index.js';
|
|
10
10
|
import { MAX_SITE_NAME_LENGTH } from '../../utils/validation.js';
|
|
11
11
|
import { link } from '../link/link.js';
|
|
@@ -29,9 +29,10 @@ export const sitesCreate = async (options, command) => {
|
|
|
29
29
|
log(`Using team: ${team.name}`);
|
|
30
30
|
}
|
|
31
31
|
else {
|
|
32
|
+
const teams = requireTeams(accounts);
|
|
32
33
|
accountSlug = await select({
|
|
33
34
|
message: 'Team:',
|
|
34
|
-
choices:
|
|
35
|
+
choices: teams.map((account) => ({
|
|
35
36
|
value: account.slug,
|
|
36
37
|
name: account.name,
|
|
37
38
|
})),
|
package/dist/utils/team.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { MinimalAccount } from './types.js';
|
|
2
|
+
export declare const requireTeams: (accounts: MinimalAccount[] | undefined) => MinimalAccount[];
|
|
2
3
|
export declare const resolveTeam: (accounts: MinimalAccount[]) => MinimalAccount | undefined;
|
|
3
4
|
export declare const resolveTeamForNonInteractive: (accounts: MinimalAccount[], commandExample: string) => MinimalAccount;
|
|
4
5
|
//# sourceMappingURL=team.d.ts.map
|
package/dist/utils/team.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { logAndThrowError } from './command-helpers.js';
|
|
2
|
+
export const requireTeams = (accounts) => {
|
|
3
|
+
const teams = accounts ?? [];
|
|
4
|
+
if (teams.length === 0) {
|
|
5
|
+
return logAndThrowError('No teams available. Please ensure you have access to at least one team.');
|
|
6
|
+
}
|
|
7
|
+
return teams;
|
|
8
|
+
};
|
|
2
9
|
export const resolveTeam = (accounts) => {
|
|
3
10
|
if (accounts.length === 1) {
|
|
4
11
|
return accounts[0];
|
|
@@ -6,14 +13,12 @@ export const resolveTeam = (accounts) => {
|
|
|
6
13
|
return accounts.find((acc) => acc.default);
|
|
7
14
|
};
|
|
8
15
|
export const resolveTeamForNonInteractive = (accounts, commandExample) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
const team = resolveTeam(accounts);
|
|
16
|
+
const teams = requireTeams(accounts);
|
|
17
|
+
const team = resolveTeam(teams);
|
|
13
18
|
if (team) {
|
|
14
19
|
return team;
|
|
15
20
|
}
|
|
16
|
-
const availableTeams =
|
|
21
|
+
const availableTeams = teams.map((t) => t.slug).join(', ');
|
|
17
22
|
return logAndThrowError(`Multiple teams available. Please specify which team to use.\n` +
|
|
18
23
|
`Available teams: ${availableTeams}\n\n` +
|
|
19
24
|
`Example: ${commandExample}\n\n` +
|
|
@@ -3,9 +3,8 @@ import { dirname, join } from 'path';
|
|
|
3
3
|
import process, { version as nodejsVersion } from 'process';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { getGlobalConfigStore } from '@netlify/dev-utils';
|
|
6
|
-
import { isCI } from 'ci-info';
|
|
7
6
|
import execa from '../execa.js';
|
|
8
|
-
import { cliVersion } from './utils.js';
|
|
7
|
+
import { cliVersion, isTelemetryDisabledByEnv } from './utils.js';
|
|
9
8
|
const dirPath = dirname(fileURLToPath(import.meta.url));
|
|
10
9
|
let currentCommand;
|
|
11
10
|
export const setCommandForErrorReporting = (command) => {
|
|
@@ -21,7 +20,7 @@ export const setCommandForErrorReporting = (command) => {
|
|
|
21
20
|
*/
|
|
22
21
|
// @ts-expect-error TS(7006) FIXME: Parameter 'error' implicitly has an 'any' type.
|
|
23
22
|
export const reportError = async function (error, config = {}) {
|
|
24
|
-
if (
|
|
23
|
+
if (isTelemetryDisabledByEnv()) {
|
|
25
24
|
return;
|
|
26
25
|
}
|
|
27
26
|
// convert a NotifiableError to an error class
|
|
@@ -2,10 +2,10 @@ import { dirname, join } from 'path';
|
|
|
2
2
|
import process, { version as nodejsVersion } from 'process';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { getGlobalConfigStore } from '@netlify/dev-utils';
|
|
5
|
-
import {
|
|
5
|
+
import { id as ciVendor, isPR } from 'ci-info';
|
|
6
6
|
import { getDrivingAgent } from '../agent-detection.js';
|
|
7
7
|
import execa from '../execa.js';
|
|
8
|
-
import { isTelemetryDisabled, cliVersion } from './utils.js';
|
|
8
|
+
import { isTelemetryDisabled, isTelemetryDisabledByEnv, cliVersion } from './utils.js';
|
|
9
9
|
import isValidEventName from './validation.js';
|
|
10
10
|
const dirPath = dirname(fileURLToPath(import.meta.url));
|
|
11
11
|
function send(type, payload) {
|
|
@@ -49,11 +49,15 @@ const getAgentProperties = () => {
|
|
|
49
49
|
agent_other_value: agent?.otherValue,
|
|
50
50
|
};
|
|
51
51
|
};
|
|
52
|
+
const getCIProperties = () => ({
|
|
53
|
+
ci_vendor: ciVendor ?? undefined,
|
|
54
|
+
ci_is_pr: isPR ?? undefined,
|
|
55
|
+
});
|
|
52
56
|
/**
|
|
53
57
|
* Tracks a custom event with the provided payload
|
|
54
58
|
*/
|
|
55
59
|
export async function track(eventName, payload = {}) {
|
|
56
|
-
if (
|
|
60
|
+
if (isTelemetryDisabledByEnv()) {
|
|
57
61
|
return;
|
|
58
62
|
}
|
|
59
63
|
const globalConfig = await getGlobalConfigStore();
|
|
@@ -78,12 +82,12 @@ export async function track(eventName, payload = {}) {
|
|
|
78
82
|
anonymousId: cliId,
|
|
79
83
|
duration,
|
|
80
84
|
status,
|
|
81
|
-
properties: { ...properties, nodejsVersion, cliVersion, ...getAgentProperties() },
|
|
85
|
+
properties: { ...properties, nodejsVersion, cliVersion, ...getAgentProperties(), ...getCIProperties() },
|
|
82
86
|
};
|
|
83
87
|
return send('track', defaultData);
|
|
84
88
|
}
|
|
85
89
|
export async function identify(payload) {
|
|
86
|
-
if (
|
|
90
|
+
if (isTelemetryDisabledByEnv()) {
|
|
87
91
|
return;
|
|
88
92
|
}
|
|
89
93
|
const globalConfig = await getGlobalConfigStore();
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import process from 'process';
|
|
1
2
|
import getCLIPackageJson from '../get-cli-package-json.js';
|
|
2
3
|
export const { version: cliVersion } = await getCLIPackageJson();
|
|
3
4
|
// @ts-expect-error TS(7006) FIXME: Parameter 'config' implicitly has an 'any' type.
|
|
4
5
|
export const isTelemetryDisabled = function (config) {
|
|
5
6
|
return config.get('telemetryDisabled');
|
|
6
7
|
};
|
|
8
|
+
const isEnabledFlag = (value) => value !== undefined && !['', '0', 'false'].includes(value);
|
|
9
|
+
// An env var opt-out matters in CI, where the global config written by `--telemetry-disable` rarely persists.
|
|
10
|
+
export const isTelemetryDisabledByEnv = () => isEnabledFlag(process.env.NETLIFY_TELEMETRY_DISABLED) || isEnabledFlag(process.env.DO_NOT_TRACK);
|
|
7
11
|
//# sourceMappingURL=utils.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
|
-
"version": "27.
|
|
3
|
+
"version": "27.13.0",
|
|
4
4
|
"description": "Netlify command line tool",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
"@types/write-file-atomic": "^4.0.3",
|
|
183
183
|
"@types/ws": "^8.18.1",
|
|
184
184
|
"@types/yauzl": "^2.10.3",
|
|
185
|
-
"@vitest/coverage-v8": "^
|
|
185
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
186
186
|
"@vitest/eslint-plugin": "1.3.13",
|
|
187
187
|
"c8": "^10.1.3",
|
|
188
188
|
"cheerio": "^1.1.2",
|
|
@@ -210,7 +210,7 @@
|
|
|
210
210
|
"typescript-eslint": "~8.65.0",
|
|
211
211
|
"typescript-native": "npm:typescript@~7.0.2",
|
|
212
212
|
"verdaccio": "^6.3.2",
|
|
213
|
-
"vitest": "^
|
|
213
|
+
"vitest": "^5.0.0"
|
|
214
214
|
},
|
|
215
215
|
"engines": {
|
|
216
216
|
"node": ">=22.13.0"
|