Skip to content

Commit

Permalink
feature: Adds utility functions to add envars and update Redwood toml…
Browse files Browse the repository at this point in the history
… for plugin packages to cli helpers for use in simplifying CLI setup commands (#9324)

When writing a CLI plugin for setup and custom commands, there are a
number of tasks that almost always done:

* adding an envar
* updating redwood.toml to setup the new plugin

This PR:

* adds a utility function to add the envar and uses in the the
addEnvVarTask
* this function now ensures no duplicate envars are added if
setup/command is run more than once
* updates the tmp to setup the 
```
[experimental.cli]
  autoInstall = true
  [[experimental.cli.plugins]]
    package = "@unkey/redwoodjs"
```

section for a given package.

Tests are included.

---------

Co-authored-by: Josh GM Walker <56300765+Josh-Walker-GM@users.noreply.github.com>
  • Loading branch information
dthyresson and Josh-Walker-GM authored Oct 25, 2023
1 parent 8e59d91 commit a12d411
Show file tree
Hide file tree
Showing 5 changed files with 481 additions and 9 deletions.
2 changes: 2 additions & 0 deletions packages/cli-helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@
"dependencies": {
"@babel/core": "^7.22.20",
"@babel/runtime-corejs3": "7.23.1",
"@iarna/toml": "2.2.5",
"@opentelemetry/api": "1.4.1",
"@redwoodjs/project-config": "6.0.7",
"@redwoodjs/telemetry": "6.0.7",
"chalk": "4.1.2",
"core-js": "3.32.2",
"dotenv": "16.3.1",
"execa": "5.1.1",
"listr2": "6.6.1",
"lodash": "4.17.21",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`addEnvVar addEnvVar adds environment variables as part of a setup task should add a comment that the existing environment variable value was not changed, but include its new value as a comment 1`] = `
"EXISTING_VAR=value
# CommentedVar=123
# Note: The existing environment variable EXISTING_VAR was not overwritten. Uncomment to use its new value.
# Updated existing variable Comment
# EXISTING_VAR = new_value
"
`;

exports[`addEnvVar addEnvVar adds environment variables as part of a setup task should add a new environment variable when it does not exist 1`] = `
"EXISTING_VAR = value
# CommentedVar = 123
# New Variable Comment
NEW_VAR = new_value
"
`;

exports[`addEnvVar addEnvVar adds environment variables as part of a setup task should add a new environment variable when it does not exist when existing envars have no spacing 1`] = `
"EXISTING_VAR=value
# CommentedVar = 123
# New Variable Comment
NEW_VAR = new_value
"
`;

exports[`addEnvVar addEnvVar adds environment variables as part of a setup task should handle existing environment variables and new value with quoted values by not updating the original value 1`] = `
"EXISTING_VAR = "value"
# CommentedVar = 123
# Note: The existing environment variable EXISTING_VAR was not overwritten. Uncomment to use its new value.
# New Variable Comment
# EXISTING_VAR = new_value
"
`;

exports[`addEnvVar addEnvVar adds environment variables as part of a setup task should handle existing environment variables with quoted values 1`] = `
"EXISTING_VAR = "value"
# CommentedVar = 123
"
`;

exports[`addEnvVar addEnvVar adds environment variables as part of a setup task should handle existing environment variables with quoted values and no spacing 1`] = `
"EXISTING_VAR="value"
# CommentedVar=123
"
`;

exports[`updateTomlConfig updateTomlConfig configures a new CLI plugin adds package but keeps autoInstall false 1`] = `
"[web]
title = "Redwood App"
port = 8_910
apiUrl = "/.redwood/functions"
includeEnvironmentVariables = [ ]
[api]
port = 8_911
[experimental.cli]
autoInstall = false
[[experimental.cli.plugins]]
package = "@example/test-package-when-autoInstall-false"
enabled = true
"
`;

exports[`updateTomlConfig updateTomlConfig configures a new CLI plugin adds when experimental cli has some plugins configured 1`] = `
"[web]
title = "Redwood App"
port = 8_910
apiUrl = "/.redwood/functions"
includeEnvironmentVariables = [ ]
[api]
port = 8_911
[experimental.cli]
autoInstall = true
[[experimental.cli.plugins]]
package = "@existing-example/some-package-when-cli-has-some-packages-configured"
[[experimental.cli.plugins]]
package = "@example/test-package-name"
enabled = true
"
`;

exports[`updateTomlConfig updateTomlConfig configures a new CLI plugin adds when experimental cli is not configured 1`] = `
"[web]
title = "Redwood App"
port = 8_910
apiUrl = "/.redwood/functions"
includeEnvironmentVariables = [ ]
[api]
port = 8_911
[experimental.cli]
autoInstall = true
[[experimental.cli.plugins]]
package = "@example/test-package-when-cli-not-configured"
enabled = true
"
`;

exports[`updateTomlConfig updateTomlConfig configures a new CLI plugin adds when experimental cli is setup but has no plugins configured 1`] = `
"[web]
title = "Redwood App"
port = 8_910
apiUrl = "/.redwood/functions"
includeEnvironmentVariables = [ ]
[api]
port = 8_911
[experimental.cli]
autoInstall = true
[[experimental.cli.plugins]]
package = "@example/test-package-when-no-plugins-configured"
enabled = true
"
`;

exports[`updateTomlConfig updateTomlConfig configures a new CLI plugin does not add duplicate place when experimental cli has that plugin configured 1`] = `
"[web]
title = "Redwood App"
port = 8_910
apiUrl = "/.redwood/functions"
includeEnvironmentVariables = [ ]
[api]
port = 8_911
[experimental.cli]
autoInstall = true
[[experimental.cli.plugins]]
package = "@existing-example/some-package-name-already-exists"
"
`;
214 changes: 214 additions & 0 deletions packages/cli-helpers/src/lib/__tests__/project.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import fs from 'fs'

import toml from '@iarna/toml'

import { updateTomlConfig, addEnvVar } from '../project' // Replace with the correct path to your module

jest.mock('fs')

const defaultRedwoodToml = {
web: {
title: 'Redwood App',
port: 8910,
apiUrl: '/.redwood/functions',
includeEnvironmentVariables: [],
},
api: {
port: 8911,
},
}

const getRedwoodToml = () => {
return defaultRedwoodToml
}

jest.mock('@redwoodjs/project-config', () => {
return {
getPaths: () => {
return {
generated: {
base: '.redwood',
},
base: '',
}
},
getConfigPath: () => {
return '.redwood.toml'
},
getConfig: () => {
return getRedwoodToml()
},
}
})

describe('addEnvVar', () => {
let envFileContent = ''

describe('addEnvVar adds environment variables as part of a setup task', () => {
beforeEach(() => {
jest.spyOn(fs, 'existsSync').mockImplementation(() => {
return true
})

jest.spyOn(fs, 'readFileSync').mockImplementation(() => {
return envFileContent
})

jest.spyOn(fs, 'writeFileSync').mockImplementation((envPath, envFile) => {
expect(envPath).toContain('.env')
return envFile
})
})

afterEach(() => {
jest.restoreAllMocks()
envFileContent = ''
})

it('should add a new environment variable when it does not exist', () => {
envFileContent = 'EXISTING_VAR = value\n# CommentedVar = 123\n'
const file = addEnvVar('NEW_VAR', 'new_value', 'New Variable Comment')

expect(file).toMatchSnapshot()
})

it('should add a new environment variable when it does not exist when existing envars have no spacing', () => {
envFileContent = 'EXISTING_VAR=value\n# CommentedVar = 123\n'
const file = addEnvVar('NEW_VAR', 'new_value', 'New Variable Comment')

expect(file).toMatchSnapshot()
})

it('should add a comment that the existing environment variable value was not changed, but include its new value as a comment', () => {
envFileContent = 'EXISTING_VAR=value\n# CommentedVar=123\n'
const file = addEnvVar(
'EXISTING_VAR',
'new_value',
'Updated existing variable Comment'
)

expect(file).toMatchSnapshot()
})

it('should handle existing environment variables with quoted values', () => {
envFileContent = `EXISTING_VAR = "value"\n# CommentedVar = 123\n`
const file = addEnvVar('EXISTING_VAR', 'value', 'New Variable Comment')

expect(file).toMatchSnapshot()
})

it('should handle existing environment variables with quoted values and no spacing', () => {
envFileContent = `EXISTING_VAR="value"\n# CommentedVar=123\n`
const file = addEnvVar('EXISTING_VAR', 'value', 'New Variable Comment')

expect(file).toMatchSnapshot()
})

it('should handle existing environment variables and new value with quoted values by not updating the original value', () => {
envFileContent = `EXISTING_VAR = "value"\n# CommentedVar = 123\n`
const file = addEnvVar(
'EXISTING_VAR',
'new_value',
'New Variable Comment'
)

expect(file).toMatchSnapshot()
})
})
})

describe('updateTomlConfig', () => {
describe('updateTomlConfig configures a new CLI plugin', () => {
beforeEach(() => {
jest.spyOn(fs, 'existsSync').mockImplementation(() => {
return true
})

jest.spyOn(fs, 'readFileSync').mockImplementation(() => {
return toml.stringify(defaultRedwoodToml)
})

jest
.spyOn(fs, 'writeFileSync')
.mockImplementation((tomlPath, tomlFile) => {
expect(tomlPath).toContain('redwood.toml')
return tomlFile
})
})

afterEach(() => {
jest.restoreAllMocks()
})

it('adds when experimental cli is not configured', () => {
const file = updateTomlConfig(
'@example/test-package-when-cli-not-configured'
)
expect(file).toMatchSnapshot()
})

it('adds when experimental cli has some plugins configured', () => {
defaultRedwoodToml['experimental'] = {
cli: {
autoInstall: true,
plugins: [
{
package:
'@existing-example/some-package-when-cli-has-some-packages-configured',
},
],
},
}

const file = updateTomlConfig('@example/test-package-name')
expect(file).toMatchSnapshot()
})

it('adds when experimental cli is setup but has no plugins configured', () => {
defaultRedwoodToml['experimental'] = {
cli: {
autoInstall: true,
},
}

const file = updateTomlConfig(
'@example/test-package-when-no-plugins-configured'
)

expect(file).toMatchSnapshot()
})

it('adds package but keeps autoInstall false', () => {
defaultRedwoodToml['experimental'] = {
cli: {
autoInstall: false,
},
}

const file = updateTomlConfig(
'@example/test-package-when-autoInstall-false'
)

expect(file).toMatchSnapshot()
})

it('does not add duplicate place when experimental cli has that plugin configured', () => {
defaultRedwoodToml['experimental'] = {
cli: {
autoInstall: true,
plugins: [
{
package: '@existing-example/some-package-name-already-exists',
},
],
},
}

const file = updateTomlConfig(
'@existing-example/some-package-name-already-exists'
)

expect(file).toMatchSnapshot()
})
})
})
Loading

0 comments on commit a12d411

Please sign in to comment.