From 120bdfbf95ecc3700a16558c2a6553b225a989b0 Mon Sep 17 00:00:00 2001 From: Dennis Seah Date: Thu, 12 Mar 2020 13:16:39 -0700 Subject: [PATCH 1/5] [FEATURE] scaffold app and helm repo in spk setup command --- src/commands/project/create-variable-group.ts | 15 +- src/commands/setup.md | 13 +- src/commands/setup.test.ts | 6 +- src/commands/setup.ts | 52 +++--- src/lib/pipelines/variableGroup.test.ts | 29 ++++ src/lib/pipelines/variableGroup.ts | 20 +++ src/lib/setup/constants.ts | 4 + src/lib/setup/helmTemplates.ts | 67 ++++++++ src/lib/setup/scaffold.test.ts | 122 ++++++++++++++- src/lib/setup/scaffold.ts | 148 +++++++++++++++++- src/lib/setup/setupLog.test.ts | 10 ++ src/lib/setup/setupLog.ts | 2 + 12 files changed, 445 insertions(+), 43 deletions(-) create mode 100644 src/lib/setup/helmTemplates.ts diff --git a/src/commands/project/create-variable-group.ts b/src/commands/project/create-variable-group.ts index b629aed10..d8df95112 100644 --- a/src/commands/project/create-variable-group.ts +++ b/src/commands/project/create-variable-group.ts @@ -115,10 +115,10 @@ export const execute = async ( ); // set the variable group name - await setVariableGroupInBedrockFile(projectPath, variableGroup.name!); + setVariableGroupInBedrockFile(projectPath, variableGroup.name!); // update hld-lifecycle.yaml with variable groups in bedrock.yaml - await updateLifeCyclePipeline(projectPath); + updateLifeCyclePipeline(projectPath); // print newly created variable group echo(JSON.stringify(variableGroup, null, 2)); @@ -225,13 +225,10 @@ export const setVariableGroupInBedrockFile = ( const absProjectRoot = path.resolve(rootProjectPath); logger.info(`Setting variable group ${variableGroupName}`); - let bedrockFile: IBedrockFile | undefined; - - // Get bedrock.yaml - bedrockFile = Bedrock(rootProjectPath); + 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( @@ -257,10 +254,10 @@ export const setVariableGroupInBedrockFile = ( */ export const updateLifeCyclePipeline = (rootProjectPath: string) => { 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 diff --git a/src/commands/setup.md b/src/commands/setup.md index 35c7c0853..0a3829750 100644 --- a/src/commands/setup.md +++ b/src/commands/setup.md @@ -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. @@ -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 diff --git a/src/commands/setup.test.ts b/src/commands/setup.test.ts index a5a668de5..aa05bf9c9 100644 --- a/src/commands/setup.test.ts +++ b/src/commands/setup.test.ts @@ -76,8 +76,10 @@ const testExecuteFunc = async (usePrompt = true, hasProject = true) => { .spyOn(gitService, "getGitApi") .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()); diff --git a/src/commands/setup.ts b/src/commands/setup.ts index 41ce88dfe..b7e801156 100644 --- a/src/commands/setup.ts +++ b/src/commands/setup.ts @@ -18,7 +18,12 @@ 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"; @@ -81,6 +86,28 @@ export const getErrorMessage = ( return err.toString(); }; +export const createAppRepoTasks = async (rc: IRequestContext) => { + if (rc.toCreateAppRepo) { + 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, + ACR, + RESOURCE_GROUP_LOCATION + ); + } +}; + /** * Executes the command, can all exit function with 0 or 1 * when command completed successfully or failed respectively. @@ -109,26 +136,9 @@ export const execute = async ( await hldRepo(gitAPI, requestContext); await manifestRepo(gitAPI, requestContext); await createHLDtoManifestPipeline(buildAPI, requestContext); - - if (requestContext.toCreateAppRepo) { - 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(requestContext); + await helmRepo(gitAPI, requestContext); + await appRepo(gitAPI, requestContext); createSetupLog(requestContext); await exitFn(0); diff --git a/src/lib/pipelines/variableGroup.test.ts b/src/lib/pipelines/variableGroup.test.ts index 8258fa957..26f8b5823 100644 --- a/src/lib/pipelines/variableGroup.test.ts +++ b/src/lib/pipelines/variableGroup.test.ts @@ -16,11 +16,13 @@ import { logger } from "../../logger"; import { IVariableGroupData, IVariableGroupDataVariable } from "../../types"; +import * as azdoClient from "../azdoClient"; import { addVariableGroup, addVariableGroupWithKeyVaultMap, authorizeAccessToAllPipelines, buildVariablesMap, + deleteVariableGroup, doAddVariableGroup } from "./variableGroup"; @@ -418,3 +420,30 @@ 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" + } + ] + } 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: () => [] + } as any); + const deleted = await deleteVariableGroup({}, "test"); + expect(delFn).toBeCalledTimes(0); + expect(deleted).toBeFalsy(); + }); +}); diff --git a/src/lib/pipelines/variableGroup.ts b/src/lib/pipelines/variableGroup.ts index 10edf0ddd..d37b47e32 100644 --- a/src/lib/pipelines/variableGroup.ts +++ b/src/lib/pipelines/variableGroup.ts @@ -243,3 +243,23 @@ export const buildVariablesMap = async ( logger.debug(`variablesMap: ${JSON.stringify(variablesMap)}`); return variablesMap; }; + +/** + * 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: IAzureDevOpsOpts, + name: string +) => { + const taskClient = await getTaskAgentApi(opts); + const groups = await taskClient.getVariableGroups(opts.project!, name); + if (groups && groups.length > 0 && groups[0].id) { + await taskClient.deleteVariableGroup(opts.project!, groups[0].id); + return true; + } + return false; +}; diff --git a/src/lib/setup/constants.ts b/src/lib/setup/constants.ts index a150abfa0..0f1d26458 100644 --- a/src/lib/setup/constants.ts +++ b/src/lib/setup/constants.ts @@ -8,6 +8,8 @@ export interface IRequestContext { createdProject?: boolean; scaffoldHLD?: boolean; scaffoldManifest?: boolean; + scaffoldHelm?: boolean; + scaffoldAppService?: boolean; createdHLDtoManifestPipeline?: boolean; createServicePrincipal?: boolean; servicePrincipalId?: string; @@ -21,6 +23,7 @@ export interface IRequestContext { 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"; @@ -29,6 +32,7 @@ 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 VARIABLE_GROUP = "quick-start-vg"; export const SETUP_LOG = "setup.log"; export const HLD_DEFAULT_GIT_URL = diff --git a/src/lib/setup/helmTemplates.ts b/src/lib/setup/helmTemplates.ts new file mode 100644 index 000000000..4803c5d1d --- /dev/null +++ b/src/lib/setup/helmTemplates.ts @@ -0,0 +1,67 @@ +export const chartTemplate = `description: Simple Helm Chart For Integration Tests +name: @@CHART_APP_NAME@@-app +version: 0.1.0`; + +export const valuesTemplate = `# Default values for test app. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: @@ACR_NAME@@.azurecr.io/@@CHART_APP_NAME@@ + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 80 + containerPort: 8080 +`; + +export const mainTemplate = `--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: { { .Chart.Name } } +spec: + replicas: { { .Values.replicaCount } } + selector: + matchLabels: + app.kubernetes.io/name: { { .Chart.Name } } + app.kubernetes.io/instance: { { .Release.Name } } + minReadySeconds: { { .Values.minReadySeconds } } + strategy: + type: RollingUpdate # describe how we do rolling updates + rollingUpdate: + maxUnavailable: 1 # When updating take one pod down at a time + maxSurge: 1 # When updating never have more than one extra pod. If replicas = 2 then never 3 pods when updating + template: + metadata: + labels: + app: { { .Chart.Name } } + app.kubernetes.io/name: { { .Chart.Name } } + app.kubernetes.io/instance: { { .Release.Name } } + annotations: + prometheus.io/port: "{{ .Values.service.containerPort}}" + prometheus.io/scrape: "true" + spec: + containers: + - name: { { .Chart.Name } } + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: { { .Values.image.pullPolicy } } + ports: + - containerPort: { { .Values.service.containerPort } } +--- +apiVersion: v1 +kind: Service +metadata: + name: { { .Chart.Name } } + labels: + app: { { .Chart.Name } } +spec: + type: LoadBalancer + ports: + - port: 8080 + name: http + selector: + app: { { .Chart.Name } } +`; diff --git a/src/lib/setup/scaffold.test.ts b/src/lib/setup/scaffold.test.ts index 434e60ffb..a63f5bcac 100644 --- a/src/lib/setup/scaffold.test.ts +++ b/src/lib/setup/scaffold.test.ts @@ -1,11 +1,29 @@ import * as fs from "fs-extra"; import * as path from "path"; import simpleGit from "simple-git/promise"; -import * as hldInit from "../../commands/hld/init"; + +import * as cmdCreateVariableGroup from "../../commands/project/create-variable-group"; +import * as projectInit from "../../commands/project/init"; +import * as createService from "../../commands/service/create"; + +import * as variableGroup from "../../lib/pipelines/variableGroup"; import { createTempDir } from "../ioUtil"; -import { HLD_REPO, IRequestContext, MANIFEST_REPO } from "./constants"; +import { + APP_REPO, + HELM_REPO, + HLD_REPO, + IRequestContext, + MANIFEST_REPO +} from "./constants"; import * as gitService from "./gitService"; -import { hldRepo, manifestRepo } from "./scaffold"; +import { + appRepo, + helmRepo, + hldRepo, + initService, + manifestRepo, + setupVariableGroup +} from "./scaffold"; import * as scaffold from "./scaffold"; const createRequestContext = (workspace: string): IRequestContext => { @@ -68,9 +86,9 @@ describe("test hldRepo function", () => { expect(fs.statSync(folder).isDirectory()).toBeTruthy(); ["component.yaml", "manifest-generation.yaml"].forEach(f => { - const readmeMdPath = path.join(folder, f); - expect(fs.existsSync(readmeMdPath)).toBe(true); - expect(fs.statSync(readmeMdPath).isFile()).toBeTruthy(); + const sPath = path.join(folder, f); + expect(fs.existsSync(sPath)).toBe(true); + expect(fs.statSync(sPath).isFile()).toBeTruthy(); }); }); it("negative test", async () => { @@ -83,3 +101,95 @@ describe("test hldRepo function", () => { ).rejects.toThrow(); }); }); + +describe("test helmRepo function", () => { + it("positive test", async () => { + const tempDir = createTempDir(); + jest + .spyOn(gitService, "createRepoInAzureOrg") + .mockReturnValueOnce({} as any); + jest + .spyOn(gitService, "commitAndPushToRemote") + .mockReturnValueOnce({} as any); + const git = simpleGit(); + git.init = jest.fn(); + + await helmRepo({} as any, createRequestContext(tempDir)); + const folder = path.join(tempDir, HELM_REPO); + expect(fs.existsSync(folder)).toBe(true); + expect(fs.statSync(folder).isDirectory()).toBeTruthy(); + + const folderAppChart = path.join(folder, APP_REPO, "chart"); + ["Chart.yaml", "values.yaml"].forEach(f => { + const sPath = path.join(folderAppChart, f); + expect(fs.existsSync(sPath)).toBe(true); + expect(fs.statSync(sPath).isFile()).toBeTruthy(); + }); + const folderAppChartTemplates = path.join(folderAppChart, "templates"); + ["all-in-one.yaml"].forEach(f => { + const sPath = path.join(folderAppChartTemplates, f); + expect(fs.existsSync(sPath)).toBe(true); + expect(fs.statSync(sPath).isFile()).toBeTruthy(); + }); + }); + it("negative test", async () => { + const tempDir = createTempDir(); + jest.spyOn(gitService, "createRepoInAzureOrg").mockImplementation(() => { + throw new Error("fake"); + }); + await expect( + helmRepo({} as any, createRequestContext(tempDir)) + ).rejects.toThrow(); + }); +}); + +describe("test appRepo function", () => { + it("positive test", async () => { + const tempDir = createTempDir(); + jest + .spyOn(gitService, "createRepoInAzureOrg") + .mockReturnValueOnce({} as any); + jest + .spyOn(gitService, "commitAndPushToRemote") + .mockReturnValueOnce({} as any); + const git = simpleGit(); + git.init = jest.fn(); + + jest.spyOn(scaffold, "setupVariableGroup").mockResolvedValueOnce(); + jest.spyOn(scaffold, "initService").mockResolvedValueOnce(); + jest.spyOn(projectInit, "initialize").mockImplementationOnce(async () => { + fs.createFileSync("README.md"); + }); + + await appRepo({} as any, createRequestContext(tempDir)); + const folder = path.join(tempDir, APP_REPO); + expect(fs.existsSync(folder)).toBe(true); + expect(fs.statSync(folder).isDirectory()).toBeTruthy(); + }); + it("sanity test, initService", async () => { + jest.spyOn(createService, "createService").mockResolvedValueOnce(); + await initService("test"); + }); + it("sanity test on setupVariableGroup", async () => { + jest + .spyOn(variableGroup, "deleteVariableGroup") + .mockResolvedValueOnce(true); + jest.spyOn(cmdCreateVariableGroup, "create").mockResolvedValueOnce({}); + jest + .spyOn(cmdCreateVariableGroup, "setVariableGroupInBedrockFile") + .mockReturnValueOnce(); + jest + .spyOn(cmdCreateVariableGroup, "updateLifeCyclePipeline") + .mockReturnValueOnce(); + await setupVariableGroup(createRequestContext("/dummy")); + }); + it("negative test", async () => { + const tempDir = createTempDir(); + jest.spyOn(gitService, "createRepoInAzureOrg").mockImplementation(() => { + throw new Error("fake"); + }); + await expect( + appRepo({} as any, createRequestContext(tempDir)) + ).rejects.toThrow(); + }); +}); diff --git a/src/lib/setup/scaffold.ts b/src/lib/setup/scaffold.ts index 66717f253..07bb9ca0a 100644 --- a/src/lib/setup/scaffold.ts +++ b/src/lib/setup/scaffold.ts @@ -1,19 +1,34 @@ import { IGitApi } from "azure-devops-node-api/GitApi"; import fs from "fs-extra"; +import path from "path"; import simplegit from "simple-git/promise"; import { initialize as hldInitialize } from "../../commands/hld/init"; +import { + create as createVariableGroup, + setVariableGroupInBedrockFile, + updateLifeCyclePipeline +} from "../../commands/project/create-variable-group"; +import { initialize as projectInitialize } from "../../commands/project/init"; +import { createService } from "../../commands/service/create"; +import { IAzureDevOpsOpts } from "../../lib/git"; +import { deleteVariableGroup } from "../../lib/pipelines/variableGroup"; import { logger } from "../../logger"; import { + ACR, + APP_REPO, + HELM_REPO, HLD_DEFAULT_COMPONENT_NAME, HLD_DEFAULT_DEF_PATH, HLD_DEFAULT_GIT_URL, HLD_REPO, IRequestContext, - MANIFEST_REPO + MANIFEST_REPO, + VARIABLE_GROUP } from "./constants"; import { createDirectory, moveToAbsPath, moveToRelativePath } from "./fsUtil"; import { createRepoInAzureOrg } from "./gitService"; import { commitAndPushToRemote } from "./gitService"; +import { chartTemplate, mainTemplate, valuesTemplate } from "./helmTemplates"; export const createRepo = async ( gitApi: IGitApi, @@ -43,6 +58,7 @@ export const manifestRepo = async (gitApi: IGitApi, rc: IRequestContext) => { const curFolder = process.cwd(); try { + logger.info(`creating git repo ${repoName} in project ${rc.projectName}`); const git = await createRepo( gitApi, repoName, @@ -55,6 +71,7 @@ export const manifestRepo = async (gitApi: IGitApi, rc: IRequestContext) => { await commitAndPushToRemote(git, rc, repoName); rc.scaffoldManifest = true; + logger.info("Completed scaffold Manifest Repo"); } finally { moveToAbsPath(curFolder); @@ -73,6 +90,7 @@ export const hldRepo = async (gitApi: IGitApi, rc: IRequestContext) => { const curFolder = process.cwd(); try { + logger.info(`creating git repo ${repoName} in project ${rc.projectName}`); const git = await createRepo( gitApi, repoName, @@ -91,8 +109,136 @@ export const hldRepo = async (gitApi: IGitApi, rc: IRequestContext) => { await commitAndPushToRemote(git, rc, repoName); rc.scaffoldHLD = true; + logger.info("Completed scaffold HLD Repo"); } finally { moveToAbsPath(curFolder); } }; + +/** + * Create chart directory and add helm chart files + */ +export const createChartArtifacts = () => { + createDirectory(APP_REPO); + moveToRelativePath(APP_REPO); + createDirectory("chart"); + moveToRelativePath("chart"); + + const chart = chartTemplate.replace("@@CHART_APP_NAME@@", APP_REPO); + fs.writeFileSync(path.join(process.cwd(), "Chart.yaml"), chart); + + const values = valuesTemplate + .replace("@@CHART_APP_NAME@@", APP_REPO) + .replace("@@ACR_NAME@@", ACR); + fs.writeFileSync(path.join(process.cwd(), "values.yaml"), values); + + createDirectory("templates"); + moveToRelativePath("templates"); + + fs.writeFileSync(path.join(process.cwd(), "all-in-one.yaml"), mainTemplate); +}; + +export const helmRepo = async (gitApi: IGitApi, rc: IRequestContext) => { + logger.info("Scaffolding helm Repo"); + const repoName = HELM_REPO; + const curFolder = process.cwd(); + + try { + logger.info(`creating git repo ${repoName} in project ${rc.projectName}`); + const git = await createRepo( + gitApi, + repoName, + rc.projectName, + rc.workspace + ); + createChartArtifacts(); + moveToAbsPath(curFolder); + moveToRelativePath(rc.workspace); + moveToRelativePath(repoName); + + await git.add("./*"); + await commitAndPushToRemote(git, rc, repoName); + rc.scaffoldHelm = true; + + logger.info("Completed scaffold helm Repo"); + } finally { + moveToAbsPath(curFolder); + } +}; + +export const setupVariableGroup = async (rc: IRequestContext) => { + const accessOpts: IAzureDevOpsOpts = { + orgName: rc.orgName, + personalAccessToken: rc.accessToken, + project: rc.projectName + }; + + await deleteVariableGroup(accessOpts, VARIABLE_GROUP); + await createVariableGroup( + VARIABLE_GROUP, + ACR, + HLD_DEFAULT_GIT_URL, + rc.servicePrincipalId, + rc.servicePrincipalPassword, + rc.servicePrincipalTenantId, + accessOpts + ); + logger.info(`Successfully created variable group, ${VARIABLE_GROUP}`); + + setVariableGroupInBedrockFile(".", VARIABLE_GROUP); + updateLifeCyclePipeline("."); +}; + +export const initService = async (repoName: string) => { + await createService(".", repoName, { + displayName: repoName, + gitPush: false, + helmChartChart: "", + helmChartRepository: "", + helmConfigAccessTokenVariable: "ACCESS_TOKEN_SECRET", + helmConfigBranch: "master", + helmConfigGit: HLD_DEFAULT_GIT_URL, + helmConfigPath: `${repoName}/chart`, + k8sBackend: "", + k8sBackendPort: "80", + k8sPort: 0, + maintainerEmail: "", + maintainerName: "", + middlewares: "", + middlewaresArray: [], + packagesDir: "", + pathPrefix: "", + pathPrefixMajorVersion: "", + ringNames: ["master"], + variableGroups: [VARIABLE_GROUP] + }); +}; + +export const appRepo = async (gitApi: IGitApi, rc: IRequestContext) => { + logger.info("Scaffolding app Repo"); + const repoName = APP_REPO; + const curFolder = process.cwd(); + + try { + logger.info(`creating git repo ${repoName} in project ${rc.projectName}`); + const git = await createRepo( + gitApi, + repoName, + rc.projectName, + rc.workspace + ); + + await projectInitialize("."); + await git.add("./*"); + await commitAndPushToRemote(git, rc, repoName); + + await setupVariableGroup(rc); + await initService(repoName); + + rc.scaffoldAppService = true; + logger.info("Completed scaffold app Repo"); + } finally { + moveToAbsPath(curFolder); + } +}; diff --git a/src/lib/setup/setupLog.test.ts b/src/lib/setup/setupLog.test.ts index f90aeb3d7..7540c1c2d 100644 --- a/src/lib/setup/setupLog.test.ts +++ b/src/lib/setup/setupLog.test.ts @@ -21,7 +21,9 @@ const positiveTest = (logExist?: boolean, withAppCreation = false) => { createdResourceGroup: false, orgName: "orgName", projectName: "projectName", + scaffoldAppService: true, scaffoldHLD: true, + scaffoldHelm: true, scaffoldManifest: true, subscriptionId: "72f988bf-86f1-41af-91ab-2d7cd011db48", workspace: "workspace" @@ -54,6 +56,8 @@ const positiveTest = (logExist?: boolean, withAppCreation = false) => { "workspace: workspace", "Project Created: yes", "High Level Definition Repo Scaffolded: yes", + "Helm Repo Scaffolded: yes", + "Sample App Repo Scaffolded: yes", "Manifest Repo Scaffolded: yes", "HLD to Manifest Pipeline Created: yes", "Service Principal Created: no", @@ -75,6 +79,8 @@ const positiveTest = (logExist?: boolean, withAppCreation = false) => { "workspace: workspace", "Project Created: yes", "High Level Definition Repo Scaffolded: yes", + "Helm Repo Scaffolded: yes", + "Sample App Repo Scaffolded: yes", "Manifest Repo Scaffolded: yes", "HLD to Manifest Pipeline Created: yes", "Service Principal Created: no", @@ -113,7 +119,9 @@ describe("test create function", () => { error: "things broke", orgName: "orgName", projectName: "projectName", + scaffoldAppService: true, scaffoldHLD: true, + scaffoldHelm: true, scaffoldManifest: true, workspace: "workspace" }, @@ -134,6 +142,8 @@ describe("test create function", () => { "workspace: workspace", "Project Created: yes", "High Level Definition Repo Scaffolded: yes", + "Helm Repo Scaffolded: yes", + "Sample App Repo Scaffolded: yes", "Manifest Repo Scaffolded: yes", "HLD to Manifest Pipeline Created: yes", "Service Principal Created: no", diff --git a/src/lib/setup/setupLog.ts b/src/lib/setup/setupLog.ts index bc2e48de1..9e9b55c75 100644 --- a/src/lib/setup/setupLog.ts +++ b/src/lib/setup/setupLog.ts @@ -24,6 +24,8 @@ export const create = (rc: IRequestContext | undefined, file?: string) => { `workspace: ${rc.workspace}`, `Project Created: ${getBooleanVal(rc.createdProject)}`, `High Level Definition Repo Scaffolded: ${getBooleanVal(rc.scaffoldHLD)}`, + `Helm Repo Scaffolded: ${getBooleanVal(rc.scaffoldHelm)}`, + `Sample App Repo Scaffolded: ${getBooleanVal(rc.scaffoldAppService)}`, `Manifest Repo Scaffolded: ${getBooleanVal(rc.scaffoldManifest)}`, `HLD to Manifest Pipeline Created: ${getBooleanVal( rc.createdHLDtoManifestPipeline From b0b37bcc67597d0a1c4de370f068bf43ac4a33db Mon Sep 17 00:00:00 2001 From: Dennis Seah Date: Fri, 13 Mar 2020 17:07:26 -0700 Subject: [PATCH 2/5] fix eslint error --- src/commands/setup.ts | 2 +- .../azure/containerRegistryService.test.ts | 28 +-- src/lib/azure/resourceService.test.ts | 29 +-- src/lib/pipelines/variableGroup.ts | 4 +- yarn.lock | 217 +----------------- 5 files changed, 30 insertions(+), 250 deletions(-) diff --git a/src/commands/setup.ts b/src/commands/setup.ts index b298a45a4..5f6f5d5d2 100644 --- a/src/commands/setup.ts +++ b/src/commands/setup.ts @@ -88,7 +88,7 @@ export const getErrorMessage = ( return err.toString(); }; -export const createAppRepoTasks = async (rc: IRequestContext) => { +export const createAppRepoTasks = async (rc: RequestContext): Promise => { if (rc.toCreateAppRepo) { rc.createdResourceGroup = await createResourceGroup( rc.servicePrincipalId!, diff --git a/src/lib/azure/containerRegistryService.test.ts b/src/lib/azure/containerRegistryService.test.ts index 6290f450f..2ce1c6dd9 100644 --- a/src/lib/azure/containerRegistryService.test.ts +++ b/src/lib/azure/containerRegistryService.test.ts @@ -1,10 +1,7 @@ import { - ContainerRegistryManagementClientOptions, RegistriesCreateResponse, - Registry + RegistriesListResponse } from "@azure/arm-containerregistry/src/models"; -import { RequestOptionsBase } from "@azure/ms-rest-js"; -import { ApplicationTokenCredentials } from "@azure/ms-rest-nodeauth"; import * as restAuth from "@azure/ms-rest-nodeauth"; import { @@ -16,29 +13,22 @@ import * as containerRegistryService from "./containerRegistryService"; jest.mock("@azure/arm-containerregistry", () => { class MockClient { - constructor( - cred: ApplicationTokenCredentials, - subId: string, - options?: ContainerRegistryManagementClientOptions - ) { + constructor() { return { registries: { - create: async ( - resourceGroupName: string, - registryName: string, - registry: Registry, - opts?: RequestOptionsBase - ): Promise => { + create: async (): Promise => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any return {} as any; }, - list: () => { + list: (): Promise => { 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; } } }; @@ -49,14 +39,10 @@ jest.mock("@azure/arm-containerregistry", () => { }; }); -const accessToken = "pat"; -const orgName = "org"; -const projectName = "project"; const servicePrincipalId = "1eba2d04-1506-4278-8f8c-b1eb2fc462a8"; const servicePrincipalPassword = "e4c19d72-96d6-4172-b195-66b3b1c36db1"; const servicePrincipalTenantId = "72f988bf-86f1-41af-91ab-2d7cd011db47"; const subscriptionId = "test"; -const workspace = "test"; const RESOURCE_GROUP = "quick-start-rg"; const RESOURCE_GROUP_LOCATION = "westus2"; diff --git a/src/lib/azure/resourceService.test.ts b/src/lib/azure/resourceService.test.ts index 30c33ce19..342b53dd6 100644 --- a/src/lib/azure/resourceService.test.ts +++ b/src/lib/azure/resourceService.test.ts @@ -1,10 +1,7 @@ import { - ResourceGroup, ResourceGroupsCreateOrUpdateResponse, - ResourceManagementClientOptions + ResourceGroupsListResponse } from "@azure/arm-resources/src/models"; -import { RequestOptionsBase } from "@azure/ms-rest-js"; -import { ApplicationTokenCredentials } from "@azure/ms-rest-nodeauth"; import * as restAuth from "@azure/ms-rest-nodeauth"; import { create, getResourceGroups, isExist } from "./resourceService"; import * as resourceService from "./resourceService"; @@ -13,28 +10,24 @@ const RESOURCE_GROUP_LOCATION = "westus2"; jest.mock("@azure/arm-resources", () => { class MockClient { - constructor( - cred: ApplicationTokenCredentials, - subId: string, - options?: ResourceManagementClientOptions - ) { + constructor() { return { resourceGroups: { - createOrUpdate: async ( - resourceGroupName: string, - parameters: ResourceGroup, - opts?: RequestOptionsBase - ): Promise => { + createOrUpdate: async (): Promise< + ResourceGroupsCreateOrUpdateResponse + > => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any return {} as any; }, - list: () => { + list: (): Promise => { return [ { id: "1234567890-abcdef", location: RESOURCE_GROUP_LOCATION, name: "test" } - ]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ] as any; } } }; @@ -45,14 +38,10 @@ jest.mock("@azure/arm-resources", () => { }; }); -const accessToken = "pat"; -const orgName = "org"; -const projectName = "project"; const servicePrincipalId = "1eba2d04-1506-4278-8f8c-b1eb2fc462a8"; const servicePrincipalPassword = "e4c19d72-96d6-4172-b195-66b3b1c36db1"; const servicePrincipalTenantId = "72f988bf-86f1-41af-91ab-2d7cd011db47"; const subscriptionId = "test"; -const workspace = "test"; const RESOURCE_GROUP = "quick-start-rg"; describe("Resource Group tests", () => { diff --git a/src/lib/pipelines/variableGroup.ts b/src/lib/pipelines/variableGroup.ts index 7ff56980b..e169d4306 100644 --- a/src/lib/pipelines/variableGroup.ts +++ b/src/lib/pipelines/variableGroup.ts @@ -252,9 +252,9 @@ export const buildVariablesMap = async ( * @returns true if group exists and deleted. */ export const deleteVariableGroup = async ( - opts: IAzureDevOpsOpts, + opts: AzureDevOpsOpts, name: string -) => { +): Promise => { const taskClient = await getTaskAgentApi(opts); const groups = await taskClient.getVariableGroups(opts.project!, name); if (groups && groups.length > 0 && groups[0].id) { diff --git a/yarn.lock b/yarn.lock index cd70865e1..62ae30f4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1011,11 +1011,6 @@ abab@^2.0.0: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -1163,7 +1158,7 @@ append-transform@^1.0.0: dependencies: default-require-extensions "^2.0.0" -aproba@^1.0.3, aproba@^1.1.1: +aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== @@ -1173,14 +1168,6 @@ archy@^1.0.0: resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -1943,11 +1930,6 @@ console-browserify@^1.1.0: resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -2144,13 +2126,6 @@ debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -2173,11 +2148,6 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -2224,11 +2194,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - des.js@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" @@ -2242,11 +2207,6 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - detect-newline@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" @@ -3004,13 +2964,6 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -3044,20 +2997,6 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - gensync@^1.0.0-beta.1: version "1.0.0-beta.1" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" @@ -3262,11 +3201,6 @@ has-symbols@^1.0.0, has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -3396,7 +3330,7 @@ husky@>=1: slash "^3.0.0" which-pm-runs "^1.0.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -3413,13 +3347,6 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -ignore-walk@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -3484,7 +3411,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: +ini@^1.3.4, ini@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -4828,21 +4755,6 @@ minimist@^1.1.1, minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -4967,15 +4879,6 @@ ncp@~2.0.0: resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= -needle@^2.2.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.3.tgz#a041ad1d04a871b0ebb666f40baaf1fb47867117" - integrity sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - neo-async@^2.5.0, neo-async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" @@ -5061,30 +4964,6 @@ node-notifier@^5.4.2: shellwords "^0.1.1" which "^1.3.0" -node-pre-gyp@*: - version "0.14.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" - integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4.4.2" - -nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== - dependencies: - abbrev "1" - osenv "^0.1.4" - normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -5112,27 +4991,6 @@ normalize-url@^3.3.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== -npm-bundled@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" - integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== - dependencies: - npm-normalize-package-bin "^1.0.1" - -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - -npm-packlist@^1.1.6: - version "1.4.8" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" - integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - npm-normalize-package-bin "^1.0.1" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -5147,16 +5005,6 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -5314,7 +5162,7 @@ os-browserify@^0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -os-homedir@^1.0.0, os-homedir@^1.0.1: +os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= @@ -5328,19 +5176,11 @@ os-locale@^3.1.0: lcid "^2.0.0" mem "^4.0.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -5830,16 +5670,6 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - react-is@^16.12.0, react-is@^16.8.4: version "16.13.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527" @@ -5862,7 +5692,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -6098,7 +5928,7 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: +rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -6230,7 +6060,7 @@ semver-regex@^2.0.0: resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -6245,7 +6075,7 @@ serialize-javascript@^2.1.2: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== -set-blocking@^2.0.0, set-blocking@~2.0.0: +set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= @@ -6606,7 +6436,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.1.1: +string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -6724,11 +6554,6 @@ strip-json-comments@^3.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - supports-color@6.1.0, supports-color@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" @@ -6780,19 +6605,6 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar@^4.4.2: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - terser-webpack-plugin@^1.4.2, terser-webpack-plugin@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" @@ -7379,13 +7191,6 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - winston-transport@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.3.0.tgz#df68c0c202482c448d9b47313c07304c2d7c2c66" @@ -7535,7 +7340,7 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: +yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== From 23c8d7f5d6c82755dd17398a23bd86a07249f5ae Mon Sep 17 00:00:00 2001 From: Dennis Seah Date: Sun, 15 Mar 2020 09:20:16 -0700 Subject: [PATCH 3/5] making acr name configurable that's not hardcode it --- src/commands/setup.ts | 3 +-- src/lib/setup/constants.ts | 3 ++- src/lib/setup/prompt.test.ts | 32 +++++++++++++++++++++++++++++- src/lib/setup/prompt.ts | 36 +++++++++++++++++++++++++++++++++- src/lib/setup/scaffold.ts | 13 +++++++----- src/lib/setup/setupLog.test.ts | 4 ++++ src/lib/setup/setupLog.ts | 1 + src/lib/validator.test.ts | 13 ++++++++++++ src/lib/validator.ts | 19 ++++++++++++++++++ 9 files changed, 114 insertions(+), 10 deletions(-) diff --git a/src/commands/setup.ts b/src/commands/setup.ts index 5f6f5d5d2..19b84309e 100644 --- a/src/commands/setup.ts +++ b/src/commands/setup.ts @@ -9,7 +9,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, @@ -104,7 +103,7 @@ export const createAppRepoTasks = async (rc: RequestContext): Promise => { rc.servicePrincipalTenantId!, rc.subscriptionId!, RESOURCE_GROUP, - ACR, + rc.acrName!, RESOURCE_GROUP_LOCATION ); } diff --git a/src/lib/setup/constants.ts b/src/lib/setup/constants.ts index b4a8a2255..6271c8fb1 100644 --- a/src/lib/setup/constants.ts +++ b/src/lib/setup/constants.ts @@ -3,6 +3,7 @@ export interface RequestContext { projectName: string; accessToken: string; workspace: string; + acrName?: string; toCreateAppRepo?: boolean; toCreateSP?: boolean; createdProject?: boolean; @@ -31,7 +32,7 @@ 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"; diff --git a/src/lib/setup/prompt.test.ts b/src/lib/setup/prompt.test.ts index 8ffba9579..44af1f85e 100644 --- a/src/lib/setup/prompt.test.ts +++ b/src/lib/setup/prompt.test.ts @@ -6,7 +6,12 @@ import path from "path"; import uuid from "uuid/v4"; import { createTempDir } from "../../lib/ioUtil"; import { DEFAULT_PROJECT_NAME, RequestContext, WORKSPACE } from "./constants"; -import { getAnswerFromFile, prompt, promptForSubscriptionId } from "./prompt"; +import { + getAnswerFromFile, + prompt, + promptForACRName, + promptForSubscriptionId +} from "./prompt"; import * as servicePrincipalService from "./servicePrincipalService"; import * as subscriptionService from "./subscriptionService"; @@ -39,6 +44,10 @@ describe("test prompt function", () => { jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ create_service_principal: true }); + jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ + acr_name: "testACR" + }); + jest .spyOn(servicePrincipalService, "createWithAzCLI") .mockReturnValueOnce(Promise.resolve()); @@ -52,6 +61,7 @@ describe("test prompt function", () => { const ans = await prompt(); expect(ans).toStrictEqual({ accessToken: "pat", + acrName: "testACR", orgName: "org", projectName: "project", subscriptionId: "72f988bf-86f1-41af-91ab-2d7cd011db48", @@ -76,6 +86,9 @@ describe("test prompt function", () => { az_sp_password: "a510c1ff-358c-4ed4-96c8-eb23f42bbc5b", az_sp_tenant: "72f988bf-86f1-41af-91ab-2d7cd011db47" }); + jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ + acr_name: "testACR" + }); jest.spyOn(subscriptionService, "getSubscriptions").mockResolvedValueOnce([ { id: "72f988bf-86f1-41af-91ab-2d7cd011db48", @@ -85,6 +98,7 @@ describe("test prompt function", () => { const ans = await prompt(); expect(ans).toStrictEqual({ accessToken: "pat", + acrName: "testACR", orgName: "org", projectName: "project", servicePrincipalId: "b510c1ff-358c-4ed4-96c8-eb23f42bb65b", @@ -278,3 +292,19 @@ describe("test promptForSubscriptionId function", () => { expect(mockRc.subscriptionId).toBe("12334567890"); }); }); + +describe("test promptForACRName function", () => { + it("positive test", async () => { + const mockRc: RequestContext = { + accessToken: "pat", + orgName: "org", + projectName: "project", + workspace: WORKSPACE + }; + jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ + acr_name: "testACR" + }); + await promptForACRName(mockRc); + expect(mockRc.acrName).toBe("testACR"); + }); +}); diff --git a/src/lib/setup/prompt.ts b/src/lib/setup/prompt.ts index 067313d5d..addea0d8e 100644 --- a/src/lib/setup/prompt.ts +++ b/src/lib/setup/prompt.ts @@ -3,6 +3,7 @@ import fs from "fs"; import inquirer from "inquirer"; import { validateAccessToken, + validateACRName, validateOrgName, validateProjectName, validateServicePrincipalId, @@ -10,7 +11,12 @@ import { validateServicePrincipalTenantId, validateSubscriptionId } from "../validator"; -import { DEFAULT_PROJECT_NAME, RequestContext, WORKSPACE } from "./constants"; +import { + DEFAULT_PROJECT_NAME, + RequestContext, + WORKSPACE, + ACR_NAME +} from "./constants"; import { createWithAzCLI } from "./servicePrincipalService"; import { getSubscriptions } from "./subscriptionService"; @@ -77,6 +83,26 @@ export const promptForServicePrincipal = async ( rc.servicePrincipalTenantId = answers.az_sp_tenant as string; }; +/** + * Prompts for ACR name, default value is "quickStartACR". + * This is needed bacause ACR name has to be unique within Azure. + * + * @param rc Request Context + */ +export const promptForACRName = async (rc: RequestContext): Promise => { + const questions = [ + { + default: ACR_NAME, + message: `Enter Azure Container Register Name. The registry name must be unique within Azure\n`, + name: "acr_name", + type: "input", + validate: validateACRName + } + ]; + const answers = await inquirer.prompt(questions); + rc.acrName = answers.acr_name as string; +}; + /** * Prompts for creating service principal. User can choose * Yes or No. @@ -150,6 +176,7 @@ export const prompt = async (): Promise => { if (rc.toCreateAppRepo) { await promptForServicePrincipalCreation(rc); + await promptForACRName(rc); } return rc; }; @@ -231,6 +258,12 @@ export const getAnswerFromFile = (file: string): RequestContext => { throw new Error(vToken); } + const acrName = map.az_acr_name || ACR_NAME; + const vACRName = validateACRName(acrName); + if (typeof vACRName === "string") { + throw new Error(vACRName); + } + const rc: RequestContext = { accessToken: map.azdo_pat, orgName: map.azdo_org_name, @@ -238,6 +271,7 @@ export const getAnswerFromFile = (file: string): RequestContext => { servicePrincipalId: map.az_sp_id, servicePrincipalPassword: map.az_sp_password, servicePrincipalTenantId: map.az_sp_tenant, + acrName, workspace: WORKSPACE }; diff --git a/src/lib/setup/scaffold.ts b/src/lib/setup/scaffold.ts index 9bedb6c61..4933d8d00 100644 --- a/src/lib/setup/scaffold.ts +++ b/src/lib/setup/scaffold.ts @@ -14,7 +14,6 @@ import { AzureDevOpsOpts } from "../../lib/git"; import { deleteVariableGroup } from "../../lib/pipelines/variableGroup"; import { logger } from "../../logger"; import { - ACR, APP_REPO, HELM_REPO, HLD_DEFAULT_COMPONENT_NAME, @@ -123,8 +122,10 @@ export const hldRepo = async ( /** * Create chart directory and add helm chart files + * + * @param acrName Azure Container Registry Name. */ -export const createChartArtifacts = (): void => { +export const createChartArtifacts = (acrName: string): void => { createDirectory(APP_REPO); moveToRelativePath(APP_REPO); createDirectory("chart"); @@ -135,7 +136,7 @@ export const createChartArtifacts = (): void => { const values = valuesTemplate .replace("@@CHART_APP_NAME@@", APP_REPO) - .replace("@@ACR_NAME@@", ACR); + .replace("@@ACR_NAME@@", acrName); fs.writeFileSync(path.join(process.cwd(), "values.yaml"), values); createDirectory("templates"); @@ -160,7 +161,8 @@ export const helmRepo = async ( rc.projectName, rc.workspace ); - createChartArtifacts(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + createChartArtifacts(rc.acrName!); moveToAbsPath(curFolder); moveToRelativePath(rc.workspace); moveToRelativePath(repoName); @@ -185,7 +187,8 @@ export const setupVariableGroup = async (rc: RequestContext): Promise => { await deleteVariableGroup(accessOpts, VARIABLE_GROUP); await createVariableGroup( VARIABLE_GROUP, - ACR, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + rc.acrName!, HLD_DEFAULT_GIT_URL, rc.servicePrincipalId, rc.servicePrincipalPassword, diff --git a/src/lib/setup/setupLog.test.ts b/src/lib/setup/setupLog.test.ts index f73a594c5..2c98a7220 100644 --- a/src/lib/setup/setupLog.test.ts +++ b/src/lib/setup/setupLog.test.ts @@ -21,6 +21,7 @@ const positiveTest = (logExist?: boolean, withAppCreation = false): void => { createdResourceGroup: false, orgName: "orgName", projectName: "projectName", + acrName: "testacr", scaffoldAppService: true, scaffoldHLD: true, scaffoldHelm: true, @@ -53,6 +54,7 @@ const positiveTest = (logExist?: boolean, withAppCreation = false): void => { "az_sp_password=********", "az_sp_tenant=72f988bf-86f1-41af-91ab-2d7cd011db47", "az_subscription_id=72f988bf-86f1-41af-91ab-2d7cd011db48", + "az_acr_name=testacr", "workspace: workspace", "Project Created: yes", "High Level Definition Repo Scaffolded: yes", @@ -76,6 +78,7 @@ const positiveTest = (logExist?: boolean, withAppCreation = false): void => { "az_sp_password=", "az_sp_tenant=", "az_subscription_id=72f988bf-86f1-41af-91ab-2d7cd011db48", + "az_acr_name=testacr", "workspace: workspace", "Project Created: yes", "High Level Definition Repo Scaffolded: yes", @@ -139,6 +142,7 @@ describe("test create function", () => { "az_sp_password=", "az_sp_tenant=", "az_subscription_id=", + "az_acr_name=", "workspace: workspace", "Project Created: yes", "High Level Definition Repo Scaffolded: yes", diff --git a/src/lib/setup/setupLog.ts b/src/lib/setup/setupLog.ts index 6ac7a790d..d685c18c5 100644 --- a/src/lib/setup/setupLog.ts +++ b/src/lib/setup/setupLog.ts @@ -21,6 +21,7 @@ export const create = (rc: RequestContext | undefined, file?: string): void => { `az_sp_password=${rc.servicePrincipalPassword ? "********" : ""}`, `az_sp_tenant=${rc.servicePrincipalTenantId || ""}`, `az_subscription_id=${rc.subscriptionId || ""}`, + `az_acr_name=${rc.acrName || ""}`, `workspace: ${rc.workspace}`, `Project Created: ${getBooleanVal(rc.createdProject)}`, `High Level Definition Repo Scaffolded: ${getBooleanVal(rc.scaffoldHLD)}`, diff --git a/src/lib/validator.test.ts b/src/lib/validator.test.ts index b7a74b0da..a1a30a347 100644 --- a/src/lib/validator.test.ts +++ b/src/lib/validator.test.ts @@ -9,6 +9,7 @@ import { isPortNumberString, ORG_NAME_VIOLATION, validateAccessToken, + validateACRName, validateForNonEmptyValue, validateOrgName, validatePrereqs, @@ -235,3 +236,15 @@ describe("test validateSubscriptionId function", () => { expect(validateSubscriptionId("abc123-456")).toBeTruthy(); }); }); + +describe("test validateACRName function", () => { + it("sanity test", () => { + expect(validateACRName("")).toBe( + "Must enter an Azure Container Registry Name." + ); + expect(validateACRName("xyz-")).toBe( + "The value for Azure Container Registry Name is invalid." + ); + expect(validateACRName("abc12356")).toBeTruthy(); + }); +}); diff --git a/src/lib/validator.ts b/src/lib/validator.ts index 07b789333..3db8e9fc3 100644 --- a/src/lib/validator.ts +++ b/src/lib/validator.ts @@ -116,6 +116,10 @@ export const isDashHex = (value: string): boolean => { return !!value.match(/^[a-f0-9-]+$/); }; +export const isAlphaNumeric = (value: string): boolean => { + return !!value.match(/^[a-zA-Z0-9]+$/); +}; + /** * Returns true if project name is proper. * @@ -241,3 +245,18 @@ export const validateSubscriptionId = (value: string): string | boolean => { } return true; }; + +/** + * Returns true if Azure Container Registry Name is valid + * + * @param value Azure Container Registry Name. + */ +export const validateACRName = (value: string): string | boolean => { + if (!hasValue(value)) { + return "Must enter an Azure Container Registry Name."; + } + if (!isAlphaNumeric(value)) { + return "The value for Azure Container Registry Name is invalid."; + } + return true; +}; From 681ea40c3b5c603a8b20166ac8ae4d202c08ea83 Mon Sep 17 00:00:00 2001 From: Dennis Seah Date: Sun, 15 Mar 2020 17:46:59 -0700 Subject: [PATCH 4/5] added code to check if acr name is between 5 and 50 chars long --- src/lib/validator.test.ts | 7 +++++++ src/lib/validator.ts | 3 +++ 2 files changed, 10 insertions(+) diff --git a/src/lib/validator.test.ts b/src/lib/validator.test.ts index a1a30a347..85134b29d 100644 --- a/src/lib/validator.test.ts +++ b/src/lib/validator.test.ts @@ -245,6 +245,13 @@ describe("test validateACRName function", () => { expect(validateACRName("xyz-")).toBe( "The value for Azure Container Registry Name is invalid." ); + expect(validateACRName("1")).toBe( + "The value for Azure Container Registry Name is invalid because it has to be between 5 and 50 characters long." + ); + expect(validateACRName("1234567890a".repeat(10))).toBe( + "The value for Azure Container Registry Name is invalid because it has to be between 5 and 50 characters long." + ); + expect(validateACRName("abc12356")).toBeTruthy(); }); }); diff --git a/src/lib/validator.ts b/src/lib/validator.ts index 3db8e9fc3..507c880c2 100644 --- a/src/lib/validator.ts +++ b/src/lib/validator.ts @@ -258,5 +258,8 @@ export const validateACRName = (value: string): string | boolean => { if (!isAlphaNumeric(value)) { return "The value for Azure Container Registry Name is invalid."; } + if (value.length < 5 || value.length > 50) { + return "The value for Azure Container Registry Name is invalid because it has to be between 5 and 50 characters long."; + } return true; }; From 3aa02c0909a75680c3f8de66dab7bf3a9c087371 Mon Sep 17 00:00:00 2001 From: Dennis Seah Date: Tue, 17 Mar 2020 20:05:09 -0700 Subject: [PATCH 5/5] fix lint --- src/commands/deployment/dashboard.test.ts | 16 ++-- src/commands/deployment/validate.test.ts | 24 ++--- src/commands/init.test.ts | 28 +++--- src/commands/init.ts | 10 +- src/commands/setup.test.ts | 12 +-- src/commands/setup.ts | 16 ++-- src/lib/pipelines/serviceEndpoint.test.ts | 106 +++++++++++----------- src/lib/pipelines/variableGroup.test.ts | 48 +++++----- src/lib/setup/prompt.test.ts | 42 ++++----- 9 files changed, 151 insertions(+), 151 deletions(-) diff --git a/src/commands/deployment/dashboard.test.ts b/src/commands/deployment/dashboard.test.ts index 5bfb6c5c0..7a8d64c8e 100644 --- a/src/commands/deployment/dashboard.test.ts +++ b/src/commands/deployment/dashboard.test.ts @@ -30,18 +30,18 @@ afterAll(() => { const mockConfig = (): void => { (Config as jest.Mock).mockReturnValueOnce({ - azure_devops: { - access_token: uuid(), + "azure_devops": { + "access_token": uuid(), org: uuid(), project: uuid() }, introspection: { azure: { - account_name: uuid(), + "account_name": uuid(), key: uuid(), - partition_key: uuid(), - source_repo_access_token: "test_token", - table_name: uuid() + "partition_key": uuid(), + "source_repo_access_token": "test_token", + "table_name": uuid() } } }); @@ -208,8 +208,8 @@ describe("Fallback to azure devops access token", () => { describe("Extract manifest repository information", () => { test("Manifest repository information is successfully extracted", () => { (Config as jest.Mock).mockReturnValue({ - azure_devops: { - manifest_repository: + "azure_devops": { + "manifest_repository": "https://dev.azure.com/bhnook/fabrikam/_git/materialized" } }); diff --git a/src/commands/deployment/validate.test.ts b/src/commands/deployment/validate.test.ts index 9059041d0..5e93c9c24 100644 --- a/src/commands/deployment/validate.test.ts +++ b/src/commands/deployment/validate.test.ts @@ -134,16 +134,16 @@ afterAll(() => { describe("Validate deployment configuration", () => { test("valid deployment configuration", async () => { const config: ConfigYaml = { - azure_devops: { + "azure_devops": { org: uuid(), project: uuid() }, introspection: { azure: { - account_name: uuid(), + "account_name": uuid(), key: Promise.resolve(uuid()), - partition_key: uuid(), - table_name: uuid() + "partition_key": uuid(), + "table_name": uuid() } } }; @@ -210,7 +210,7 @@ describe("test runSelfTest function", () => { introspection: { azure: { key: Promise.resolve(uuid()), - table_name: undefined + "table_name": undefined } } }; @@ -229,7 +229,7 @@ describe("test runSelfTest function", () => { introspection: { azure: { key: Promise.resolve(uuid()), - table_name: undefined + "table_name": undefined } } }; @@ -244,7 +244,7 @@ describe("test runSelfTest function", () => { introspection: { azure: { key: Promise.resolve(uuid()), - table_name: undefined + "table_name": undefined } } }; @@ -277,7 +277,7 @@ describe("Validate missing deployment.storage configuration", () => { const config: ConfigYaml = { introspection: { azure: { - account_name: undefined, + "account_name": undefined, key: Promise.resolve(uuid()) } } @@ -292,7 +292,7 @@ describe("Validate missing deployment.storage configuration", () => { introspection: { azure: { key: Promise.resolve(uuid()), - table_name: undefined + "table_name": undefined } } }; @@ -306,7 +306,7 @@ describe("Validate missing deployment.storage configuration", () => { introspection: { azure: { key: Promise.resolve(uuid()), - partition_key: undefined + "partition_key": undefined } } }; @@ -343,7 +343,7 @@ describe("Validate missing deployment.pipeline configuration", () => { describe("Validate missing deployment.pipeline configuration", () => { test("missing deployment.pipeline.org configuration", async () => { const config: ConfigYaml = { - azure_devops: { + "azure_devops": { org: undefined }, introspection: { @@ -359,7 +359,7 @@ describe("Validate missing deployment.pipeline configuration", () => { describe("Validate missing deployment.pipeline configuration", () => { test("missing deployment.pipeline.project configuration", async () => { const config: ConfigYaml = { - azure_devops: { + "azure_devops": { org: "org", project: undefined }, diff --git a/src/commands/init.test.ts b/src/commands/init.test.ts index 0df298385..d1fb26609 100644 --- a/src/commands/init.test.ts +++ b/src/commands/init.test.ts @@ -106,8 +106,8 @@ describe("Test execute function", () => { describe("test getConfig function", () => { it("with configuration file", () => { const mockedValues = { - azure_devops: { - access_token: "access_token", + "azure_devops": { + "access_token": "access_token", org: "org", project: "project" } @@ -124,8 +124,8 @@ describe("test getConfig function", () => { }); const cfg = getConfig(); expect(cfg).toStrictEqual({ - azure_devops: { - access_token: "", + "azure_devops": { + "access_token": "", org: "", project: "" } @@ -141,7 +141,7 @@ describe("test validatePersonalAccessToken function", () => { }) ); const result = await validatePersonalAccessToken({ - access_token: "token", + "access_token": "token", org: "org", project: "project" }); @@ -153,7 +153,7 @@ describe("test validatePersonalAccessToken function", () => { .spyOn(axios, "get") .mockReturnValueOnce(Promise.reject(new Error("fake"))); const result = await validatePersonalAccessToken({ - access_token: "token", + "access_token": "token", org: "org", project: "project" }); @@ -166,16 +166,16 @@ const testHandleInteractiveModeFunc = async ( verified: boolean ): Promise => { jest.spyOn(init, "getConfig").mockReturnValueOnce({ - azure_devops: { - access_token: "", + "azure_devops": { + "access_token": "", org: "", project: "" } }); jest.spyOn(init, "prompt").mockResolvedValueOnce({ - azdo_org_name: "org_name", - azdo_pat: "pat", - azdo_project_name: "project" + "azdo_org_name": "org_name", + "azdo_pat": "pat", + "azdo_project_name": "project" }); jest .spyOn(init, "validatePersonalAccessToken") @@ -206,9 +206,9 @@ describe("test handleInteractiveMode function", () => { describe("test prompt function", () => { it("positive test", async done => { const answers = { - azdo_org_name: "org", - azdo_pat: "pat", - azdo_project_name: "project" + "azdo_org_name": "org", + "azdo_pat": "pat", + "azdo_project_name": "project" }; jest.spyOn(inquirer, "prompt").mockResolvedValueOnce(answers); const ans = await prompt({}); diff --git a/src/commands/init.ts b/src/commands/init.ts index 0e0f4c01e..e3c96806a 100644 --- a/src/commands/init.ts +++ b/src/commands/init.ts @@ -76,9 +76,9 @@ export const prompt = async (curConfig: ConfigYaml): Promise => { ]; const answers = await inquirer.prompt(questions); return { - azdo_org_name: answers.azdo_org_name as string, - azdo_pat: answers.azdo_pat as string, - azdo_project_name: answers.azdo_project_name as string + "azdo_org_name": answers.azdo_org_name as string, + "azdo_pat": answers.azdo_pat as string, + "azdo_project_name": answers.azdo_project_name as string }; }; @@ -93,8 +93,8 @@ export const getConfig = (): ConfigYaml => { } catch (_) { // current config is not found. return { - azure_devops: { - access_token: "", + "azure_devops": { + "access_token": "", org: "", project: "" } diff --git a/src/commands/setup.test.ts b/src/commands/setup.test.ts index ffe77f17f..12dbd7177 100644 --- a/src/commands/setup.test.ts +++ b/src/commands/setup.test.ts @@ -37,7 +37,7 @@ describe("test createSPKConfig function", () => { createSPKConfig(mockRequestContext); const data = readYaml(tmpFile); expect(data.azure_devops).toStrictEqual({ - access_token: "pat", + "access_token": "pat", org: "orgname", project: "project" }); @@ -56,16 +56,16 @@ describe("test createSPKConfig function", () => { const data = readYaml(tmpFile); expect(data.azure_devops).toStrictEqual({ - access_token: "pat", + "access_token": "pat", org: "orgname", project: "project" }); expect(data.introspection).toStrictEqual({ azure: { - service_principal_id: rc.servicePrincipalId, - service_principal_secret: rc.servicePrincipalPassword, - subscription_id: rc.subscriptionId, - tenant_id: rc.servicePrincipalTenantId + "service_principal_id": rc.servicePrincipalId, + "service_principal_secret": rc.servicePrincipalPassword, + "subscription_id": rc.subscriptionId, + "tenant_id": rc.servicePrincipalTenantId } }); }); diff --git a/src/commands/setup.ts b/src/commands/setup.ts index a5bebaaf8..a93bec0d6 100644 --- a/src/commands/setup.ts +++ b/src/commands/setup.ts @@ -45,23 +45,23 @@ interface APIError { export const createSPKConfig = (rc: RequestContext): void => { const data = rc.toCreateAppRepo ? { - azure_devops: { - access_token: rc.accessToken, + "azure_devops": { + "access_token": rc.accessToken, org: rc.orgName, project: rc.projectName }, introspection: { azure: { - service_principal_id: rc.servicePrincipalId, - service_principal_secret: rc.servicePrincipalPassword, - subscription_id: rc.subscriptionId, - tenant_id: rc.servicePrincipalTenantId + "service_principal_id": rc.servicePrincipalId, + "service_principal_secret": rc.servicePrincipalPassword, + "subscription_id": rc.subscriptionId, + "tenant_id": rc.servicePrincipalTenantId } } } : { - azure_devops: { - access_token: rc.accessToken, + "azure_devops": { + "access_token": rc.accessToken, org: rc.orgName, project: rc.projectName } diff --git a/src/lib/pipelines/serviceEndpoint.test.ts b/src/lib/pipelines/serviceEndpoint.test.ts index 58d3824f7..374d530cc 100644 --- a/src/lib/pipelines/serviceEndpoint.test.ts +++ b/src/lib/pipelines/serviceEndpoint.test.ts @@ -26,22 +26,22 @@ const servicePrincipalSecret: string = uuid(); const tenantId: string = uuid(); const mockedConfig = { - azure_devops: { + "azure_devops": { orrg: uuid() } }; const mockedYaml = { description: "mydesc", - key_vault_provider: { + "key_vault_provider": { name: "vault", - service_endpoint: { + "service_endpoint": { name: serviceEndpointName, - service_principal_id: servicePrincipalId, - service_principal_secret: servicePrincipalSecret, - subscription_id: subscriptionId, - subscription_name: subscriptionName, - tenant_id: tenantId + "service_principal_id": servicePrincipalId, + "service_principal_secret": servicePrincipalSecret, + "subscription_id": subscriptionId, + "subscription_name": subscriptionName, + "tenant_id": tenantId } }, name: "myvg" @@ -112,11 +112,11 @@ const mockedInvalidServiceEndpointResponse = { const createServiceEndpointInput: ServiceEndpointData = { name: serviceEndpointName, - service_principal_id: servicePrincipalId, - service_principal_secret: servicePrincipalSecret, - subscription_id: subscriptionId, - subscription_name: subscriptionName, - tenant_id: tenantId + "service_principal_id": servicePrincipalId, + "service_principal_secret": servicePrincipalSecret, + "subscription_id": subscriptionId, + "subscription_name": subscriptionName, + "tenant_id": tenantId }; beforeAll(() => { @@ -131,14 +131,14 @@ describe("Validate service endpoint parameters creation", () => { test("valid service endpoint params", () => { (readYaml as jest.Mock).mockReturnValue({ description: "mydesc", - key_vault_provider: { - service_endpoint: { + "key_vault_provider": { + "service_endpoint": { name: serviceEndpointName, - service_principal_id: servicePrincipalId, - service_principal_secret: servicePrincipalSecret, - subscription_id: subscriptionId, - subscription_name: subscriptionName, - tenant_id: tenantId + "service_principal_id": servicePrincipalId, + "service_principal_secret": servicePrincipalSecret, + "subscription_id": subscriptionId, + "subscription_name": subscriptionName, + "tenant_id": tenantId } } }); @@ -167,13 +167,13 @@ describe("Validate service endpoint parameters creation", () => { test("should fail creating service endpoint params without the name", () => { (readYaml as jest.Mock).mockReturnValue({ description: "mydesc", - key_vault_provider: { - service_endpoint: { - service_principal_id: servicePrincipalId, - service_principal_secret: servicePrincipalSecret, - subscription_id: subscriptionId, - subscription_name: subscriptionName, - tenant_id: tenantId + "key_vault_provider": { + "service_endpoint": { + "service_principal_id": servicePrincipalId, + "service_principal_secret": servicePrincipalSecret, + "subscription_id": subscriptionId, + "subscription_name": subscriptionName, + "tenant_id": tenantId } } }); @@ -192,13 +192,13 @@ describe("Validate service endpoint parameters creation", () => { test("should fail creating service endpoint params without service principal id", () => { (readYaml as jest.Mock).mockReturnValue({ description: "mydesc", - key_vault_provider: { - service_endpoint: { + "key_vault_provider": { + "service_endpoint": { name: serviceEndpointName, - service_principal_secret: servicePrincipalSecret, - subscription_id: subscriptionId, - subscription_name: subscriptionName, - tenant_id: tenantId + "service_principal_secret": servicePrincipalSecret, + "subscription_id": subscriptionId, + "subscription_name": subscriptionName, + "tenant_id": tenantId } } }); @@ -217,13 +217,13 @@ describe("Validate service endpoint parameters creation", () => { test("should fail creating service endpoint params without service principal secret", () => { (readYaml as jest.Mock).mockReturnValue({ description: "mydesc", - key_vault_provider: { - service_endpoint: { + "key_vault_provider": { + "service_endpoint": { name: serviceEndpointName, - service_principal_id: servicePrincipalId, - subscription_id: subscriptionId, - subscription_name: subscriptionName, - tenant_id: tenantId + "service_principal_id": servicePrincipalId, + "subscription_id": subscriptionId, + "subscription_name": subscriptionName, + "tenant_id": tenantId } } }); @@ -242,13 +242,13 @@ describe("Validate service endpoint parameters creation", () => { test("should fail creating service endpoint params without subscription id", () => { (readYaml as jest.Mock).mockReturnValue({ description: "mydesc", - key_vault_provider: { - service_endpoint: { + "key_vault_provider": { + "service_endpoint": { name: serviceEndpointName, - service_principal_id: servicePrincipalId, - service_principal_secret: servicePrincipalSecret, - subscription_name: subscriptionName, - tenant_id: tenantId + "service_principal_id": servicePrincipalId, + "service_principal_secret": servicePrincipalSecret, + "subscription_name": subscriptionName, + "tenant_id": tenantId } } }); @@ -267,13 +267,13 @@ describe("Validate service endpoint parameters creation", () => { test("should fail creating service endpoint params without subscription name", () => { (readYaml as jest.Mock).mockReturnValue({ description: "mydesc", - key_vault_provider: { - service_endpoint: { + "key_vault_provider": { + "service_endpoint": { name: serviceEndpointName, - service_principal_id: servicePrincipalId, - service_principal_secret: servicePrincipalSecret, - subscription_id: subscriptionId, - tenant_id: tenantId + "service_principal_id": servicePrincipalId, + "service_principal_secret": servicePrincipalSecret, + "subscription_id": subscriptionId, + "tenant_id": tenantId } } }); @@ -292,8 +292,8 @@ describe("Validate service endpoint parameters creation", () => { test("should fail creating service endpoint params without entire section", () => { (readYaml as jest.Mock).mockReturnValue({ description: "mydesc", - key_vault_provider: { - service_endpoint: {} + "key_vault_provider": { + "service_endpoint": {} } }); const input = readYaml(""); diff --git a/src/lib/pipelines/variableGroup.test.ts b/src/lib/pipelines/variableGroup.test.ts index 22801277d..af97c5b02 100644 --- a/src/lib/pipelines/variableGroup.test.ts +++ b/src/lib/pipelines/variableGroup.test.ts @@ -119,14 +119,14 @@ describe("addVariableGroupWithKeyVaultMap", () => { test("should fail when key vault name is not set for variable group", async () => { (readYaml as jest.Mock).mockReturnValue({ description: "mydesc", - key_vault_provider: { - service_endpoint: { + "key_vault_provider": { + "service_endpoint": { name: "sename", - service_principal_id: "id", - service_principal_secret: "secret", - subscription_id: "id", - subscription_name: "subname", - tenant_id: "tid" + "service_principal_id": "id", + "service_principal_secret": "secret", + "subscription_id": "id", + "subscription_name": "subname", + "tenant_id": "tid" } }, name: "myvg", @@ -153,9 +153,9 @@ describe("addVariableGroupWithKeyVaultMap", () => { test("should fail when service endpoint data is not set for variable group", async () => { (readYaml as jest.Mock).mockReturnValue({ description: "myvg desc", - key_vault_provider: { + "key_vault_provider": { name: "mykv", - service_endpoint: {} + "service_endpoint": {} }, name: "myvg", variables: [ @@ -180,15 +180,15 @@ describe("addVariableGroupWithKeyVaultMap", () => { test("should pass when variable group data is valid", async () => { (readYaml as jest.Mock).mockReturnValue({ description: "myvg desc", - key_vault_provider: { + "key_vault_provider": { name: "mykv", - service_endpoint: { + "service_endpoint": { name: "epname", - service_principal_id: "pricid", - service_principal_secret: "princsecret", - subscription_id: "subid", - subscription_name: "subname", - tenant_id: "tenid" + "service_principal_id": "pricid", + "service_principal_secret": "princsecret", + "subscription_id": "subid", + "subscription_name": "subname", + "tenant_id": "tenid" } }, name: "myvg", @@ -255,15 +255,15 @@ describe("doAddVariableGroup", () => { test("should pass when variable group with key vault data is set", async () => { (readYaml as jest.Mock).mockReturnValue({ description: uuid(), - key_vault_data: { + "key_vault_data": { name: "mykv", - service_endpoint: { + "service_endpoint": { name: "epname", - service_principal_id: "pricid", - service_principal_secret: "princsecret", - subscription_id: "subid", - subscription_name: "subname", - tenant_id: "tenid" + "service_principal_id": "pricid", + "service_principal_secret": "princsecret", + "subscription_id": "subid", + "subscription_name": "subname", + "tenant_id": "tenid" } }, name: uuid(), @@ -312,7 +312,7 @@ describe("authorizeAccessToAllPipelines", () => { }); test("should pass when valid variable group is passed", async () => { jest.spyOn(config, "Config").mockReturnValueOnce({ - azure_devops: { + "azure_devops": { project: "test" } }); diff --git a/src/lib/setup/prompt.test.ts b/src/lib/setup/prompt.test.ts index e61a22ce2..0baa06aed 100644 --- a/src/lib/setup/prompt.test.ts +++ b/src/lib/setup/prompt.test.ts @@ -17,10 +17,10 @@ import * as subscriptionService from "./subscriptionService"; describe("test prompt function", () => { it("positive test: No App Creation", async () => { const answers = { - azdo_org_name: "org", - azdo_pat: "pat", - azdo_project_name: "project", - create_app_repo: false + "azdo_org_name": "org", + "azdo_pat": "pat", + "azdo_project_name": "project", + "create_app_repo": false }; jest.spyOn(inquirer, "prompt").mockResolvedValueOnce(answers); const ans = await prompt(); @@ -34,17 +34,17 @@ describe("test prompt function", () => { }); it("positive test: create SP", async () => { const answers = { - azdo_org_name: "org", - azdo_pat: "pat", - azdo_project_name: "project", - create_app_repo: true + "azdo_org_name": "org", + "azdo_pat": "pat", + "azdo_project_name": "project", + "create_app_repo": true }; jest.spyOn(inquirer, "prompt").mockResolvedValueOnce(answers); jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ - create_service_principal: true + "create_service_principal": true }); jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ - acr_name: "testACR" + "acr_name": "testACR" }); jest @@ -71,22 +71,22 @@ describe("test prompt function", () => { }); it("positive test: no create SP", async () => { const answers = { - azdo_org_name: "org", - azdo_pat: "pat", - azdo_project_name: "project", - create_app_repo: true + "azdo_org_name": "org", + "azdo_pat": "pat", + "azdo_project_name": "project", + "create_app_repo": true }; jest.spyOn(inquirer, "prompt").mockResolvedValueOnce(answers); jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ - create_service_principal: false + "create_service_principal": false }); jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ - az_sp_id: "b510c1ff-358c-4ed4-96c8-eb23f42bb65b", - az_sp_password: "a510c1ff-358c-4ed4-96c8-eb23f42bbc5b", - az_sp_tenant: "72f988bf-86f1-41af-91ab-2d7cd011db47" + "az_sp_id": "b510c1ff-358c-4ed4-96c8-eb23f42bb65b", + "az_sp_password": "a510c1ff-358c-4ed4-96c8-eb23f42bbc5b", + "az_sp_tenant": "72f988bf-86f1-41af-91ab-2d7cd011db47" }); jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ - acr_name: "testACR" + "acr_name": "testACR" }); jest.spyOn(subscriptionService, "getSubscriptions").mockResolvedValueOnce([ { @@ -279,7 +279,7 @@ describe("test promptForSubscriptionId function", () => { } ]); jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ - az_subscription: "subscription2" + "az_subscription": "subscription2" }); const mockRc: RequestContext = { accessToken: "pat", @@ -301,7 +301,7 @@ describe("test promptForACRName function", () => { workspace: WORKSPACE }; jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ - acr_name: "testACR" + "acr_name": "testACR" }); await promptForACRName(mockRc); expect(mockRc.acrName).toBe("testACR");