diff --git a/src/lib/azure/azurecredentials.ts b/src/lib/azure/azurecredentials.ts index 1a475f705..ebfe926e9 100644 --- a/src/lib/azure/azurecredentials.ts +++ b/src/lib/azure/azurecredentials.ts @@ -1,11 +1,23 @@ -/* eslint-disable @typescript-eslint/no-use-before-define */ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { ClientSecretCredential } from "@azure/identity"; import * as msRestNodeAuth from "@azure/ms-rest-nodeauth"; import { Config } from "../../config"; import { logger } from "../../logger"; import { AzureAccessOpts } from "../../types"; +const verifyConfigDefined = ( + servicePrincipalId?: string, + servicePrincipalPassword?: string, + tenantId?: string +): boolean => { + if (servicePrincipalId && servicePrincipalPassword && tenantId) { + return true; + } + logger.error( + `Configuration is missing required fields tenant_id, service_principal_id and service_principal_secret. Please run the init command` + ); + return false; +}; + /** * Create an instance of `ClientSecretCredential` and returns for Azure data plane activities * @param opts optionally override spk config with Azure subscription access options @@ -34,9 +46,14 @@ export const getCredentials = async ( ) { return undefined; } + + // verifyConfigDefined has confirmed that these values are defined. return new ClientSecretCredential( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion tenantId!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion servicePrincipalId!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion servicePrincipalPassword! ); }; @@ -68,23 +85,13 @@ export const getManagementCredentials = async ( return undefined; } + // verifyConfigDefined has confirmed that these values are defined. return msRestNodeAuth.loginWithServicePrincipalSecret( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion servicePrincipalId!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion servicePrincipalPassword!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion tenantId! ); }; - -const verifyConfigDefined = ( - servicePrincipalId?: string, - servicePrincipalPassword?: string, - tenantId?: string -): boolean => { - if (servicePrincipalId && servicePrincipalPassword && tenantId) { - return true; - } - logger.error( - `Configuration is missing required fields tenant_id, service_principal_id and service_principal_secret. Please run the init command` - ); - return false; -}; diff --git a/src/lib/azure/containerRegistryService.ts b/src/lib/azure/containerRegistryService.ts index 91c18f30a..c0155cbaf 100644 --- a/src/lib/azure/containerRegistryService.ts +++ b/src/lib/azure/containerRegistryService.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { ContainerRegistryManagementClient } from "@azure/arm-containerregistry"; import { loginWithServicePrincipalSecret } from "@azure/ms-rest-nodeauth"; import { logger } from "../../logger"; @@ -64,10 +63,12 @@ export const getContainerRegistries = async ( const registries = await client.registries.list(); logger.info("Successfully acquired Azure container registries"); return registries.map((r) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const id = r.id! as string; const match = id.match(/\/resourceGroups\/(.+?)\//); return { id, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion name: r.name!, resourceGroup: match ? match[1] : "", }; diff --git a/src/lib/azure/keyvault.test.ts b/src/lib/azure/keyvault.test.ts index 538139e45..d409399dd 100644 --- a/src/lib/azure/keyvault.test.ts +++ b/src/lib/azure/keyvault.test.ts @@ -1,10 +1,4 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { - GetSecretOptions, - KeyVaultSecret, - SecretClient, - SetSecretOptions, -} from "@azure/keyvault-secrets"; +import { KeyVaultSecret } from "@azure/keyvault-secrets"; import uuid from "uuid/v4"; import { disableVerboseLogging, enableVerboseLogging } from "../../logger"; import { getSecret, setSecret } from "./keyvault"; @@ -16,10 +10,7 @@ const secretValue = uuid(); jest.spyOn(keyvault, "getClient").mockReturnValue( Promise.resolve({ - getSecret: async ( - secretName: string, - options?: GetSecretOptions - ): Promise => { + getSecret: async (): Promise => { return { name: "test", properties: { @@ -29,11 +20,7 @@ jest.spyOn(keyvault, "getClient").mockReturnValue( value: "secretValue", }; }, - setSecret: async ( - secretName: string, - value: string, - options?: SetSecretOptions - ): Promise => { + setSecret: async (): Promise => { return { name: "test", properties: { @@ -42,7 +29,8 @@ jest.spyOn(keyvault, "getClient").mockReturnValue( }, }; }, - } as SecretClient) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any) ); beforeAll(() => { @@ -67,14 +55,11 @@ describe("set secret", () => { test("negative test", async () => { jest.spyOn(keyvault, "getClient").mockReturnValueOnce( Promise.resolve({ - setSecret: ( - secretName: string, - value: string, - options?: SetSecretOptions - ): Promise => { + setSecret: (): Promise => { throw new Error("fake error"); }, - } as SecretClient) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any) ); try { await setSecret(keyVaultName, mockedName, secretValue); @@ -100,16 +85,14 @@ describe("get secret", () => { it("negative test: secret not found", async () => { jest.spyOn(keyvault, "getClient").mockReturnValueOnce( Promise.resolve({ - getSecret: ( - secretName: string, - options?: GetSecretOptions - ): Promise => { + getSecret: (): Promise => { throw { code: "SecretNotFound", statusCode: 404, }; }, - } as SecretClient) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any) ); try { const val = await getSecret(keyVaultName, mockedName); @@ -121,16 +104,14 @@ describe("get secret", () => { it("negative test: other errors", async () => { jest.spyOn(keyvault, "getClient").mockReturnValueOnce( Promise.resolve({ - getSecret: ( - secretName: string, - options?: GetSecretOptions - ): Promise => { + getSecret: (): Promise => { throw { code: "something else", statusCode: 400, }; }, - } as SecretClient) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any) ); try { await getSecret(keyVaultName, mockedName); diff --git a/src/lib/azure/keyvault.ts b/src/lib/azure/keyvault.ts index 9e6a48f20..71ceb782d 100644 --- a/src/lib/azure/keyvault.ts +++ b/src/lib/azure/keyvault.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { SecretClient } from "@azure/keyvault-secrets"; import { logger } from "../../logger"; import { AzureAccessOpts } from "../../types"; @@ -30,6 +29,7 @@ export const getClient = async ( ): Promise => { const url = `https://${keyVaultName}.vault.azure.net`; const credentials = await getCredentials(opts); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return new SecretClient(url, credentials!); }; diff --git a/src/lib/git/azure.test.ts b/src/lib/git/azure.test.ts index 8c922a76e..9c67f7534 100644 --- a/src/lib/git/azure.test.ts +++ b/src/lib/git/azure.test.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ - import { WebApi } from "azure-devops-node-api"; import uuid from "uuid/v4"; import { Config } from "../../config"; @@ -145,7 +143,9 @@ describe("createPullRequest", () => { expect(true).toBe(false); } catch (err) { expect(err).toBeDefined(); - expect(err!.message).toMatch(/0 repositories found with remote url/); + if (err) { + expect(err.message).toMatch(/0 repositories found with remote url/); + } } gitApi.getBranches = originalBranches; @@ -163,7 +163,7 @@ describe("createPullRequest", () => { }); it("negative test", async () => { gitApi.createPullRequest = async (): Promise => { - throw new Error("fake"); + throw Error("fake"); }; await expect( @@ -175,7 +175,7 @@ describe("createPullRequest", () => { }); it("negative test: TF401179 error", async () => { gitApi.createPullRequest = async (): Promise => { - throw new Error("TF401179"); + throw Error("TF401179"); }; await expect( diff --git a/src/lib/git/azure.ts b/src/lib/git/azure.ts index 959fac4e0..45c649eb3 100644 --- a/src/lib/git/azure.ts +++ b/src/lib/git/azure.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import * as azdo from "azure-devops-node-api"; import { IGitApi } from "azure-devops-node-api/GitApi"; import AZGitInterfaces, { @@ -87,7 +86,7 @@ export const generatePRUrl = async ( ) { const gitAPI = await GitAPI(); const parentRepo = await gitAPI.getRepository(pr.repository.id); - return `${parentRepo.webUrl!}/pullrequest/${pr.pullRequestId}`; + return `${parentRepo.webUrl}/pullrequest/${pr.pullRequestId}`; } throw Error( `Failed to generate PR URL; PR did not contain a valid repository ID` @@ -170,10 +169,11 @@ export const getMatchingBranch = async ( await Promise.all( reposWithMatchingOrigin.map(async (repo) => { logger.info(`Retrieving branches for repository '${repo.name}'`); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const branches = await gitAPI.getBranches(repo.id!); return { branches: branches.filter((branch) => { - return [sourceRef, targetRef].includes(branch.name!); + return branch.name && [sourceRef, targetRef].includes(branch.name); }), repo, }; @@ -219,6 +219,7 @@ const handleErrorForCreatePullRequest = async ( targetRefName: `refs/heads/${targetRef}`, }; const existingPRs = await gitAPI.getPullRequests( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion repoToPRAgainst.id!, searchCriteria ); @@ -275,12 +276,13 @@ export const createPullRequest = async ( ); logger.info( - `Creating pull request in repository '${repoToPRAgainst.name!}' to merge branch '${sourceRef}' into '${targetRef}'` + `Creating pull request in repository '${repoToPRAgainst.name}' to merge branch '${sourceRef}' into '${targetRef}'` ); try { const createdPR = await gitAPI.createPullRequest( prConfig, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion repoToPRAgainst.id! ); logger.info( diff --git a/src/lib/gitutils.ts b/src/lib/gitutils.ts index 98cb277cb..fc81642e7 100644 --- a/src/lib/gitutils.ts +++ b/src/lib/gitutils.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-use-before-define */ import GitUrlParse from "git-url-parse"; import path from "path"; import url from "url"; @@ -114,21 +113,6 @@ export const pushBranch = async (branchName: string): Promise => { } }; -/** - * Tries to fetch the Git origin from an AzDo set environment variable, else falls back to fetching it from Git directly. - * @param absRepoPath The Absolute Path to the Repository to fetch the origin url. - */ -export const tryGetGitOrigin = async ( - absRepoPath?: string -): Promise => { - return getAzdoOriginUrl().catch(() => { - logger.warn( - "Could not get Git Origin for Azure DevOps - are you running 'spk' _not_ in a pipeline?" - ); - return getOriginUrl(absRepoPath); - }); -}; - /** * Gets the origin url. * @param absRepositoryPath The Absolute Path to the Repository to fetch the origin @@ -166,6 +150,21 @@ export const getAzdoOriginUrl = async (): Promise => { } }; +/** + * Tries to fetch the Git origin from an AzDo set environment variable, else falls back to fetching it from Git directly. + * @param absRepoPath The Absolute Path to the Repository to fetch the origin url. + */ +export const tryGetGitOrigin = async ( + absRepoPath?: string +): Promise => { + return getAzdoOriginUrl().catch(() => { + logger.warn( + "Could not get Git Origin for Azure DevOps - are you running 'spk' _not_ in a pipeline?" + ); + return getOriginUrl(absRepoPath); + }); +}; + /** * Will return the name of the repository * Currently only AzDo repos are supported diff --git a/src/lib/setup/azureStorage.test.ts b/src/lib/setup/azureStorage.test.ts index 36b860004..4e1cfa399 100644 --- a/src/lib/setup/azureStorage.test.ts +++ b/src/lib/setup/azureStorage.test.ts @@ -3,7 +3,7 @@ import { createStorage, createStorageAccount, tryToCreateStorageAccount, - waitForStorageAccountToBeProvisioned + waitForStorageAccountToBeProvisioned, } from "./azureStorage"; import * as azureStorage from "./azureStorage"; import { RequestContext } from "./constants"; @@ -12,7 +12,7 @@ import * as azure from "../azure/storage"; const testCreateStorage = async (positive: boolean): Promise => { jest.spyOn(azureStorage, "tryToCreateStorageAccount").mockImplementationOnce( (rc: RequestContext): Promise => { - return new Promise(resolve => { + return new Promise((resolve) => { rc.createdStorageAccount = true; resolve(); }); @@ -29,7 +29,7 @@ const testCreateStorage = async (positive: boolean): Promise => { orgName: "notUsed", projectName: "notUsed", accessToken: "notUsed", - workspace: "notUsed" + workspace: "notUsed", }; if (positive) { @@ -63,7 +63,7 @@ describe("test tryToCreateStorageAccount function", () => { orgName: "notUsed", projectName: "notUsed", accessToken: "notUsed", - workspace: "notUsed" + workspace: "notUsed", }; await tryToCreateStorageAccount(rc); expect(rc.createdStorageAccount).toBeTruthy(); @@ -77,7 +77,7 @@ describe("test tryToCreateStorageAccount function", () => { .mockResolvedValueOnce(true); jest.spyOn(inquirer, "prompt").mockResolvedValueOnce({ // eslint-disable-next-line @typescript-eslint/camelcase - azdo_storage_account_name: "teststore" + azdo_storage_account_name: "teststore", }); jest .spyOn(azureStorage, "waitForStorageAccountToBeProvisioned") @@ -87,7 +87,7 @@ describe("test tryToCreateStorageAccount function", () => { orgName: "notUsed", projectName: "notUsed", accessToken: "notUsed", - workspace: "notUsed" + workspace: "notUsed", }; await tryToCreateStorageAccount(rc); expect(rc.createdStorageAccount).toBeTruthy(); @@ -126,7 +126,7 @@ describe("test waitForStorageAccountToBeProvisioned function", () => { const fn = jest.spyOn(azure, "getStorageAccount"); fn.mockReset(); fn.mockResolvedValueOnce({ - provisioningState: "Succeeded" + provisioningState: "Succeeded", // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); await waitForStorageAccountToBeProvisioned("dummy"); @@ -137,12 +137,12 @@ describe("test waitForStorageAccountToBeProvisioned function", () => { fn.mockReset(); fn.mockResolvedValueOnce({ - provisioningState: "" + provisioningState: "", // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); fn.mockResolvedValueOnce({ - provisioningState: "Succeeded" + provisioningState: "Succeeded", // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); diff --git a/src/lib/setup/azureStorage.ts b/src/lib/setup/azureStorage.ts index 530a6c97e..aba08a6a3 100644 --- a/src/lib/setup/azureStorage.ts +++ b/src/lib/setup/azureStorage.ts @@ -3,13 +3,13 @@ import { RESOURCE_GROUP, STORAGE_ACCOUNT_NAME, STORAGE_TABLE_NAME, - RESOURCE_GROUP_LOCATION + RESOURCE_GROUP_LOCATION, } from "./constants"; import { createStorageAccount as createAccount, createTableIfNotExists, getStorageAccount, - getStorageAccountKey + getStorageAccountKey, } from "../azure/storage"; import * as promptBuilder from "../promptBuilder"; import inquirer from "inquirer"; @@ -46,7 +46,7 @@ export const tryToCreateStorageAccount = async ( let res = await createStorageAccount(rc.storageAccountName); while (res === undefined) { const ans = await inquirer.prompt([ - promptBuilder.azureStorageAccountName() + promptBuilder.azureStorageAccountName(), ]); rc.storageAccountName = ans.azdo_storage_account_name as string; res = await createStorageAccount(rc.storageAccountName); diff --git a/src/lib/setup/setupLog.ts b/src/lib/setup/setupLog.ts index 4e42ae3dc..54ea60898 100644 --- a/src/lib/setup/setupLog.ts +++ b/src/lib/setup/setupLog.ts @@ -41,7 +41,7 @@ export const create = (rc: RequestContext | undefined, file?: string): void => { `Build Pipeline Created: ${getBooleanVal(rc.createdBuildPipeline)}`, `ACR Created: ${getBooleanVal(rc.createdACR)}`, `Storage Account Created: ${getBooleanVal(rc.createdStorageAccount)}`, - `Storage Table Created: ${getBooleanVal(rc.createdStorageTable)}` + `Storage Table Created: ${getBooleanVal(rc.createdStorageTable)}`, ]; if (rc.error) { buff.push(`Error: ${rc.error}`); diff --git a/src/lib/setup/variableGroup.test.ts b/src/lib/setup/variableGroup.test.ts index 4db69e4a4..a909163eb 100644 --- a/src/lib/setup/variableGroup.test.ts +++ b/src/lib/setup/variableGroup.test.ts @@ -14,7 +14,7 @@ const mockRequestContext: RequestContext = { servicePrincipalTenantId: "servicePrincipalTenantId", storageAccountAccessKey: "storageAccountAccessKey", storageAccountName: "storageAccountName", - storageTableName: "storageTableName" + storageTableName: "storageTableName", }; describe("test create function", () => { @@ -39,9 +39,9 @@ describe("test createVariableData function", () => { "servicePrincipalTenantId", "storageAccountAccessKey", "storageAccountName", - "storageTableName" + "storageTableName", ]; - properties.forEach(prop => { + properties.forEach((prop) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const clone = deepClone(mockRequestContext) as any; delete clone[prop]; diff --git a/src/lib/setup/variableGroup.ts b/src/lib/setup/variableGroup.ts index 3852b369c..1e7839de3 100644 --- a/src/lib/setup/variableGroup.ts +++ b/src/lib/setup/variableGroup.ts @@ -26,40 +26,40 @@ export const createVariableData = ( validateData(rc); return { ACR_NAME: { - value: rc.acrName + value: rc.acrName, }, HLD_REPO: { - value: getAzureRepoUrl(rc.orgName, rc.projectName, HLD_REPO) + value: getAzureRepoUrl(rc.orgName, rc.projectName, HLD_REPO), }, PAT: { isSecret: true, - value: rc.accessToken + value: rc.accessToken, }, SP_APP_ID: { isSecret: true, - value: rc.servicePrincipalId + value: rc.servicePrincipalId, }, SP_PASS: { isSecret: true, - value: rc.servicePrincipalPassword + value: rc.servicePrincipalPassword, }, SP_TENANT: { isSecret: true, - value: rc.servicePrincipalTenantId + value: rc.servicePrincipalTenantId, }, INTROSPECTION_ACCOUNT_KEY: { isSecret: true, - value: rc.storageAccountAccessKey + value: rc.storageAccountAccessKey, }, INTROSPECTION_ACCOUNT_NAME: { - value: rc.storageAccountName + value: rc.storageAccountName, }, INTROSPECTION_PARTITION_KEY: { - value: STORAGE_PARTITION_KEY + value: STORAGE_PARTITION_KEY, }, INTROSPECTION_TABLE_NAME: { - value: rc.storageTableName - } + value: rc.storageTableName, + }, }; }; @@ -73,6 +73,6 @@ export const create = async ( description: "Created by spk quick start command", name, type: "Vsts", - variables: createVariableData(rc) + variables: createVariableData(rc), }); };