Skip to content
This repository was archived by the owner on Apr 13, 2020. It is now read-only.
Merged
3 changes: 0 additions & 3 deletions src/commands/hld/reconcile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// eslint-disable-next-line @typescript-eslint/camelcase
import child_process from "child_process";
import commander from "commander";
import fs from "fs";
Expand Down Expand Up @@ -28,7 +27,6 @@ import { errorStatusCode } from "../../lib/errorStatusCode";
* reject()
*/
interface ExecResult {
// eslint-disable-next-line @typescript-eslint/camelcase
error?: child_process.ExecException;
value?: { stdout: string; stderr: string };
}
Expand All @@ -43,7 +41,6 @@ interface ExecResult {
*/
const exec = async (cmd: string, pipeIO = false): Promise<ExecResult> => {
return new Promise<ExecResult>((resolve) => {
// eslint-disable-next-line @typescript-eslint/camelcase
const child = child_process.exec(cmd, (error, stdout, stderr) => {
return resolve({
error: error ?? undefined,
Expand Down
28 changes: 20 additions & 8 deletions src/commands/project/create-variable-group.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import fs from "fs";
import yaml from "js-yaml";
import mockFs from "mock-fs";
Expand Down Expand Up @@ -252,7 +251,10 @@ describe("setVariableGroupInBedrockFile", () => {
const bedrockFile = readBedrockFile(randomTmpDir);

logger.info(`filejson: ${JSON.stringify(bedrockFile)}`);
expect(bedrockFile.variableGroups![0]).toBe(variableGroupName);
expect(bedrockFile.variableGroups).toBeDefined();
if (bedrockFile.variableGroups) {
expect(bedrockFile.variableGroups[0]).toBe(variableGroupName);
}
});

test("Should pass adding a valid variable group name when bedrock file exists when variableGroups length is > 0", async () => {
Expand All @@ -273,8 +275,11 @@ describe("setVariableGroupInBedrockFile", () => {

const bedrockFile = readBedrockFile(randomTmpDir);
logger.info(`filejson: ${JSON.stringify(bedrockFile)}`);
expect(bedrockFile.variableGroups![0]).toBe(prevariableGroupName);
expect(bedrockFile.variableGroups![1]).toBe(variableGroupName);
expect(bedrockFile.variableGroups).toBeDefined();
if (bedrockFile.variableGroups) {
expect(bedrockFile.variableGroups[0]).toBe(prevariableGroupName);
expect(bedrockFile.variableGroups[1]).toBe(variableGroupName);
}
});
});

Expand Down Expand Up @@ -343,7 +348,10 @@ describe("updateLifeCyclePipeline", () => {

const hldLifeCycleYaml = readYaml<AzurePipelinesYaml>(hldFilePath);
logger.info(`filejson: ${JSON.stringify(hldLifeCycleYaml)}`);
expect(hldLifeCycleYaml.variables!.length).toBeLessThanOrEqual(0);
expect(hldLifeCycleYaml.variables).toBeDefined();
if (hldLifeCycleYaml.variables) {
expect(hldLifeCycleYaml.variables.length).toBeLessThanOrEqual(0);
}
});

test("Should pass adding variable groups when bedrock file exists with one variableGroup", async () => {
Expand Down Expand Up @@ -379,9 +387,13 @@ describe("updateLifeCyclePipeline", () => {

const hldLifeCycleYaml = readYaml<AzurePipelinesYaml>(hldFilePath);
logger.info(`filejson: ${JSON.stringify(hldLifeCycleYaml)}`);
expect(hldLifeCycleYaml.variables![0]).toEqual({
group: variableGroupName,
});
expect(hldLifeCycleYaml.variables).toBeDefined();

if (hldLifeCycleYaml.variables) {
expect(hldLifeCycleYaml.variables[0]).toEqual({
group: variableGroupName,
});
}
});
});

Expand Down
226 changes: 112 additions & 114 deletions src/commands/project/create-variable-group.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-use-before-define */

import { VariableGroup } from "azure-devops-node-api/interfaces/ReleaseInterfaces";
import commander from "commander";
import path from "path";
Expand Down Expand Up @@ -55,118 +53,6 @@ export const validateValues = (projectName: string, orgName: string): void => {
validateOrgNameThrowable(orgName);
};

/**
* Executes the command.
*
* @param variableGroupName Variable Group Name
* @param opts Option object from command
*/
export const execute = async (
variableGroupName: string,
opts: CommandOptions,
exitFn: (status: number) => Promise<void>
): Promise<void> => {
if (!hasValue(variableGroupName)) {
await exitFn(1);
return;
}

try {
const projectPath = process.cwd();
logger.verbose(`project path: ${projectPath}`);

checkDependencies(projectPath);

const { azure_devops } = Config();

const {
registryName,
servicePrincipalId,
servicePrincipalPassword,
tenant,
hldRepoUrl = azure_devops?.hld_repository,
orgName = azure_devops?.org,
personalAccessToken = azure_devops?.access_token,
devopsProject = azure_devops?.project,
} = opts;

const accessOpts: AzureDevOpsOpts = {
orgName,
personalAccessToken,
project: devopsProject,
};

logger.debug(`access options: ${JSON.stringify(accessOpts)}`);

const errors = validateForRequiredValues(decorator, {
devopsProject,
hldRepoUrl,
orgName,
personalAccessToken,
registryName,
servicePrincipalId,
servicePrincipalPassword,
tenant,
});

if (errors.length !== 0) {
await exitFn(1);
return;
}

// validateForRequiredValues assure that devopsProject
// and orgName are not empty string
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
validateValues(devopsProject!, orgName!);

const variableGroup = await create(
variableGroupName,
registryName,
hldRepoUrl,
servicePrincipalId,
servicePrincipalPassword,
tenant,
accessOpts
);

// set the variable group name
// variableGroup.name is set at this point that's it should have value
// and not empty string or undefined. having || "" is just to avoid
// eslint error
setVariableGroupInBedrockFile(projectPath, variableGroup.name || "");

// update hld-lifecycle.yaml with variable groups in bedrock.yaml
updateLifeCyclePipeline(projectPath);

// print newly created variable group
echo(JSON.stringify(variableGroup, null, 2));

logger.info(
"Successfully created a variable group in Azure DevOps project!"
);
await exitFn(0);
} catch (err) {
logger.error(`Error occurred while creating variable group`);
logger.error(err);
await exitFn(1);
}
};

/**
* Adds the create command to the variable-group command object
*
* @param command Commander command object to decorate
*/
export const commandDecorator = (command: commander.Command): void => {
buildCmd(command, decorator).action(
async (variableGroupName: string, opts: CommandOptions) => {
await execute(variableGroupName, opts, async (status: number) => {
await exitCmd(logger, process.exit, status);
});
}
);
};

/**
* Creates a Azure DevOps variable group
*
Expand Down Expand Up @@ -319,3 +205,115 @@ export const updateLifeCyclePipeline = (rootProjectPath: string): void => {
// Write out
write(pipelineFile, absProjectRoot, fileName);
};

/**
* Executes the command.
*
* @param variableGroupName Variable Group Name
* @param opts Option object from command
*/
export const execute = async (
variableGroupName: string,
opts: CommandOptions,
exitFn: (status: number) => Promise<void>
): Promise<void> => {
if (!hasValue(variableGroupName)) {
await exitFn(1);
return;
}

try {
const projectPath = process.cwd();
logger.verbose(`project path: ${projectPath}`);

checkDependencies(projectPath);

const { azure_devops } = Config();

const {
registryName,
servicePrincipalId,
servicePrincipalPassword,
tenant,
hldRepoUrl = azure_devops?.hld_repository,
orgName = azure_devops?.org,
personalAccessToken = azure_devops?.access_token,
devopsProject = azure_devops?.project,
} = opts;

const accessOpts: AzureDevOpsOpts = {
orgName,
personalAccessToken,
project: devopsProject,
};

logger.debug(`access options: ${JSON.stringify(accessOpts)}`);

const errors = validateForRequiredValues(decorator, {
devopsProject,
hldRepoUrl,
orgName,
personalAccessToken,
registryName,
servicePrincipalId,
servicePrincipalPassword,
tenant,
});

if (errors.length !== 0) {
await exitFn(1);
return;
}

// validateForRequiredValues assure that devopsProject
// and orgName are not empty string
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
validateValues(devopsProject!, orgName!);

const variableGroup = await create(
variableGroupName,
registryName,
hldRepoUrl,
servicePrincipalId,
servicePrincipalPassword,
tenant,
accessOpts
);

// set the variable group name
// variableGroup.name is set at this point that's it should have value
// and not empty string or undefined. having || "" is just to avoid
// eslint error
setVariableGroupInBedrockFile(projectPath, variableGroup.name || "");

// update hld-lifecycle.yaml with variable groups in bedrock.yaml
updateLifeCyclePipeline(projectPath);

// print newly created variable group
echo(JSON.stringify(variableGroup, null, 2));

logger.info(
"Successfully created a variable group in Azure DevOps project!"
);
await exitFn(0);
} catch (err) {
logger.error(`Error occurred while creating variable group`);
logger.error(err);
await exitFn(1);
}
};

/**
* Adds the create command to the variable-group command object
*
* @param command Commander command object to decorate
*/
export const commandDecorator = (command: commander.Command): void => {
buildCmd(command, decorator).action(
async (variableGroupName: string, opts: CommandOptions) => {
await execute(variableGroupName, opts, async (status: number) => {
await exitCmd(logger, process.exit, status);
});
}
);
};
7 changes: 4 additions & 3 deletions src/commands/project/pipeline.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import {
checkDependencies,
execute,
fetchValidateValues,
CommandOptions,
ConfigValues,
installLifecyclePipeline,
CommandOptions,
} from "./pipeline";
import { deepClone } from "../../lib/util";

Expand All @@ -29,7 +30,7 @@ afterAll(() => {

const gitUrl = "https://github.com/CatalystCode/spk.git";

const mockValues: CommandOptions = {
const mockValues: ConfigValues = {
buildScriptUrl: "buildScriptUrl",
devopsProject: "azDoProject",
orgName: "orgName",
Expand All @@ -40,7 +41,7 @@ const mockValues: CommandOptions = {
yamlFileBranch: "master",
};

jest.spyOn(azdo, "validateRepository").mockReturnValue(Promise.resolve());
jest.spyOn(azdo, "validateRepository").mockResolvedValue();

const mockMissingValues: CommandOptions = {
buildScriptUrl: undefined,
Expand Down
Loading