netlify-cli 16.9.1 → 16.9.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "16.9.1",
4
+ "version": "16.9.3",
5
5
  "author": "Netlify Inc.",
6
6
  "type": "module",
7
7
  "engines": {
@@ -47,10 +47,8 @@
47
47
  "@netlify/build": "29.23.4",
48
48
  "@netlify/build-info": "7.10.1",
49
49
  "@netlify/config": "20.9.0",
50
- "@netlify/edge-bundler": "9.3.0",
50
+ "@netlify/edge-bundler": "9.4.1",
51
51
  "@netlify/local-functions-proxy": "1.1.1",
52
- "@netlify/sdk": "^1.1.5",
53
- "@netlify/serverless-functions-api": "1.10.0",
54
52
  "@netlify/zip-it-and-ship-it": "9.25.4",
55
53
  "@octokit/rest": "19.0.13",
56
54
  "ansi-escapes": "6.2.0",
@@ -149,7 +147,7 @@
149
147
  "update-notifier": "6.0.2",
150
148
  "uuid": "9.0.0",
151
149
  "wait-port": "1.0.4",
152
- "winston": "3.8.2",
153
- "write-file-atomic": "5.0.1"
150
+ "write-file-atomic": "5.0.1",
151
+ "zod": "^3.22.4"
154
152
  }
155
153
  }
@@ -74,7 +74,7 @@ const build = async (options, command) => {
74
74
  export const createBuildCommand = (program) =>
75
75
  program
76
76
  .command('build')
77
- .description('(Beta) Build on your local machine')
77
+ .description('Build on your local machine')
78
78
  .option(
79
79
  '--context <context>',
80
80
  'Specify a build context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
@@ -50,7 +50,7 @@ export const createCompletionCommand = (program) => {
50
50
 
51
51
  return program
52
52
  .command('completion')
53
- .description('(Beta) Generate shell completion script\nRun this command to see instructions for your shell.')
53
+ .description('Generate shell completion script\nRun this command to see instructions for your shell.')
54
54
  .addExamples(['netlify completion:install'])
55
55
  .action((options, command) => {
56
56
  command.help()
@@ -1,14 +1,11 @@
1
- /* eslint-disable import/extensions */
1
+ import fs from 'fs'
2
2
  import { resolve } from 'path'
3
3
  import { exit, env } from 'process'
4
4
 
5
- // eslint-disable-next-line n/no-missing-import
6
- import { getConfiguration } from '@netlify/sdk/cli-utils'
7
- // eslint-disable-next-line n/no-unpublished-import
8
- import fs from 'fs-extra'
9
5
  import inquirer from 'inquirer'
10
6
  import yaml from 'js-yaml'
11
7
  import fetch from 'node-fetch'
8
+ import { z } from 'zod'
12
9
 
13
10
  import { getBuildOptions } from '../../lib/build.mjs'
14
11
  import { getToken, chalk, log } from '../../utils/command-helpers.mjs'
@@ -176,7 +173,7 @@ export async function registerIntegration(workingDir, siteId, accountId, localIn
176
173
  })
177
174
 
178
175
  const filePath = resolve(workingDir, 'integration.yaml')
179
- await fs.writeFile(filePath, updatedIntegrationConfig)
176
+ await fs.promises.writeFile(filePath, updatedIntegrationConfig)
180
177
 
181
178
  log(chalk.yellow('Your integration.yaml file has been updated. Please commit and push these changes.'))
182
179
  }
@@ -304,12 +301,66 @@ export async function updateIntegration(
304
301
  })
305
302
 
306
303
  const filePath = resolve(workingDir, 'integration.yaml')
307
- await fs.writeFile(filePath, updatedIntegrationConfig)
304
+ await fs.promises.writeFile(filePath, updatedIntegrationConfig)
308
305
 
309
306
  log(chalk.yellow('Changes to the integration.yaml file are complete. Please commit and push these changes.'))
310
307
  }
311
308
  }
312
309
 
310
+ const possibleFiles = ['integration.yaml', 'integration.yml', 'integration.netlify.yaml', 'integration.netlify.yml']
311
+ const IntegrationConfigurationSchema = z.object({
312
+ name: z.string().optional(),
313
+ description: z.string().optional(),
314
+ slug: z.string().regex(/^[a-z\d-]+$/, 'slug must be lowercase with dashes'),
315
+ scopes: z
316
+ .object({
317
+ all: z.boolean().optional(),
318
+ site: z.array(z.enum(['read', 'write'])).optional(),
319
+ env: z.array(z.enum(['read', 'write', 'delete'])).optional(),
320
+ user: z.array(z.enum(['read', 'write'])).optional(),
321
+ })
322
+ .optional(),
323
+ integrationLevel: z.enum(['site', 'team', 'team-and-site']).optional(),
324
+ })
325
+
326
+ const getConfigurationFile = (workingDir) => {
327
+ const pwd = workingDir
328
+
329
+ const fileName = possibleFiles.find((configFileName) => fs.existsSync(resolve(pwd, configFileName)))
330
+
331
+ return fileName
332
+ }
333
+
334
+ export const getConfiguration = (workingDir) => {
335
+ const pwd = workingDir
336
+
337
+ const fileName = getConfigurationFile(workingDir)
338
+
339
+ if (!fileName) {
340
+ throw new Error('No configuration file found')
341
+ }
342
+
343
+ try {
344
+ const { config } = yaml.load(fs.readFileSync(resolve(pwd, fileName), 'utf-8'))
345
+
346
+ if (!config) {
347
+ throw new Error('No configuration found')
348
+ }
349
+
350
+ const parseResult = IntegrationConfigurationSchema.safeParse(config)
351
+
352
+ if (!parseResult.success) {
353
+ console.error(parseResult.error.message)
354
+ throw new Error('Invalid Configuration')
355
+ }
356
+
357
+ return config
358
+ } catch (error) {
359
+ console.error(error)
360
+ console.error(`No configuration found in ${fileName} in ${pwd}`)
361
+ exit(1)
362
+ }
363
+ }
313
364
  /**
314
365
  * The deploy command for Netlify Integrations
315
366
  * @param {import('commander').OptionValues} options
@@ -330,7 +381,7 @@ const deploy = async (options, command) => {
330
381
  // Confirm that a site is linked and that the user is logged in
331
382
  checkOptions(buildOptions)
332
383
 
333
- const { description, integrationLevel, name, scopes, slug } = await getConfiguration()
384
+ const { description, integrationLevel, name, scopes, slug } = await getConfiguration(command.workingDir)
334
385
  const localIntegrationConfig = { name, description, scopes, slug, integrationLevel }
335
386
 
336
387
  const { accountId } = await getSiteInformation({
@@ -394,4 +445,3 @@ export const createDeployCommand = (program) =>
394
445
  .option('-a, --auth <token>', 'Netlify auth token to deploy with', env.NETLIFY_AUTH_TOKEN)
395
446
  .option('-s, --site <name-or-id>', 'A site name or ID to deploy to', env.NETLIFY_SITE_ID)
396
447
  .action(deploy)
397
- /* eslint-enable import/extensions */
@@ -27,6 +27,6 @@ const recipesListCommand = async () => {
27
27
  export const createRecipesListCommand = (program) =>
28
28
  program
29
29
  .command('recipes:list')
30
- .description(`(Beta) List the recipes available to create and modify files in a project`)
30
+ .description(`List the recipes available to create and modify files in a project`)
31
31
  .addExamples(['netlify recipes:list'])
32
32
  .action(recipesListCommand)
@@ -81,7 +81,7 @@ export const createRecipesCommand = (program) => {
81
81
  program
82
82
  .command('recipes')
83
83
  .argument('[name]', 'name of the recipe')
84
- .description(`(Beta) Create and modify files in a project using pre-defined recipes`)
84
+ .description(`Create and modify files in a project using pre-defined recipes`)
85
85
  .option('-n, --name <name>', 'recipe name to use')
86
86
  .addExamples(['netlify recipes my-recipe', 'netlify recipes --name my-recipe'])
87
87
  .action(recipesCommand)
@@ -167,7 +167,7 @@ export const createServeCommand = (program) =>
167
167
  program
168
168
  .command('serve')
169
169
  .description(
170
- '(Beta) Build the site for production and serve locally. This does not watch the code for changes, so if you need to rebuild your site then you must exit and run `serve` again.',
170
+ 'Build the site for production and serve locally. This does not watch the code for changes, so if you need to rebuild your site then you must exit and run `serve` again.',
171
171
  )
172
172
  .option(
173
173
  '--context <context>',
@@ -28,7 +28,7 @@ export const deploySite = async (
28
28
  concurrentHash = DEFAULT_CONCURRENT_HASH,
29
29
  concurrentUpload = DEFAULT_CONCURRENT_UPLOAD,
30
30
  configPath = null,
31
- deployId: deployIdOpt = null,
31
+ deployId,
32
32
  deployTimeout = DEFAULT_DEPLOY_TIMEOUT,
33
33
  draft = false,
34
34
  filter,
@@ -37,8 +37,6 @@ export const deploySite = async (
37
37
  hashAlgorithm,
38
38
  manifestPath,
39
39
  maxRetry = DEFAULT_MAX_RETRY,
40
- // API calls this the 'title'
41
- message: title,
42
40
  siteEnv,
43
41
  siteRoot,
44
42
  skipFunctionsCache,
@@ -120,9 +118,9 @@ For more information, visit https://ntl.fyi/cli-native-modules.`)
120
118
  phase: 'start',
121
119
  })
122
120
 
123
- let deploy
124
- let deployParams = cleanDeep({
121
+ const deployParams = cleanDeep({
125
122
  siteId,
123
+ deploy_id: deployId,
126
124
  body: {
127
125
  files,
128
126
  functions,
@@ -133,19 +131,11 @@ For more information, visit https://ntl.fyi/cli-native-modules.`)
133
131
  draft,
134
132
  },
135
133
  })
136
- if (deployIdOpt === null) {
137
- if (title) {
138
- deployParams = { ...deployParams, title }
139
- }
140
- deploy = await api.createSiteDeploy(deployParams)
141
- } else {
142
- deployParams = { ...deployParams, deploy_id: deployIdOpt }
143
- deploy = await api.updateSiteDeploy(deployParams)
144
- }
134
+ let deploy = await api.updateSiteDeploy(deployParams)
145
135
 
146
136
  if (deployParams.body.async) deploy = await waitForDiff(api, deploy.id, siteId, deployTimeout)
147
137
 
148
- const { id: deployId, required: requiredFiles, required_functions: requiredFns } = deploy
138
+ const { required: requiredFiles, required_functions: requiredFns } = deploy
149
139
 
150
140
  statusCb({
151
141
  type: 'create-deploy',