Skip to content
This repository was archived by the owner on Apr 13, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions src/lib/azure/azurecredentials.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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!
);
};
Expand Down Expand Up @@ -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;
};
3 changes: 2 additions & 1 deletion src/lib/azure/containerRegistryService.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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] : "",
};
Expand Down
47 changes: 14 additions & 33 deletions src/lib/azure/keyvault.test.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -16,10 +10,7 @@ const secretValue = uuid();

jest.spyOn(keyvault, "getClient").mockReturnValue(
Promise.resolve({
getSecret: async (
secretName: string,
options?: GetSecretOptions
): Promise<KeyVaultSecret> => {
getSecret: async (): Promise<KeyVaultSecret> => {
return {
name: "test",
properties: {
Expand All @@ -29,11 +20,7 @@ jest.spyOn(keyvault, "getClient").mockReturnValue(
value: "secretValue",
};
},
setSecret: async (
secretName: string,
value: string,
options?: SetSecretOptions
): Promise<KeyVaultSecret> => {
setSecret: async (): Promise<KeyVaultSecret> => {
return {
name: "test",
properties: {
Expand All @@ -42,7 +29,8 @@ jest.spyOn(keyvault, "getClient").mockReturnValue(
},
};
},
} as SecretClient)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any)
);

beforeAll(() => {
Expand All @@ -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<KeyVaultSecret> => {
setSecret: (): Promise<KeyVaultSecret> => {
throw new Error("fake error");
},
} as SecretClient)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any)
);
try {
await setSecret(keyVaultName, mockedName, secretValue);
Expand All @@ -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<KeyVaultSecret> => {
getSecret: (): Promise<KeyVaultSecret> => {
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);
Expand All @@ -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<KeyVaultSecret> => {
getSecret: (): Promise<KeyVaultSecret> => {
throw {
code: "something else",
statusCode: 400,
};
},
} as SecretClient)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any)
);
try {
await getSecret(keyVaultName, mockedName);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/azure/keyvault.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -30,6 +29,7 @@ export const getClient = async (
): Promise<SecretClient> => {
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!);
};

Expand Down
10 changes: 5 additions & 5 deletions src/lib/git/azure.test.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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;
Expand All @@ -163,7 +163,7 @@ describe("createPullRequest", () => {
});
it("negative test", async () => {
gitApi.createPullRequest = async (): Promise<unknown> => {
throw new Error("fake");
throw Error("fake");
};

await expect(
Expand All @@ -175,7 +175,7 @@ describe("createPullRequest", () => {
});
it("negative test: TF401179 error", async () => {
gitApi.createPullRequest = async (): Promise<unknown> => {
throw new Error("TF401179");
throw Error("TF401179");
};

await expect(
Expand Down
10 changes: 6 additions & 4 deletions src/lib/git/azure.ts
Original file line number Diff line number Diff line change
@@ -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, {
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -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,
};
Expand Down Expand Up @@ -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
);
Expand Down Expand Up @@ -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(
Expand Down
31 changes: 15 additions & 16 deletions src/lib/gitutils.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -114,21 +113,6 @@ export const pushBranch = async (branchName: string): Promise<void> => {
}
};

/**
* 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<string> => {
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
Expand Down Expand Up @@ -166,6 +150,21 @@ export const getAzdoOriginUrl = async (): Promise<string> => {
}
};

/**
* 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<string> => {
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
Expand Down
Loading