forked from Azure/pipelines
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Action to trigger azure pipeline added
- Loading branch information
Nishu Bansal
committed
Oct 24, 2019
1 parent
56a326f
commit ec6db43
Showing
12 changed files
with
869 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: 'Azure Pipeline' | ||
description: 'Trigger an Azure pipeline release' | ||
inputs: | ||
azure-devops-url: | ||
description: 'Fullyqualified URL to the Azure DevOps organization(eg, https://dev.azure.com/organization or https://server.example.com:8080/tfs/DefaultCollection)' | ||
required: true | ||
azure-devops-project: | ||
description: 'Name of the Azure DevOps Project' | ||
required: true | ||
azure-pipeline-name: | ||
description: 'Name of the Azure Pipline to be triggered' | ||
required: true | ||
azure-devops-token: | ||
description: 'Paste personal access token of the user as value of secret variable:AZURE_DEVOPS_TOKEN' | ||
required: false | ||
pipeline-type: | ||
description: 'YAML or Designer' | ||
required: false | ||
default: 'YAML' | ||
runs: | ||
using: 'node12' | ||
main: 'lib/main.js' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const core = __importStar(require("@actions/core")); | ||
const task_parameters_1 = require("./task.parameters"); | ||
const pipeline_runner_1 = require("./pipeline.runner"); | ||
function main() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
const pipelineRunner = new pipeline_runner_1.PipelineRunner(task_parameters_1.TaskParameters.getTaskParams()); | ||
core.info("Starting pipeline runner"); | ||
yield pipelineRunner.start(); | ||
core.info("pipeline runner completed"); | ||
} | ||
catch (error) { | ||
const errorMessage = JSON.stringify(error); | ||
core.setFailed(`Error: "${error.message}" Details: "${errorMessage}"`); | ||
} | ||
}); | ||
} | ||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const core = __importStar(require("@actions/core")); | ||
const azdev = __importStar(require("azure-devops-node-api")); | ||
const task_parameters_1 = require("./task.parameters"); | ||
const ReleaseInterfaces = __importStar(require("azure-devops-node-api/interfaces/ReleaseInterfaces")); | ||
const BuildInterfaces = __importStar(require("azure-devops-node-api/interfaces/BuildInterfaces")); | ||
const pipeline_helper_1 = require("./util/pipeline.helper"); | ||
class PipelineRunner { | ||
constructor(taskParameters) { | ||
this.repository = pipeline_helper_1.PipelineHelper.processEnv("GITHUB_REPOSITORY"); | ||
this.branch = pipeline_helper_1.PipelineHelper.processEnv("GITHUB_REF"); | ||
this.commitId = pipeline_helper_1.PipelineHelper.processEnv("GITHUB_SHA"); | ||
this.githubRepo = "GitHub"; | ||
this.yaml = "YAML"; | ||
this.designer = "DESIGNER"; | ||
this.taskParameters = taskParameters; | ||
} | ||
start() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
var taskParams = task_parameters_1.TaskParameters.getTaskParams(); | ||
let authHandler = azdev.getPersonalAccessTokenHandler(taskParams.azureDevopsToken); | ||
let url = taskParams.azureDevopsUrl; | ||
core.info("Creating connection with Azure DevOps service : " + url); | ||
let webApi = new azdev.WebApi(taskParams.azureDevopsUrl, authHandler); | ||
core.info("Connection created"); | ||
if (pipeline_helper_1.PipelineHelper.equals(taskParams.azurePipelineType, this.yaml)) { | ||
core.info("Triggering Yaml pipeline : " + this.taskParameters.azurePipelineName); | ||
yield this.RunYamlPipeline(webApi); | ||
} | ||
else if (pipeline_helper_1.PipelineHelper.equals(taskParams.azurePipelineType, this.designer)) { | ||
core.info("Triggering Designer pipeline : " + this.taskParameters.azurePipelineName); | ||
yield this.RunDesignerPipeline(webApi); | ||
} | ||
} | ||
catch (error) { | ||
let errorMessage = `${error.message}`; | ||
core.setFailed(errorMessage); | ||
} | ||
}); | ||
} | ||
RunYamlPipeline(webApi) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
let buildApi = yield webApi.getBuildApi(); | ||
let projectName = this.taskParameters.azureDevopsproject; | ||
let pipelineName = this.taskParameters.azurePipelineName; | ||
// Get matching build definitions for the given project and pipeline name | ||
const buildDefinitions = yield buildApi.getDefinitions(projectName, pipelineName); | ||
// If more than 1 definition is returned, Throw Error | ||
if (buildDefinitions == null || buildDefinitions.length != 1) { | ||
let errorMessage = `YAML Pipeline named "${pipelineName}" in project ${projectName} not found`; | ||
throw Error(errorMessage); | ||
} | ||
// Extract Id from build definition | ||
let buildDefinitionReference = buildDefinitions[0]; | ||
let buildDefinitionId = buildDefinitionReference.id; | ||
// Get build definition for the matching definition Id | ||
let buildDefinition = yield buildApi.getDefinition(projectName, buildDefinitionId); | ||
core.info("Pipeline object : " + pipeline_helper_1.PipelineHelper.getPrintObject(buildDefinition)); | ||
// Fetch repository details from build definition | ||
let repositoryId = buildDefinition.repository.id.trim(); | ||
let repositoryType = buildDefinition.repository.type.trim(); | ||
let sourceBranch = null; | ||
let sourceVersion = null; | ||
// If definition is linked to existing github repo, pass github source branch and source version to build | ||
if (pipeline_helper_1.PipelineHelper.equals(repositoryId, this.repository) && pipeline_helper_1.PipelineHelper.equals(repositoryType, this.githubRepo)) { | ||
core.info("pipeline is linked to same Github repo"); | ||
sourceBranch = this.branch, | ||
sourceVersion = this.commitId; | ||
} | ||
else { | ||
core.info("pipeline is not linked to same Github repo"); | ||
} | ||
let build = { | ||
definition: { | ||
id: buildDefinition.id | ||
}, | ||
project: { | ||
id: buildDefinition.project.id | ||
}, | ||
sourceBranch: sourceBranch, | ||
sourceVersion: sourceVersion, | ||
reason: BuildInterfaces.BuildReason.Triggered | ||
}; | ||
core.info("Input - \n" + pipeline_helper_1.PipelineHelper.getPrintObject(build)); | ||
// Queue build | ||
let buildQueueResult = yield buildApi.queueBuild(build, build.project.id, true); | ||
if (buildQueueResult != null) { | ||
core.info("Output - \n" + pipeline_helper_1.PipelineHelper.getPrintObject(buildQueueResult)); | ||
// If build result contains validation errors set result to FAILED | ||
if (buildQueueResult.validationResults != null && buildQueueResult.validationResults.length > 0) { | ||
let errorAndWarningMessage = pipeline_helper_1.PipelineHelper.getErrorAndWarningMessageFromBuildResult(buildQueueResult.validationResults); | ||
core.setFailed("Errors: " + errorAndWarningMessage.errorMessage + " Warnings: " + errorAndWarningMessage.warningMessage); | ||
} | ||
else { | ||
core.info(`\Pipeline "${pipelineName}" started - Id: ${buildQueueResult.id}`); | ||
if (buildQueueResult._links != null && buildQueueResult._links.web != null) { | ||
core.setOutput('pipeline-url', buildQueueResult._links.web.href); | ||
} | ||
} | ||
} | ||
} | ||
catch (error) { | ||
core.error(error); | ||
core.setFailed("Pipeline failed"); | ||
} | ||
}); | ||
} | ||
RunDesignerPipeline(webApi) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
let releaseApi = yield webApi.getReleaseApi(); | ||
// Get release definitions for the given project name and pipeline name | ||
const releaseDefinitions = yield releaseApi.getReleaseDefinitions(this.taskParameters.azureDevopsproject, this.taskParameters.azurePipelineName, ReleaseInterfaces.ReleaseDefinitionExpands.Artifacts); | ||
if (releaseDefinitions == null || releaseDefinitions.length != 1) { | ||
// If more than 1 definition found, throw ERROR | ||
let errorMessage = `Designer Pipeline named "${this.taskParameters.azurePipelineName}" in project ${this.taskParameters.azureDevopsproject} not found`; | ||
throw Error(errorMessage); | ||
} | ||
let releaseDefinition = releaseDefinitions[0]; | ||
core.info("Pipeline object : " + pipeline_helper_1.PipelineHelper.getPrintObject(releaseDefinition)); | ||
// Filter Github artifacts from release definition | ||
let gitHubArtifacts = releaseDefinition.artifacts.filter(pipeline_helper_1.PipelineHelper.isGitHubArtifact); | ||
let artifacts = new Array(); | ||
if (gitHubArtifacts == null || gitHubArtifacts.length == 0) { | ||
core.info("Pipeline is not linked to any GitHub artifact"); | ||
// If no GitHub artifacts found it means pipeline is not linked to any GitHub artifact | ||
} | ||
else { | ||
// If pipeline has any matching Github artifact | ||
core.info("Pipeline is linked to GitHub artifact. Looking for now matching repository"); | ||
gitHubArtifacts.forEach(gitHubArtifact => { | ||
if (gitHubArtifact.definitionReference != null && pipeline_helper_1.PipelineHelper.equals(gitHubArtifact.definitionReference.definition.name, this.repository)) { | ||
// Add version information for matching GitHub artifact | ||
let artifactMetadata = { | ||
alias: gitHubArtifact.alias, | ||
instanceReference: { | ||
id: this.commitId, | ||
sourceBranch: this.branch, | ||
sourceRepositoryType: this.githubRepo, | ||
sourceRepositoryId: this.repository, | ||
sourceVersion: this.commitId | ||
} | ||
}; | ||
core.info("pipeline is linked to same Github repo"); | ||
artifacts.push(artifactMetadata); | ||
} | ||
}); | ||
} | ||
let releaseStartMetadata = { | ||
definitionId: releaseDefinition.id, | ||
reason: ReleaseInterfaces.ReleaseReason.ContinuousIntegration, | ||
artifacts: artifacts | ||
}; | ||
core.info("Input - \n" + pipeline_helper_1.PipelineHelper.getPrintObject(releaseStartMetadata)); | ||
// create release | ||
let release = yield releaseApi.createRelease(releaseStartMetadata, this.taskParameters.azureDevopsproject); | ||
if (release != null) { | ||
core.info("Output - \n" + pipeline_helper_1.PipelineHelper.getPrintObject(release)); | ||
if (release != null && release._links != null && release._links.web != null) { | ||
core.setOutput('pipeline-url', release._links.web.href); | ||
} | ||
core.info("Release is created"); | ||
} | ||
} | ||
catch (error) { | ||
core.error(error); | ||
core.setFailed("Pipeline failed"); | ||
} | ||
}); | ||
} | ||
} | ||
exports.PipelineRunner = PipelineRunner; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
"use strict"; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const core = __importStar(require("@actions/core")); | ||
class TaskParameters { | ||
constructor() { | ||
this._azureDevopsUrl = core.getInput('azure-devops-url', { required: true }); | ||
this._azureDevopsProject = core.getInput('azure-devops-project', { required: true }); | ||
this._azurePipelineName = core.getInput('azure-pipeline-name', { required: true }); | ||
this._azureDevopsToken = core.getInput('azure-devops-token', { required: true }); | ||
this._azurePipelineType = 'YAML'; | ||
if (core.getInput('azure-pipeline-type')) { | ||
this._azurePipelineType = core.getInput('azure-pipeline-type'); | ||
} | ||
} | ||
static getTaskParams() { | ||
if (!this.taskparams) { | ||
this.taskparams = new TaskParameters(); | ||
} | ||
return this.taskparams; | ||
} | ||
get azureDevopsUrl() { | ||
return this._azureDevopsUrl; | ||
} | ||
get azureDevopsproject() { | ||
return this._azureDevopsProject; | ||
} | ||
get azurePipelineName() { | ||
return this._azurePipelineName; | ||
} | ||
get azureDevopsToken() { | ||
return this._azureDevopsToken; | ||
} | ||
get azurePipelineType() { | ||
return this._azurePipelineType; | ||
} | ||
} | ||
exports.TaskParameters = TaskParameters; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
"use strict"; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const BuildInterfaces = __importStar(require("azure-devops-node-api/interfaces/BuildInterfaces")); | ||
class PipelineHelper { | ||
static equals(str1, str2) { | ||
if (str1 === str2) { | ||
return true; | ||
} | ||
if (str1 === null) { | ||
return false; | ||
} | ||
if (str2 === null) { | ||
return false; | ||
} | ||
return str1.trim().toUpperCase() === str2.trim().toUpperCase(); | ||
} | ||
static getPrintObject(object) { | ||
return JSON.stringify(object, null, 4); | ||
} | ||
static processEnv(envVarName) { | ||
const variable = process.env[envVarName]; | ||
if (!variable) { | ||
throw new Error(`env.${envVarName} is not set`); | ||
} | ||
return variable; | ||
} | ||
; | ||
static isGitHubArtifact(arifact) { | ||
if (arifact != null && arifact.type != null && arifact.type.toUpperCase() === "GITHUB") { | ||
return true; | ||
} | ||
return false; | ||
} | ||
static getErrorAndWarningMessageFromBuildResult(validationResults) { | ||
let errorMessage = ""; | ||
let warningMessage = ""; | ||
if (validationResults && validationResults.length > 0) { | ||
let errors = validationResults.filter((result) => { | ||
return result.result === BuildInterfaces.ValidationResult.Error; | ||
}); | ||
if (errors.length > 0) { | ||
errorMessage = this._joinValidateResults(errors); | ||
} | ||
else { | ||
warningMessage = this._joinValidateResults(validationResults); | ||
} | ||
} | ||
// Taking into account server errors also which comes not in form of array, like no build queue permissions | ||
else if (validationResults) { | ||
errorMessage = this._getErrorMessageFromServer(validationResults); | ||
} | ||
return { | ||
errorMessage: errorMessage, | ||
warningMessage: warningMessage | ||
}; | ||
} | ||
static _joinValidateResults(validateResults) { | ||
let resultMessages = validateResults.map((validationResult) => { | ||
return validationResult.message; | ||
}); | ||
resultMessages = resultMessages.filter((message) => !!message); | ||
return resultMessages.join(","); | ||
} | ||
static _getErrorMessageFromServer(validationResult) { | ||
let errorMessage = ""; | ||
if (validationResult) { | ||
errorMessage = validationResult.message || ""; | ||
} | ||
if (validationResult && validationResult.serverError && errorMessage.length === 0) { | ||
errorMessage = validationResult.serverError.message || ""; | ||
} | ||
return errorMessage; | ||
} | ||
} | ||
exports.PipelineHelper = PipelineHelper; |
Oops, something went wrong.