2019-06-23 03:35:23 -07:00
import {
IHookFunctions ,
IWebhookFunctions ,
} from 'n8n-core' ;
import {
IDataObject ,
INodeType ,
2020-10-01 05:01:39 -07:00
INodeTypeDescription ,
2019-10-11 04:02:44 -07:00
IWebhookResponseData ,
2021-04-16 09:33:36 -07:00
NodeApiError ,
NodeOperationError ,
2019-06-23 03:35:23 -07:00
} from 'n8n-workflow' ;
import {
githubApiRequest ,
} from './GenericFunctions' ;
export class GithubTrigger implements INodeType {
description : INodeTypeDescription = {
displayName : 'Github Trigger' ,
name : 'githubTrigger' ,
2021-01-19 23:33:17 -08:00
icon : 'file:github.svg' ,
2019-06-23 03:35:23 -07:00
group : [ 'trigger' ] ,
version : 1 ,
2019-07-26 04:20:28 -07:00
subtitle : '={{$parameter["owner"] + "/" + $parameter["repository"] + ": " + $parameter["events"].join(", ")}}' ,
2021-07-03 05:40:16 -07:00
description : 'Starts the workflow when Github events occur' ,
2019-06-23 03:35:23 -07:00
defaults : {
name : 'Github Trigger' ,
} ,
inputs : [ ] ,
outputs : [ 'main' ] ,
credentials : [
{
name : 'githubApi' ,
required : true ,
2020-06-09 13:50:09 -07:00
displayOptions : {
show : {
authentication : [
'accessToken' ,
] ,
} ,
} ,
} ,
{
name : 'githubOAuth2Api' ,
required : true ,
displayOptions : {
show : {
authentication : [
'oAuth2' ,
] ,
} ,
} ,
} ,
2019-06-23 03:35:23 -07:00
] ,
webhooks : [
{
name : 'default' ,
httpMethod : 'POST' ,
2019-08-28 08:16:09 -07:00
responseMode : 'onReceived' ,
2019-06-23 03:35:23 -07:00
path : 'webhook' ,
} ,
] ,
properties : [
2020-06-09 13:50:09 -07:00
{
displayName : 'Authentication' ,
name : 'authentication' ,
type : 'options' ,
options : [
{
name : 'Access Token' ,
value : 'accessToken' ,
} ,
{
name : 'OAuth2' ,
value : 'oAuth2' ,
} ,
] ,
default : 'accessToken' ,
} ,
2019-06-23 03:35:23 -07:00
{
displayName : 'Repository Owner' ,
name : 'owner' ,
type : 'string' ,
default : '' ,
required : true ,
placeholder : 'n8n-io' ,
2022-05-06 14:01:25 -07:00
description : 'Owner of the repsitory' ,
2019-06-23 03:35:23 -07:00
} ,
{
displayName : 'Repository Name' ,
name : 'repository' ,
type : 'string' ,
default : '' ,
required : true ,
placeholder : 'n8n' ,
2022-05-06 14:01:25 -07:00
description : 'The name of the repsitory' ,
2019-06-23 03:35:23 -07:00
} ,
{
displayName : 'Events' ,
name : 'events' ,
type : 'multiOptions' ,
options : [
{
name : '*' ,
value : '*' ,
2022-05-06 14:01:25 -07:00
description : 'Any time any event is triggered (Wildcard Event)' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'check_run' ,
value : 'check_run' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a check run is created, rerequested, completed, or has a requested_action' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'check_suite' ,
value : 'check_suite' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a check suite is completed, requested, or rerequested' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'commit_comment' ,
value : 'commit_comment' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a commit comment is created' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'content_reference' ,
value : 'content_reference' ,
description : 'Triggered when the body or comment of an issue or pull request includes a URL that matches a configured content reference domain. Only GitHub Apps can receive this event.' ,
} ,
{
name : 'create' ,
value : 'create' ,
2022-05-06 14:01:25 -07:00
description : 'Represents a created repository, branch, or tag' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'delete' ,
value : 'delete' ,
2022-05-06 14:01:25 -07:00
description : 'Represents a deleted branch or tag' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'deploy_key' ,
value : 'deploy_key' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a deploy key is added or removed from a repository' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'deployment' ,
value : 'deployment' ,
2022-05-06 14:01:25 -07:00
description : 'Represents a deployment' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'deployment_status' ,
value : 'deployment_status' ,
2022-05-06 14:01:25 -07:00
description : 'Represents a deployment status' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'fork' ,
value : 'fork' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a user forks a repository' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'github_app_authorization' ,
value : 'github_app_authorization' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when someone revokes their authorization of a GitHub App' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'gollum' ,
value : 'gollum' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a Wiki page is created or updated' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'installation' ,
value : 'installation' ,
2021-10-27 13:00:13 -07:00
description : 'Triggered when someone installs (created), uninstalls (deleted), or accepts new permissions (new_permissions_accepted) for a GitHub App. When a GitHub App owner requests new permissions, the person who installed the GitHub App must accept the new permissions request.' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'installation_repositories' ,
value : 'installation_repositories' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a repository is added or removed from an installation' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'issue_comment' ,
value : 'issue_comment' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when an issue comment is created, edited, or deleted' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'issues' ,
value : 'issues' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when an issue is opened, edited, deleted, transferred, pinned, unpinned, closed, reopened, assigned, unassigned, labeled, unlabeled, locked, unlocked, milestoned, or demilestoned' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'label' ,
value : 'label' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a repository\'s label is created, edited, or deleted' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'marketplace_purchase' ,
value : 'marketplace_purchase' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when someone purchases a GitHub Marketplace plan, cancels their plan, upgrades their plan (effective immediately), downgrades a plan that remains pending until the end of the billing cycle, or cancels a pending plan change' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'member' ,
value : 'member' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a user accepts an invitation or is removed as a collaborator to a repository, or has their permissions changed' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'membership' ,
value : 'membership' ,
description : 'Triggered when a user is added or removed from a team. Organization hooks only.' ,
} ,
{
name : 'meta' ,
value : 'meta' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when the webhook that this event is configured on is deleted' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'milestone' ,
value : 'milestone' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a milestone is created, closed, opened, edited, or deleted' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'organization' ,
value : 'organization' ,
description : 'Triggered when an organization is deleted and renamed, and when a user is added, removed, or invited to an organization. Organization hooks only.' ,
} ,
{
name : 'org_block' ,
value : 'org_block' ,
description : 'Triggered when an organization blocks or unblocks a user. Organization hooks only.' ,
} ,
{
name : 'page_build' ,
value : 'page_build' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered on push to a GitHub Pages enabled branch (gh-pages for project pages, master for user and organization pages)' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'project_card' ,
value : 'project_card' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a project card is created, edited, moved, converted to an issue, or deleted' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'project_column' ,
value : 'project_column' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a project column is created, updated, moved, or deleted' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'project' ,
value : 'project' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a project is created, updated, closed, reopened, or deleted' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'public' ,
value : 'public' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a private repository is open sourced' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'pull_request' ,
value : 'pull_request' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a pull request is assigned, unassigned, labeled, unlabeled, opened, edited, closed, reopened, synchronize, ready_for_review, locked, unlocked, a pull request review is requested, or a review request is removed' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'pull_request_review' ,
value : 'pull_request_review' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a pull request review is submitted into a non-pending state, the body is edited, or the review is dismissed' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'pull_request_review_comment' ,
value : 'pull_request_review_comment' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a comment on a pull request\'s unified diff is created, edited, or deleted (in the Files Changed tab)' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'push' ,
value : 'push' ,
description : 'Triggered on a push to a repository branch. Branch pushes and repository tag pushes also trigger webhook push events. This is the default event.' ,
} ,
{
name : 'release' ,
value : 'release' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a release is published, unpublished, created, edited, deleted, or prereleased' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'repository' ,
value : 'repository' ,
description : 'Triggered when a repository is created, archived, unarchived, renamed, edited, transferred, made public, or made private. Organization hooks are also triggered when a repository is deleted.' ,
} ,
{
name : 'repository_import' ,
value : 'repository_import' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a successful, cancelled, or failed repository import finishes for a GitHub organization or a personal repository' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'repository_vulnerability_alert' ,
value : 'repository_vulnerability_alert' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a security alert is created, dismissed, or resolved' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'security_advisory' ,
value : 'security_advisory' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a new security advisory is published, updated, or withdrawn' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'star' ,
value : 'star' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a star is added or removed from a repository' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'status' ,
value : 'status' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when the status of a Git commit changes' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'team' ,
value : 'team' ,
2022-04-22 09:29:51 -07:00
description : 'Triggered when an organization\'s team is created, deleted, edited, added_to_repository, or removed_from_repository. Organization hooks only.' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'team_add' ,
value : 'team_add' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when a repository is added to a team' ,
2019-06-23 03:35:23 -07:00
} ,
{
name : 'watch' ,
value : 'watch' ,
2022-05-06 14:01:25 -07:00
description : 'Triggered when someone stars a repository' ,
2019-06-23 03:35:23 -07:00
} ,
] ,
required : true ,
default : [ ] ,
2022-05-06 14:01:25 -07:00
description : 'The events to listen to' ,
2019-06-23 03:35:23 -07:00
} ,
] ,
} ;
// @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 ;
const endpoint = ` /repos/ ${ owner } / ${ repository } /hooks/ ${ webhookData . webhookId } ` ;
try {
await githubApiRequest . 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-06-23 03:35:23 -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-06-23 03:35:23 -07:00
}
// If it did not error then the webhook exists
return true ;
} ,
async create ( this : IHookFunctions ) : Promise < boolean > {
2019-12-23 05:29:28 -08:00
const webhookUrl = this . getNodeWebhookUrl ( 'default' ) as string ;
if ( webhookUrl . includes ( '//localhost' ) ) {
2021-04-16 09:33:36 -07:00
throw new NodeOperationError ( this . getNode ( ) , 'The Webhook can not work on "localhost". Please, either setup n8n on a custom domain or start with "--tunnel"!' ) ;
2019-12-23 05:29:28 -08:00
}
2019-06-23 03:35:23 -07:00
const owner = this . getNodeParameter ( 'owner' ) as string ;
const repository = this . getNodeParameter ( 'repository' ) as string ;
const events = this . getNodeParameter ( 'events' , [ ] ) ;
const endpoint = ` /repos/ ${ owner } / ${ repository } /hooks ` ;
const body = {
name : 'web' ,
config : {
url : webhookUrl ,
content_type : 'json' ,
// secret: '...later...',
insecure_ssl : '1' , // '0' -> not allow inscure ssl | '1' -> allow insercure SSL
} ,
events ,
active : true ,
} ;
2019-12-14 12:44:56 -08:00
const webhookData = this . getWorkflowStaticData ( 'node' ) ;
2019-08-08 09:43:35 -07:00
let responseData ;
try {
responseData = await githubApiRequest . call ( this , 'POST' , endpoint , body ) ;
2021-04-16 09:33:36 -07:00
} catch ( error ) {
2021-04-30 19:12:11 -07:00
if ( error . httpCode === '422' ) {
2019-12-14 12:44:56 -08:00
// Webhook exists already
// Get the data of the already registered webhook
responseData = await githubApiRequest . call ( this , 'GET' , endpoint , body ) ;
for ( const webhook of responseData as IDataObject [ ] ) {
if ( ( webhook ! . config ! as IDataObject ) . url ! === webhookUrl ) {
// Webhook got found
if ( JSON . stringify ( webhook . events ) === JSON . stringify ( events ) ) {
// Webhook with same events exists already so no need to
// create it again simply save the webhook-id
webhookData . webhookId = webhook . id as string ;
webhookData . webhookEvents = webhook . events as string [ ] ;
return true ;
}
}
}
2021-04-16 09:33:36 -07:00
throw new NodeOperationError ( this . getNode ( ) , 'A webhook with the identical URL probably exists already. Please delete it manually on Github!' ) ;
2019-08-08 09:43:35 -07:00
}
2021-04-16 09:33:36 -07:00
throw error ;
2019-08-08 09:43:35 -07:00
}
2019-06-23 03:35:23 -07:00
if ( responseData . id === undefined || responseData . active !== true ) {
// Required data is missing so was not successful
2021-04-16 09:33:36 -07:00
throw new NodeApiError ( this . getNode ( ) , responseData , { message : 'Github webhook creation response did not contain the expected data.' } ) ;
2019-06-23 03:35:23 -07:00
}
webhookData . webhookId = responseData . id as string ;
webhookData . webhookEvents = responseData . events 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 ;
const endpoint = ` /repos/ ${ owner } / ${ repository } /hooks/ ${ webhookData . webhookId } ` ;
const body = { } ;
try {
await githubApiRequest . call ( this , 'DELETE' , endpoint , body ) ;
2021-04-16 09:33:36 -07:00
} catch ( error ) {
2019-06-23 03:35:23 -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 ;
} ,
} ,
} ;
2019-10-11 04:02:44 -07:00
async webhook ( this : IWebhookFunctions ) : Promise < IWebhookResponseData > {
2019-06-23 03:35:23 -07:00
const bodyData = this . getBodyData ( ) ;
// Check if the webhook is only the ping from Github to confirm if it workshook_id
if ( bodyData . hook_id !== undefined && bodyData . action === undefined ) {
// Is only the ping and not an actual webhook call. So return 'OK'
// but do not start the workflow.
return {
2020-10-22 06:46:03 -07:00
webhookResponse : 'OK' ,
2019-06-23 03:35:23 -07:00
} ;
}
// Is a regular webhoook call
// TODO: Add headers & requestPath
const returnData : IDataObject [ ] = [ ] ;
returnData . push (
{
body : bodyData ,
headers : this.getHeaderData ( ) ,
query : this.getQueryData ( ) ,
2020-10-22 09:00:28 -07:00
} ,
2019-06-23 03:35:23 -07:00
) ;
return {
workflowData : [
2020-10-22 06:46:03 -07:00
this . helpers . returnJsonArray ( returnData ) ,
2019-06-23 03:35:23 -07:00
] ,
} ;
}
}