netlify-cli 17.37.2 → 17.38.1

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.
Files changed (106) hide show
  1. package/bin/run.js +4 -2
  2. package/dist/commands/addons/addons.d.ts.map +1 -1
  3. package/dist/commands/addons/addons.js +0 -1
  4. package/dist/commands/base-command.d.ts.map +1 -1
  5. package/dist/commands/base-command.js +2 -1
  6. package/dist/commands/blobs/blobs-delete.d.ts.map +1 -1
  7. package/dist/commands/blobs/blobs-delete.js +7 -1
  8. package/dist/commands/blobs/blobs-set.d.ts +1 -0
  9. package/dist/commands/blobs/blobs-set.d.ts.map +1 -1
  10. package/dist/commands/blobs/blobs-set.js +10 -2
  11. package/dist/commands/deploy/deploy.js +2 -2
  12. package/dist/commands/deploy/index.d.ts.map +1 -1
  13. package/dist/commands/deploy/index.js +4 -3
  14. package/dist/commands/env/env-clone.d.ts.map +1 -1
  15. package/dist/commands/env/env-clone.js +12 -3
  16. package/dist/commands/env/env-set.d.ts.map +1 -1
  17. package/dist/commands/env/env-set.js +8 -3
  18. package/dist/commands/env/env-unset.d.ts.map +1 -1
  19. package/dist/commands/env/env-unset.js +7 -3
  20. package/dist/commands/init/index.d.ts.map +1 -1
  21. package/dist/commands/init/index.js +0 -1
  22. package/dist/commands/integration/deploy.d.ts.map +1 -1
  23. package/dist/commands/integration/deploy.js +11 -20
  24. package/dist/commands/main.d.ts +34 -0
  25. package/dist/commands/main.d.ts.map +1 -1
  26. package/dist/commands/main.js +36 -6
  27. package/dist/commands/sites/sites-create-template.d.ts +2 -3
  28. package/dist/commands/sites/sites-create-template.d.ts.map +1 -1
  29. package/dist/commands/sites/sites-create-template.js +113 -92
  30. package/dist/commands/sites/sites-create.d.ts.map +1 -1
  31. package/dist/commands/sites/sites.d.ts.map +1 -1
  32. package/dist/commands/sites/sites.js +0 -1
  33. package/dist/tsconfig.tsbuildinfo +1 -1
  34. package/dist/utils/command-helpers.d.ts +16 -0
  35. package/dist/utils/command-helpers.d.ts.map +1 -1
  36. package/dist/utils/command-helpers.js +7 -0
  37. package/dist/utils/framework-server.d.ts.map +1 -1
  38. package/dist/utils/framework-server.js +2 -2
  39. package/dist/utils/gh-auth.js +1 -1
  40. package/dist/utils/headers.js +1 -1
  41. package/dist/utils/prompts/blob-delete-prompts.d.ts +2 -0
  42. package/dist/utils/prompts/blob-delete-prompts.d.ts.map +1 -0
  43. package/dist/utils/prompts/blob-delete-prompts.js +11 -0
  44. package/dist/utils/prompts/blob-set-prompt.d.ts +2 -0
  45. package/dist/utils/prompts/blob-set-prompt.d.ts.map +1 -0
  46. package/dist/utils/prompts/blob-set-prompt.js +11 -0
  47. package/dist/utils/prompts/confirm-prompt.d.ts +2 -0
  48. package/dist/utils/prompts/confirm-prompt.d.ts.map +1 -0
  49. package/dist/utils/prompts/confirm-prompt.js +20 -0
  50. package/dist/utils/prompts/env-clone-prompt.d.ts +11 -0
  51. package/dist/utils/prompts/env-clone-prompt.d.ts.map +1 -0
  52. package/dist/utils/prompts/env-clone-prompt.js +27 -0
  53. package/dist/utils/prompts/env-set-prompts.d.ts +2 -0
  54. package/dist/utils/prompts/env-set-prompts.d.ts.map +1 -0
  55. package/dist/utils/prompts/env-set-prompts.js +11 -0
  56. package/dist/utils/prompts/env-unset-prompts.d.ts +8 -0
  57. package/dist/utils/prompts/env-unset-prompts.d.ts.map +1 -0
  58. package/dist/utils/prompts/env-unset-prompts.js +17 -0
  59. package/dist/utils/prompts/prompt-messages.d.ts +25 -0
  60. package/dist/utils/prompts/prompt-messages.d.ts.map +1 -0
  61. package/dist/utils/prompts/prompt-messages.js +25 -0
  62. package/dist/utils/redirects.js +1 -1
  63. package/dist/utils/run-build.d.ts +2 -0
  64. package/dist/utils/run-build.d.ts.map +1 -1
  65. package/dist/utils/run-program.d.ts +3 -0
  66. package/dist/utils/run-program.d.ts.map +1 -0
  67. package/dist/utils/run-program.js +12 -0
  68. package/dist/utils/scripted-commands.d.ts +3 -0
  69. package/dist/utils/scripted-commands.d.ts.map +1 -0
  70. package/dist/utils/scripted-commands.js +17 -0
  71. package/dist/utils/sites/create-template.d.ts +14 -0
  72. package/dist/utils/sites/create-template.d.ts.map +1 -0
  73. package/dist/utils/sites/create-template.js +46 -0
  74. package/dist/utils/sites/utils.d.ts +8 -6
  75. package/dist/utils/sites/utils.d.ts.map +1 -1
  76. package/dist/utils/sites/utils.js +10 -4
  77. package/dist/utils/static-server.d.ts +3 -1
  78. package/dist/utils/static-server.d.ts.map +1 -1
  79. package/dist/utils/static-server.js +2 -0
  80. package/dist/utils/types.d.ts +14 -1
  81. package/dist/utils/types.d.ts.map +1 -1
  82. package/functions-templates/javascript/hello-world/{{name}}.mjs +13 -0
  83. package/functions-templates/javascript/scheduled-function/{{name}}.mjs +11 -0
  84. package/functions-templates/rust/hello-world/Cargo.toml +1 -1
  85. package/functions-templates/typescript/hello-world/package-lock.json +15 -15
  86. package/functions-templates/typescript/hello-world/package.json +1 -1
  87. package/functions-templates/typescript/hello-world/{{name}}.mts +14 -0
  88. package/functions-templates/typescript/scheduled-function/package.json +1 -1
  89. package/functions-templates/typescript/scheduled-function/{{name}}.mts +11 -0
  90. package/npm-shrinkwrap.json +849 -626
  91. package/package.json +14 -14
  92. package/functions-templates/javascript/hello-world/{{name}}.js +0 -17
  93. package/functions-templates/javascript/identity-signup/.netlify-function-template.mjs +0 -5
  94. package/functions-templates/javascript/identity-signup/{{name}}.js +0 -29
  95. package/functions-templates/javascript/sanity-create/.netlify-function-template.mjs +0 -5
  96. package/functions-templates/javascript/sanity-create/package.json +0 -20
  97. package/functions-templates/javascript/sanity-create/{{name}}.js +0 -72
  98. package/functions-templates/javascript/sanity-groq/.netlify-function-template.mjs +0 -5
  99. package/functions-templates/javascript/sanity-groq/package.json +0 -21
  100. package/functions-templates/javascript/sanity-groq/{{name}}.js +0 -56
  101. package/functions-templates/javascript/scheduled-function/{{name}}.js +0 -12
  102. package/functions-templates/javascript/submission-created/.netlify-function-template.mjs +0 -5
  103. package/functions-templates/javascript/submission-created/package.json +0 -19
  104. package/functions-templates/javascript/submission-created/{{name}}.js +0 -29
  105. package/functions-templates/typescript/hello-world/{{name}}.ts +0 -12
  106. package/functions-templates/typescript/scheduled-function/{{name}}.ts +0 -12
@@ -1,53 +1,18 @@
1
1
  import inquirer from 'inquirer';
2
2
  import pick from 'lodash/pick.js';
3
- // @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'pars... Remove this comment to see the full error message
4
- import parseGitHubUrl from 'parse-github-url';
5
3
  import { render } from 'prettyjson';
6
- import { chalk, error, getTerminalLink, log, logJson, warn } from '../../utils/command-helpers.js';
4
+ import { v4 as uuid } from 'uuid';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { chalk, error, getTerminalLink, log, logJson, warn, GitHubAPIError, } from '../../utils/command-helpers.js';
7
8
  import execa from '../../utils/execa.js';
8
9
  import getRepoData from '../../utils/get-repo-data.js';
9
10
  import { getGitHubToken } from '../../utils/init/config-github.js';
10
11
  import { configureRepo } from '../../utils/init/config.js';
11
- import { createRepo, getTemplatesFromGitHub, validateTemplate } from '../../utils/sites/utils.js';
12
+ import { deployedSiteExists, getGitHubLink, getTemplateName } from '../../utils/sites/create-template.js';
13
+ import { callLinkSite, createRepo, validateTemplate } from '../../utils/sites/utils.js';
12
14
  import { track } from '../../utils/telemetry/index.js';
13
15
  import { getSiteNameInput } from './sites-create.js';
14
- export const fetchTemplates = async (token) => {
15
- const templatesFromGithubOrg = await getTemplatesFromGitHub(token);
16
- return templatesFromGithubOrg
17
- .filter((repo) => !repo.archived && !repo.disabled)
18
- .map((template) => ({
19
- name: template.name,
20
- sourceCodeUrl: template.html_url,
21
- slug: template.full_name,
22
- }));
23
- };
24
- // @ts-expect-error TS(7031) FIXME: Binding element 'ghToken' implicitly has an 'any' ... Remove this comment to see the full error message
25
- const getTemplateName = async ({ ghToken, options, repository }) => {
26
- if (repository) {
27
- const { repo } = parseGitHubUrl(repository);
28
- return repo || `netlify-templates/${repository}`;
29
- }
30
- if (options.url) {
31
- const urlFromOptions = new URL(options.url);
32
- return urlFromOptions.pathname.slice(1);
33
- }
34
- const templates = await fetchTemplates(ghToken);
35
- log(`Choose one of our starter templates. Netlify will create a new repo for this template in your GitHub account.`);
36
- const { templateName } = await inquirer.prompt([
37
- {
38
- type: 'list',
39
- name: 'templateName',
40
- message: 'Template:',
41
- choices: templates.map((template) => ({
42
- value: template.slug,
43
- name: template.name,
44
- })),
45
- },
46
- ]);
47
- return templateName;
48
- };
49
- // @ts-expect-error TS(7031) FIXME: Binding element 'options' implicitly has an 'any' ... Remove this comment to see the full error message
50
- const getGitHubLink = ({ options, templateName }) => options.url || `https://github.com/${templateName}`;
51
16
  export const sitesCreateTemplate = async (repository, options, command) => {
52
17
  const { api } = command.netlify;
53
18
  await command.authenticate();
@@ -73,7 +38,6 @@ export const sitesCreateTemplate = async (repository, options, command) => {
73
38
  type: 'list',
74
39
  name: 'accountSlug',
75
40
  message: 'Team:',
76
- // @ts-expect-error TS(7006) FIXME: Parameter 'account' implicitly has an 'any' type.
77
41
  choices: accounts.map((account) => ({
78
42
  value: account.slug,
79
43
  name: account.name,
@@ -86,95 +50,152 @@ export const sitesCreateTemplate = async (repository, options, command) => {
86
50
  let site;
87
51
  let repoResp;
88
52
  // Allow the user to reenter site name if selected one isn't available
89
- // @ts-expect-error TS(7006) FIXME: Parameter 'name' implicitly has an 'any' type.
90
- const inputSiteName = async (name) => {
53
+ const inputSiteName = async (name, hasExistingRepo) => {
91
54
  const { name: inputName } = await getSiteNameInput(name);
55
+ const siteName = inputName.trim();
56
+ if (siteName && (await deployedSiteExists(siteName))) {
57
+ log('A site with that name already exists');
58
+ return inputSiteName();
59
+ }
92
60
  try {
93
- const siteName = inputName.trim();
94
- // Create new repo from template
95
- repoResp = await createRepo(templateName, ghToken, siteName || templateName);
96
- // @ts-expect-error TS(18046) - 'repoResp' if of type 'unknown'
97
- if (repoResp.errors) {
98
- // @ts-expect-error TS(18046) - 'repoResp' if of type 'unknown'
99
- if (repoResp.errors[0].includes('Name already exists on this account')) {
100
- warn(`Oh no! We found already a repository with this name. It seems you have already created a template with the name ${templateName}. Please try to run the command again and provide a different name.`);
101
- // @ts-expect-error TS(2554) FIXME: Expected 1 arguments, but got 0.
102
- await inputSiteName();
61
+ const sites = await api.listSites({ name: siteName, filter: 'all' });
62
+ const siteFoundByName = sites.find((filteredSite) => filteredSite.name === siteName);
63
+ if (siteFoundByName) {
64
+ log('A site with that name already exists on your account');
65
+ return inputSiteName();
66
+ }
67
+ }
68
+ catch (error_) {
69
+ error(error_);
70
+ }
71
+ if (!hasExistingRepo) {
72
+ try {
73
+ // Create new repo from template
74
+ let gitHubInputName = siteName || templateName;
75
+ repoResp = await createRepo(templateName, ghToken, gitHubInputName);
76
+ if (repoResp.errors && repoResp.errors[0].includes('Name already exists on this account')) {
77
+ if (gitHubInputName === templateName) {
78
+ gitHubInputName += `-${uuid().split('-')[0]}`;
79
+ repoResp = await createRepo(templateName, ghToken, gitHubInputName);
80
+ }
81
+ else {
82
+ warn(`It seems you have already created a repository with the name ${gitHubInputName}.`);
83
+ return inputSiteName();
84
+ }
85
+ }
86
+ if (!repoResp.id) {
87
+ throw new GitHubAPIError(repoResp.status, repoResp.message);
88
+ }
89
+ hasExistingRepo = true;
90
+ }
91
+ catch (error_) {
92
+ if (error_.status === '404') {
93
+ error(`Could not create repository: ${error_.message}. Ensure that your GitHub personal access token grants permission to create repositories`);
103
94
  }
104
95
  else {
105
- throw new Error(
106
- // @ts-expect-error TS(18046) - 'repoResp' if of type 'unknown'
107
- `Oops! Seems like something went wrong trying to create the repository. We're getting the following error: '${repoResp.errors[0]}'. You can try to re-run this command again or open an issue in our repository: https://github.com/netlify/cli/issues`);
96
+ error(`Something went wrong trying to create the repository. We're getting the following error: '${error_.message}'. You can try to re-run this command again or open an issue in our repository: https://github.com/netlify/cli/issues`);
108
97
  }
109
98
  }
110
- else {
111
- site = await api.createSiteInTeam({
112
- accountSlug,
113
- body: {
114
- repo: {
115
- provider: 'github',
116
- // @ts-expect-error TS(18046) - 'repoResp' if of type 'unknown'
117
- repo: repoResp.full_name,
118
- // @ts-expect-error TS(18046) - 'repoResp' if of type 'unknown'
119
- private: repoResp.private,
120
- // @ts-expect-error TS(18046) - 'repoResp' if of type 'unknown'
121
- branch: repoResp.default_branch,
122
- },
123
- name: siteName,
99
+ }
100
+ try {
101
+ site = await api.createSiteInTeam({
102
+ accountSlug,
103
+ body: {
104
+ repo: {
105
+ provider: 'github',
106
+ repo: repoResp.full_name,
107
+ private: repoResp.private,
108
+ branch: repoResp.default_branch,
124
109
  },
125
- });
126
- }
110
+ name: siteName,
111
+ },
112
+ });
127
113
  }
128
114
  catch (error_) {
129
- if (error_.status === 422 || error_.message === 'Duplicate repo') {
130
- warn(`${name}.netlify.app already exists or a repository named ${name} already exists on this account. Please try a different slug.`);
131
- // @ts-expect-error TS(2554) FIXME: Expected 1 arguments, but got 0.
132
- await inputSiteName();
133
- }
134
- else {
135
- error(`createSiteInTeam error: ${error_.status}: ${error_.message}`);
115
+ if (error_.status === 422) {
116
+ log(`createSiteInTeam error: ${error_.status}: ${error_.message}`);
117
+ log('Cannot create a site with that name. Site name may already exist. Please try a new name.');
118
+ return inputSiteName(undefined, hasExistingRepo);
136
119
  }
120
+ error(`createSiteInTeam error: ${error_.status}: ${error_.message}`);
137
121
  }
122
+ return [site, repoResp];
138
123
  };
139
- await inputSiteName(nameFlag);
124
+ [site, repoResp] = await inputSiteName(nameFlag);
140
125
  log();
141
126
  log(chalk.greenBright.bold.underline(`Site Created`));
142
127
  log();
143
- // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'.
144
128
  const siteUrl = site.ssl_url || site.url;
145
129
  log(render({
146
- // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'.
147
130
  'Admin URL': site.admin_url,
148
131
  URL: siteUrl,
149
- // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'.
150
132
  'Site ID': site.id,
151
- // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'.
152
133
  'Repo URL': site.build_settings.repo_url,
153
134
  }));
154
135
  track('sites_createdFromTemplate', {
155
- // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'.
156
136
  siteId: site.id,
157
- // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'.
158
137
  adminUrl: site.admin_url,
159
138
  siteUrl,
160
139
  });
161
140
  const { cloneConfirm } = await inquirer.prompt({
162
141
  type: 'confirm',
163
142
  name: 'cloneConfirm',
164
- message: `Do you want to clone the repository?`,
143
+ message: `Do you want to clone the repository to your local machine?`,
165
144
  default: true,
166
145
  });
167
146
  if (cloneConfirm) {
168
147
  log();
169
- // @ts-expect-error TS(18046) - 'repoResp' if of type 'unknown'
170
- await execa('git', ['clone', repoResp.clone_url, `${repoResp.name}`]);
171
- // @ts-expect-error TS(18046) - 'repoResp' if of type 'unknown'
148
+ if (repoResp.clone_url) {
149
+ await execa('git', ['clone', repoResp.clone_url, `${repoResp.name}`]);
150
+ }
172
151
  log(`🚀 Repository cloned successfully. You can find it under the ${chalk.magenta(repoResp.name)} folder`);
152
+ const { linkConfirm } = await inquirer.prompt({
153
+ type: 'confirm',
154
+ name: 'linkConfirm',
155
+ message: `Do you want to link the cloned directory to the site?`,
156
+ default: true,
157
+ });
158
+ if (linkConfirm) {
159
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
160
+ const cliPath = path.resolve(__dirname, '../../../bin/run.js');
161
+ let stdout;
162
+ if (repoResp.name) {
163
+ stdout = await callLinkSite(cliPath, repoResp.name, '\n');
164
+ }
165
+ else {
166
+ error();
167
+ return;
168
+ }
169
+ const linkedSiteUrlRegex = /Site url:\s+(\S+)/;
170
+ const lineMatch = linkedSiteUrlRegex.exec(stdout);
171
+ const urlMatch = lineMatch ? lineMatch[1] : undefined;
172
+ if (urlMatch) {
173
+ log(`\nDirectory ${chalk.cyanBright(repoResp.name)} linked to site ${chalk.cyanBright(urlMatch)}\n`);
174
+ log(`${chalk.cyanBright.bold('cd', repoResp.name)} to use other netlify cli commands in the cloned directory.\n`);
175
+ }
176
+ else {
177
+ const linkedSiteMatch = /Site already linked to\s+(\S+)/.exec(stdout);
178
+ const linkedSiteNameMatch = linkedSiteMatch ? linkedSiteMatch[1] : undefined;
179
+ if (linkedSiteNameMatch) {
180
+ log(`\nThis directory appears to be linked to ${chalk.cyanBright(linkedSiteNameMatch)}`);
181
+ log('This can happen if you cloned the template into a subdirectory of an existing Netlify project.');
182
+ log(`You may need to move the ${chalk.cyanBright(repoResp.name)} directory out of its parent directory and then re-run the ${chalk.cyanBright('link')} command manually\n`);
183
+ }
184
+ else {
185
+ log('A problem occurred linking the site');
186
+ log('You can try again manually by running:');
187
+ log(chalk.cyanBright(`cd ${repoResp.name} && netlify link\n`));
188
+ }
189
+ }
190
+ }
191
+ else {
192
+ log('To link the cloned directory manually, run:');
193
+ log(chalk.cyanBright(`cd ${repoResp.name} && netlify link\n`));
194
+ }
173
195
  }
174
196
  if (options.withCi) {
175
197
  log('Configuring CI');
176
198
  const repoData = await getRepoData({ workingDir: command.workingDir });
177
- // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'.
178
199
  await configureRepo({ command, siteId: site.id, repoData, manual: options.manual });
179
200
  }
180
201
  if (options.json) {
@@ -1 +1 @@
1
- {"version":3,"file":"sites-create.d.ts","sourceRoot":"","sources":["../../../src/commands/sites/sites-create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AASxC,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAI5C,eAAO,MAAM,gBAAgB,SAAgB,MAAM,GAAG,SAAS;UAAmB,MAAM;EAevF,CAAA;AAED,eAAO,MAAM,WAAW,YAAmB,YAAY,WAAW,WAAW,uBAuH5E,CAAA"}
1
+ {"version":3,"file":"sites-create.d.ts","sourceRoot":"","sources":["../../../src/commands/sites/sites-create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAUxC,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAG5C,eAAO,MAAM,gBAAgB,SAAgB,MAAM,GAAG,SAAS;UAAmB,MAAM;EAevF,CAAA;AAED,eAAO,MAAM,WAAW,YAAmB,YAAY,WAAW,WAAW,uBAuH5E,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../../src/commands/sites/sites.ts"],"names":[],"mappings":"AAEA,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAkB5C,eAAO,MAAM,8BAA8B,YAAa,WAAW,SAsBlE,CAAA;AAED,eAAO,MAAM,wBAAwB,YAAa,WAAW,SAoB5D,CAAA;AAED,eAAO,MAAM,kBAAkB,YAAa,WAAW,gBA6BtD,CAAA"}
1
+ {"version":3,"file":"sites.d.ts","sourceRoot":"","sources":["../../../src/commands/sites/sites.ts"],"names":[],"mappings":"AAEA,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAkB5C,eAAO,MAAM,8BAA8B,YAAa,WAAW,SAsBlE,CAAA;AAED,eAAO,MAAM,wBAAwB,YAAa,WAAW,SAoB5D,CAAA;AAED,eAAO,MAAM,kBAAkB,YAAa,WAAW,gBA4BtD,CAAA"}
@@ -63,7 +63,6 @@ export const createSitesCommand = (program) => {
63
63
  .command('sites:delete')
64
64
  .description('Delete a site\nThis command will permanently delete the site on Netlify. Use with caution.')
65
65
  .argument('<siteId>', 'Site ID to delete.')
66
- .option('-f, --force', 'delete without prompting (useful for CI)')
67
66
  .addExamples(['netlify sites:delete 1234-3262-1211'])
68
67
  .action(async (siteId, options, command) => {
69
68
  const { sitesDelete } = await import('./sites-delete.js');