-
Notifications
You must be signed in to change notification settings - Fork 821
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: append whitespace to cli-inputs.json for updated build dir (#11024
) * feat: detect when attrs is added to cfn template and append whitespace for amplify push * test: add unit test to cover appending whitespace to cli-inputs.json file
- Loading branch information
1 parent
262276a
commit 92536d7
Showing
3 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
112 changes: 112 additions & 0 deletions
112
packages/amplify-cli/src/__tests__/extensions/amplify-helpers/update-tracked-files.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import fs from 'fs-extra'; | ||
import { updateCognitoTrackedFiles } from '../../../extensions/amplify-helpers/update-tracked-files'; | ||
|
||
const cloudBackendCfnTemplatePath = '/amplify/#cloud-backend/auth/cognito/build/cognito-cloudformation-template.json'; | ||
const backendCfnTemplatePath = '/amplify/backend/auth/cognito/build/cognito-cloudformation-template.json'; | ||
const cliInputsFile = '/amplify/backend/auth/cognito/cli-inputs.json'; | ||
|
||
let cloudBackendExists: boolean; | ||
let setInCloudBackendDir: boolean; | ||
|
||
jest.mock('amplify-cli-core', () => { | ||
const { stateManager } = jest.requireActual('amplify-cli-core'); | ||
|
||
return { | ||
JSONUtilities: { | ||
readJson: jest.fn().mockImplementation(path => { | ||
const cfnTemplate = { | ||
Resources: { | ||
UserPool: { | ||
Properties: {}, | ||
}, | ||
}, | ||
}; | ||
|
||
if ((path === cloudBackendCfnTemplatePath && setInCloudBackendDir) || path === backendCfnTemplatePath) { | ||
cfnTemplate.Resources.UserPool.Properties = { | ||
UserAttributeUpdateSettings: { | ||
AttributesRequireVerificationBeforeUpdate: [ | ||
'email', | ||
], | ||
}, | ||
}; | ||
} | ||
|
||
return cfnTemplate; | ||
}), | ||
}, | ||
pathManager: { | ||
getBackendDirPath: jest.fn().mockReturnValue('/amplify/backend'), | ||
getCurrentCloudBackendDirPath: jest.fn().mockReturnValue('/amplify/#cloud-backend'), | ||
}, | ||
stateManager: { | ||
...stateManager, | ||
getMeta: jest.fn().mockReturnValue({ | ||
auth: { | ||
cognito: { | ||
service: 'Cognito', | ||
}, | ||
}, | ||
}), | ||
}, | ||
}; | ||
}); | ||
|
||
describe('updateCognitoTrackedFiles', () => { | ||
const fsMock = fs as jest.Mocked<typeof fs>; | ||
|
||
beforeEach(() => { | ||
fsMock.existsSync = jest.fn().mockImplementation(path => { | ||
if (path === '/amplify/#cloud-backend') { | ||
return cloudBackendExists; | ||
} | ||
return true; | ||
}); | ||
|
||
fsMock.appendFile = jest.fn(); | ||
}); | ||
|
||
afterEach(() => { | ||
fsMock.existsSync.mockReset(); | ||
fsMock.appendFile.mockReset(); | ||
|
||
cloudBackendExists = false; | ||
setInCloudBackendDir = false; | ||
}); | ||
|
||
describe('when backend and cloud backend do not match', () => { | ||
beforeEach(() => { | ||
cloudBackendExists = true; | ||
setInCloudBackendDir = false; | ||
}); | ||
|
||
it('appends white space', async () => { | ||
await updateCognitoTrackedFiles(); | ||
expect(fsMock.appendFile).toHaveBeenCalledTimes(1); | ||
expect(fsMock.appendFile).toBeCalledWith(cliInputsFile, ' '); | ||
}); | ||
}); | ||
|
||
describe('when backend and cloud backend do match', () => { | ||
beforeEach(() => { | ||
cloudBackendExists = true; | ||
setInCloudBackendDir = true; | ||
}); | ||
|
||
it('does not append white space', async () => { | ||
await updateCognitoTrackedFiles(); | ||
expect(fsMock.appendFile).toHaveBeenCalledTimes(0); | ||
}); | ||
}); | ||
|
||
describe('when cloud backend does not exist', () => { | ||
beforeEach(() => { | ||
cloudBackendExists = false; | ||
}); | ||
|
||
it('does not append white space', async () => { | ||
await updateCognitoTrackedFiles(); | ||
expect(fsMock.appendFile).toHaveBeenCalledTimes(0); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
packages/amplify-cli/src/extensions/amplify-helpers/update-tracked-files.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import * as path from 'path'; | ||
import fs from 'fs-extra'; | ||
import { | ||
$TSAny, JSONUtilities, pathManager, stateManager, | ||
} from 'amplify-cli-core'; | ||
|
||
const { | ||
readJson, | ||
} = JSONUtilities; | ||
|
||
/** | ||
* Updates Cognito files that are tracked so that the diff is detected for an `amplify push` | ||
*/ | ||
export const updateCognitoTrackedFiles = async (): Promise<void> => { | ||
const currentCloudBackendDir = pathManager.getCurrentCloudBackendDirPath(); | ||
const localBackendDir = pathManager.getBackendDirPath(); | ||
const amplifyMeta = stateManager.getMeta(); | ||
const cognitoResource = stateManager.getResourceFromMeta(amplifyMeta, 'auth', 'Cognito', undefined, false); | ||
|
||
if (!fs.existsSync(currentCloudBackendDir) || !cognitoResource) { | ||
return; | ||
} | ||
|
||
const { resourceName } = cognitoResource; | ||
|
||
if (await detectCognitoDiff(currentCloudBackendDir, localBackendDir, resourceName)) { | ||
await addExtraLineToCliInputsJson(localBackendDir, resourceName); | ||
} | ||
}; | ||
|
||
const detectCognitoDiff = async ( | ||
currentCloudBackendDir: string, | ||
localBackendDir: string, | ||
resourceName: string, | ||
): Promise<boolean> => detectCognitoAttributesRequireVerificationBeforeUpdateDiff( | ||
currentCloudBackendDir, | ||
localBackendDir, | ||
resourceName, | ||
); | ||
|
||
const detectCognitoAttributesRequireVerificationBeforeUpdateDiff = async ( | ||
currentCloudBackendDir: string, | ||
localBackendDir: string, | ||
resourceName: string, | ||
): Promise<boolean> => { | ||
const cloudBackendUserAttrUpdateSettings = await readCfnTemplateUserAttributeSettings(currentCloudBackendDir, resourceName); | ||
const backendUserAttrUpdateSettings = await readCfnTemplateUserAttributeSettings(localBackendDir, resourceName); | ||
const updateNotInCloudBackend: boolean = !cloudBackendUserAttrUpdateSettings?.AttributesRequireVerificationBeforeUpdate | ||
|| cloudBackendUserAttrUpdateSettings?.AttributesRequireVerificationBeforeUpdate[0] !== 'email'; | ||
const updateInLocalBackend: boolean = backendUserAttrUpdateSettings?.AttributesRequireVerificationBeforeUpdate.length === 1 | ||
&& backendUserAttrUpdateSettings?.AttributesRequireVerificationBeforeUpdate[0] === 'email'; | ||
|
||
return updateNotInCloudBackend && updateInLocalBackend; | ||
}; | ||
|
||
type UserAttributeUpdateSettings = { | ||
AttributesRequireVerificationBeforeUpdate: string[] | ||
} | ||
|
||
const readCfnTemplateUserAttributeSettings = async ( | ||
backendDir: string, | ||
resourceName: string, | ||
): Promise<UserAttributeUpdateSettings | undefined> => { | ||
const cfnTemplatePath = path.join(backendDir, 'auth', resourceName, 'build', `${resourceName}-cloudformation-template.json`); | ||
const cfnTemplate: $TSAny = readJson(cfnTemplatePath, { throwIfNotExist: false }); | ||
|
||
if (!cfnTemplate) { | ||
return undefined; | ||
} | ||
|
||
return cfnTemplate.Resources.UserPool?.Properties?.UserAttributeUpdateSettings; | ||
}; | ||
|
||
const addExtraLineToCliInputsJson = async (backendDir: string, resourceName: string): Promise<void> => { | ||
const cliInputsFile = path.join(backendDir, 'auth', resourceName, 'cli-inputs.json'); | ||
|
||
if (fs.existsSync(cliInputsFile)) { | ||
fs.appendFile(cliInputsFile, ' '); | ||
} | ||
}; |