Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/two-emus-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@smartthings/cli-lib": patch
---

added support for removing managed config values
81 changes: 77 additions & 4 deletions packages/lib/src/__tests__/cli-config.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import yaml from 'js-yaml'

import { loadConfigFile, mergeProfiles, ProfilesByName } from '..'
import { CLIConfig, CLIConfigDescription, loadConfig, resetManagedConfig, seeConfigDocs, setConfigKey } from '../cli-config'
import {
CLIConfig,
CLIConfigDescription,
loadConfig,
resetManagedConfig,
resetManagedConfigKey,
seeConfigDocs,
setConfigKey,
} from '../cli-config'
import * as cliConfigModule from '../cli-config'
import { readFile, writeFile, yamlExists } from '../io-util'

Expand Down Expand Up @@ -191,8 +199,8 @@ describe('cli-config', () => {
profileName: 'chosenProfile',
}

const profiles: ProfilesByName = { mainConfig: { mainConfigProfile: { key: 'value' } } }
const managedProfiles: ProfilesByName = { managedConfig: { managedConfigProfile: { key: 'value' } } }
const profiles: ProfilesByName = { mainConfigProfile: { key: 'value' } }
const managedProfiles: ProfilesByName = { managedConfigProfile: { key: 'value' } }

const yamlDumpMock = jest.mocked(yaml.dump)
const writeFileMock = jest.mocked(writeFile)
Expand Down Expand Up @@ -277,6 +285,71 @@ describe('cli-config', () => {
expect(mergeProfilesSpy).toHaveBeenCalledWith(profiles, updatedManagedConfig)
})

describe('resetManagedConfigKey', () => {
const deepCopy = <T> (input: T): T => JSON.parse(JSON.stringify(input))
const makeConfig = (profiles: ProfilesByName, managedProfiles: ProfilesByName): CLIConfig => deepCopy({
...description,
profileName: 'defaultProfile',
profiles,
managedProfiles,
mergedProfiles: mergeProfiles(profiles, managedProfiles),
} as CLIConfig)

const profilesWithKeyToRemove: ProfilesByName = {
profile1: {
keyToRemove: 'remove value',
},
profile2: {
keyToRemove: 'value to remove',
},
}
const profilesWithKeysRemoved: ProfilesByName = {
profile1: {},
profile2: {},
}

const predicateMock = jest.fn()

it('does nothing when key not present', async () => {
const cliConfig = makeConfig(profiles, managedProfiles)

await expect(resetManagedConfigKey(cliConfig, 'unusedKey', predicateMock)).resolves.not.toThrow()

expect(cliConfig).toStrictEqual(makeConfig(profiles, managedProfiles))
expect(predicateMock).toHaveBeenCalledTimes(0)
})

it('does not modify user config', async () => {
const cliConfig = makeConfig(profilesWithKeyToRemove, managedProfiles)

predicateMock.mockReturnValue(true)
await expect(resetManagedConfigKey(cliConfig, 'keyToRemove', predicateMock)).resolves.not.toThrow()

expect(cliConfig).toStrictEqual(makeConfig(profilesWithKeyToRemove, managedProfiles))
expect(predicateMock).toHaveBeenCalledTimes(0)
})

it('keeps keys that fail predicate', async () => {
const cliConfig = makeConfig(profiles, profilesWithKeyToRemove)

predicateMock.mockReturnValue(false)
await expect(resetManagedConfigKey(cliConfig, 'keyToRemove', predicateMock)).resolves.not.toThrow()

expect(cliConfig).toStrictEqual(makeConfig(profiles, profilesWithKeyToRemove))
expect(predicateMock).toHaveBeenCalledTimes(2)
})

it('removes managed keys that match predicate', async () => {
const cliConfig = makeConfig(profiles, profilesWithKeyToRemove)

predicateMock.mockReturnValue(true)
await expect(resetManagedConfigKey(cliConfig, 'keyToRemove', predicateMock)).resolves.not.toThrow()

expect(cliConfig).toStrictEqual(makeConfig(profiles, profilesWithKeysRemoved))
expect(predicateMock).toHaveBeenCalledTimes(2)
})
})

test('resetManagedConfig', async () => {
const managedProfilesWithProfileToReset: ProfilesByName = { ...managedProfiles, profileToReset: { not: 'empty' } }
const cliConfig = {
Expand All @@ -289,7 +362,7 @@ describe('cli-config', () => {
yamlDumpMock.mockReturnValueOnce('yaml output')
mergeProfilesSpy.mockReturnValueOnce(updateMergedConfig)

expect(await resetManagedConfig(cliConfig, 'profileToReset')).resolves.not.toThrow
await expect(resetManagedConfig(cliConfig, 'profileToReset')).resolves.not.toThrow()

expect(cliConfig.managedProfiles.profileToReset).toBeUndefined()
expect(cliConfig.mergedProfiles).toBe(updateMergedConfig)
Expand Down
18 changes: 18 additions & 0 deletions packages/lib/src/cli-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ export const setConfigKey = async (config: CLIConfig, key: string, value: unknow
config.mergedProfiles = mergeProfiles(config.profiles, config.managedProfiles)
}

/**
* Reset the specified managed config key for for all profiles. The `predicate` is called for each
* value found and the key will only be reset if it returns true.
*
* This can be used to wipe out default values when something is deleted.
*/
export const resetManagedConfigKey = async (config: CLIConfig, key: string, predicate: (value: unknown) => boolean): Promise<void> => {
config.managedProfiles = Object.fromEntries(Object.entries(config.managedProfiles).map(([profileName, profile]) => {
if (key in profile && predicate(profile[key])) {
delete profile[key]
}
return [profileName, profile]
}))

await writeFile(config.managedConfigFilename, managedConfigHeader + yaml.dump(config.managedProfiles))
config.mergedProfiles = mergeProfiles(config.profiles, config.managedProfiles)
}

/**
* Reset all managed config options for the specified profile.
*/
Expand Down
1 change: 1 addition & 0 deletions packages/testlib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jest.mock('@smartthings/cli-lib', () => {
calculateOutputFormat: jest.fn(),
writeOutput: jest.fn(),
buildOutputFormatter: jest.fn(),
resetManagedConfigKey: jest.fn(),
}
})

Expand Down