Skip to content

Commit

Permalink
Merge pull request #31 from MicroFocus/nissim_defect_pipeline_name
Browse files Browse the repository at this point in the history
Nissim defect pipeline name
  • Loading branch information
nissimshitrit authored Apr 16, 2024
2 parents 80002ea + 9f611aa commit 9da4a6b
Show file tree
Hide file tree
Showing 21 changed files with 1,008 additions and 512 deletions.
125 changes: 73 additions & 52 deletions src/BaseTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ import {WebApi} from "azure-devops-node-api";
import {ConnectionUtils} from "./ConnectionUtils";
import {PipelineParametersService} from "./services/pipelines/PipelineParametersService";

const Query = require('@microfocus/alm-octane-js-rest-sdk/lib/query');
import { Query } from '@microfocus/alm-octane-js-rest-sdk';
import * as ba from "azure-devops-node-api/BuildApi";

export class BaseTask {
public static ALM_OCTANE_PIPELINE_START = 'AlmOctanePipelineStart';
Expand Down Expand Up @@ -91,6 +92,9 @@ export class BaseTask {
protected experiments: {[name:string]: boolean} = {};
protected parametersService: PipelineParametersService;

private octanePipelineName: string;
private useFullPipelinePath:string;

protected constructor(tl: any) {
this.tl = tl;
let logLevel = this.tl.getVariable('ALMOctaneLogLevel');
Expand Down Expand Up @@ -138,15 +142,10 @@ export class BaseTask {
this.collectionUri + this.projectId, this.instanceId, null, new Date().getTime());
let events = new CiEventsList(serverInfo, [event]);

let eventObj = {
url: this.analyticsCiInternalApiUrlPart +'/events',
body: events.toJSON()
}

let ret = await octaneSDKConnection._requestHandler._requestor.put(eventObj);

this.logger.debug('sendEvent response:' + ret);
this.logger.debug('sendEvent response:' + ret);
let ret = await octaneSDKConnection._requestHandler._requestor
.put(this.analyticsCiInternalApiUrlPart +'/events',events.toJSON());
this.logger.debug('sendEvent response:' + ret.status);
}

public async sendTestResult(octaneSDKConnection, testResult: string) {
Expand All @@ -155,16 +154,14 @@ export class BaseTask {

this.logger.debug('Sending results to:' + testResultsApiUrl + '\nThe result string is:\n' + testResult);

let testResultObj = {
url: testResultsApiUrl,
const options = {
headers: {'Content-Type': 'application/xml'},
json: false,
body: testResult
};
}

let ret = await octaneSDKConnection._requestHandler._requestor.post(testResultObj);
let ret = await octaneSDKConnection._requestHandler._requestor.post(testResultsApiUrl,testResult,options);

this.logger.debug('sendTestResult response:\n' + ret);
this.logger.debug('sendTestResult response:' + ret.status + ', result: ' + ret.result);
}

private buildAnalyticsCiInternalApiUrlPart() {
Expand Down Expand Up @@ -258,6 +255,8 @@ export class BaseTask {
this.isPipelineEndJob = this.agentJobName.toLowerCase() === BaseTask.ALM_OCTANE_PIPELINE_END.toLowerCase();
this.isPipelineJob = this.isPipelineStartJob || this.isPipelineEndJob;
this.pipelineFullName = this.projectFullName + '.' + this.buildDefinitionName + '@@@' + this.agentJobName;
this.octanePipelineName = this.tl.getInput(InputConstants.PIPELINE_NAME,false);
this.useFullPipelinePath = this.tl.getInput(InputConstants.IS_FULL_PATHNAME,false);

this.logger.info('Pipeline full name:' + this.pipelineFullName);
}
Expand All @@ -281,12 +280,20 @@ export class BaseTask {
protected async initializeExperiments(octaneSDKConnection,ws):Promise<void>{
const currentVersion = await this.getOctaneVersion(octaneSDKConnection);
this.logger.info("Octane current version: " + currentVersion);
if(this.isVersionGreaterOrEquals(currentVersion,'16.1.14')){
this.experiments = await this.getExperiments(octaneSDKConnection,ws);
} else if (this.isVersionGreaterOrEquals(currentVersion,'16.0.316')){
const isRunPipelineFromOctaneEnable = await this.isExperimentEnable(octaneSDKConnection,ws);
this.experiments['run_azure_pipeline'] = isRunPipelineFromOctaneEnable;

if(this.isVersionGreaterOrEquals(currentVersion,'16.0.316')) {
this.experiments['run_azure_pipeline'] = true;
}
if(this.isVersionGreaterOrEquals(currentVersion,'16.1.18')){
this.experiments['run_azure_pipeline_with_parameters'] = true;
}
if(this.isVersionGreaterOrEquals(currentVersion,'16.1.34')){
this.experiments['support_azure_multi_branch'] = true;
}
if(this.isVersionGreaterOrEquals(currentVersion,'16.1.41')){
this.experiments['upgrade_azure_test_runs_paths'] = true;
}

if(this.experiments.run_azure_pipeline || this.experiments.run_azure_pipeline_with_parameters ){
await this.updatePluginVersion(octaneSDKConnection);
this.logger.info("Send plugin details to Octane.");
Expand Down Expand Up @@ -427,14 +434,15 @@ export class BaseTask {
.and(Query.field(EntityTypeConstants.CI_SERVER_ENTITY_TYPE).equal(Query.field('id').equal(ciServer.id))).build();

const ciJobs = await octaneSDKConnection.get(EntityTypeRestEndpointConstants.CI_JOB_REST_API_NAME)
.fields('pipeline,definition_id')
.fields('pipeline,definition_id,name')
.query(pipelineQuery).execute();

if(ciJobs && ciJobs.total_count > 0 && ciJobs.data) {
pipelines = ciJobs.data.filter(ciJob => ciJob.pipeline).map(ciJob => ciJob.pipeline);
}
if (!pipelines || pipelines.length == 0) {
rootJobName = rootJobName + '@@@' + this.definitionId + '@@@' + this.sourceBranch;
pipelineName = await this.getPipelineName(pipelineName);
let result = await this.createPipeline(octaneSDKConnection, pipelineName, rootJobName, ciServer);
return result[0].data[0];
} else {
Expand All @@ -444,6 +452,9 @@ export class BaseTask {
if(ciJobsToUpdate?.length > 0) {
this.logger.info('Updating ' + ciJobsToUpdate.length +' CI jobs of Octane');
await this.updateExistCIJobs(ciJobsToUpdate,ciServer.id,workspaceId,octaneSDKConnection);
} else {
this.logger.info('check if need to update ci job name');
await this.updateExistCiJobNameIfNeeded(ciJobs.data,workspaceId,ciServer.id,octaneSDKConnection);
}
}
return pipelines[0];
Expand All @@ -459,6 +470,23 @@ export class BaseTask {
}
}

private async getPipelineName(pipelineName:string):Promise<string>{
if(!this.useFullPipelinePath || this.useFullPipelinePath?.toLowerCase() === 'false'){
return this.octanePipelineName || pipelineName;
}
const api: WebApi = ConnectionUtils.getWebApiWithProxy(this.collectionUri, this.authenticationService.getAzureAccessToken());
let buildApi: ba.IBuildApi = await api.getBuildApi();
let build_info = await buildApi.getBuild(this.projectName, parseInt(this.buildId));
let pipelineNameForCreate = build_info?.definition?.path && build_info?.definition.path !== '\\' ? build_info.definition.path + '\\' + pipelineName : pipelineName;
if(pipelineNameForCreate.startsWith('\\')){
pipelineNameForCreate = pipelineNameForCreate.substring(1);
}
if(pipelineNameForCreate.indexOf('\\') > 0) {
return pipelineNameForCreate.replaceAll('\\','/');
}
return pipelineNameForCreate;
}

protected async getCiJob(octaneSDKConnection, rootJobName, ciServer) {
const ciJobQuery = Query.field('ci_id').equal(BaseTask.escapeOctaneQueryValue(this.getParentJobCiId()))
.and(Query.field(EntityTypeConstants.CI_SERVER_ENTITY_TYPE).equal(Query.field('id').equal(ciServer.id))).build();
Expand All @@ -478,9 +506,9 @@ export class BaseTask {
if(!octaneVersionVariable) {
const urlStatus = this.analyticsCiInternalApiUrlPart + '/servers/connectivity/status'
const response = await octaneSDKConnection._requestHandler._requestor.get(urlStatus);
this.logger.debug("Octane connectivity status response: " + JSON.stringify(response));
this.tl.setVariable('ALMOctaneVersion',response.octaneVersion);
return response.octaneVersion;
this.logger.debug("Octane connectivity status response: " + JSON.stringify(response.data));
this.tl.setVariable('ALMOctaneVersion',response.data.octaneVersion);
return response.data.octaneVersion;
}
return octaneVersionVariable;

Expand Down Expand Up @@ -581,6 +609,25 @@ export class BaseTask {
await octaneSDKConnection._requestHandler.update(url,ciJobsToUpdate);
}

private async updateExistCiJobNameIfNeeded(ciJobs,workspaceId,ciServerId,octaneSDKConnection){
let ciJobsToUpdate = [];
for(const ciJob of ciJobs){
if(ciJob.name === this.agentJobName || BaseTask.ALM_OCTANE_PIPELINE_START.toLowerCase() === ciJob.name?.toLowerCase()) {
ciJobsToUpdate.push({
'name': this.buildDefinitionName,
'jobId': ciJob.id,
'jobCiId': this.getParentJobCiId()
});
}
}
if(ciJobsToUpdate.length > 0) {
this.logger.info('CI Jobs update body:' + ciJobs);

const url = this.ciInternalAzureApiUrlPart.replace('{workspace_id}', workspaceId) + '/ci_job_update?ci-server-id=' + ciServerId;
await octaneSDKConnection._requestHandler.update(url, ciJobsToUpdate);
}
}

private createPipelineBody(pipeline){
return {
'id': pipeline.id,
Expand All @@ -591,40 +638,14 @@ export class BaseTask {
let jobCiId = this.getParentJobCiId();

return {
'name': this.buildDefinitionName,
'jobId': ciJob.id,
'definitionId': this.definitionId,
'jobCiId': jobCiId,
'parameters': parameters
}
}

private async isExperimentEnable(octaneSDKConnection,workspaceId): Promise<boolean>{
const experimentUrl = this.ciInternalAzureApiUrlPart.replace('{workspace_id}',workspaceId) + '/experiment_run_pipeline';
const response = await octaneSDKConnection._requestHandler._requestor.get(experimentUrl);
this.logger.info("Octane experiment 'run_azure_pipeline' enabled: " + response);
return response;
}

private async getExperiments(octaneSDKConnection,workspaceId): Promise<{[name:string]: boolean}>{
const octaneExperimentsVariable = this.tl.getVariable(OctaneVariablesName.EXPERIMENTS);
this.logger.info('Octane experiments variables ' + (octaneExperimentsVariable ? 'exist' : 'not exist'));
if(!octaneExperimentsVariable) {
const experimentUrl = this.ciInternalAzureApiUrlPart.replace('{workspace_id}', workspaceId) + '/azure_pipeline_experiments';
const response = await octaneSDKConnection._requestHandler._requestor.get(experimentUrl);
if (response) {
this.logger.info("Octane experiments status: " +
Object.keys(response).map(expr => expr + '=' + response[expr]).join(', '));
}
this.tl.setVariable(OctaneVariablesName.EXPERIMENTS,JSON.stringify(response));
return response;
} else {
const octaneExperiments = JSON.parse(octaneExperimentsVariable);
this.logger.info("Octane experiments from Variable: " +
Object.keys(octaneExperiments).map(expr => expr + '=' + octaneExperiments[expr]).join(', '));
return octaneExperiments;
}
}

private async createPipeline(octaneSDKConnection, pipelineName, rootJobName, ciServer) {
let pipeline;
const api: WebApi = ConnectionUtils.getWebApiWithProxy(this.collectionUri, this.authenticationService.getAzureAccessToken());
Expand All @@ -636,7 +657,7 @@ export class BaseTask {
'name': pipelineName,
'ci_server': {'type': EntityTypeConstants.CI_SERVER_ENTITY_TYPE, 'id': ciServer.id},
'jobs': [{
'name': this.agentJobName,
'name': this.buildDefinitionName,
'jobCiId': this.getParentJobCiId(),
'definitionId': this.definitionId,
'parameters': parameters,
Expand Down
5 changes: 4 additions & 1 deletion src/ExtensionConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ export enum InputConstants {
TESTS_TO_RUN = 'testsToRun',
EXECUTION_ID = 'executionId',
SUITE_RUN_ID = 'suiteRunId',
CREATE_PIPELINE = 'CreatePipelineCheckbox'
CREATE_PIPELINE = 'CreatePipelineCheckbox',

PIPELINE_NAME = 'PipelineNameCreated',
IS_FULL_PATHNAME = 'UseFullPipelinePath'
}

export enum SystemVariablesConstants {
Expand Down
7 changes: 3 additions & 4 deletions src/MetadataUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,20 @@
*/
import {EntityTypeConstants} from "./ExtensionConstants";

const Query = require('@microfocus/alm-octane-js-rest-sdk/lib/query');
const OctaneSDK = require('@microfocus/alm-octane-js-rest-sdk').Octane;
import {Octane, Query} from '@microfocus/alm-octane-js-rest-sdk';

export class MetadataUtils {
public static async enhanceOctaneSDKConnectionWithEntitiesMetadata(octaneSDKConnection) {
let entitiesMetadataQuery = Query.field('name').equal(EntityTypeConstants.CI_SERVER_ENTITY_TYPE)
.or().field('name').equal(EntityTypeConstants.PIPELINE_ENTITY_TYPE).build();
octaneSDKConnection.entitiesMetadata = await octaneSDKConnection
.get(OctaneSDK.entityTypes.entitiesMetadata).query(entitiesMetadataQuery).execute();
.get(Octane.entityTypes.entitiesMetadata).query(entitiesMetadataQuery).execute();
}

public static async enhanceOctaneSDKConnectionWithFieldsMetadata(octaneSDKConnection) {
let fieldMetadataQuery = Query.field('entity_name').equal(EntityTypeConstants.CI_SERVER_ENTITY_TYPE)
.or().field('entity_name').equal(EntityTypeConstants.PIPELINE_ENTITY_TYPE).build();
octaneSDKConnection.fieldsMetadata = await octaneSDKConnection
.get(OctaneSDK.entityTypes.fieldsMetadata).query(fieldMetadataQuery).execute();
.get(Octane.entityTypes.fieldsMetadata).query(fieldMetadataQuery).execute();
}
}
6 changes: 3 additions & 3 deletions src/PipelinesOrchestratorTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export class PipelinesOrchestratorTask {
let serverConnectivityStatusObj = await this.octaneSDKConnection._requestHandler._requestor.get(
this.analyticsCiInternalApiUrlPart + '/servers/connectivity/status');

this.logger.info('Server connectivity status:' + JSON.stringify(serverConnectivityStatusObj));
this.logger.info('Server connectivity status:' + JSON.stringify(serverConnectivityStatusObj.data));

await new Promise<void>((async (resolve, reject) => {
const loopStartTime = Date.now();
Expand All @@ -192,7 +192,7 @@ export class PipelinesOrchestratorTask {
this.logger.info((new Date()).toTimeString() + ': Requesting tasks from Octane through: ' + this.eventObj.url);
response = await this.octaneSDKConnection._requestHandler._requestor.get(this.eventObj);

if (this.areThereAnyTasksToProcess(response)) {
if (this.areThereAnyTasksToProcess(response.data)) {
this.logger.info((new Date()).toTimeString() + ': Received ' + response.length + ' tasks to process');

for(let i = 0; i < response.length; i++) {
Expand Down Expand Up @@ -242,6 +242,6 @@ export class PipelinesOrchestratorTask {
};

let ret = await octaneSDKConnection._requestHandler._requestor.put(ackResponseObj);
this.logger.info('Octane response from receiving task status: ' + ret);
this.logger.info('Octane response from receiving task status: ' + ret.status);
}
}
3 changes: 1 addition & 2 deletions src/TestRunnerStartTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ import {CiParameter} from "./dto/events/CiParameter";
import {TestsConverter} from "./services/test_converter/TestsConverter";
import {CiEvent} from "./dto/events/CiEvent";

const Query = require('@microfocus/alm-octane-js-rest-sdk/lib/query');

import { Query } from '@microfocus/alm-octane-js-rest-sdk';
export class TestRunnerStartTask extends BaseTask {

private executorId: string;
Expand Down
25 changes: 12 additions & 13 deletions src/debug/ScheduledPipelineTaskDebug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,16 @@ function buildGetAbridgedTaskAsyncQueryParams() {
}

async function sendAckResponse(octaneSDKConnection: any, taskId: string) {
let ackResponseObj = {
url: analyticsCiInternalApiUrlPart + '/servers/' + selfIdentity + "/tasks/" + taskId + "/result",
const url = analyticsCiInternalApiUrlPart + '/servers/' + selfIdentity + "/tasks/" + taskId + "/result";
const body = {status: 201};

const options = {
headers: {ACCEPT_HEADER: 'application/json'},
json: true,
body: {status: 201}
};
}

let ret = await octaneSDKConnection._requestHandler._requestor.put(ackResponseObj);
console.log(ret);
let ret = await octaneSDKConnection._requestHandler._requestor.put(url,body,options);
console.log(ret.status);
}

async function runPipeline(ret: any) {
Expand Down Expand Up @@ -255,18 +256,16 @@ async function runScheduledTask() {

let counter = 0;
let fn = async () => {
let eventObj = {
url: analyticsCiInternalApiUrlPart + 'servers/' + selfIdentity + "/tasks" + buildGetAbridgedTaskAsyncQueryParams(),
const url = analyticsCiInternalApiUrlPart + 'servers/' + selfIdentity + "/tasks" + buildGetAbridgedTaskAsyncQueryParams();

let ret;
const options = {
headers: {ACCEPT_HEADER: 'application/json'},
json: true,
body: ""
}

let ret;

try {
// retrieving the job, if any, from Octane
ret = await octaneSDKConnection._requestHandler._requestor.get(eventObj);
ret = await octaneSDKConnection._requestHandler._requestor.get(url,"",options);
console.log(ret);
// sending back ACK
if (ret != undefined) {
Expand Down
4 changes: 2 additions & 2 deletions src/debug/debug-conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ interface Octane {
workspaces: string;
auth: Auth;
framework: string;
createPipeline: string;
createPipelineCheckbox: string;
}

interface Endpoint {
Expand Down Expand Up @@ -155,7 +155,7 @@ export class DebugConfToDebugMapsConverter {
map.set(InputConstants.GITHUB_REPOSITORY_CONNECTION, conf.repository.repositoryConnection);
map.set(InputConstants.CUCUMBER_REPORT_PATH, conf.testInjection.gherkin.cucumber.cucumberReportPath);
map.set(InputConstants.FRAMEWORK, conf.octane.framework);
map.set(InputConstants.CREATE_PIPELINE, conf.octane.createPipeline);
map.set(InputConstants.CREATE_PIPELINE, conf.octane.createPipelineCheckbox);
}

private static populateSystemVariablesMap(conf: TomlDebugConf, map: Map<string, any>) {
Expand Down
Loading

0 comments on commit 9da4a6b

Please sign in to comment.