netlify-cli 9.9.2 → 9.11.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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
- "version": "9.9.2",
3
+ "version": "9.11.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "netlify-cli",
9
- "version": "9.9.2",
9
+ "version": "9.11.0",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
@@ -15,7 +15,7 @@
15
15
  "@netlify/framework-info": "^9.0.2",
16
16
  "@netlify/local-functions-proxy": "^1.1.1",
17
17
  "@netlify/plugin-edge-handlers": "^3.0.7",
18
- "@netlify/plugins-list": "^6.14.0",
18
+ "@netlify/plugins-list": "^6.15.0",
19
19
  "@netlify/routing-local-proxy": "^0.34.1",
20
20
  "@netlify/zip-it-and-ship-it": "^5.9.0",
21
21
  "@octokit/rest": "^18.0.0",
@@ -4328,9 +4328,9 @@
4328
4328
  }
4329
4329
  },
4330
4330
  "node_modules/@netlify/plugins-list": {
4331
- "version": "6.14.0",
4332
- "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.14.0.tgz",
4333
- "integrity": "sha512-AOlFh13F5TLLq9uJ+/ahamWYnZAJIo36H55FnWvDlnfFvkp9aIfjHvMv4qL8/Tvc6a5Ulx1NYrL8Fpw6qd5YCw==",
4331
+ "version": "6.15.0",
4332
+ "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.15.0.tgz",
4333
+ "integrity": "sha512-CGvHVRS+IInm+dyn8qEGrADsFiWY/HC8z+taIPQ9d7sZlNr3ShtXHq5fdHVHGH2A9WDVeh8+Xan87196KyE3IQ==",
4334
4334
  "engines": {
4335
4335
  "node": "^12.20.0 || ^14.14.0 || >=16.0.0"
4336
4336
  }
@@ -27317,9 +27317,9 @@
27317
27317
  }
27318
27318
  },
27319
27319
  "@netlify/plugins-list": {
27320
- "version": "6.14.0",
27321
- "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.14.0.tgz",
27322
- "integrity": "sha512-AOlFh13F5TLLq9uJ+/ahamWYnZAJIo36H55FnWvDlnfFvkp9aIfjHvMv4qL8/Tvc6a5Ulx1NYrL8Fpw6qd5YCw=="
27320
+ "version": "6.15.0",
27321
+ "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.15.0.tgz",
27322
+ "integrity": "sha512-CGvHVRS+IInm+dyn8qEGrADsFiWY/HC8z+taIPQ9d7sZlNr3ShtXHq5fdHVHGH2A9WDVeh8+Xan87196KyE3IQ=="
27323
27323
  },
27324
27324
  "@netlify/routing-local-proxy": {
27325
27325
  "version": "0.34.1",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "9.9.2",
4
+ "version": "9.11.0",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
@@ -205,7 +205,7 @@
205
205
  "@netlify/framework-info": "^9.0.2",
206
206
  "@netlify/local-functions-proxy": "^1.1.1",
207
207
  "@netlify/plugin-edge-handlers": "^3.0.7",
208
- "@netlify/plugins-list": "^6.14.0",
208
+ "@netlify/plugins-list": "^6.15.0",
209
209
  "@netlify/routing-local-proxy": "^0.34.1",
210
210
  "@netlify/zip-it-and-ship-it": "^5.9.0",
211
211
  "@octokit/rest": "^18.0.0",
@@ -302,6 +302,7 @@ const runDeploy = async ({
302
302
  }) => {
303
303
  let results
304
304
  let deployId
305
+
305
306
  try {
306
307
  if (deployToProduction) {
307
308
  await prepareProductionDeploy({ siteData, api })
@@ -462,10 +463,26 @@ const deploy = async (options, command) => {
462
463
  await command.authenticate(options.auth)
463
464
 
464
465
  let siteId = options.site || site.id
466
+
465
467
  let siteData = {}
466
468
  if (siteId) {
467
469
  try {
468
- siteData = await api.getSite({ siteId })
470
+ const [{ siteError, siteFoundById }, sites] = await Promise.all([
471
+ api
472
+ .getSite({ siteId })
473
+ .then((data) => ({ siteFoundById: data }))
474
+ .catch((error_) => ({ siteError: error_ })),
475
+ api.listSites({ name: options.site, filter: 'all' }),
476
+ ])
477
+ const siteFoundByName = sites.find((filteredSite) => filteredSite.name === options.site)
478
+ if (siteFoundById) {
479
+ siteData = siteFoundById
480
+ } else if (siteFoundByName) {
481
+ siteData = siteFoundByName
482
+ siteId = siteFoundByName.id
483
+ } else {
484
+ throw siteError
485
+ }
469
486
  } catch (error_) {
470
487
  // TODO specifically handle known cases (e.g. no account access)
471
488
  if (error_.status === 404) {
@@ -674,7 +691,7 @@ Support for package.json's main field, and intrinsic index.js entrypoints are co
674
691
  .option('-o, --open', 'Open site after deploy', false)
675
692
  .option('-m, --message <message>', 'A short message to include in the deploy log')
676
693
  .option('-a, --auth <token>', 'Netlify auth token to deploy with', env.NETLIFY_AUTH_TOKEN)
677
- .option('-s, --site <id>', 'A site ID to deploy to', env.NETLIFY_SITE_ID)
694
+ .option('-s, --site <name-or-id>', 'A site name or ID to deploy to', env.NETLIFY_SITE_ID)
678
695
  .option('--json', 'Output deployment data as JSON')
679
696
  .option('--timeout <number>', 'Timeout to wait for deployment to finish', (value) => Number.parseInt(value))
680
697
  .option('--trigger', 'Trigger a new build of your site on Netlify without uploading local files')
@@ -687,6 +704,7 @@ Support for package.json's main field, and intrinsic index.js entrypoints are co
687
704
  )
688
705
  .addExamples([
689
706
  'netlify deploy',
707
+ 'netlify deploy --site my-first-site',
690
708
  'netlify deploy --prod',
691
709
  'netlify deploy --prod --open',
692
710
  'netlify deploy --prodIfUnlocked',
@@ -2,12 +2,14 @@
2
2
 
3
3
  const inquirer = require('inquirer')
4
4
  const pick = require('lodash/pick')
5
+ const parseGitHubUrl = require('parse-github-url')
5
6
  const prettyjson = require('prettyjson')
7
+ const terminalLink = require('terminal-link')
6
8
 
7
9
  const { chalk, error, getRepoData, log, logJson, track, warn } = require('../../utils')
8
10
  const { configureRepo } = require('../../utils/init/config')
9
11
  const { getGitHubToken } = require('../../utils/init/config-github')
10
- const { createRepo, getTemplatesFromGitHub } = require('../../utils/sites/utils')
12
+ const { createRepo, getTemplatesFromGitHub, validateTemplate } = require('../../utils/sites/utils')
11
13
 
12
14
  const { getSiteNameInput } = require('./sites-create')
13
15
 
@@ -23,12 +25,45 @@ const fetchTemplates = async (token) => {
23
25
  }))
24
26
  }
25
27
 
28
+ const getTemplateName = async ({ ghToken, options, repository }) => {
29
+ if (repository) {
30
+ const { repo } = parseGitHubUrl(repository)
31
+ return repo || `netlify-templates/${repository}`
32
+ }
33
+
34
+ if (options.url) {
35
+ const urlFromOptions = new URL(options.url)
36
+ return urlFromOptions.pathname.slice(1)
37
+ }
38
+
39
+ const templates = await fetchTemplates(ghToken)
40
+
41
+ log(`Choose one of our starter templates. Netlify will create a new repo for this template in your GitHub account.`)
42
+
43
+ const { templateName } = await inquirer.prompt([
44
+ {
45
+ type: 'list',
46
+ name: 'templateName',
47
+ message: 'Template:',
48
+ choices: templates.map((template) => ({
49
+ value: template.slug,
50
+ name: template.name,
51
+ })),
52
+ },
53
+ ])
54
+
55
+ return templateName
56
+ }
57
+
58
+ const getGitHubLink = ({ options, templateName }) => options.url || `https://github.com/${templateName}`
59
+
26
60
  /**
27
61
  * The sites:create-template command
62
+ * @param repository {string}
28
63
  * @param {import('commander').OptionValues} options
29
64
  * @param {import('../base-command').BaseCommand} command
30
65
  */
31
- const sitesCreateTemplate = async (options, command) => {
66
+ const sitesCreateTemplate = async (repository, options, command) => {
32
67
  const { api } = command.netlify
33
68
 
34
69
  await command.authenticate()
@@ -36,27 +71,22 @@ const sitesCreateTemplate = async (options, command) => {
36
71
  const { globalConfig } = command.netlify
37
72
  const ghToken = await getGitHubToken({ globalConfig })
38
73
 
39
- let { url: templateUrl } = options
40
-
41
- if (templateUrl) {
42
- const urlFromOptions = new URL(templateUrl)
43
- templateUrl = { templateName: urlFromOptions.pathname.slice(1) }
44
- } else {
45
- const templates = await fetchTemplates(ghToken)
46
-
47
- log(`Choose one of our starter templates. Netlify will create a new repo for this template in your GitHub account.`)
48
-
49
- templateUrl = await inquirer.prompt([
50
- {
51
- type: 'list',
52
- name: 'templateName',
53
- message: 'Template:',
54
- choices: templates.map((template) => ({
55
- value: template.slug,
56
- name: template.name,
57
- })),
58
- },
59
- ])
74
+ const templateName = await getTemplateName({ ghToken, options, repository })
75
+ const { exists, isTemplate } = await validateTemplate({ templateName, ghToken })
76
+ if (!exists) {
77
+ const githubLink = getGitHubLink({ options, templateName })
78
+ error(
79
+ `Could not find template ${chalk.bold(templateName)}. Please verify it exists and you can ${terminalLink(
80
+ 'access to it on GitHub',
81
+ githubLink,
82
+ )}`,
83
+ )
84
+ return
85
+ }
86
+ if (!isTemplate) {
87
+ const githubLink = getGitHubLink({ options, templateName })
88
+ error(`${terminalLink(chalk.bold(templateName), githubLink)} is not a valid GitHub template`)
89
+ return
60
90
  }
61
91
 
62
92
  const accounts = await api.listAccountsForUser()
@@ -90,12 +120,12 @@ const sitesCreateTemplate = async (options, command) => {
90
120
  const siteName = inputName ? inputName.trim() : siteSuggestion
91
121
 
92
122
  // Create new repo from template
93
- const repoResp = await createRepo(templateUrl, ghToken, siteName)
123
+ const repoResp = await createRepo(templateName, ghToken, siteName)
94
124
 
95
125
  if (repoResp.errors) {
96
126
  if (repoResp.errors[0].includes('Name already exists on this account')) {
97
127
  warn(
98
- `Oh no! We found already a repository with this name. It seems you have already created a template with the name ${templateUrl.templateName}. Please try to run the command again and provide a different name.`,
128
+ `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.`,
99
129
  )
100
130
  await inputSiteName()
101
131
  } else {
@@ -206,7 +236,13 @@ Create a site from a starter template.`,
206
236
  .option('-u, --url [url]', 'template url')
207
237
  .option('-a, --account-slug [slug]', 'account slug to create the site under')
208
238
  .option('-c, --with-ci', 'initialize CI hooks during site creation')
239
+ .argument('[repository]', 'repository to use as starter template')
209
240
  .addHelpText('after', `(Beta) Create a site from starter template.`)
241
+ .addExamples([
242
+ 'netlify sites:create-template',
243
+ 'netlify sites:create-template nextjs-blog-theme',
244
+ 'netlify sites:create-template my-github-profile/my-template',
245
+ ])
210
246
  .action(sitesCreateTemplate)
211
247
 
212
248
  module.exports = { createSitesFromTemplateCommand, fetchTemplates }
package/src/lib/build.js CHANGED
@@ -18,11 +18,12 @@ const netlifyBuildPromise = import('@netlify/build')
18
18
  * @param {import('commander').OptionValues} config.options
19
19
  * @returns {BuildConfig}
20
20
  */
21
- const getBuildOptions = ({ cachedConfig, options: { debug, dry, json, offline, silent }, token }) => ({
21
+ const getBuildOptions = ({ cachedConfig, options: { context, debug, dry, json, offline, silent }, token }) => ({
22
22
  cachedConfig,
23
23
  token,
24
24
  dry,
25
25
  debug,
26
+ context,
26
27
  mode: 'cli',
27
28
  telemetry: false,
28
29
  // buffer = true will not stream output
@@ -120,7 +120,8 @@ const createHandler = function (options) {
120
120
  if (func.isBackground) {
121
121
  handleBackgroundFunction(functionName, response)
122
122
 
123
- const { error } = await func.invoke(event, clientContext)
123
+ // background functions do not receive a clientContext
124
+ const { error } = await func.invoke(event)
124
125
 
125
126
  handleBackgroundFunctionResult(functionName, error)
126
127
  } else if (await func.isScheduled()) {
@@ -12,8 +12,27 @@ const getTemplatesFromGitHub = async (token) => {
12
12
  return allTemplates
13
13
  }
14
14
 
15
- const createRepo = async (templateUrl, ghToken, siteName) => {
16
- const resp = await fetch(`https://api.github.com/repos/${templateUrl.templateName}/generate`, {
15
+ const validateTemplate = async ({ ghToken, templateName }) => {
16
+ const response = await fetch(`https://api.github.com/repos/${templateName}`, {
17
+ headers: {
18
+ Authorization: `token ${ghToken}`,
19
+ },
20
+ })
21
+
22
+ if (response.status === 404) {
23
+ return { exists: false }
24
+ }
25
+
26
+ if (!response.ok) {
27
+ throw new Error(`Error fetching template ${templateName}: ${await response.text()}`)
28
+ }
29
+
30
+ const data = await response.json()
31
+ return { exists: true, isTemplate: data.is_template }
32
+ }
33
+
34
+ const createRepo = async (templateName, ghToken, siteName) => {
35
+ const resp = await fetch(`https://api.github.com/repos/${templateName}/generate`, {
17
36
  method: 'POST',
18
37
  headers: {
19
38
  Authorization: `token ${ghToken}`,
@@ -27,4 +46,4 @@ const createRepo = async (templateUrl, ghToken, siteName) => {
27
46
  return data
28
47
  }
29
48
 
30
- module.exports = { getTemplatesFromGitHub, createRepo }
49
+ module.exports = { getTemplatesFromGitHub, createRepo, validateTemplate }