Skip to content

Commit

Permalink
Merge pull request #687 from adobe/issues/pipeline-variables-service
Browse files Browse the repository at this point in the history
feat(variables): support service-specific pipeline variables. fixes #686
  • Loading branch information
proactivebit authored Apr 8, 2024
2 parents 47fbbf9 + b1001e9 commit 30b3d18
Show file tree
Hide file tree
Showing 15 changed files with 397 additions and 81 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: [14.x, 16.x]
node-version: [16.x]
include:
- os: ubuntu-latest
node-version: 14.x
node-version: 16.x
reportCoverage: true
runs-on: ${{ matrix.os }}

Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

# [4.2.0](https://github.com/adobe/aio-cli-plugin-cloudmanager/compare/4.1.0...4.2.0) (2024-25-03)


### Features

* **variables:** support service-specific pipeline variables [#686](https://github.com/adobe/aio-cli-plugin-cloudmanager/issues/686) ([3c3d804](https://github.com/adobe/aio-cli-plugin-cloudmanager/commit/3c3d80404df16ad4375f079c67cfef3ea6b15fbd))

# [4.1.0](https://github.com/adobe/aio-cli-plugin-cloudmanager/compare/4.0.0...4.1.0) (2023-06-14)


Expand Down
50 changes: 36 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ Cloud Manager Plugin for the [Adobe I/O CLI](https://github.com/adobe/aio-cli)

* [Adobe I/O CLI](https://github.com/adobe/aio-cli)
* Node.js version compatibility:
* 12.x -- 12.0.0 or higher.
* 14.x -- 14.0.0 or higher.
* 16.x -- currently incompatible due to lack of support from aio-cli.
* 16.x -- 16.0.0 or higher.
* Use with odd Node versions is *not* recommended.

> Although not recommended for general use, it is possible to use this plugin outside of the Adobe I/O CLI. See [Standalone Use](#standalone-use) below.
Expand Down Expand Up @@ -1043,19 +1041,43 @@ ARGUMENTS
PIPELINEID the pipeline id
OPTIONS
-d, --delete=delete variables/secrets to delete
-j, --json output in json format
-p, --programId=programId the programId. if not specified, defaults to 'cloudmanager_programid' config value
-s, --secret=secret secret values in KEY VALUE format
-v, --variable=variable variable values in KEY VALUE format
-y, --yaml output in yaml format
--imsContextName=imsContextName the alternate IMS context name to use instead of aio-cli-plugin-cloudmanager
-d, --delete=delete variables/secrets to delete
-j, --json output in json format
-p, --programId=programId the programId. if not specified, defaults to 'cloudmanager_programid' config value
-s, --secret=secret secret values in KEY VALUE format
-v, --variable=variable variable values in KEY VALUE format
-y, --yaml output in yaml format
--imsContextName=imsContextName the alternate IMS context name to use instead of aio-cli-plugin-cloudmanager
--jsonFile=jsonFile if set, read variables from a JSON array provided as a file; variables set through
--variable or --secret flag will take precedence
--jsonFile=jsonFile if set, read variables from a JSON array provided as a file; variables set through
--variable or --secret flag will take precedence
--jsonStdin if set, read variables from a JSON array provided as standard input; variables set
through --variable or --secret flag will take precedence
--jsonStdin if set, read variables from a JSON array provided as standard input; variables set
through --variable or --secret flag will take precedence
--buildDelete=buildDelete variables/secrets to delete for build service
--buildSecret=buildSecret secret values in KEY VALUE format for build service
--buildVariable=buildVariable variable values in KEY VALUE format for build service
--functionalTestDelete=functionalTestDelete variables/secrets to delete for functionalTest service
--functionalTestSecret=functionalTestSecret secret values in KEY VALUE format for functionalTest service
--functionalTestVariable=functionalTestVariable variable values in KEY VALUE format for functionalTest service
--uiTestDelete=uiTestDelete variables/secrets to delete for uiTest service
--uiTestSecret=uiTestSecret secret values in KEY VALUE format for uiTest service
--uiTestVariable=uiTestVariable variable values in KEY VALUE format for uiTest service
--loadTestDelete=loadTestDelete variables/secrets to delete for loadTest service
--loadTestSecret=loadTestSecret secret values in KEY VALUE format for loadTest service
--loadTestVariable=loadTestVariable variable values in KEY VALUE format for loadTest service
--yamlFile=yamlFile if set, read variables from a YAML array provided as a file; variables set through
--variable or --secret flag will take precedence
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@adobe/aio-cli-plugin-cloudmanager",
"description": "Cloud Manager commands for the Adobe I/O CLI",
"version": "4.1.0",
"version": "4.2.0",
"author": "Adobe Inc.",
"bugs": "https://github.com/adobe/aio-cli-plugin-cloudmanager/issues",
"dependencies": {
Expand Down Expand Up @@ -43,7 +43,7 @@
"execa": "5.1.1",
"fetch-mock": "9.11.0",
"husky": "5.2.0",
"jest": "27.5.1",
"jest": "29.7.0",
"jest-extended": "2.0.0",
"jest-junit": "13.0.0",
"node-wget": "0.4.3",
Expand All @@ -53,7 +53,7 @@
"tmp": "0.2.1"
},
"engines": {
"node": ">=12"
"node": ">=16"
},
"files": [
"/oclif.manifest.json",
Expand Down Expand Up @@ -145,7 +145,7 @@
"prepack": "oclif-dev manifest && oclif-dev readme",
"postpack": "rm -f oclif.manifest.json",
"version": "oclif-dev readme && git add README.md",
"e2e": "jest --collectCoverage=false --testRegex './e2e/e2e.js'",
"e2e": "jest --collectCoverage=false --testRegex \"/e2e/*\"",
"semantic-release": "semantic-release",
"semantic-release-dry-run": "semantic-release --dry-run",
"postinstall": "husky install",
Expand Down Expand Up @@ -203,4 +203,4 @@
"@semantic-release/github"
]
}
}
}
80 changes: 57 additions & 23 deletions src/base-variables-command.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ const _ = require('lodash')
const { codes: validationCodes } = require('./ValidationErrors')

class BaseVariablesCommand extends BaseCommand {
getFlagDefs () {
return {
getFlagDefs (services) {
const coreFlagDefs = {
variable: {
type: 'string',
},
Expand All @@ -36,6 +36,21 @@ class BaseVariablesCommand extends BaseCommand {
action: 'delete',
},
}

const result = {
...coreFlagDefs,
}

services.forEach(service => {
Object.keys(coreFlagDefs).forEach(coreFlagKey => {
const flagName = _.camelCase(`${service} ${coreFlagKey}`)
result[flagName] = {
...coreFlagDefs[coreFlagKey],
service,
}
})
})
return result
}

outputTable (result, flags, extraColumns = {}) {
Expand Down Expand Up @@ -167,27 +182,30 @@ BaseVariablesCommand.coreSetterFlags = {
}),
}

BaseVariablesCommand.setterFlags = {
...BaseVariablesCommand.coreSetterFlags,
jsonStdin: flags.boolean({
default: false,
description: 'if set, read variables from a JSON array provided as standard input; variables set through --variable or --secret flag will take precedence',
exclusive: ['jsonFile', 'yamlStdin', 'yamlFile'],
}),
jsonFile: flags.string({
description: 'if set, read variables from a JSON array provided as a file; variables set through --variable or --secret flag will take precedence',
exclusive: ['jsonStdin', 'yamlStdin', 'yamlFile'],
}),
yamlStdin: flags.boolean({
default: false,
description: 'if set, read variables from a YAML array provided as standard input; variables set through --variable or --secret flag will take precedence',
exclusive: ['jsonStdin', 'jsonFile', 'yamlFile'],
}),
yamlFile: flags.string({
description: 'if set, read variables from a YAML array provided as a file; variables set through --variable or --secret flag will take precedence',
exclusive: ['jsonStdin', 'jsonFile', 'yamlStdin'],
}),
...commonFlags.outputFormat,
BaseVariablesCommand.setterFlags = (services) => {
return {
...BaseVariablesCommand.coreSetterFlags,
jsonStdin: flags.boolean({
default: false,
description: 'if set, read variables from a JSON array provided as standard input; variables set through --variable or --secret flag will take precedence',
exclusive: ['jsonFile', 'yamlStdin', 'yamlFile'],
}),
jsonFile: flags.string({
description: 'if set, read variables from a JSON array provided as a file; variables set through --variable or --secret flag will take precedence',
exclusive: ['jsonStdin', 'yamlStdin', 'yamlFile'],
}),
yamlStdin: flags.boolean({
default: false,
description: 'if set, read variables from a YAML array provided as standard input; variables set through --variable or --secret flag will take precedence',
exclusive: ['jsonStdin', 'jsonFile', 'yamlFile'],
}),
yamlFile: flags.string({
description: 'if set, read variables from a YAML array provided as a file; variables set through --variable or --secret flag will take precedence',
exclusive: ['jsonStdin', 'jsonFile', 'yamlStdin'],
}),
...commonFlags.outputFormat,
...BaseVariablesCommand.serviceSetterFlags(services),
}
}

BaseVariablesCommand.getterFlags = {
Expand Down Expand Up @@ -237,4 +255,20 @@ BaseVariablesCommand.loadVariablesFromYaml = (rawData, currentVariableTypes, var
loadVariableData(data, currentVariableTypes, variables)
}

BaseVariablesCommand.serviceSetterFlags = (services) => {
const serviceFlags = {}
services.forEach(service => {
Object.keys(BaseVariablesCommand.coreSetterFlags).forEach(coreFlagKey => {
const coreFlag = BaseVariablesCommand.coreSetterFlags[coreFlagKey]
const flagName = _.camelCase(`${service} ${coreFlagKey}`)
serviceFlags[flagName] = flags.string({
description: `${coreFlag.description} for ${service} service`,
multiple: true,
})
})
})

return serviceFlags
}

module.exports = BaseVariablesCommand
2 changes: 1 addition & 1 deletion src/commands/cloudmanager/environment/bind-ip-allowlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ BindIPAllowlist.description = 'Bind an IP Allowlist to an environment'
BindIPAllowlist.args = [
commonArgs.environmentId,
{ name: 'ipAllowlistId', required: true, description: 'the IP allowlist id' },
commonArgs.service,
commonArgs.environmentServices,
]

BindIPAllowlist.flags = {
Expand Down
31 changes: 3 additions & 28 deletions src/commands/cloudmanager/environment/set-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ const BaseVariablesCommand = require('../../../base-variables-command')
const { initSdk, sanitizeEnvironmentId } = require('../../../cloudmanager-helpers')
const { flags } = require('@oclif/command')
const Config = require('@adobe/aio-lib-core-config')
const _ = require('lodash')
const commonFlags = require('../../../common-flags')
const commonArgs = require('../../../common-args')
const { services } = require('../../../constants')
const { environmentServices } = require('../../../constants')
const { codes: validationCodes } = require('../../../ValidationErrors')

const IGNORED_PREFIXES = [
Expand All @@ -29,20 +28,7 @@ const IGNORED_PREFIXES = [

class SetEnvironmentVariablesCommand extends BaseEnvironmentVariablesCommand {
getFlagDefs () {
const coreFlagDefs = super.getFlagDefs()
const result = {
...coreFlagDefs,
}
services.forEach(service => {
Object.keys(coreFlagDefs).forEach(coreFlagKey => {
const flagName = _.camelCase(`${service} ${coreFlagKey}`)
result[flagName] = {
...coreFlagDefs[coreFlagKey],
service,
}
})
})
return result
return super.getFlagDefs(environmentServices)
}

async run () {
Expand Down Expand Up @@ -83,21 +69,10 @@ SetEnvironmentVariablesCommand.args = [
SetEnvironmentVariablesCommand.flags = {
...commonFlags.global,
...commonFlags.programId,
...BaseVariablesCommand.setterFlags,
...BaseVariablesCommand.setterFlags(environmentServices),
strict: flags.boolean({ description: 'performs strict validation of internal variables. Can also be enabled by setting configuration property cloudmanager.environmentVariables.strictValidation to a truthy value.' }),
}

services.forEach(service => {
Object.keys(BaseVariablesCommand.coreSetterFlags).forEach(coreFlagKey => {
const coreFlag = BaseVariablesCommand.coreSetterFlags[coreFlagKey]
const flagName = _.camelCase(`${service} ${coreFlagKey}`)
SetEnvironmentVariablesCommand.flags[flagName] = flags.string({
description: `${coreFlag.description} for ${service} service`,
multiple: true,
})
})
})

SetEnvironmentVariablesCommand.aliases = [
'cloudmanager:set-environment-variables',
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ UnbindIPAllowlist.strict = false
UnbindIPAllowlist.args = [
commonArgs.environmentId,
{ name: 'ipAllowlistId', required: true, description: 'the IP allowlist id' },
commonArgs.service,
commonArgs.environmentServices,
]

UnbindIPAllowlist.flags = {
Expand Down
2 changes: 1 addition & 1 deletion src/commands/cloudmanager/ip-allowlist/bind.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ BindIPAllowlist.strict = false
BindIPAllowlist.args = [
{ name: 'ipAllowlistId', required: true, description: 'the IP allowlist id' },
commonArgs.environmentId,
commonArgs.service,
commonArgs.environmentServices,
]

BindIPAllowlist.flags = {
Expand Down
2 changes: 1 addition & 1 deletion src/commands/cloudmanager/ip-allowlist/unbind.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ UnbindIPAllowlist.strict = false
UnbindIPAllowlist.args = [
{ name: 'ipAllowlistId', required: true, description: 'the IP allowlist id' },
commonArgs.environmentId,
commonArgs.service,
commonArgs.environmentServices,
]

UnbindIPAllowlist.flags = {
Expand Down
7 changes: 6 additions & 1 deletion src/commands/cloudmanager/pipeline/set-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ const BasePipelineVariablesCommand = require('../../../base-pipeline-variables-c
const BaseVariablesCommand = require('../../../base-variables-command')
const { initSdk } = require('../../../cloudmanager-helpers')
const commonFlags = require('../../../common-flags')
const { pipelineServices } = require('../../../constants')

class SetPipelineVariablesCommand extends BasePipelineVariablesCommand {
getFlagDefs () {
return super.getFlagDefs(pipelineServices)
}

async run () {
const { args, flags } = this.parse(SetPipelineVariablesCommand)

Expand All @@ -37,7 +42,7 @@ SetPipelineVariablesCommand.args = [
SetPipelineVariablesCommand.flags = {
...commonFlags.global,
...commonFlags.programId,
...BaseVariablesCommand.setterFlags,
...BaseVariablesCommand.setterFlags(pipelineServices),
}

SetPipelineVariablesCommand.aliases = [
Expand Down
4 changes: 2 additions & 2 deletions src/common-args.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ OF ANY KIND, either express or implied. See the License for the specific languag
governing permissions and limitations under the License.
*/

const { services } = require('./constants')
const { environmentServices } = require('./constants')

module.exports = {
service: { name: 'service', required: true, options: services, description: 'the service name' },
environmentServices: { name: 'service', required: true, options: environmentServices, description: 'the service name' },
environmentId: { name: 'environmentId', required: true, description: 'the environment id' },
}
3 changes: 2 additions & 1 deletion src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ governing permissions and limitations under the License.
*/

module.exports = {
services: ['author', 'publish', 'preview'],
environmentServices: ['author', 'publish', 'preview'],
pipelineServices: ['build', 'functionalTest', 'uiTest', 'loadTest'],
defaultImsContextName: 'aio-cli-plugin-cloudmanager',
exitCodes: {
GENERAL: 1,
Expand Down
10 changes: 10 additions & 0 deletions test/__mocks__/@adobe/aio-lib-cloudmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ function createDefaultMock () {
}, {
name: 'I_AM_A_SECRET',
type: 'secretString',
}, {
name: 'FUNCTIONAL_VARIABLE',
value: 'something',
service: 'functionalTest',
type: 'string',
}, {
name: 'BUILD_SECRET',
value: 'something',
service: 'build',
type: 'secretString',
}])),
setPipelineVariables: jest.fn(() => Promise.resolve()),
deleteProgram: jest.fn(() => Promise.resolve()),
Expand Down
Loading

0 comments on commit 30b3d18

Please sign in to comment.