diff --git a/docs/hld-management.md b/docs/hld-management.md index 90d5f68b8..c1d3c893c 100644 --- a/docs/hld-management.md +++ b/docs/hld-management.md @@ -77,7 +77,7 @@ invoke "manifest generation" and configuration into Kubernetes yaml. ``` -Usage: hld install-manifest-pipeline|m [options] +Usage: hld install-manifest-pipeline|p [options] Install the manifest generation pipeline to your Azure DevOps instance. Default values are set in spk-config.yaml and can be loaded via spk init or overriden via option flags. @@ -89,6 +89,7 @@ Options: -u, --hld-url HLD Repository URL -m, --manifest-url Manifest Repository URL -d, --devops-project Azure DevOps Project + -b, --build-script Build Script URL. By default it is 'https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/build.sh'. -h, --help output usage information ``` diff --git a/docs/project-management.md b/docs/project-management.md index 69a30cd47..f0a2a68dc 100644 --- a/docs/project-management.md +++ b/docs/project-management.md @@ -111,5 +111,6 @@ Options: -u, --repo-url Repository URL -e, --hld-url HLD Repository URL -d, --devops-project Azure DevOps Project + -b, --build-script Build Script URL. By default it is 'https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/build.sh'. -h, --help output usage information ``` diff --git a/docs/service-management.md b/docs/service-management.md index 0f873caea..687d02c56 100644 --- a/docs/service-management.md +++ b/docs/service-management.md @@ -65,7 +65,7 @@ https://docs.microsoft.com/en-us/azure/devops/pipelines/process/stages?view=azur ``` Usage: service install-build-pipeline|p [options] -Install the build and push to acr pipeline for a service to your Azure DevOps instance. +Install the build and push to acr pipeline for a service to your Azure DevOps instance Options: -n, --pipeline-name Name of the pipeline to be created @@ -74,6 +74,7 @@ Options: -r, --repo-name Repository Name in Azure DevOps -u, --repo-url Repository URL -d, --devops-project Azure DevOps Project + -b, --build-script Build Script URL. By default it is 'https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/build.sh'. -l, --packages-dir The mono-repository directory containing this service definition. ie. '--packages-dir packages' if my-service is located under ./packages/my-service. Omitting this option implies this is a not a mono-repository. -h, --help output usage information ``` diff --git a/src/commands/hld/pipeline.test.ts b/src/commands/hld/pipeline.test.ts index f51bd5420..7579b14d0 100644 --- a/src/commands/hld/pipeline.test.ts +++ b/src/commands/hld/pipeline.test.ts @@ -22,15 +22,26 @@ afterAll(() => { }); describe("required pipeline variables", () => { - it("should use access token and repo as pipeline vars", () => { - const variables = requiredPipelineVariables("foo", "bar"); + it("should use have the proper pipeline vars vars", () => { + const variables = requiredPipelineVariables( + "somePAT", + "buildScriptUrl", + "manifestRepoUrl" + ); + + expect(Object.keys(variables).length).toBe(3); - expect(Object.keys(variables).length).toBe(2); - expect(variables.PAT.value).toBe("foo"); + expect(variables.PAT.value).toBe("somePAT"); expect(variables.PAT.isSecret).toBe(true); + expect(variables.PAT.allowOverride).toBe(true); + + expect(variables.BUILD_SCRIPT_URL.value).toBe("buildScriptUrl"); + expect(variables.BUILD_SCRIPT_URL.isSecret).toBe(false); + expect(variables.BUILD_SCRIPT_URL.allowOverride).toBe(true); - expect(variables.MANIFEST_REPO.value).toBe("bar"); + expect(variables.MANIFEST_REPO.value).toBe("manifestRepoUrl"); expect(variables.MANIFEST_REPO.isSecret).toBe(false); + expect(variables.MANIFEST_REPO.allowOverride).toBe(true); }); }); @@ -40,13 +51,14 @@ describe("create hld to manifest pipeline test", () => { const exitFn = jest.fn(); await installHldToManifestPipeline( - "foo", - "bar", - "wow", - "amazing", - "meow", - "baz", + "orgName", + "personalAccessToken", + "hldRepoName", + "hldRepoUrl", + "manifestRepoUrl", + "project", "pipelineName", + "buildScriptUrl", exitFn ); @@ -58,13 +70,14 @@ describe("create hld to manifest pipeline test", () => { const exitFn = jest.fn(); await installHldToManifestPipeline( - "foo", - "bar", - "baz", - "wow", - "wao", - "baz", + "orgName", + "personalAccessToken", + "hldRepoName", + "hldRepoUrl", + "manifestRepoUrl", + "project", "pipelineName", + "buildScriptUrl", exitFn ); @@ -79,13 +92,14 @@ describe("create hld to manifest pipeline test", () => { const exitFn = jest.fn(); await installHldToManifestPipeline( - "foo", - "bar", - "baz", - "wow", - "wao", - "baz", + "orgName", + "personalAccessToken", + "hldRepoName", + "hldRepoUrl", + "manifestRepoUrl", + "project", "pipelineName", + "buildScriptUrl", exitFn ); @@ -99,13 +113,14 @@ describe("create hld to manifest pipeline test", () => { const exitFn = jest.fn(); await installHldToManifestPipeline( - "foo", - "bar", - "baz", - "wow", - "wao", - "baz", + "orgName", + "personalAccessToken", + "hldRepoName", + "hldRepoUrl", + "manifestRepoUrl", + "project", "pipelineName", + "buildScriptUrl", exitFn ); diff --git a/src/commands/hld/pipeline.ts b/src/commands/hld/pipeline.ts index 7244c99a5..6864bd545 100644 --- a/src/commands/hld/pipeline.ts +++ b/src/commands/hld/pipeline.ts @@ -5,6 +5,7 @@ import { } from "azure-devops-node-api/interfaces/BuildInterfaces"; import commander from "commander"; import { Config } from "../../config"; +import { BUILD_SCRIPT_URL } from "../../lib/constants"; import { getRepositoryName } from "../../lib/gitutils"; import { createPipelineForDefinition, @@ -20,7 +21,7 @@ export const installHldToManifestPipelineDecorator = ( ): void => { command .command("install-manifest-pipeline") - .alias("m") + .alias("p") .description( "Install the manifest generation pipeline to your Azure DevOps instance. Default values are set in spk-config.yaml and can be loaded via spk init or overriden via option flags." ) @@ -37,6 +38,10 @@ export const installHldToManifestPipelineDecorator = ( .option("-u, --hld-url ", "HLD Repository URL") .option("-m, --manifest-url ", "Manifest Repository URL") .option("-d, --devops-project ", "Azure DevOps Project") + .option( + "-b, --build-script ", + `Build Script URL. By default it is '${BUILD_SCRIPT_URL}'.` + ) .action(async opts => { const { azure_devops } = Config(); @@ -52,7 +57,8 @@ export const installHldToManifestPipelineDecorator = ( personalAccessToken = azure_devops && azure_devops.access_token, devopsProject = azure_devops && azure_devops.project, hldName = getRepositoryName(hldUrl), - pipelineName = hldName + "-to-" + manifestRepoName + pipelineName = hldName + "-to-" + manifestRepoName, + buildScriptUrl = BUILD_SCRIPT_URL } = opts; logger.debug(`orgName: ${orgName}`); @@ -62,6 +68,7 @@ export const installHldToManifestPipelineDecorator = ( logger.debug(`manifestUrl: ${manifestUrl}`); logger.debug(`hldName: ${hldName}`); logger.debug(`hldUrl: ${hldUrl}`); + logger.debug(`buildScriptUrl: ${buildScriptUrl}`); try { if (typeof pipelineName !== "string") { @@ -105,6 +112,11 @@ export const installHldToManifestPipelineDecorator = ( `--devops-project must be of type 'string', ${typeof devopsProject} given.` ); } + if (typeof buildScriptUrl !== "string") { + throw new Error( + `--build-script must be of type 'string', ${typeof buildScriptUrl} given.` + ); + } } catch (err) { logger.error( `Error occurred validating inputs for hld install-manifest-pipeline` @@ -122,6 +134,7 @@ export const installHldToManifestPipelineDecorator = ( manifestUrl, devopsProject, pipelineName, + buildScriptUrl, process.exit ); } catch (err) { @@ -143,6 +156,8 @@ export const installHldToManifestPipelineDecorator = ( * @param hldRepoUrl URL to the HLD repository * @param manifestRepoUrl URL to the materialized manifest repository * @param project Azure DevOps project that the HLD and Materialized manifest repository is in + * @param pipelineName Name of this build pipeline in AzDo + * @param buildScriptUrl Build Script URL */ export const installHldToManifestPipeline = async ( orgName: string, @@ -152,6 +167,7 @@ export const installHldToManifestPipeline = async ( manifestRepoUrl: string, project: string, pipelineName: string, + buildScriptUrl: string, exitFn: (status: number) => void ) => { let devopsClient; @@ -172,7 +188,11 @@ export const installHldToManifestPipeline = async ( pipelineName: pipelineName, repositoryName: hldRepoName, repositoryUrl: hldRepoUrl, - variables: requiredPipelineVariables(personalAccessToken, manifestRepoUrl), + variables: requiredPipelineVariables( + personalAccessToken, + buildScriptUrl, + manifestRepoUrl + ), yamlFileBranch: "master", yamlFilePath: `manifest-generation.yaml` } as IAzureRepoPipelineConfig); @@ -208,14 +228,21 @@ export const installHldToManifestPipeline = async ( /** * Builds and returns variables required for the HLD to Manifest pipeline. * @param accessToken Access token with access to the manifest repository. + * @param buildScriptUrl Build Script URL * @param manifestRepoUrl URL to the materialized manifest repository. - * @returns Object containing the necessary run-time variables for the HLD to Manifest repository. + * @returns Object containing the necessary run-time variables for the HLD to Manifest pipeline. */ export const requiredPipelineVariables = ( accessToken: string, + buildScriptUrl: string, manifestRepoUrl: string ): { [key: string]: BuildDefinitionVariable } => { return { + BUILD_SCRIPT_URL: { + allowOverride: true, + isSecret: false, + value: buildScriptUrl + }, MANIFEST_REPO: { allowOverride: true, isSecret: false, diff --git a/src/commands/project/pipeline.test.ts b/src/commands/project/pipeline.test.ts index 42ac43071..8b2ad046b 100644 --- a/src/commands/project/pipeline.test.ts +++ b/src/commands/project/pipeline.test.ts @@ -8,7 +8,10 @@ import { queueBuild } from "../../lib/pipelines/pipelines"; -import { installPipeline } from "./pipeline"; +import { + installLifecyclePipeline, + requiredPipelineVariables +} from "./pipeline"; beforeAll(() => { enableVerboseLogging(); @@ -18,12 +21,36 @@ afterAll(() => { disableVerboseLogging(); }); +describe("required pipeline variables", () => { + it("should use have the proper pipeline vars vars", () => { + const variables = requiredPipelineVariables( + "somePAT", + "buildScriptUrl", + "hldRepoUrl" + ); + + expect(Object.keys(variables).length).toBe(3); + + expect(variables.PAT.value).toBe("somePAT"); + expect(variables.PAT.isSecret).toBe(true); + expect(variables.PAT.allowOverride).toBe(true); + + expect(variables.BUILD_SCRIPT_URL.value).toBe("buildScriptUrl"); + expect(variables.BUILD_SCRIPT_URL.isSecret).toBe(false); + expect(variables.BUILD_SCRIPT_URL.allowOverride).toBe(true); + + expect(variables.HLD_REPO.value).toBe("hldRepoUrl"); + expect(variables.HLD_REPO.isSecret).toBe(false); + expect(variables.HLD_REPO.allowOverride).toBe(true); + }); +}); + describe("create hld to manifest pipeline test", () => { it("should create a pipeline", async () => { (createPipelineForDefinition as jest.Mock).mockReturnValue({ id: 10 }); const exitFn = jest.fn(); - await installPipeline( + await installLifecyclePipeline( "orgName", "PAT", "pipelineName", @@ -31,6 +58,7 @@ describe("create hld to manifest pipeline test", () => { "repoUrl", "hldRepoUrl", "azDoProject", + "buildScriptUrl", exitFn ); @@ -41,7 +69,7 @@ describe("create hld to manifest pipeline test", () => { (getBuildApiClient as jest.Mock).mockReturnValue(Promise.reject()); const exitFn = jest.fn(); - await installPipeline( + await installLifecyclePipeline( "orgName", "PAT", "pipelineName", @@ -49,6 +77,7 @@ describe("create hld to manifest pipeline test", () => { "repoUrl", "hldRepoUrl", "azDoProject", + "buildScriptUrl", exitFn ); @@ -62,7 +91,7 @@ describe("create hld to manifest pipeline test", () => { ); const exitFn = jest.fn(); - await installPipeline( + await installLifecyclePipeline( "orgName", "PAT", "pipelineName", @@ -70,6 +99,7 @@ describe("create hld to manifest pipeline test", () => { "repoUrl", "hldRepoUrl", "azDoProject", + "buildScriptUrl", exitFn ); @@ -82,7 +112,7 @@ describe("create hld to manifest pipeline test", () => { (queueBuild as jest.Mock).mockReturnValue(Promise.reject()); const exitFn = jest.fn(); - await installPipeline( + await installLifecyclePipeline( "orgName", "PAT", "pipelineName", @@ -90,6 +120,7 @@ describe("create hld to manifest pipeline test", () => { "repoUrl", "hldRepoUrl", "azDoProject", + "buildScriptUrl", exitFn ); diff --git a/src/commands/project/pipeline.ts b/src/commands/project/pipeline.ts index f0327d16e..51c614505 100644 --- a/src/commands/project/pipeline.ts +++ b/src/commands/project/pipeline.ts @@ -5,6 +5,7 @@ import { } from "azure-devops-node-api/interfaces/BuildInterfaces"; import commander from "commander"; import { Config } from "../../config"; +import { BUILD_SCRIPT_URL } from "../../lib/constants"; import { getOriginUrl, getRepositoryName, @@ -40,6 +41,10 @@ export const deployLifecyclePipelineCommandDecorator = ( .option("-u, --repo-url ", "Repository URL") .option("-e, --hld-url ", "HLD Repository URL") .option("-d, --devops-project ", "Azure DevOps Project") + .option( + "-b, --build-script ", + `Build Script URL. By default it is '${BUILD_SCRIPT_URL}'.` + ) .action(async opts => { const gitOriginUrl = await getOriginUrl(); const { azure_devops } = Config(); @@ -51,7 +56,8 @@ export const deployLifecyclePipelineCommandDecorator = ( pipelineName = getRepositoryName(gitOriginUrl) + "-lifecycle", repoName = getRepositoryName(gitOriginUrl), repoUrl = getRepositoryUrl(gitOriginUrl), - hldUrl = azure_devops && azure_devops.hld_repository + hldUrl = azure_devops && azure_devops.hld_repository, + buildScriptUrl = BUILD_SCRIPT_URL } = opts; logger.debug(`orgName: ${orgName}`); @@ -61,6 +67,7 @@ export const deployLifecyclePipelineCommandDecorator = ( logger.debug(`repoUrl: ${repoUrl}`); logger.debug(`hldUrl: ${hldUrl}`); logger.debug(`devopsProject: ${devopsProject}`); + logger.debug(`buildScriptUrl: ${buildScriptUrl}`); try { if (typeof pipelineName !== "string") { @@ -68,52 +75,51 @@ export const deployLifecyclePipelineCommandDecorator = ( `--pipeline-name must be of type 'string', ${typeof pipelineName} given.` ); } - if (typeof personalAccessToken !== "string") { throw new Error( `--personal-access-token must be of type 'string', ${typeof personalAccessToken} given.` ); } - if (typeof orgName !== "string") { throw new Error( `--org-url must be of type 'string', ${typeof orgName} given.` ); } - if (typeof repoName !== "string") { throw new Error( `--repo-name must be of type 'string', ${typeof repoName} given.` ); } - if (typeof repoUrl !== "string") { throw new Error( `--repo-url must be of type 'string', ${typeof repoUrl} given.` ); } - if (typeof hldUrl !== "string") { throw new Error( `--hld-url must be of type 'string', ${typeof hldUrl} given.` ); } - if (typeof devopsProject !== "string") { throw new Error( `--devops-project must be of type 'string', ${typeof devopsProject} given.` ); } + if (typeof buildScriptUrl !== "string") { + throw new Error( + `--build-script must be of type 'string', ${typeof buildScriptUrl} given.` + ); + } } catch (err) { logger.error( - `Error occurred validating inputs for install-lifecycle-pipeline` + `Error occurred validating inputs for project install-lifecycle-pipeline` ); logger.error(err); process.exit(1); } try { - await installPipeline( + await installLifecyclePipeline( orgName, personalAccessToken, pipelineName, @@ -121,6 +127,7 @@ export const deployLifecyclePipelineCommandDecorator = ( repoUrl, hldUrl, devopsProject, + buildScriptUrl, process.exit ); } catch (err) { @@ -143,9 +150,10 @@ export const deployLifecyclePipelineCommandDecorator = ( * @param repositoryUrl * @param hldRepoUrl * @param project + * @param buildScriptUrl Build Script URL * @param exitFn */ -export const installPipeline = async ( +export const installLifecyclePipeline = async ( orgName: string, personalAccessToken: string, pipelineName: string, @@ -153,6 +161,7 @@ export const installPipeline = async ( repositoryUrl: string, hldRepoUrl: string, project: string, + buildScriptUrl: string, exitFn: (status: number) => void ) => { let devopsClient: IBuildApi | undefined; @@ -173,7 +182,11 @@ export const installPipeline = async ( pipelineName, repositoryName, repositoryUrl, - variables: requiredPipelineVariables(personalAccessToken, hldRepoUrl), + variables: requiredPipelineVariables( + personalAccessToken, + buildScriptUrl, + hldRepoUrl + ), yamlFileBranch: "master", yamlFilePath: "hld-lifecycle.yaml" }); @@ -216,14 +229,21 @@ export const installPipeline = async ( /** * Builds and returns variables required for the lifecycle pipeline. * @param accessToken Access token with access to the HLD repository. - * @param hldRepoUrl to the HLD repository. - * @returns Object containing the necessary run-time variables for the lifecycle repository. + * @param buildScriptUrl Build Script URL + * @param hldRepoUrl to the HLD repository. + * @returns Object containing the necessary run-time variables for the lifecycle pipeline. */ export const requiredPipelineVariables = ( accessToken: string, + buildScriptUrl: string, hldRepoUrl: string ): { [key: string]: BuildDefinitionVariable } => { return { + BUILD_SCRIPT_URL: { + allowOverride: true, + isSecret: false, + value: buildScriptUrl + }, HLD_REPO: { allowOverride: true, isSecret: false, diff --git a/src/commands/service/pipeline.test.ts b/src/commands/service/pipeline.test.ts index c7a37b2e3..e41e53cd5 100644 --- a/src/commands/service/pipeline.test.ts +++ b/src/commands/service/pipeline.test.ts @@ -8,7 +8,10 @@ import { queueBuild } from "../../lib/pipelines/pipelines"; -import { installPipeline } from "./pipeline"; +import { + installBuildUpdatePipeline, + requiredPipelineVariables +} from "./pipeline"; beforeAll(() => { enableVerboseLogging(); @@ -18,20 +21,33 @@ afterAll(() => { disableVerboseLogging(); }); +describe("required pipeline variables", () => { + it("should use have the proper pipeline vars vars", () => { + const variables = requiredPipelineVariables("buildScriptUrl"); + + expect(Object.keys(variables).length).toBe(1); + + expect(variables.BUILD_SCRIPT_URL.value).toBe("buildScriptUrl"); + expect(variables.BUILD_SCRIPT_URL.isSecret).toBe(false); + expect(variables.BUILD_SCRIPT_URL.allowOverride).toBe(true); + }); +}); + describe("create pipeline tests", () => { it("should create a pipeline", async () => { (createPipelineForDefinition as jest.Mock).mockReturnValue({ id: 10 }); const exitFn = jest.fn(); - await installPipeline( - "foo", - "bar", - "baz", - "wow", - "wao", - "amazing", - "meow", - ".", + await installBuildUpdatePipeline( + "serviceName", + "orgName", + "personalAccessToken", + "pipelineName", + "repositoryName", + "repositoryUrl", + "project", + "packagesDir", + "buildScriptUrl", exitFn ); @@ -42,15 +58,16 @@ describe("create pipeline tests", () => { (getBuildApiClient as jest.Mock).mockReturnValue(Promise.reject()); const exitFn = jest.fn(); - await installPipeline( - "foo", - "bar", - "baz", - "wow", - "wao", - "amazing", - "meow", - ".", + await installBuildUpdatePipeline( + "serviceName", + "orgName", + "personalAccessToken", + "pipelineName", + "repositoryName", + "repositoryUrl", + "project", + "packagesDir", + "buildScriptUrl", exitFn ); @@ -64,15 +81,16 @@ describe("create pipeline tests", () => { ); const exitFn = jest.fn(); - await installPipeline( - "foo", - "bar", - "baz", - "wow", - "wao", - "amazing", - "meow", - ".", + await installBuildUpdatePipeline( + "serviceName", + "orgName", + "personalAccessToken", + "pipelineName", + "repositoryName", + "repositoryUrl", + "project", + "packagesDir", + "buildScriptUrl", exitFn ); @@ -85,15 +103,16 @@ describe("create pipeline tests", () => { (queueBuild as jest.Mock).mockReturnValue(Promise.reject()); const exitFn = jest.fn(); - await installPipeline( - "foo", - "bar", - "baz", - "wow", - "wao", - "amazing", - "meow", - ".", + await installBuildUpdatePipeline( + "serviceName", + "orgName", + "personalAccessToken", + "pipelineName", + "repositoryName", + "repositoryUrl", + "project", + "packagesDir", + "buildScriptUrl", exitFn ); diff --git a/src/commands/service/pipeline.ts b/src/commands/service/pipeline.ts index 7cf10f2d2..8d6da6098 100644 --- a/src/commands/service/pipeline.ts +++ b/src/commands/service/pipeline.ts @@ -1,8 +1,12 @@ import { IBuildApi } from "azure-devops-node-api/BuildApi"; -import { BuildDefinition } from "azure-devops-node-api/interfaces/BuildInterfaces"; +import { + BuildDefinition, + BuildDefinitionVariable +} from "azure-devops-node-api/interfaces/BuildInterfaces"; import commander from "commander"; import path from "path"; import { Config } from "../../config"; +import { BUILD_SCRIPT_URL } from "../../lib/constants"; import { getOriginUrl, getRepositoryName, @@ -37,6 +41,10 @@ export const installBuildPipelineCommandDecorator = ( .option("-r, --repo-name ", "Repository Name in Azure DevOps") .option("-u, --repo-url ", "Repository URL") .option("-d, --devops-project ", "Azure DevOps Project") + .option( + "-b, --build-script ", + `Build Script URL. By default it is '${BUILD_SCRIPT_URL}'.` + ) .option( "-l, --packages-dir ", "The mono-repository directory containing this service definition. ie. '--packages-dir packages' if my-service is located under ./packages/my-service. Omitting this option implies this is a not a mono-repository." @@ -52,7 +60,8 @@ export const installBuildPipelineCommandDecorator = ( pipelineName = serviceName + "-pipeline", packagesDir, // allow to be undefined in the case of a mono-repo repoName = getRepositoryName(gitOriginUrl), - repoUrl = getRepositoryUrl(gitOriginUrl) + repoUrl = getRepositoryUrl(gitOriginUrl), + buildScriptUrl = BUILD_SCRIPT_URL } = opts; logger.debug(`orgName: ${orgName}`); @@ -62,6 +71,7 @@ export const installBuildPipelineCommandDecorator = ( logger.debug(`packagesDir: ${packagesDir}`); logger.debug(`repoName: ${repoName}`); logger.debug(`repoUrl: ${repoUrl}`); + logger.debug(`buildScriptUrl: ${buildScriptUrl}`); try { if (typeof pipelineName !== "string") { @@ -69,36 +79,36 @@ export const installBuildPipelineCommandDecorator = ( `--pipeline-name must be of type 'string', ${typeof pipelineName} given.` ); } - if (typeof personalAccessToken !== "string") { throw new Error( `--personal-access-token must be of type 'string', ${typeof personalAccessToken} given.` ); } - if (typeof orgName !== "string") { throw new Error( `--org-url must be of type 'string', ${typeof orgName} given.` ); } - if (typeof repoName !== "string") { throw new Error( `--repo-name must be of type 'string', ${typeof repoName} given.` ); } - if (typeof repoUrl !== "string") { throw new Error( `--repo-url must be of type 'string', ${typeof repoUrl} given.` ); } - if (typeof devopsProject !== "string") { throw new Error( `--devops-project must be of type 'string', ${typeof devopsProject} given.` ); } + if (typeof buildScriptUrl !== "string") { + throw new Error( + `--build-script must be of type 'string', ${typeof buildScriptUrl} given.` + ); + } } catch (err) { logger.error(`Error occurred validating inputs for ${serviceName}`); logger.error(err); @@ -106,7 +116,7 @@ export const installBuildPipelineCommandDecorator = ( } try { - await installPipeline( + await installBuildUpdatePipeline( serviceName, orgName, personalAccessToken, @@ -115,6 +125,7 @@ export const installBuildPipelineCommandDecorator = ( repoUrl, devopsProject, packagesDir, + buildScriptUrl, process.exit ); } catch (err) { @@ -136,9 +147,10 @@ export const installBuildPipelineCommandDecorator = ( * @param repositoryUrl * @param project * @param packagesDir The directory containing the services for a mono-repo. If undefined; implies that we are operating on a standard service repository + * @param buildScriptUrl Build Script URL * @param exitFn */ -export const installPipeline = async ( +export const installBuildUpdatePipeline = async ( serviceName: string, orgName: string, personalAccessToken: string, @@ -147,6 +159,7 @@ export const installPipeline = async ( repositoryUrl: string, project: string, packagesDir: string | undefined, + buildScriptUrl: string, exitFn: (status: number) => void ) => { let devopsClient: IBuildApi | undefined; @@ -167,6 +180,7 @@ export const installPipeline = async ( pipelineName, repositoryName, repositoryUrl, + variables: requiredPipelineVariables(buildScriptUrl), yamlFileBranch: "master", yamlFilePath: packagesDir // if a packages dir is supplied, its a mono-repo ? path.join(packagesDir, serviceName, "azure-pipelines.yaml") // if a packages dir is supplied, its a mono-repo; concat / @@ -207,3 +221,20 @@ export const installPipeline = async ( return exitFn(1); } }; + +/** + * Builds and returns variables required for the Build & Update service pipeline. + * @param buildScriptUrl Build Script URL + * @returns Object containing the necessary run-time variables for the Build & Update service pipeline. + */ +export const requiredPipelineVariables = ( + buildScriptUrl: string +): { [key: string]: BuildDefinitionVariable } => { + return { + BUILD_SCRIPT_URL: { + allowOverride: true, + isSecret: false, + value: buildScriptUrl + } + }; +}; diff --git a/src/lib/constants.ts b/src/lib/constants.ts new file mode 100644 index 000000000..7c86d9e0b --- /dev/null +++ b/src/lib/constants.ts @@ -0,0 +1,2 @@ +export const BUILD_SCRIPT_URL = + "https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/build.sh"; diff --git a/src/lib/fileutils.ts b/src/lib/fileutils.ts index 1d73416de..6d51a44af 100644 --- a/src/lib/fileutils.ts +++ b/src/lib/fileutils.ts @@ -161,10 +161,13 @@ export const starterAzurePipelines = async (opts: { { script: generateYamlScript([ `# Download build.sh`, - `curl https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/build.sh > build.sh`, + `curl $BEDROCK_BUILD_SCRIPT > build.sh`, `chmod +x ./build.sh` ]), - displayName: "Download bedrock bash scripts" + displayName: "Download bedrock bash scripts", + env: { + BEDROCK_BUILD_SCRIPT: "$(BUILD_SCRIPT_URL)" + } }, ...cleanedPaths.map(projectPath => { logger.info(`projectPath: ${projectPath}`); @@ -384,15 +387,14 @@ const manifestGenerationPipelineYaml = () => { clean: true }, { - bash: generateYamlScript([ - // TODO: Double check this script, it's turning it tnto a list with a '-'. + script: generateYamlScript([ + `# Download build.sh`, `curl $BEDROCK_BUILD_SCRIPT > build.sh`, `chmod +x ./build.sh` ]), - displayName: "Download Bedrock orchestration script", + displayName: "Download bedrock bash scripts", env: { - BEDROCK_BUILD_SCRIPT: - "https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/build.sh" + BEDROCK_BUILD_SCRIPT: "$(BUILD_SCRIPT_URL)" } }, { @@ -481,10 +483,13 @@ const hldLifecyclePipelineYaml = () => { { script: generateYamlScript([ `# Download build.sh`, - `curl https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/build.sh > build.sh`, + `curl $BEDROCK_BUILD_SCRIPT > build.sh`, `chmod +x ./build.sh` ]), - displayName: "Download bedrock bash scripts" + displayName: "Download bedrock bash scripts", + env: { + BEDROCK_BUILD_SCRIPT: "$(BUILD_SCRIPT_URL)" + } }, { script: generateYamlScript([ diff --git a/src/test/mockFactory.ts b/src/test/mockFactory.ts index b2f70f311..25bc539a7 100644 --- a/src/test/mockFactory.ts +++ b/src/test/mockFactory.ts @@ -98,10 +98,13 @@ export const createTestHldLifecyclePipelineYaml = ( { script: generateYamlScript([ `# Download build.sh`, - `curl https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/build.sh > build.sh`, + `curl $BEDROCK_BUILD_SCRIPT > build.sh`, `chmod +x ./build.sh` ]), - displayName: "Download bedrock bash scripts" + displayName: "Download bedrock bash scripts", + env: { + BEDROCK_BUILD_SCRIPT: "$(BUILD_SCRIPT_URL)" + } }, { script: generateYamlScript([ @@ -189,11 +192,14 @@ export const createTestHldAzurePipelinesYaml = ( clean: true }, { - bash: "curl $BEDROCK_BUILD_SCRIPT > build.sh\nchmod +x ./build.sh", - displayName: "Download Bedrock orchestration script", + script: generateYamlScript([ + `# Download build.sh`, + `curl $BEDROCK_BUILD_SCRIPT > build.sh`, + `chmod +x ./build.sh` + ]), + displayName: "Download bedrock bash scripts", env: { - BEDROCK_BUILD_SCRIPT: - "https://raw.githubusercontent.com/Microsoft/bedrock/master/gitops/azure-devops/build.sh" + BEDROCK_BUILD_SCRIPT: "$(BUILD_SCRIPT_URL)" } }, { diff --git a/src/types.d.ts b/src/types.d.ts index f815f6d50..0d1873eb7 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -91,6 +91,7 @@ export interface IAzurePipelinesYaml { env?: { AZURE_DEVOPS_EXT_PAT?: string; ACCESS_TOKEN_SECRET?: string; + BEDROCK_BUILD_SCRIPT?: string; REPO?: string; }; }>;