Integrated workflow list and run API to get lastSuccessRunCommit

This commit is contained in:
Koushik Dey 2020-08-05 10:43:46 +05:30
parent 3919a9ee22
commit 3d1e46f18f
9 changed files with 151 additions and 63 deletions

View File

@ -384,7 +384,6 @@ test("utility - getLastSuccessfulRunSha() - Get Commits under different conditio
if (name == errorWebRequest)
return Promise.resolve(errorWebResponse);
});*/
jest.spyOn(httpClient, 'sendRequest').mockImplementation(() => Promise.resolve(lastSuccessfulRunUrlResponse));
//Invoke and assert
await expect(utility.getLastSuccessfulRunSha(process.env.GITHUB_TOKEN)).resolves.not.toThrowError;

View File

@ -41,9 +41,9 @@ function getWorkflowAnnotationsJson(lastSuccessRunSha) {
+ `}`;
}
exports.getWorkflowAnnotationsJson = getWorkflowAnnotationsJson;
function getWorkflowAnnotationKeyLabel() {
function getWorkflowAnnotationKeyLabel(workflowFilePath) {
const hashKey = require("crypto").createHash("MD5")
.update(`${process.env.GITHUB_REPOSITORY}/${process.env.GITHUB_WORKFLOW}`)
.update(`${process.env.GITHUB_REPOSITORY}/${workflowFilePath}`)
.digest("hex");
return `githubWorkflow_${hashKey}`;
}

View File

@ -17,10 +17,10 @@ class GitHubClient {
this._repository = repository;
this._token = token;
}
getSuccessfulRunsOnBranch(branch, force) {
getSuccessfulRunsOnBranch(branch, workflowFileName, force) {
return __awaiter(this, void 0, void 0, function* () {
if (force || !this._successfulRunsOnBranchPromise) {
const lastSuccessfulRunUrl = `https://api.github.com/repos/${this._repository}/actions/runs?status=success&branch=${branch}`;
const lastSuccessfulRunUrl = `https://api.github.com/repos/${this._repository}/actions/workflows/${workflowFileName}/runs?status=success&branch=${branch}`;
const webRequest = new httpClient_1.WebRequest();
webRequest.method = "GET";
webRequest.uri = lastSuccessfulRunUrl;
@ -34,5 +34,22 @@ class GitHubClient {
return this._successfulRunsOnBranchPromise;
});
}
getWorkflows(force) {
return __awaiter(this, void 0, void 0, function* () {
if (force || !this._workflowsPromise) {
const getWorkflowFileNameUrl = `https://api.github.com/repos/${this._repository}/actions/workflows`;
const webRequest = new httpClient_1.WebRequest();
webRequest.method = "GET";
webRequest.uri = getWorkflowFileNameUrl;
webRequest.headers = {
Authorization: `Bearer ${this._token}`
};
core.debug(`Getting workflows for repo: ${this._repository}`);
const response = yield httpClient_1.sendRequest(webRequest);
this._workflowsPromise = Promise.resolve(response);
}
return this._workflowsPromise;
});
}
}
exports.GitHubClient = GitHubClient;

View File

@ -111,25 +111,26 @@ function checkManifestStability(kubectl, resources) {
});
}
function annotateAndLabelResources(files, kubectl, resourceTypes, allPods) {
const annotationKeyLabel = models.getWorkflowAnnotationKeyLabel();
annotateResources(files, kubectl, resourceTypes, allPods, annotationKeyLabel);
labelResources(files, kubectl, annotationKeyLabel);
return __awaiter(this, void 0, void 0, function* () {
const workflowFilePath = yield utility_1.getWorkflowFilePath(TaskInputParameters.githubToken);
const annotationKeyLabel = models.getWorkflowAnnotationKeyLabel(workflowFilePath);
annotateResources(files, kubectl, resourceTypes, allPods, annotationKeyLabel);
labelResources(files, kubectl, annotationKeyLabel);
});
}
function annotateResources(files, kubectl, resourceTypes, allPods, annotationKey) {
return __awaiter(this, void 0, void 0, function* () {
const annotateResults = [];
const lastSuccessSha = yield utility_1.getLastSuccessfulRunSha(TaskInputParameters.githubToken);
let annotationKeyValStr = annotationKey + '=' + models.getWorkflowAnnotationsJson(lastSuccessSha);
annotateResults.push(kubectl.annotate('namespace', TaskInputParameters.namespace, [annotationKeyValStr], true));
annotateResults.push(kubectl.annotateFiles(files, [annotationKeyValStr], true));
resourceTypes.forEach(resource => {
if (resource.type.toUpperCase() !== models.KubernetesWorkload.pod.toUpperCase()) {
utility_1.annotateChildPods(kubectl, resource.type, resource.name, annotationKeyValStr, allPods)
.forEach(execResult => annotateResults.push(execResult));
}
});
utility_1.checkForErrors(annotateResults, true);
const annotateResults = [];
const lastSuccessSha = utility_1.getLastSuccessfulRunSha(kubectl, TaskInputParameters.namespace, annotationKey);
let annotationKeyValStr = annotationKey + '=' + models.getWorkflowAnnotationsJson(lastSuccessSha);
annotateResults.push(kubectl.annotate('namespace', TaskInputParameters.namespace, [annotationKeyValStr], true));
annotateResults.push(kubectl.annotateFiles(files, [annotationKeyValStr], true));
resourceTypes.forEach(resource => {
if (resource.type.toUpperCase() !== models.KubernetesWorkload.pod.toUpperCase()) {
utility_1.annotateChildPods(kubectl, resource.type, resource.name, annotationKeyValStr, allPods)
.forEach(execResult => annotateResults.push(execResult));
}
});
utility_1.checkForErrors(annotateResults, true);
}
function labelResources(files, kubectl, label) {
utility_1.checkForErrors([kubectl.labelFiles(files, [`workflow=${label}`], true)], true);

View File

@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCurrentTime = exports.getRandomInt = exports.sleep = exports.annotateChildPods = exports.getLastSuccessfulRunSha = exports.checkForErrors = exports.isEqual = exports.getExecutableExtension = void 0;
exports.getCurrentTime = exports.getRandomInt = exports.sleep = exports.annotateChildPods = exports.getWorkflowFilePath = exports.getLastSuccessfulRunSha = exports.checkForErrors = exports.isEqual = exports.getExecutableExtension = void 0;
const os = require("os");
const core = require("@actions/core");
const githubClient_1 = require("../githubClient");
@ -60,29 +60,55 @@ function checkForErrors(execResults, warnIfError) {
}
}
exports.checkForErrors = checkForErrors;
function getLastSuccessfulRunSha(githubToken) {
return __awaiter(this, void 0, void 0, function* () {
let lastSuccessRunSha = '';
const gitHubClient = new githubClient_1.GitHubClient(process.env.GITHUB_REPOSITORY, githubToken);
const branch = process.env.GITHUB_REF.replace("refs/heads/", "");
const response = yield gitHubClient.getSuccessfulRunsOnBranch(branch);
if (response.statusCode == httpClient_1.StatusCodes.OK
&& !!response.body
&& !!response.body.total_count) {
if (response.body.total_count > 0) {
lastSuccessRunSha = response.body.workflow_runs[0].head_sha;
function getLastSuccessfulRunSha(kubectl, namespaceName, annotationKey) {
const result = kubectl.getResource('namespace', namespaceName);
if (!result) {
core.debug(`Failed to get commits from cluster.`);
return '';
}
else {
if (result.stderr) {
core.debug(`${result.stderr}`);
return process.env.GITHUB_SHA;
}
else if (result.stdout) {
const annotationsSet = JSON.parse(result.stdout).metadata.annotations;
if (!!annotationsSet[annotationKey]) {
return JSON.parse(annotationsSet[annotationKey].replace(/'/g, '"')).commit;
}
else {
lastSuccessRunSha = 'NA';
return 'NA';
}
}
else if (response.statusCode != httpClient_1.StatusCodes.OK) {
core.debug(`An error occured while getting succeessful run results. Statuscode: ${response.statusCode}, StatusMessage: ${response.statusMessage}`);
}
return Promise.resolve(lastSuccessRunSha);
});
}
}
exports.getLastSuccessfulRunSha = getLastSuccessfulRunSha;
function getWorkflowFilePath(githubToken) {
return __awaiter(this, void 0, void 0, function* () {
let workflowFilePath = process.env.GITHUB_WORKFLOW;
if (!workflowFilePath.startsWith('.github/workflows/')) {
const githubClient = new githubClient_1.GitHubClient(process.env.GITHUB_REPOSITORY, githubToken);
const response = yield githubClient.getWorkflows();
if (response.statusCode == httpClient_1.StatusCodes.OK
&& !!response.body
&& !!response.body.total_count) {
if (response.body.total_count > 0) {
for (let workflow of response.body.workflows) {
if (process.env.GITHUB_WORKFLOW === workflow.name) {
workflowFilePath = workflow.path;
break;
}
}
}
}
else if (response.statusCode != httpClient_1.StatusCodes.OK) {
core.debug(`An error occured while getting list of workflows on the repo. Statuscode: ${response.statusCode}, StatusMessage: ${response.statusMessage}`);
}
}
return Promise.resolve(workflowFilePath);
});
}
exports.getWorkflowFilePath = getWorkflowFilePath;
function annotateChildPods(kubectl, resourceType, resourceName, annotationKeyValStr, allPods) {
const commandExecutionResults = [];
let owner = resourceName;

View File

@ -40,9 +40,9 @@ export function getWorkflowAnnotationsJson(lastSuccessRunSha: string): string {
+ `'provider': 'GitHub'`
+ `}`;
}
export function getWorkflowAnnotationKeyLabel(): string {
export function getWorkflowAnnotationKeyLabel(workflowFilePath: string): string {
const hashKey = require("crypto").createHash("MD5")
.update(`${process.env.GITHUB_REPOSITORY}/${process.env.GITHUB_WORKFLOW}`)
.update(`${process.env.GITHUB_REPOSITORY}/${workflowFilePath}`)
.digest("hex");
return `githubWorkflow_${hashKey}`;
}

View File

@ -7,9 +7,9 @@ export class GitHubClient {
this._token = token;
}
public async getSuccessfulRunsOnBranch(branch: string, force?: boolean): Promise<any> {
public async getSuccessfulRunsOnBranch(branch: string, workflowFileName: string, force?: boolean): Promise<any> {
if (force || !this._successfulRunsOnBranchPromise) {
const lastSuccessfulRunUrl = `https://api.github.com/repos/${this._repository}/actions/runs?status=success&branch=${branch}`;
const lastSuccessfulRunUrl = `https://api.github.com/repos/${this._repository}/actions/workflows/${workflowFileName}/runs?status=success&branch=${branch}`;
const webRequest = new WebRequest();
webRequest.method = "GET";
webRequest.uri = lastSuccessfulRunUrl;
@ -24,7 +24,25 @@ export class GitHubClient {
return this._successfulRunsOnBranchPromise;
}
public async getWorkflows(force?: boolean): Promise<any> {
if (force || !this._workflowsPromise) {
const getWorkflowFileNameUrl = `https://api.github.com/repos/${this._repository}/actions/workflows`;
const webRequest = new WebRequest();
webRequest.method = "GET";
webRequest.uri = getWorkflowFileNameUrl;
webRequest.headers = {
Authorization: `Bearer ${this._token}`
};
core.debug(`Getting workflows for repo: ${this._repository}`);
const response: WebResponse = await sendRequest(webRequest);
this._workflowsPromise = Promise.resolve(response);
}
return this._workflowsPromise;
}
private _repository: string;
private _token: string;
private _successfulRunsOnBranchPromise: Promise<any>;
private _workflowsPromise: Promise<any>;
}

View File

@ -17,7 +17,7 @@ import { IExecSyncResult } from '../../utilities/tool-runner';
import { deployPodCanary } from './pod-canary-deployment-helper';
import { deploySMICanary } from './smi-canary-deployment-helper';
import { checkForErrors, annotateChildPods, getLastSuccessfulRunSha } from "../utility";
import { checkForErrors, annotateChildPods, getWorkflowFilePath, getLastSuccessfulRunSha } from "../utility";
export async function deploy(kubectl: Kubectl, manifestFilePaths: string[], deploymentStrategy: string) {
@ -112,15 +112,16 @@ async function checkManifestStability(kubectl: Kubectl, resources: Resource[]):
await KubernetesManifestUtility.checkManifestStability(kubectl, resources);
}
function annotateAndLabelResources(files: string[], kubectl: Kubectl, resourceTypes: Resource[], allPods: any) {
const annotationKeyLabel = models.getWorkflowAnnotationKeyLabel();
async function annotateAndLabelResources(files: string[], kubectl: Kubectl, resourceTypes: Resource[], allPods: any) {
const workflowFilePath = await getWorkflowFilePath(TaskInputParameters.githubToken);
const annotationKeyLabel = models.getWorkflowAnnotationKeyLabel(workflowFilePath);
annotateResources(files, kubectl, resourceTypes, allPods, annotationKeyLabel);
labelResources(files, kubectl, annotationKeyLabel);
}
async function annotateResources(files: string[], kubectl: Kubectl, resourceTypes: Resource[], allPods: any, annotationKey: string) {
function annotateResources(files: string[], kubectl: Kubectl, resourceTypes: Resource[], allPods: any, annotationKey: string) {
const annotateResults: IExecSyncResult[] = [];
const lastSuccessSha = await getLastSuccessfulRunSha(TaskInputParameters.githubToken);
const lastSuccessSha = getLastSuccessfulRunSha(kubectl, TaskInputParameters.namespace, annotationKey);
let annotationKeyValStr = annotationKey + '=' + models.getWorkflowAnnotationsJson(lastSuccessSha);
annotateResults.push(kubectl.annotate('namespace', TaskInputParameters.namespace, [annotationKeyValStr], true));
annotateResults.push(kubectl.annotateFiles(files, [annotationKeyValStr], true));

View File

@ -51,25 +51,51 @@ export function checkForErrors(execResults: IExecSyncResult[], warnIfError?: boo
}
}
export async function getLastSuccessfulRunSha(githubToken: string): Promise<string> {
let lastSuccessRunSha = '';
const gitHubClient = new GitHubClient(process.env.GITHUB_REPOSITORY, githubToken);
const branch = process.env.GITHUB_REF.replace("refs/heads/", "");
const response = await gitHubClient.getSuccessfulRunsOnBranch(branch);
if (response.statusCode == StatusCodes.OK
&& !!response.body
&& !!response.body.total_count) {
if (response.body.total_count > 0) {
lastSuccessRunSha = response.body.workflow_runs[0].head_sha;
export function getLastSuccessfulRunSha(kubectl: Kubectl, namespaceName: string, annotationKey: string): string {
const result = kubectl.getResource('namespace', namespaceName);
if (!result) {
core.debug(`Failed to get commits from cluster.`);
return '';
}
else {
if (result.stderr) {
core.debug(`${result.stderr}`);
return process.env.GITHUB_SHA;
}
else {
lastSuccessRunSha = 'NA';
else if (result.stdout) {
const annotationsSet = JSON.parse(result.stdout).metadata.annotations;
if (!!annotationsSet[annotationKey]) {
return JSON.parse(annotationsSet[annotationKey].replace(/'/g, '"')).commit;
}
else {
return 'NA';
}
}
}
else if (response.statusCode != StatusCodes.OK) {
core.debug(`An error occured while getting succeessful run results. Statuscode: ${response.statusCode}, StatusMessage: ${response.statusMessage}`);
}
export async function getWorkflowFilePath(githubToken: string): Promise<string> {
let workflowFilePath = process.env.GITHUB_WORKFLOW;
if (!workflowFilePath.startsWith('.github/workflows/')) {
const githubClient = new GitHubClient(process.env.GITHUB_REPOSITORY, githubToken);
const response = await githubClient.getWorkflows();
if (response.statusCode == StatusCodes.OK
&& !!response.body
&& !!response.body.total_count) {
if (response.body.total_count > 0) {
for (let workflow of response.body.workflows) {
if (process.env.GITHUB_WORKFLOW === workflow.name) {
workflowFilePath = workflow.path;
break;
}
}
}
}
else if (response.statusCode != StatusCodes.OK) {
core.debug(`An error occured while getting list of workflows on the repo. Statuscode: ${response.statusCode}, StatusMessage: ${response.statusMessage}`);
}
}
return Promise.resolve(lastSuccessRunSha);
return Promise.resolve(workflowFilePath);
}
export function annotateChildPods(kubectl: Kubectl, resourceType: string, resourceName: string, annotationKeyValStr: string, allPods): IExecSyncResult[] {