Skip to content
This repository was archived by the owner on Apr 13, 2020. It is now read-only.
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
11 changes: 11 additions & 0 deletions input1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
azdo_org_name=veseah
azdo_project_name=SPK12345
azdo_pat=doegx7fx26zj5gwgzlbz4rphh5h5dzwqelxaucibyvgxp45vhlna
az_create_app=true
az_create_sp=false
az_sp_id=53441b1b-132e-4dba-992f-9009d86ddfa3
az_sp_password=e79ff863-5b90-4340-b9e9-f7cede7a03bd
az_sp_tenant=72f988bf-86f1-41af-91ab-2d7cd011db47
az_subscription_id=dd831253-787f-4dc8-8eb0-ac9d052177d9
az_acr_name=quickStartACR

6 changes: 3 additions & 3 deletions src/commands/project/create-variable-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export const setVariableGroupInBedrockFile = (
const bedrockFile = Bedrock(rootProjectPath);

if (typeof bedrockFile === "undefined") {
throw new Error(`Bedrock file does not exist.`);
throw Error(`Bedrock file does not exist.`);
}

logger.verbose(
Expand All @@ -259,10 +259,10 @@ export const setVariableGroupInBedrockFile = (
*/
export const updateLifeCyclePipeline = (rootProjectPath: string): void => {
if (!hasValue(rootProjectPath)) {
throw new Error("Project root path is not valid");
throw Error("Project root path is not valid");
}

const fileName: string = PROJECT_PIPELINE_FILENAME;
const fileName = PROJECT_PIPELINE_FILENAME;
const absProjectRoot = path.resolve(rootProjectPath);

// Get bedrock.yaml
Expand Down
13 changes: 9 additions & 4 deletions src/commands/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ for a few questions
2. Subscription Id is automatically retrieved with the Service Principal
credential. In case, there are two or more subscriptions, you will be
prompt to select one of them.
3. Create a resource group, `quick-start-rg` if it does not exist.
4. Create a Azure Container Registry, `quickStartACR` in resource group,
`quick-start-rg` if it does not exist.

It can also run in a non interactive mode by providing a file that contains
answers to the above questions.
Expand Down Expand Up @@ -58,7 +55,15 @@ The followings shall be created
already exists.
1. And initial commit shall be made to this repo
5. A High Level Definition (HLD) to Manifest pipeline.
6. A Service Principal (if requested)
6. If user chose to create sample app repo
1. A Service Principal (if requested)
2. A resource group, `quick-start-rg` if it does not exist.
3. A Azure Container Registry, `quickStartACR` in resource group,
`quick-start-rg` if it does not exist.
4. A Git Repo, `quick-start-helm`, it shall be deleted and recreated if is
already exists.
5. A Git Repo, `quick-start-app`, it shall be deleted and recreated if is
already exists.

## Setup log

Expand Down
6 changes: 4 additions & 2 deletions src/commands/setup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ const testExecuteFunc = async (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.mockReturnValueOnce(Promise.resolve({} as any));
jest.spyOn(fsUtil, "createDirectory").mockReturnValueOnce();
jest.spyOn(scaffold, "hldRepo").mockReturnValueOnce(Promise.resolve());
jest.spyOn(scaffold, "manifestRepo").mockReturnValueOnce(Promise.resolve());
jest.spyOn(scaffold, "hldRepo").mockResolvedValueOnce();
jest.spyOn(scaffold, "manifestRepo").mockResolvedValueOnce();
jest.spyOn(scaffold, "helmRepo").mockResolvedValueOnce();
jest.spyOn(scaffold, "appRepo").mockResolvedValueOnce();
jest
.spyOn(pipelineService, "createHLDtoManifestPipeline")
.mockReturnValueOnce(Promise.resolve());
Expand Down
70 changes: 42 additions & 28 deletions src/commands/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { create as createACR } from "../lib/azure/containerRegistryService";
import { create as createResourceGroup } from "../lib/azure/resourceService";
import { build as buildCmd, exit as exitCmd } from "../lib/commandBuilder";
import {
ACR,
RequestContext,
RESOURCE_GROUP,
RESOURCE_GROUP_LOCATION,
Expand All @@ -18,10 +17,16 @@ import { getGitApi } from "../lib/setup/gitService";
import { createHLDtoManifestPipeline } from "../lib/setup/pipelineService";
import { createProjectIfNotExist } from "../lib/setup/projectService";
import { getAnswerFromFile, prompt } from "../lib/setup/prompt";
import { hldRepo, manifestRepo } from "../lib/setup/scaffold";
import {
appRepo,
helmRepo,
hldRepo,
manifestRepo
} from "../lib/setup/scaffold";
import { create as createSetupLog } from "../lib/setup/setupLog";
import { logger } from "../logger";
import decorator from "./setup.decorator.json";
import { IGitApi } from "azure-devops-node-api/GitApi";

interface CommandOptions {
file: string | undefined;
Expand Down Expand Up @@ -79,6 +84,40 @@ export const getErrorMessage = (
return err.toString();
};

export const createAppRepoTasks = async (
gitAPI: IGitApi,
rc: RequestContext
): Promise<void> => {
if (
rc.toCreateAppRepo &&
rc.servicePrincipalId &&
rc.servicePrincipalPassword &&
rc.servicePrincipalTenantId &&
rc.subscriptionId &&
rc.acrName
) {
rc.createdResourceGroup = await createResourceGroup(
rc.servicePrincipalId,
rc.servicePrincipalPassword,
rc.servicePrincipalTenantId,
rc.subscriptionId,
RESOURCE_GROUP,
RESOURCE_GROUP_LOCATION
);
rc.createdACR = await createACR(
rc.servicePrincipalId,
rc.servicePrincipalPassword,
rc.servicePrincipalTenantId,
rc.subscriptionId,
RESOURCE_GROUP,
rc.acrName,
RESOURCE_GROUP_LOCATION
);
await helmRepo(gitAPI, rc);
await appRepo(gitAPI, rc);
}
};

/**
* Executes the command, can all exit function with 0 or 1
* when command completed successfully or failed respectively.
Expand Down Expand Up @@ -106,32 +145,7 @@ export const execute = async (
await hldRepo(gitAPI, requestContext);
await manifestRepo(gitAPI, requestContext);
await createHLDtoManifestPipeline(buildAPI, requestContext);

if (
requestContext.toCreateAppRepo &&
requestContext.servicePrincipalId &&
requestContext.servicePrincipalPassword &&
requestContext.servicePrincipalTenantId &&
requestContext.subscriptionId
) {
requestContext.createdResourceGroup = await createResourceGroup(
requestContext.servicePrincipalId,
requestContext.servicePrincipalPassword,
requestContext.servicePrincipalTenantId,
requestContext.subscriptionId,
RESOURCE_GROUP,
RESOURCE_GROUP_LOCATION
);
requestContext.createdACR = await createACR(
requestContext.servicePrincipalId,
requestContext.servicePrincipalPassword,
requestContext.servicePrincipalTenantId,
requestContext.subscriptionId,
RESOURCE_GROUP,
ACR,
RESOURCE_GROUP_LOCATION
);
}
await createAppRepoTasks(gitAPI, requestContext);

createSetupLog(requestContext);
await exitFn(0);
Expand Down
11 changes: 7 additions & 4 deletions src/lib/azure/containerRegistryService.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { RegistriesCreateResponse } from "@azure/arm-containerregistry/src/models";
import {
RegistriesCreateResponse,
RegistriesListResponse
} from "@azure/arm-containerregistry/src/models";

import * as restAuth from "@azure/ms-rest-nodeauth";
import {
Expand All @@ -17,15 +20,15 @@ jest.mock("@azure/arm-containerregistry", () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return {} as any;
},
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
list: () => {
list: (): Promise<RegistriesListResponse> => {
return [
{
id:
"/subscriptions/dd831253-787f-4dc8-8eb0-ac9d052177d9/resourceGroups/bedrockSPK/providers/Microsoft.ContainerRegistry/registries/acrWest",
name: "acrWest"
}
];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
] as any;
}
}
};
Expand Down
11 changes: 7 additions & 4 deletions src/lib/azure/resourceService.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { ResourceGroupsCreateOrUpdateResponse } from "@azure/arm-resources/src/models";
import {
ResourceGroupsCreateOrUpdateResponse,
ResourceGroupsListResponse
} from "@azure/arm-resources/src/models";
import * as restAuth from "@azure/ms-rest-nodeauth";
import { create, getResourceGroups, isExist } from "./resourceService";
import * as resourceService from "./resourceService";
Expand All @@ -16,15 +19,15 @@ jest.mock("@azure/arm-resources", () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return {} as any;
},
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
list: () => {
list: (): Promise<ResourceGroupsListResponse> => {
return [
{
id: "1234567890-abcdef",
location: RESOURCE_GROUP_LOCATION,
name: "test"
}
];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
] as any;
}
}
};
Expand Down
32 changes: 31 additions & 1 deletion src/lib/pipelines/variableGroup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import {
VariableGroupParameters
} from "azure-devops-node-api/interfaces/TaskAgentInterfaces";
import uuid from "uuid/v4";
import * as azdoClient from "../azdoClient";
import { readYaml } from "../../config";
import * as config from "../../config";
import * as azdoClient from "../azdoClient";
import {
disableVerboseLogging,
enableVerboseLogging,
Expand All @@ -17,6 +17,7 @@ import {
addVariableGroupWithKeyVaultMap,
authorizeAccessToAllPipelines,
buildVariablesMap,
deleteVariableGroup,
doAddVariableGroup
} from "./variableGroup";

Expand Down Expand Up @@ -403,3 +404,32 @@ describe("buildVariablesMap", () => {
expect(Object.keys(secretsMap).length).toBe(0);
});
});

describe("test deleteVariableGroup function", () => {
it("positive test: group found", async () => {
const delFn = jest.fn();
jest.spyOn(azdoClient, "getTaskAgentApi").mockResolvedValue({
deleteVariableGroup: delFn,
getVariableGroups: () => [
{
id: "test"
}
]
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any);
const deleted = await deleteVariableGroup({}, "test");
expect(delFn).toBeCalledTimes(1);
expect(deleted).toBeTruthy();
});
it("positive test: no matching groups found", async () => {
const delFn = jest.fn();
jest.spyOn(azdoClient, "getTaskAgentApi").mockResolvedValue({
deleteVariableGroup: delFn,
getVariableGroups: () => []
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any);
const deleted = await deleteVariableGroup({}, "test");
expect(delFn).toBeCalledTimes(0);
expect(deleted).toBeFalsy();
});
});
23 changes: 23 additions & 0 deletions src/lib/pipelines/variableGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,26 @@ export const addVariableGroupWithKeyVaultMap = async (
throw err;
}
};

/**
* Deletes variable group
*
* @param opts optionally override spk config with Azure DevOps access options
* @param name Name of group to be deleted.
* @returns true if group exists and deleted.
*/
export const deleteVariableGroup = async (
opts: AzureDevOpsOpts,
name: string
): Promise<boolean> => {
const taskClient = await getTaskAgentApi(opts);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const project = opts.project!;

const groups = await taskClient.getVariableGroups(project, name);
if (groups && groups.length > 0 && groups[0].id) {
await taskClient.deleteVariableGroup(project, groups[0].id);
return true;
}
return false;
};
7 changes: 6 additions & 1 deletion src/lib/setup/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ export interface RequestContext {
projectName: string;
accessToken: string;
workspace: string;
acrName?: string;
toCreateAppRepo?: boolean;
toCreateSP?: boolean;
createdProject?: boolean;
scaffoldHLD?: boolean;
scaffoldManifest?: boolean;
scaffoldHelm?: boolean;
scaffoldAppService?: boolean;
createdHLDtoManifestPipeline?: boolean;
createServicePrincipal?: boolean;
servicePrincipalId?: string;
Expand All @@ -21,14 +24,16 @@ export interface RequestContext {

export const MANIFEST_REPO = "quick-start-manifest";
export const HLD_REPO = "quick-start-hld";
export const HELM_REPO = "quick-start-helm";
export const APP_REPO = "quick-start-app";
export const DEFAULT_PROJECT_NAME = "BedrockRocks";
export const APP_REPO_LIFECYCLE = "quick-start-lifecycle";
export const WORKSPACE = "quick-start-env";
export const SP_USER_NAME = "service_account";
export const RESOURCE_GROUP = "quick-start-rg";
export const RESOURCE_GROUP_LOCATION = "westus2";
export const ACR = "quickStartACR";
export const ACR_NAME = "quickStartACR";
export const VARIABLE_GROUP = "quick-start-vg";
export const SETUP_LOG = "setup.log";

export const HLD_DEFAULT_GIT_URL =
Expand Down
Loading