From 9a884938127a73f13046fd521c2743ee935de716 Mon Sep 17 00:00:00 2001
From: Sarah Etter
Date: Fri, 20 Dec 2024 15:23:25 -0500
Subject: [PATCH] feat!: remove addons subcommand (#6974)
---
.gitignore | 2 -
docs/commands/addons.md | 147 ----------------
site/src/_app.js | 2 -
site/src/register-addon-thanks.md | 9 -
site/src/register-addon.md | 96 -----------
src/commands/addons/addons-auth.ts | 28 ---
src/commands/addons/addons-config.ts | 159 ------------------
src/commands/addons/addons-create.ts | 105 ------------
src/commands/addons/addons-delete.ts | 36 ----
src/commands/addons/addons-list.ts | 42 -----
src/commands/addons/addons.ts | 81 ---------
src/commands/addons/index.ts | 1 -
src/commands/main.ts | 3 -
src/utils/addons/prepare.ts | 93 +---------
src/utils/addons/render.ts | 41 -----
.../commands/addons/addons.test.js | 158 -----------------
16 files changed, 1 insertion(+), 1002 deletions(-)
delete mode 100644 docs/commands/addons.md
delete mode 100644 site/src/register-addon-thanks.md
delete mode 100644 site/src/register-addon.md
delete mode 100644 src/commands/addons/addons-auth.ts
delete mode 100644 src/commands/addons/addons-config.ts
delete mode 100644 src/commands/addons/addons-create.ts
delete mode 100644 src/commands/addons/addons-delete.ts
delete mode 100644 src/commands/addons/addons-list.ts
delete mode 100644 src/commands/addons/addons.ts
delete mode 100644 src/commands/addons/index.ts
delete mode 100644 src/utils/addons/render.ts
delete mode 100644 tests/integration/commands/addons/addons.test.js
diff --git a/.gitignore b/.gitignore
index 2be24777c50..fc6de3a7e59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,8 +26,6 @@ test-site
site/dist
site-cra
site/src/**/*.md
-!site/src/register-addon.md
-!site/src/register-addon-thanks.md
# tests
.verdaccio-storage
diff --git a/docs/commands/addons.md b/docs/commands/addons.md
deleted file mode 100644
index f0f79e48305..00000000000
--- a/docs/commands/addons.md
+++ /dev/null
@@ -1,147 +0,0 @@
----
-title: Netlify CLI addons command
----
-
-# `addons`
-
-The addons command will manage Netlify addons.
-
-For more information on add-ons see our [Netlify partner add-ons docs](https://docs.netlify.com/integrations/partner-add-ons/get-started/)
-
-## About
-
-> ⚠️ The addons command is [deprecated](https://docs.netlify.com/platform/release-phases/#deprecated) and will become unavailable in a future update.
-
-**Usage**
-
-```bash
-netlify addons
-```
-
-**Flags**
-
-- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
-- `debug` (*boolean*) - Print debugging information
-
-| Subcommand | description |
-|:--------------------------- |:-----|
-| [`addons:auth`](/docs/commands/addons.md#addonsauth) | Login to add-on provider |
-| [`addons:config`](/docs/commands/addons.md#addonsconfig) | Configure add-on settings |
-| [`addons:create`](/docs/commands/addons.md#addonscreate) | Add an add-on extension to your site |
-| [`addons:delete`](/docs/commands/addons.md#addonsdelete) | Remove an add-on extension to your site |
-| [`addons:list`](/docs/commands/addons.md#addonslist) | List currently installed add-ons for site |
-
-
-**Examples**
-
-```bash
-netlify addons:create addon-xyz
-netlify addons:list
-netlify addons:config addon-xyz
-netlify addons:delete addon-xyz
-netlify addons:auth addon-xyz
-```
-
----
-## `addons:auth`
-
-Login to add-on provider
-
-**Usage**
-
-```bash
-netlify addons:auth
-```
-
-**Arguments**
-
-- name - Add-on slug
-
-**Flags**
-
-- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
-- `debug` (*boolean*) - Print debugging information
-
----
-## `addons:config`
-
-Configure add-on settings
-
-**Usage**
-
-```bash
-netlify addons:config
-```
-
-**Arguments**
-
-- name - Add-on namespace
-
-**Flags**
-
-- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
-- `debug` (*boolean*) - Print debugging information
-
----
-## `addons:create`
-
-Add an add-on extension to your site
-Add-ons are a way to extend the functionality of your Netlify site
-
-**Usage**
-
-```bash
-netlify addons:create
-```
-
-**Arguments**
-
-- name - Add-on namespace
-
-**Flags**
-
-- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
-- `debug` (*boolean*) - Print debugging information
-
----
-## `addons:delete`
-
-Remove an add-on extension to your site
-Add-ons are a way to extend the functionality of your Netlify site
-
-**Usage**
-
-```bash
-netlify addons:delete
-```
-
-**Arguments**
-
-- name - Add-on namespace
-
-**Flags**
-
-- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
-- `force` (*boolean*) - delete without prompting (useful for CI)
-- `debug` (*boolean*) - Print debugging information
-
----
-## `addons:list`
-
-List currently installed add-ons for site
-
-**Usage**
-
-```bash
-netlify addons:list
-```
-
-**Flags**
-
-- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
-- `json` (*boolean*) - Output add-on data as JSON
-- `debug` (*boolean*) - Print debugging information
-
----
-
-
diff --git a/site/src/_app.js b/site/src/_app.js
index 372a315f976..ea39201c6e8 100644
--- a/site/src/_app.js
+++ b/site/src/_app.js
@@ -37,7 +37,6 @@ const navOrder = [
'index',
'getting-started',
'commands',
- 'addons',
'api',
'blobs',
'build',
@@ -65,7 +64,6 @@ const navOrder = [
const pageNames = {
index: 'CLI Reference',
'getting-started': 'Getting Started',
- addons: 'addons (deprecated)',
}
const sortRoutes = (routes) =>
diff --git a/site/src/register-addon-thanks.md b/site/src/register-addon-thanks.md
deleted file mode 100644
index 970dffe59d4..00000000000
--- a/site/src/register-addon-thanks.md
+++ /dev/null
@@ -1,9 +0,0 @@
----
-title: Thanks for the Addon Request!
-hidden: true
-hidePagination: true
----
-
-# Thanks for reaching out!
-
-We will get back with you shortly about your Netlify addon request.
diff --git a/site/src/register-addon.md b/site/src/register-addon.md
deleted file mode 100644
index 703964fff7a..00000000000
--- a/site/src/register-addon.md
+++ /dev/null
@@ -1,96 +0,0 @@
----
-title: Register a new Netlify Addon
-description: Netlify Command line interface (CLI) documentation
-hidden: true
-hidePagination: true
----
-
-# Netlify addons
-
-> ⚠️ The addons command is [deprecated](https://docs.netlify.com/platform/release-phases/#deprecated) and will become unavailable in a future update.
-
-A Netlify addon is a way for Netlify users to extend their sites.
-
-For example a user can provision additional functionality on their site by running:
-
-```bash
-netlify addons:create your-addon-namespace
-```
-
-This would create a new instance of `your-addon-namespace` for that Netlify Site.
-
-**Some example of Netlify addons:**
-
-- Automatically inject error tracking into your app
-- Provision a new database
-- Setup `env` variables in Netlify's build context for users Automatically
-- ...sky is the limit
-
-## Register Addon
-
-Do you have an addon idea that you'd like to create? Let us know
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/commands/addons/addons-auth.ts b/src/commands/addons/addons-auth.ts
deleted file mode 100644
index 7bd89e2d261..00000000000
--- a/src/commands/addons/addons-auth.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { OptionValues } from 'commander'
-
-import { ADDON_VALIDATION, prepareAddonCommand } from '../../utils/addons/prepare.js'
-import { exit, log } from '../../utils/command-helpers.js'
-import openBrowser from '../../utils/open-browser.js'
-import BaseCommand from '../base-command.js'
-
-export const addonsAuth = async (addonName: string, options: OptionValues, command: BaseCommand) => {
- const { addon } = await prepareAddonCommand({
- command,
- addonName,
- validation: ADDON_VALIDATION.EXISTS,
- })
-
- if (!addon.auth_url) {
- log(`No Admin URL found for the "${addonName} add-on"`)
- return false
- }
-
- log()
- log(`Opening ${addonName} add-on admin URL:`)
- log()
- log(addon.auth_url)
- log()
- // @ts-expect-error TS(2345) FIXME: Argument of type '{ url: any; }' is not assignable... Remove this comment to see the full error message
- await openBrowser({ url: addon.auth_url })
- exit()
-}
diff --git a/src/commands/addons/addons-config.ts b/src/commands/addons/addons-config.ts
deleted file mode 100644
index 2d2698b0224..00000000000
--- a/src/commands/addons/addons-config.ts
+++ /dev/null
@@ -1,159 +0,0 @@
-import { OptionValues } from 'commander'
-import inquirer from 'inquirer'
-import isEmpty from 'lodash/isEmpty.js'
-
-import compare from '../../utils/addons/compare.js'
-import diffValues from '../../utils/addons/diffs/index.js'
-import { ADDON_VALIDATION, prepareAddonCommand } from '../../utils/addons/prepare.js'
-import generatePrompts from '../../utils/addons/prompts.js'
-import { renderConfigValues } from '../../utils/addons/render.js'
-import { missingConfigValues, requiredConfigValues, updateConfigValues } from '../../utils/addons/validation.js'
-import { chalk, error, log, APIError } from '../../utils/command-helpers.js'
-import { parseRawFlags } from '../../utils/parse-raw-flags.js'
-import BaseCommand from '../base-command.js'
-
-// @ts-expect-error TS(7031) FIXME: Binding element 'addonName' implicitly has an 'any... Remove this comment to see the full error message
-const update = async function ({ addonName, api, currentConfig, instanceId, newConfig, siteId }) {
- const codeDiff = diffValues(currentConfig, newConfig)
- if (!codeDiff) {
- log('No changes, exiting early')
- return false
- }
- log()
- const msg = `Updating ${addonName} add-on config values...`
- log(`${chalk.white.bold(msg)}`)
- log()
- log(`${codeDiff}\n`)
- log()
-
- try {
- await api.updateServiceInstance({
- siteId,
- addon: addonName,
- instanceId,
- body: { config: newConfig },
- })
- log(`Add-on "${addonName}" successfully updated`)
- } catch (error_) {
- error((error_ as APIError).message)
- }
-}
-
-export const addonsConfig = async (addonName: string, options: OptionValues, command: BaseCommand) => {
- const { addon, manifest, siteData } = await prepareAddonCommand({
- command,
- addonName,
- validation: ADDON_VALIDATION.EXISTS,
- })
-
- const { api, site } = command.netlify
- const siteId = site.id
-
- const hasConfig = !isEmpty(manifest.config)
- // Parse flags
- const rawFlags = parseRawFlags(command.args)
- // Get Existing Config
- const currentConfig = addon.config || {}
-
- const words = `Current "${addonName} add-on" Settings:`
- log(` ${chalk.yellowBright.bold(words)}`)
- if (hasConfig) {
- if (!rawFlags.silent) {
- renderConfigValues(addonName, manifest.config, currentConfig)
- }
- } else {
- // For addons without manifest. TODO remove once we enforce manifests
- Object.keys(currentConfig).forEach((key) => {
- log(`${key} - ${currentConfig[key]}`)
- })
- }
-
- if (hasConfig) {
- const required = requiredConfigValues(manifest.config)
- const missingValues = missingConfigValues(required, rawFlags)
-
- /* Config set by command line flags */
- if (rawFlags && missingValues.length === 0) {
- const newConfig = updateConfigValues(manifest.config, currentConfig, rawFlags)
-
- await update({
- addonName,
- currentConfig,
- newConfig,
- siteId,
- instanceId: addon.id,
- api,
- })
- return false
- }
-
- const updatePrompt = await inquirer.prompt([
- {
- type: 'confirm',
- name: 'updateNow',
- message: `Do you want to update config values?`,
- default: false,
- },
- ])
- if (!updatePrompt.updateNow) {
- log('Sounds good! Exiting configuration...')
- return false
- }
- log()
- log(` - Hit ${chalk.white.bold('enter')} to keep the existing value in (parentheses)`)
- log(` - Hit ${chalk.white.bold('down arrow')} to remove the value`)
- log(` - Hit ${chalk.white.bold('ctrl + C')} to cancel & exit configuration`)
- log()
- log(` You will need to verify the changed before we push them to your live site!`)
- log()
- const prompts = generatePrompts({
- config: manifest.config,
- configValues: currentConfig,
- })
- const userInput = await inquirer.prompt(prompts)
- // Merge user input with the flags specified
- const newConfig = updateConfigValues(manifest.config, currentConfig, userInput)
-
- const diffs = compare(currentConfig, newConfig)
- // log('compare', diffs)
- // @ts-expect-error TS(2339) FIXME: Property 'isEqual' does not exist on type 'string'... Remove this comment to see the full error message
- if (diffs.isEqual) {
- log(`No changes. exiting early`)
- return false
- }
- log()
- log(`${chalk.yellowBright.bold.underline('Confirm your updates:')}`)
- log()
- // @ts-expect-error TS(2339) FIXME: Property 'keys' does not exist on type 'string'.
- diffs.keys.forEach((key) => {
- // @ts-expect-error TS(2339) FIXME: Property 'diffs' does not exist on type 'string'.
- const { newValue, oldValue } = diffs.diffs[key]
- const oldVal = oldValue || 'NO VALUE'
- log(`${chalk.cyan(key)} changed from ${chalk.whiteBright(oldVal)} to ${chalk.green(newValue)}`)
- })
- log()
-
- const confirmPrompt = await inquirer.prompt([
- {
- type: 'confirm',
- name: 'confirmChange',
- message: `Do you want to publish the updated "${addonName} add-on" settings for ${chalk.cyan(siteData.name)}?`,
- default: false,
- },
- ])
-
- if (!confirmPrompt.confirmChange) {
- log('Canceling changes... You are good to go!')
- return false
- }
-
- await update({
- addonName,
- currentConfig,
- newConfig,
- siteId,
- instanceId: addon.id,
- api,
- })
- }
-}
diff --git a/src/commands/addons/addons-create.ts b/src/commands/addons/addons-create.ts
deleted file mode 100644
index 4453f87edba..00000000000
--- a/src/commands/addons/addons-create.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-import { OptionValues } from 'commander'
-import inquirer from 'inquirer'
-import isEmpty from 'lodash/isEmpty.js'
-
-import { ADDON_VALIDATION, prepareAddonCommand } from '../../utils/addons/prepare.js'
-import generatePrompts from '../../utils/addons/prompts.js'
-import { renderConfigValues, renderMissingValues } from '../../utils/addons/render.js'
-import { missingConfigValues, requiredConfigValues, updateConfigValues } from '../../utils/addons/validation.js'
-import { chalk, error, log, APIError } from '../../utils/command-helpers.js'
-import { parseRawFlags } from '../../utils/parse-raw-flags.js'
-import BaseCommand from '../base-command.js'
-// @ts-expect-error TS(7031) FIXME: Binding element 'addonName' implicitly has an 'any... Remove this comment to see the full error message
-const createAddon = async ({ addonName, api, config, siteData, siteId }) => {
- try {
- const response = await api.createServiceInstance({
- siteId,
- addon: addonName,
- body: { config },
- })
- log(`Add-on "${addonName}" created for ${siteData.name}`)
- if (response.config && response.config.message) {
- log()
- log(`${response.config.message}`)
- }
- } catch (error_) {
- error((error_ as APIError).message)
- }
-}
-
-export const addonsCreate = async (addonName: string, options: OptionValues, command: BaseCommand) => {
- const { manifest, siteData } = await prepareAddonCommand({
- command,
- addonName,
- validation: ADDON_VALIDATION.NOT_EXISTS,
- })
-
- const { api, site } = command.netlify
- const siteId = site.id
-
- // GET flags from `raw` data
- const rawFlags = parseRawFlags(command.args)
- const hasConfig = !isEmpty(manifest.config)
-
- let configValues = rawFlags
-
- if (hasConfig) {
- const required = requiredConfigValues(manifest.config)
- const missingValues = missingConfigValues(required, rawFlags)
- log(`Starting the setup for "${addonName} add-on"`)
- log()
-
- if (Object.keys(rawFlags).length !== 0) {
- const newConfig = updateConfigValues(manifest.config, {}, rawFlags)
-
- if (missingValues.length !== 0) {
- /* Warn user of missing required values */
- log(`${chalk.redBright.underline.bold(`Error: Missing required configuration for "${addonName} add-on"`)}`)
- log()
- renderMissingValues(missingValues, manifest)
- log()
- const msg = `netlify addons:create ${addonName}`
- log(`Please supply the configuration values as CLI flags`)
- log()
- log(`Alternatively, you can run ${chalk.cyan(msg)} with no flags to walk through the setup steps`)
- log()
- return false
- }
-
- await createAddon({ api, siteId, addonName, config: newConfig, siteData })
-
- return false
- }
-
- const words = `The ${addonName} add-on has the following configurable options:`
- log(` ${chalk.yellowBright.bold(words)}`)
- // @ts-expect-error TS(2554) FIXME: Expected 3 arguments, but got 2.
- renderConfigValues(addonName, manifest.config)
- log()
- log(` ${chalk.greenBright.bold('Lets configure those!')}`)
-
- log()
- log(` - Hit ${chalk.white.bold('enter')} to confirm value or set empty value`)
- log(` - Hit ${chalk.white.bold('ctrl + C')} to cancel & exit configuration`)
- log()
-
- const prompts = generatePrompts({
- config: manifest.config,
- configValues: rawFlags,
- })
-
- const userInput = await inquirer.prompt(prompts)
- // Merge user input with the flags specified
- configValues = updateConfigValues(manifest.config, rawFlags, userInput)
- const missingRequiredValues = missingConfigValues(required, configValues)
- if (missingRequiredValues && missingRequiredValues.length !== 0) {
- // @ts-expect-error TS(7006) FIXME: Parameter 'val' implicitly has an 'any' type.
- missingRequiredValues.forEach((val) => {
- log(`Missing required value "${val}". Please run the command again`)
- })
- return false
- }
- }
-
- await createAddon({ api, siteId, addonName, config: configValues, siteData })
-}
diff --git a/src/commands/addons/addons-delete.ts b/src/commands/addons/addons-delete.ts
deleted file mode 100644
index dee08cf0d7a..00000000000
--- a/src/commands/addons/addons-delete.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { OptionValues } from 'commander'
-import inquirer from 'inquirer'
-
-import { ADDON_VALIDATION, prepareAddonCommand } from '../../utils/addons/prepare.js'
-import { error, exit, log, APIError } from '../../utils/command-helpers.js'
-import BaseCommand from '../base-command.js'
-
-export const addonsDelete = async (addonName: string, options: OptionValues, command: BaseCommand) => {
- const { addon } = await prepareAddonCommand({
- command,
- addonName,
- validation: ADDON_VALIDATION.EXISTS,
- })
- if (!options.force && !options.f) {
- const { wantsToDelete } = await inquirer.prompt({
- type: 'confirm',
- name: 'wantsToDelete',
- message: `Are you sure you want to delete the ${addonName} add-on? (to skip this prompt, pass a --force flag)`,
- default: false,
- })
- if (!wantsToDelete) {
- exit()
- }
- }
-
- try {
- await command.netlify.api.deleteServiceInstance({
- siteId: command.netlify.site.id,
- addon: addonName,
- instanceId: addon.id,
- })
- log(`Addon "${addonName}" deleted`)
- } catch (error_) {
- error((error_ as APIError).message)
- }
-}
diff --git a/src/commands/addons/addons-list.ts b/src/commands/addons/addons-list.ts
deleted file mode 100644
index b021bb14244..00000000000
--- a/src/commands/addons/addons-list.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import AsciiTable from 'ascii-table'
-import { OptionValues } from 'commander'
-
-import { prepareAddonCommand } from '../../utils/addons/prepare.js'
-import { log, logJson } from '../../utils/command-helpers.js'
-import BaseCommand from '../base-command.js'
-
-export const addonsList = async (options: OptionValues, command: BaseCommand) => {
- // @ts-expect-error TS(2345) FIXME: Argument of type '{ command: any; }' is not assign... Remove this comment to see the full error message
- const { addons, siteData } = await prepareAddonCommand({ command })
- // Return json response for piping commands
- if (options.json) {
- logJson(addons)
- return false
- }
-
- if (!addons || addons.length === 0) {
- log(`No addons currently installed for ${siteData.name}`)
- log(`> Run \`netlify addons:create addon-namespace\` to install an addon`)
- return false
- }
-
- // @ts-expect-error TS(7006) FIXME: Parameter 'addon' implicitly has an 'any' type.
- const addonData = addons.map((addon) => ({
- namespace: addon.service_path.replace('/.netlify/', ''),
- name: addon.service_name,
- id: addon.id,
- }))
-
- // Build a table out of addons
- log(`site: ${siteData.name}`)
- const table = new AsciiTable(`Currently Installed addons`)
-
- table.setHeading('NameSpace', 'Name', 'Instance Id')
-
- // @ts-expect-error TS(7031) FIXME: Binding element 'id' implicitly has an 'any' type.
- addonData.forEach(({ id, name, namespace }) => {
- table.addRow(namespace, name, id)
- })
- // Log da addons
- log(table.toString())
-}
diff --git a/src/commands/addons/addons.ts b/src/commands/addons/addons.ts
deleted file mode 100644
index f73571409c3..00000000000
--- a/src/commands/addons/addons.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { OptionValues } from 'commander'
-
-import BaseCommand from '../base-command.js'
-
-const addons = (options: OptionValues, command: BaseCommand) => {
- command.help()
-}
-
-export const createAddonsCommand = (program: BaseCommand) => {
- program
- .command('addons:auth', { hidden: true })
- .alias('addon:auth')
- .argument('', 'Add-on slug')
- .description('Login to add-on provider')
- .action(async (addonName: string, options: OptionValues, command: BaseCommand) => {
- const { addonsAuth } = await import('./addons-auth.js')
- await addonsAuth(addonName, options, command)
- })
-
- program
- .command('addons:config', { hidden: true })
- .alias('addon:config')
- .argument('', 'Add-on namespace')
- .description('Configure add-on settings')
- // allow for any flags. Handy for variadic configuration options
- .allowUnknownOption(true)
- .action(async (addonName: string, options: OptionValues, command: BaseCommand) => {
- const { addonsConfig } = await import('./addons-config.js')
- await addonsConfig(addonName, options, command)
- })
-
- program
- .command('addons:create', { hidden: true })
- .alias('addon:create')
- .argument('', 'Add-on namespace')
- .description(
- `Add an add-on extension to your site
-Add-ons are a way to extend the functionality of your Netlify site`,
- )
- // allow for any flags. Handy for variadic configuration options
- .allowUnknownOption(true)
- .action(async (addonName: string, options: OptionValues, command: BaseCommand) => {
- const { addonsCreate } = await import('./addons-create.js')
- await addonsCreate(addonName, options, command)
- })
-
- program
- .command('addons:delete', { hidden: true })
- .alias('addon:delete')
- .argument('', 'Add-on namespace')
- .description(
- `Remove an add-on extension to your site\nAdd-ons are a way to extend the functionality of your Netlify site`,
- )
- .action(async (addonName: string, options: OptionValues, command: BaseCommand) => {
- const { addonsDelete } = await import('./addons-delete.js')
- await addonsDelete(addonName, options, command)
- })
-
- program
- .command('addons:list', { hidden: true })
- .alias('addon:list')
- .description(`List currently installed add-ons for site`)
- .option('--json', 'Output add-on data as JSON')
- .action(async (options: OptionValues, command: BaseCommand) => {
- const { addonsList } = await import('./addons-list.js')
- await addonsList(options, command)
- })
-
- return program
- .command('addons', { hidden: true })
- .alias('addon')
- .description('[Deprecated and will be removed from future versions] Manage Netlify Add-ons')
- .addExamples([
- 'netlify addons:create addon-xyz',
- 'netlify addons:list',
- 'netlify addons:config addon-xyz',
- 'netlify addons:delete addon-xyz',
- 'netlify addons:auth addon-xyz',
- ])
- .action(addons)
-}
diff --git a/src/commands/addons/index.ts b/src/commands/addons/index.ts
deleted file mode 100644
index 987ef63520b..00000000000
--- a/src/commands/addons/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { createAddonsCommand } from './addons.js'
diff --git a/src/commands/main.ts b/src/commands/main.ts
index a3ebfd70deb..4cf8bb1b21e 100644
--- a/src/commands/main.ts
+++ b/src/commands/main.ts
@@ -12,7 +12,6 @@ import getGlobalConfig from '../utils/get-global-config.js'
import getPackageJson from '../utils/get-package-json.js'
import { track, reportError } from '../utils/telemetry/index.js'
-import { createAddonsCommand } from './addons/index.js'
import { createApiCommand } from './api/index.js'
import BaseCommand from './base-command.js'
import { createBlobsCommand } from './blobs/blobs.js'
@@ -47,7 +46,6 @@ export const CI_FORCED_COMMANDS = {
'env:clone': { options: '--force', description: 'Bypasses prompts & Force the command to run.' },
'blobs:set': { options: '--force', description: 'Bypasses prompts & Force the command to run.' },
'blobs:delete': { options: '--force', description: 'Bypasses prompts & Force the command to run.' },
- 'addons:delete': { options: '-f, --force', description: 'Delete without prompting (useful for CI)' },
init: { options: '--force', description: 'Reinitialize CI hooks if the linked site is already configured to use CI' },
'sites:delete': { options: '-f, --force', description: 'Delete without prompting (useful for CI).' },
}
@@ -212,7 +210,6 @@ const mainCommand = async function (options, command) {
export const createMainCommand = () => {
const program = new BaseCommand('netlify')
// register all the commands
- createAddonsCommand(program)
createApiCommand(program)
createBlobsCommand(program)
createBuildCommand(program)
diff --git a/src/utils/addons/prepare.ts b/src/utils/addons/prepare.ts
index 2b0342429df..3f0dac99a8b 100644
--- a/src/utils/addons/prepare.ts
+++ b/src/utils/addons/prepare.ts
@@ -1,69 +1,13 @@
-import { APIError, chalk, error, exit, log, warn } from '../command-helpers.js'
+import { APIError, error } from '../command-helpers.js'
export const ADDON_VALIDATION = {
EXISTS: 'EXISTS',
NOT_EXISTS: 'NOT_EXISTS',
}
-// @ts-expect-error TS(7031) FIXME: Binding element 'addon' implicitly has an 'any' ty... Remove this comment to see the full error message
-const validateExists = ({ addon, addonName, siteData }) => {
- if (!addon || !addon.id) {
- log(`Add-on ${addonName} doesn't exist for ${siteData.name}`)
- log(`> Run \`netlify addons:create ${addonName}\` to create an instance for this site`)
- exit(1)
- }
-}
-
-// @ts-expect-error TS(7031) FIXME: Binding element 'addon' implicitly has an 'any' ty... Remove this comment to see the full error message
-const validateNotExists = ({ addon, addonName, siteData }) => {
- if (addon && addon.id) {
- log(`The "${addonName} add-on" already exists for ${siteData.name}`)
- log()
- const cmd = chalk.cyan(`\`netlify addons:config ${addonName}\``)
- log(`- To update this add-on run: ${cmd}`)
- const deleteCmd = chalk.cyan(`\`netlify addons:delete ${addonName}\``)
- log(`- To remove this add-on run: ${deleteCmd}`)
- log()
- exit(1)
- }
-}
-
// @ts-expect-error TS(7031) FIXME: Binding element 'addonName' implicitly has an 'any... Remove this comment to see the full error message
export const getCurrentAddon = ({ addonName, addons }) => addons.find((addon) => addon.service_slug === addonName)
-// @ts-expect-error TS(7031) FIXME: Binding element 'addon' implicitly has an 'any' ty... Remove this comment to see the full error message
-const validateCurrentAddon = ({ addon, addonName, siteData, validation }) => {
- switch (validation) {
- case ADDON_VALIDATION.EXISTS: {
- validateExists({ addon, addonName, siteData })
- break
- }
- case ADDON_VALIDATION.NOT_EXISTS: {
- validateNotExists({ addon, addonName, siteData })
- break
- }
- default: {
- warn(`Unknown addons validation: ${validation}`)
- break
- }
- }
-}
-
-// @ts-expect-error TS(7031) FIXME: Binding element 'addonName' implicitly has an 'any... Remove this comment to see the full error message
-export const getAddonManifest = async ({ addonName, api }) => {
- let manifest
- try {
- manifest = await api.showServiceManifest({ addonName })
- } catch (error_) {
- if ((error_ as APIError).message.includes('Not Found')) {
- error(`No add-on "${addonName}" found. Please double check your add-on name and try again`)
- } else {
- error((error_ as APIError).message)
- }
- }
- return manifest
-}
-
// @ts-expect-error TS(7031) FIXME: Binding element 'api' implicitly has an 'any' type... Remove this comment to see the full error message
export const getSiteData = async ({ api, siteId }) => {
let siteData
@@ -85,38 +29,3 @@ export const getAddons = async ({ api, siteId }) => {
}
return addons
}
-
-/**
- *
- * @param {object} config
- * @param {import('../../commands/base-command.js').default} config.command
- * @param {string} [config.addonName]
- * @param {keyof ADDON_VALIDATION} [config.validation]
- */
-// @ts-expect-error TS(7031) FIXME: Binding element 'addonName' implicitly has an 'any... Remove this comment to see the full error message
-export const prepareAddonCommand = async ({ addonName, command, validation }) => {
- const { netlify } = command
- const { api, site } = netlify
- const siteId = site.id
- if (!siteId) {
- error('No site id found, please run inside a site folder or `netlify link`')
- }
-
- await command.authenticate()
-
- const [manifest, siteData, addons] = await Promise.all([
- // TODO: check as `getAddonManifest` did not accept a parameter error
- // @ts-expect-error TS(2345) FIXME: Argument of type '{ api: any; addonName: any; erro... Remove this comment to see the full error message
- addonName ? getAddonManifest({ api, addonName, error }) : Promise.resolve(),
- getSiteData({ api, siteId }),
- getAddons({ api, siteId }),
- ])
-
- let addon
- if (addonName) {
- addon = getCurrentAddon({ addons, addonName })
- validateCurrentAddon({ addon, validation, addonName, siteData })
- }
-
- return { manifest, addons, addon, siteData }
-}
diff --git a/src/utils/addons/render.ts b/src/utils/addons/render.ts
deleted file mode 100644
index 92aed3e8b71..00000000000
--- a/src/utils/addons/render.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import AsciiTable from 'ascii-table'
-
-import { chalk } from '../command-helpers.js'
-
-// @ts-expect-error TS(7006) FIXME: Parameter 'values' implicitly has an 'any' type.
-export const renderMissingValues = function (values, manifest) {
- const display = values
- // @ts-expect-error TS(7006) FIXME: Parameter 'item' implicitly has an 'any' type.
- .map((item) => {
- const itemDisplay = chalk.redBright.bold(`${item}`)
- const niceNameDisplay = manifest.config[item].displayName
- return ` - ${itemDisplay} ${niceNameDisplay}`
- })
- .join('\n')
- console.log(display)
-}
-
-// @ts-expect-error TS(7006) FIXME: Parameter 'addonName' implicitly has an 'any' type... Remove this comment to see the full error message
-export const renderConfigValues = function (addonName, values, currentValue) {
- const table = new AsciiTable(`${addonName} add-on settings`)
-
- const tableHeader = currentValue
- ? ['Setting Name', 'Current Value', 'Description']
- : ['Setting Name', 'Description', 'Type', 'Required']
-
- table.setHeading(...tableHeader)
-
- Object.keys(values).forEach((key) => {
- const { displayName, required, type } = values[key]
- const requiredText = required ? `true` : `false`
- const typeInfo = type || ''
- const description = displayName || ''
- if (currentValue) {
- const value = currentValue[key] || 'Not supplied'
- table.addRow(key, value, description)
- } else {
- table.addRow(key, description, typeInfo, requiredText)
- }
- })
- console.log(table.toString())
-}
diff --git a/tests/integration/commands/addons/addons.test.js b/tests/integration/commands/addons/addons.test.js
deleted file mode 100644
index ad8c7ee2f80..00000000000
--- a/tests/integration/commands/addons/addons.test.js
+++ /dev/null
@@ -1,158 +0,0 @@
-import { describe, test } from 'vitest'
-
-import { callCli } from '../../utils/call-cli.js'
-import { getCLIOptions, withMockApi } from '../../utils/mock-api.js'
-import { withSiteBuilder } from '../../utils/site-builder.ts'
-
-const siteInfo = {
- account_slug: 'test-account',
- id: 'site_id',
- name: 'site-name',
-}
-const routes = [
- { path: 'sites/site_id', response: siteInfo },
- { path: 'sites/site_id/service-instances', response: [] },
- {
- path: 'accounts',
- response: [{ slug: siteInfo.account_slug }],
- },
-]
-describe.concurrent('command-addons', () => {
- test('netlify addons:list', async (t) => {
- await withSiteBuilder(t, async (builder) => {
- await builder.build()
-
- await withMockApi(routes, async ({ apiUrl }) => {
- const cliResponse = await callCli(['addons:list'], getCLIOptions({ builder, apiUrl }))
- t.expect(cliResponse.includes('No addons currently installed')).toBe(true)
- })
- })
- })
-
- test('netlify addons:list --json', async (t) => {
- await withSiteBuilder(t, async (builder) => {
- await builder.build()
-
- await withMockApi(routes, async ({ apiUrl }) => {
- const cliResponse = await callCli(['addons:list', '--json'], getCLIOptions({ builder, apiUrl }))
- const json = JSON.parse(cliResponse)
- t.expect(Array.isArray(json)).toBe(true)
- t.expect(json.length).toBe(0)
- })
- })
- })
-
- test('netlify addons:create demo', async (t) => {
- await withSiteBuilder(t, async (builder) => {
- await builder.build()
-
- const createRoutes = [
- ...routes,
- { path: 'services/demo/manifest', response: {} },
- {
- path: 'sites/site_id/services/demo/instances',
- response: {},
- method: 'POST',
- requestBody: { config: { TWILIO_ACCOUNT_SID: 'foo' } },
- },
- ]
-
- await withMockApi(createRoutes, async ({ apiUrl }) => {
- const cliResponse = await callCli(
- ['addons:create', 'demo', '--TWILIO_ACCOUNT_SID', 'foo'],
- getCLIOptions({ builder, apiUrl }),
- )
- t.expect(cliResponse.includes('Add-on "demo" created')).toBe(true)
- })
- })
- })
-
- test('After creation netlify addons:list --json', async (t) => {
- await withSiteBuilder(t, async (builder) => {
- await builder.build()
-
- const withExistingAddon = [
- { path: 'sites/site_id', response: siteInfo },
- {
- path: 'sites/site_id/service-instances',
- response: [{ service_slug: 'demo' }],
- },
- {
- path: 'accounts',
- response: [{ slug: siteInfo.account_slug }],
- },
- ]
-
- await withMockApi(withExistingAddon, async ({ apiUrl }) => {
- const cliResponse = await callCli(['addons:list', '--json'], getCLIOptions({ builder, apiUrl }))
- const json = JSON.parse(cliResponse)
- t.expect(Array.isArray(json)).toBe(true)
- t.expect(json.length).toBe(1)
- t.expect(json[0].service_slug).toEqual('demo')
- })
- })
- })
-
- test('netlify addons:config demo', async (t) => {
- await withSiteBuilder(t, async (builder) => {
- await builder.build()
-
- const configRoutes = [
- { path: 'sites/site_id', response: siteInfo },
- {
- path: 'sites/site_id/service-instances',
- response: [{ id: 'demo', service_slug: 'demo', config: { TWILIO_ACCOUNT_SID: 'foo' } }],
- },
- {
- path: 'accounts',
- response: [{ slug: siteInfo.account_slug }],
- },
- { path: 'services/demo/manifest', response: { config: { TWILIO_ACCOUNT_SID: '' } } },
- {
- path: 'sites/site_id/services/demo/instances/demo',
- response: {},
- method: 'PUT',
- requestBody: { config: { TWILIO_ACCOUNT_SID: 'bar' } },
- },
- ]
-
- await withMockApi(configRoutes, async ({ apiUrl }) => {
- const cliResponse = await callCli(
- ['addons:config', 'demo', '--TWILIO_ACCOUNT_SID', 'bar'],
- getCLIOptions({ builder, apiUrl }),
- )
- t.expect(cliResponse.includes('Updating demo add-on config values')).toBe(true)
- t.expect(cliResponse.includes('Add-on "demo" successfully updated')).toBe(true)
- })
- })
- })
-
- test('netlify addon:delete demo', async (t) => {
- await withSiteBuilder(t, async (builder) => {
- await builder.build()
-
- const deleteRoutes = [
- { path: 'sites/site_id', response: siteInfo },
- {
- path: 'sites/site_id/service-instances',
- response: [{ id: 'demo', service_slug: 'demo', config: { TWILIO_ACCOUNT_SID: 'foo' } }],
- },
- {
- path: 'accounts',
- response: [{ slug: siteInfo.account_slug }],
- },
- { path: 'services/demo/manifest', response: {} },
- {
- path: 'sites/site_id/services/demo/instances/demo',
- response: {},
- method: 'DELETE',
- },
- ]
-
- await withMockApi(deleteRoutes, async ({ apiUrl }) => {
- const cliResponse = await callCli(['addons:delete', 'demo', '--force'], getCLIOptions({ builder, apiUrl }))
- t.expect(cliResponse.includes('Addon "demo" deleted')).toBe(true)
- })
- })
- })
-})