2019-10-16 16:49:09 -07:00
import {
IHookFunctions ,
IWebhookFunctions ,
} from 'n8n-core' ;
import {
IDataObject ,
INodeType ,
2020-10-01 05:01:39 -07:00
INodeTypeDescription ,
2019-10-16 16:49:09 -07:00
IWebhookResponseData ,
2021-04-16 09:33:36 -07:00
NodeApiError ,
NodeOperationError ,
2019-10-16 16:49:09 -07:00
} from 'n8n-workflow' ;
import {
gitlabApiRequest ,
} from './GenericFunctions' ;
export class GitlabTrigger implements INodeType {
description : INodeTypeDescription = {
2020-07-24 03:56:41 -07:00
displayName : 'GitLab Trigger' ,
2019-10-16 16:49:09 -07:00
name : 'gitlabTrigger' ,
2021-03-25 09:10:02 -07:00
icon : 'file:gitlab.svg' ,
2019-10-16 16:49:09 -07:00
group : [ 'trigger' ] ,
version : 1 ,
subtitle : '={{$parameter["owner"] + "/" + $parameter["repository"] + ": " + $parameter["events"].join(", ")}}' ,
2020-07-24 03:56:41 -07:00
description : 'Starts the workflow when a GitLab event occurs.' ,
2019-10-16 16:49:09 -07:00
defaults : {
name : 'Gitlab Trigger' ,
color : '#FC6D27' ,
} ,
inputs : [ ] ,
outputs : [ 'main' ] ,
credentials : [
{
name : 'gitlabApi' ,
required : true ,
2020-06-16 06:50:17 -07:00
displayOptions : {
show : {
authentication : [
'accessToken' ,
] ,
} ,
} ,
} ,
{
name : 'gitlabOAuth2Api' ,
required : true ,
displayOptions : {
show : {
authentication : [
'oAuth2' ,
] ,
} ,
} ,
} ,
2019-10-16 16:49:09 -07:00
] ,
webhooks : [
{
name : 'default' ,
httpMethod : 'POST' ,
responseMode : 'onReceived' ,
path : 'webhook' ,
} ,
] ,
properties : [
2020-06-16 06:50:17 -07:00
{
displayName : 'Authentication' ,
name : 'authentication' ,
type : 'options' ,
options : [
{
name : 'Access Token' ,
value : 'accessToken' ,
} ,
{
name : 'OAuth2' ,
value : 'oAuth2' ,
} ,
] ,
default : 'accessToken' ,
description : 'The resource to operate on.' ,
} ,
2019-10-16 16:49:09 -07:00
{
displayName : 'Repository Owner' ,
name : 'owner' ,
type : 'string' ,
default : '' ,
required : true ,
placeholder : 'n8n-io' ,
description : 'Owner of the repsitory.' ,
} ,
{
displayName : 'Repository Name' ,
name : 'repository' ,
type : 'string' ,
default : '' ,
required : true ,
placeholder : 'n8n' ,
description : 'The name of the repsitory.' ,
} ,
{
displayName : 'Events' ,
name : 'events' ,
type : 'multiOptions' ,
options : [
{
name : '*' ,
value : '*' ,
description : 'Any time any event is triggered (Wildcard Event).' ,
} ,
{
name : 'Comment' ,
value : 'note' ,
2020-10-22 06:46:03 -07:00
description : 'Triggered when a new comment is made on commits, merge requests, issues, and code snippets.' ,
2019-10-16 16:49:09 -07:00
} ,
{
name : 'Issue' ,
value : 'issues' ,
2020-10-22 06:46:03 -07:00
description : 'Triggered when a new issue is created or an existing issue was updated/closed/reopened.' ,
2019-10-16 16:49:09 -07:00
} ,
{
name : 'Job' ,
value : 'job' ,
2020-10-22 06:46:03 -07:00
description : 'Triggered on status change of a job.' ,
2019-10-16 16:49:09 -07:00
} ,
{
name : 'Merge Request' ,
value : 'merge_requests' ,
2020-10-22 06:46:03 -07:00
description : 'Triggered when a new merge request is created, an existing merge request was updated/merged/closed or a commit is added in the source branch.' ,
2019-10-16 16:49:09 -07:00
} ,
{
name : 'Pipeline' ,
value : 'pipeline' ,
2020-10-22 06:46:03 -07:00
description : 'Triggered on status change of Pipeline.' ,
2019-10-16 16:49:09 -07:00
} ,
{
name : 'Push' ,
value : 'push' ,
2020-10-22 06:46:03 -07:00
description : 'Triggered when you push to the repository except when pushing tags.' ,
2019-10-16 16:49:09 -07:00
} ,
{
name : 'Tag' ,
value : 'tag_push' ,
2020-10-22 06:46:03 -07:00
description : 'Triggered when you create (or delete) tags to the repository.' ,
2019-10-16 16:49:09 -07:00
} ,
{
name : 'Wiki Page' ,
value : 'wiki_page' ,
2020-10-22 06:46:03 -07:00
description : 'Triggered when a wiki page is created, updated or deleted.' ,
} ,
2019-10-16 16:49:09 -07:00
] ,
required : true ,
default : [ ] ,
description : 'The events to listen to.' ,
} ,
] ,
} ;
// @ts-ignore (because of request)
webhookMethods = {
default : {
async checkExists ( this : IHookFunctions ) : Promise < boolean > {
const webhookData = this . getWorkflowStaticData ( 'node' ) ;
if ( webhookData . webhookId === undefined ) {
// No webhook id is set so no webhook can exist
return false ;
}
// Webhook got created before so check if it still exists
const owner = this . getNodeParameter ( 'owner' ) as string ;
const repository = this . getNodeParameter ( 'repository' ) as string ;
2020-06-20 09:08:30 -07:00
2021-04-15 15:27:49 -07:00
const path = ( ` ${ owner } / ${ repository } ` ) . replace ( /\//g , '%2F' ) ;
2020-06-20 09:08:30 -07:00
const endpoint = ` /projects/ ${ path } /hooks/ ${ webhookData . webhookId } ` ;
2019-10-16 16:49:09 -07:00
try {
await gitlabApiRequest . call ( this , 'GET' , endpoint , { } ) ;
2021-04-16 09:33:36 -07:00
} catch ( error ) {
2021-04-30 19:12:11 -07:00
if ( error . httpCode === '404' ) {
2019-10-16 16:49:09 -07:00
// Webhook does not exist
delete webhookData . webhookId ;
delete webhookData . webhookEvents ;
return false ;
}
// Some error occured
2021-04-16 09:33:36 -07:00
throw error ;
2019-10-16 16:49:09 -07:00
}
// If it did not error then the webhook exists
return true ;
} ,
/ * *
* Gitlab API - Add project hook :
* https : //docs.gitlab.com/ee/api/projects.html#add-project-hook
* /
async create ( this : IHookFunctions ) : Promise < boolean > {
const webhookUrl = this . getNodeWebhookUrl ( 'default' ) ;
const owner = this . getNodeParameter ( 'owner' ) as string ;
const repository = this . getNodeParameter ( 'repository' ) as string ;
let eventsArray = this . getNodeParameter ( 'events' , [ ] ) as string [ ] ;
if ( eventsArray . includes ( '*' ) ) {
eventsArray = [ 'note' , 'issues' , 'job' , 'merge_requests' , 'pipeline' , 'push' , 'tag_push' , 'wiki_page' ] ;
}
2021-04-15 15:27:49 -07:00
const events : { [ key : string ] : boolean } = { } ;
2019-10-16 16:49:09 -07:00
for ( const e of eventsArray ) {
2019-10-24 23:15:36 -07:00
events [ ` ${ e } _events ` ] = true ;
2019-10-16 16:49:09 -07:00
}
2020-06-20 09:08:30 -07:00
// gitlab set the push_events to true when the field it's not sent.
// set it to false when it's not picked by the user.
if ( events [ 'push_events' ] === undefined ) {
events [ 'push_events' ] = false ;
}
2021-04-15 15:27:49 -07:00
const path = ( ` ${ owner } / ${ repository } ` ) . replace ( /\//g , '%2F' ) ;
2020-06-20 09:08:30 -07:00
const endpoint = ` /projects/ ${ path } /hooks ` ;
2019-10-16 16:49:09 -07:00
const body = {
url : webhookUrl ,
2020-06-20 09:08:30 -07:00
. . . events ,
2019-10-16 16:49:09 -07:00
enable_ssl_verification : false ,
} ;
let responseData ;
try {
responseData = await gitlabApiRequest . call ( this , 'POST' , endpoint , body ) ;
2021-04-16 09:33:36 -07:00
} catch ( error ) {
throw new NodeApiError ( this . getNode ( ) , error ) ;
2019-10-16 16:49:09 -07:00
}
if ( responseData . id === undefined ) {
// Required data is missing so was not successful
2021-04-16 09:33:36 -07:00
throw new NodeApiError ( this . getNode ( ) , responseData , { message : 'GitLab webhook creation response did not contain the expected data.' } ) ;
2019-10-16 16:49:09 -07:00
}
const webhookData = this . getWorkflowStaticData ( 'node' ) ;
webhookData . webhookId = responseData . id as string ;
webhookData . webhookEvents = eventsArray as string [ ] ;
return true ;
} ,
async delete ( this : IHookFunctions ) : Promise < boolean > {
const webhookData = this . getWorkflowStaticData ( 'node' ) ;
if ( webhookData . webhookId !== undefined ) {
const owner = this . getNodeParameter ( 'owner' ) as string ;
const repository = this . getNodeParameter ( 'repository' ) as string ;
2020-06-20 09:08:30 -07:00
2021-04-15 15:27:49 -07:00
const path = ( ` ${ owner } / ${ repository } ` ) . replace ( /\//g , '%2F' ) ;
2020-06-20 09:08:30 -07:00
const endpoint = ` /projects/ ${ path } /hooks/ ${ webhookData . webhookId } ` ;
2019-10-16 16:49:09 -07:00
const body = { } ;
try {
await gitlabApiRequest . call ( this , 'DELETE' , endpoint , body ) ;
2021-04-16 09:33:36 -07:00
} catch ( error ) {
2019-10-16 16:49:09 -07:00
return false ;
}
// Remove from the static workflow data so that it is clear
// that no webhooks are registred anymore
delete webhookData . webhookId ;
delete webhookData . webhookEvents ;
}
return true ;
} ,
} ,
} ;
async webhook ( this : IWebhookFunctions ) : Promise < IWebhookResponseData > {
const bodyData = this . getBodyData ( ) ;
const returnData : IDataObject [ ] = [ ] ;
returnData . push (
{
body : bodyData ,
headers : this.getHeaderData ( ) ,
query : this.getQueryData ( ) ,
2020-10-22 09:00:28 -07:00
} ,
2019-10-16 16:49:09 -07:00
) ;
return {
workflowData : [
2020-10-22 06:46:03 -07:00
this . helpers . returnJsonArray ( returnData ) ,
2019-10-16 16:49:09 -07:00
] ,
} ;
}
}