diff --git a/docs/commands/data.json b/docs/commands/data.json index 38057dc8f..7bb3e0918 100644 --- a/docs/commands/data.json +++ b/docs/commands/data.json @@ -226,6 +226,11 @@ } ] }, + "hld append-variable-group": { + "command": "append-variable-group ", + "alias": "avg", + "description": "Appends the name of an existing variable group to the current manifest-generation.yaml file." + }, "hld init": { "command": "init", "alias": "i", diff --git a/src/commands/hld/append-variable-group.decorator.json b/src/commands/hld/append-variable-group.decorator.json new file mode 100644 index 000000000..8ee25be23 --- /dev/null +++ b/src/commands/hld/append-variable-group.decorator.json @@ -0,0 +1,5 @@ +{ + "command": "append-variable-group ", + "alias": "avg", + "description": "Appends the name of an existing variable group to the current manifest-generation.yaml file." +} diff --git a/src/commands/hld/append-variable-group.test.ts b/src/commands/hld/append-variable-group.test.ts new file mode 100644 index 000000000..1303d8556 --- /dev/null +++ b/src/commands/hld/append-variable-group.test.ts @@ -0,0 +1,18 @@ +import { execute } from "./append-variable-group"; +import * as fileutils from "../../lib/fileutils"; + +describe("Test execute function", () => { + it("missing variable group name", async () => { + const exitFn = jest.fn(); + await execute("my-path", "", exitFn); + expect(exitFn).toBeCalledTimes(1); + expect(exitFn.mock.calls).toEqual([[1]]); + }); + it("appends variable group", async () => { + const exitFn = jest.fn(); + spyOn(fileutils, "appendVariableGroupToPipelineYaml"); + await execute("my-path", "my-vg", exitFn); + expect(exitFn).toBeCalledTimes(1); + expect(exitFn.mock.calls).toEqual([[0]]); + }); +}); diff --git a/src/commands/hld/append-variable-group.ts b/src/commands/hld/append-variable-group.ts new file mode 100644 index 000000000..004a05d29 --- /dev/null +++ b/src/commands/hld/append-variable-group.ts @@ -0,0 +1,52 @@ +import commander from "commander"; +import { build as buildCmd, exit as exitCmd } from "../../lib/commandBuilder"; +import { RENDER_HLD_PIPELINE_FILENAME } from "../../lib/constants"; +import { appendVariableGroupToPipelineYaml } from "../../lib/fileutils"; +import { logger } from "../../logger"; +import decorator from "./append-variable-group.decorator.json"; + +/** + * Executes the command, can call exit function with 0 or 1 + * when command completed successfully or failed respectively. + * + * @param hldRepoPath The hld repository path + * @param variableGroupName The variable group name + * @param exitFn exit function + */ +export const execute = async ( + hldRepoPath: string, + variableGroupName: string, + exitFn: (status: number) => Promise +): Promise => { + if (!variableGroupName) { + logger.error("Variable group name is missing."); + await exitFn(1); + return; + } + + try { + appendVariableGroupToPipelineYaml( + hldRepoPath, + RENDER_HLD_PIPELINE_FILENAME, + variableGroupName + ); + await exitFn(0); + } catch (err) { + logger.error(`Error occurred while appending variable group.`); + logger.error(err); + await exitFn(1); + } +}; + +/** + * Adds the init command to the commander command object + * @param command Commander command object to decorate + */ +export const commandDecorator = (command: commander.Command): void => { + buildCmd(command, decorator).action(async (variableGroupName: string) => { + const hldRepoPath = process.cwd(); + await execute(hldRepoPath, variableGroupName, async (status: number) => { + await exitCmd(logger, process.exit, status); + }); + }); +}; diff --git a/src/commands/hld/index.ts b/src/commands/hld/index.ts index 9bde8bdea..8fda88d79 100644 --- a/src/commands/hld/index.ts +++ b/src/commands/hld/index.ts @@ -1,6 +1,6 @@ import { Command } from "../command"; -const subfolders = ["init", "pipeline", "reconcile"]; +const subfolders = ["init", "pipeline", "reconcile", "append-variable-group"]; export const commandDecorator = Command( "hld", diff --git a/src/lib/fileutils.test.ts b/src/lib/fileutils.test.ts index b978088cb..2b33c5b1e 100644 --- a/src/lib/fileutils.test.ts +++ b/src/lib/fileutils.test.ts @@ -28,6 +28,7 @@ import { disableVerboseLogging, enableVerboseLogging } from "../logger"; import { createTestComponentYaml, createTestHldAzurePipelinesYaml, + createTestHldAzurePipelinesYamlWithVariableGroup, createTestHldLifecyclePipelineYaml, createTestMaintainersYaml, createTestServiceBuildAndUpdatePipelineYaml, @@ -35,6 +36,7 @@ import { import { AccessYaml, AzurePipelinesYaml, MaintainersFile } from "../types"; import { addNewServiceToMaintainersFile, + appendVariableGroupToPipelineYaml, generateAccessYaml, generateDefaultHldComponentYaml, generateDockerfile, @@ -423,6 +425,44 @@ describe("generateHldAzurePipelinesYaml", () => { }); }); +describe("appendVariableGroupToHldAzurePipelinesYaml", () => { + const targetDirectory = "hld-repository"; + const writeSpy = jest.spyOn(fs, "writeFileSync"); + const appendSpy = jest.spyOn(fs, "appendFileSync"); + beforeEach(() => { + mockFs({ + "hld-repository": {}, + }); + }); + afterEach(() => { + mockFs.restore(); + }); + it("should append a variable group", () => { + const absTargetPath = path.resolve(targetDirectory); + const expectedFilePath = `${absTargetPath}/${RENDER_HLD_PIPELINE_FILENAME}`; + + const mockFsOptions = { + [`${targetDirectory}/${RENDER_HLD_PIPELINE_FILENAME}`]: createTestHldAzurePipelinesYaml() as string, + }; + mockFs(mockFsOptions); + + appendVariableGroupToPipelineYaml( + absTargetPath, + RENDER_HLD_PIPELINE_FILENAME, + "my-vg" + ); + expect(writeSpy).toBeCalledWith( + expectedFilePath, + `${getVersionMessage()}\n`, + "utf8" + ); + expect(appendSpy).toBeCalledWith( + expectedFilePath, + createTestHldAzurePipelinesYamlWithVariableGroup() + ); + }); +}); + describe("generateDefaultHldComponentYaml", () => { const targetDirectory = "hld-repository"; const writeSpy = jest.spyOn(fs, "writeFileSync"); diff --git a/src/lib/fileutils.ts b/src/lib/fileutils.ts index dd61588e5..9d1214378 100644 --- a/src/lib/fileutils.ts +++ b/src/lib/fileutils.ts @@ -19,6 +19,7 @@ import { MaintainersFile, User, } from "../types"; +import { readYaml, write } from "../config"; /** * Read given pipeline file as json object. @@ -470,6 +471,29 @@ export const updateTriggerBranchesForServiceBuildAndUpdatePipeline = ( ); }; +/** + * Appends a variable group an Azure pipeline yaml + * @param dir The directory where the pipeline yaml file is + * @param pipelineFile The name of the pipeline yaml file + * @param variableGroupName The name of the variable group to be added + */ +export const appendVariableGroupToPipelineYaml = ( + dir: string, + fileName: string, + variableGroupName: string +): void => { + const pipelineFile = readYaml(path.join(dir, fileName)) as AzurePipelinesYaml; + + if (!pipelineFile.variables) { + pipelineFile.variables = []; + } + + pipelineFile.variables.push({ group: variableGroupName }); + + logger.info(`Updating '${dir}/${fileName}'.`); + write(pipelineFile, dir, fileName); +}; + /** * Returns a the Manifest Generation Pipeline as defined here: https://github.com/microsoft/bedrock/blob/master/gitops/azure-devops/ManifestGeneration.md#add-azure-pipelines-build-yaml */ @@ -481,6 +505,7 @@ const manifestGenerationPipelineYaml = (): string => { include: ["master"], }, }, + variables: [], pool: { vmImage: VM_IMAGE, }, diff --git a/src/test/mockFactory.ts b/src/test/mockFactory.ts index 55f977a0f..79169bf9a 100644 --- a/src/test/mockFactory.ts +++ b/src/test/mockFactory.ts @@ -413,6 +413,7 @@ export const createTestHldAzurePipelinesYaml = ( include: ["master"], }, }, + variables: [], pool: { vmImage: VM_IMAGE, }, @@ -509,6 +510,19 @@ export const createTestHldAzurePipelinesYaml = ( : data; }; +export const createTestHldAzurePipelinesYamlWithVariableGroup = ( + asString = true +): AzurePipelinesYaml | string => { + const data: AzurePipelinesYaml = createTestHldAzurePipelinesYaml( + false + ) as AzurePipelinesYaml; + data.variables = [{ group: "my-vg" }]; + + return asString + ? yaml.safeDump(data, { lineWidth: Number.MAX_SAFE_INTEGER }) + : data; +}; + export const createTestComponentYaml = ( asString = true ): ComponentYaml | string => { diff --git a/tests/validations.sh b/tests/validations.sh index 9ad8e411c..2b950e680 100644 --- a/tests/validations.sh +++ b/tests/validations.sh @@ -153,7 +153,7 @@ spk hld install-manifest-pipeline --org-name $AZDO_ORG -d $AZDO_PROJECT --person # Will no longer be needed once install-manifest-pipeline supports adding a VG ################################## cd $hld_dir -printf "variables:\n - group: $vg_name\n" | cat - manifest-generation.yaml > temp && mv temp manifest-generation.yaml +spk hld append-variable-group $vg_name git add . git commit -m "Adding variable group $vg_name to pipeline" git push origin master