feat(GitHub Node): Add workflow resource operations (#10744)

This commit is contained in:
Idan Fishman 2024-10-23 13:20:20 +03:00 committed by GitHub
parent 4f1816e03d
commit d309112647
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 246 additions and 2 deletions

View file

@ -119,3 +119,13 @@ export function isBase64(content: string) {
const base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
return base64regex.test(content);
}
export function validateJSON(json: string | undefined): any {
let result;
try {
result = JSON.parse(json!);
} catch (exception) {
result = undefined;
}
return result;
}

View file

@ -14,9 +14,9 @@ import {
githubApiRequest,
githubApiRequestAllItems,
isBase64,
validateJSON,
} from './GenericFunctions';
import { getRepositories, getUsers } from './SearchFunctions';
import { getRepositories, getUsers, getWorkflows } from './SearchFunctions';
export class Github implements INodeType {
description: INodeTypeDescription = {
@ -103,6 +103,10 @@ export class Github implements INodeType {
name: 'User',
value: 'user',
},
{
name: 'Workflow',
value: 'workflow',
},
],
default: 'issue',
},
@ -391,6 +395,129 @@ export class Github implements INodeType {
default: 'create',
},
// ----------------------------------
// workflow
// ----------------------------------
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['workflow'],
},
},
options: [
{
name: 'Disable',
value: 'disable',
description: 'Disable a workflow',
action: 'Disable a workflow',
},
{
name: 'Dispatch',
value: 'dispatch',
description: 'Dispatch a workflow event',
action: 'Dispatch a workflow event',
},
{
name: 'Enable',
value: 'enable',
description: 'Enable a workflow',
action: 'Enable a workflow',
},
{
name: 'Get',
value: 'get',
description: 'Get a workflow',
action: 'Get a workflow',
},
{
name: 'Get Usage',
value: 'getUsage',
description: 'Get the usage of a workflow',
action: 'Get the usage of a workflow',
},
{
name: 'List',
value: 'list',
description: 'List workflows',
action: 'List workflows',
},
],
default: 'dispatch',
},
{
displayName: 'Workflow',
name: 'workflowId',
type: 'resourceLocator',
default: { mode: 'list', value: '' },
required: true,
modes: [
{
displayName: 'Workflow',
name: 'list',
type: 'list',
placeholder: 'Select a workflow...',
typeOptions: {
searchListMethod: 'getWorkflows',
searchable: true,
searchFilterRequired: true,
},
},
{
displayName: 'By ID',
name: 'name',
type: 'string',
placeholder: 'e.g. 12345678',
validation: [
{
type: 'regex',
properties: {
regex: '\\d+',
errorMessage: 'Not a valid Github Workflow ID',
},
},
],
},
],
displayOptions: {
show: {
resource: ['workflow'],
operation: ['disable', 'dispatch', 'get', 'getUsage', 'enable'],
},
},
description: 'The workflow to dispatch',
},
{
displayName: 'Ref',
name: 'ref',
type: 'string',
default: 'main',
required: true,
displayOptions: {
show: {
resource: ['workflow'],
operation: ['dispatch'],
},
},
description: 'The git reference for the workflow dispatch (branch, tag, or commit SHA)',
},
{
displayName: 'Inputs',
name: 'inputs',
type: 'json',
default: '{}',
displayOptions: {
show: {
resource: ['workflow'],
operation: ['dispatch'],
},
},
description: 'JSON object with input parameters for the workflow',
},
// ----------------------------------
// shared
// ----------------------------------
@ -1854,6 +1981,7 @@ export class Github implements INodeType {
listSearch: {
getUsers,
getRepositories,
getWorkflows,
},
};
@ -1886,6 +2014,12 @@ export class Github implements INodeType {
'review:get',
'review:update',
'user:invite',
'workflow:disable',
'workflow:dispatch',
'workflow:enable',
'workflow:get',
'workflow:getUsage',
'workflow:list',
];
// Operations which overwrite the returned data and return arrays
// and has so to be merged with the data of other items
@ -2348,6 +2482,77 @@ export class Github implements INodeType {
qs.per_page = this.getNodeParameter('limit', 0);
}
}
} else if (resource === 'workflow') {
if (operation === 'disable') {
// ----------------------------------
// disable
// ----------------------------------
requestMethod = 'PUT';
const workflowId = this.getNodeParameter('workflowId', i) as string;
endpoint = `/repos/${owner}/${repository}/actions/workflows/${workflowId}/disable`;
} else if (operation === 'dispatch') {
// ----------------------------------
// dispatch
// ----------------------------------
requestMethod = 'POST';
const workflowId = this.getNodeParameter('workflowId', i) as string;
endpoint = `/repos/${owner}/${repository}/actions/workflows/${workflowId}/dispatches`;
body.ref = this.getNodeParameter('ref', i) as string;
const inputs = validateJSON(
this.getNodeParameter('inputs', i) as string,
) as IDataObject;
if (inputs === undefined) {
throw new NodeOperationError(this.getNode(), 'Inputs: Invalid JSON', {
itemIndex: i,
});
}
body.inputs = inputs;
} else if (operation === 'enable') {
// ----------------------------------
// enable
// ----------------------------------
requestMethod = 'PUT';
const workflowId = this.getNodeParameter('workflowId', i) as string;
endpoint = `/repos/${owner}/${repository}/actions/workflows/${workflowId}/enable`;
} else if (operation === 'get') {
// ----------------------------------
// get
// ----------------------------------
requestMethod = 'GET';
const workflowId = this.getNodeParameter('workflowId', i) as string;
endpoint = `/repos/${owner}/${repository}/actions/workflows/${workflowId}`;
} else if (operation === 'getUsage') {
// ----------------------------------
// getUsage
// ----------------------------------
requestMethod = 'GET';
const workflowId = this.getNodeParameter('workflowId', i) as string;
endpoint = `/repos/${owner}/${repository}/actions/workflows/${workflowId}/timing`;
} else if (operation === 'list') {
// ----------------------------------
// list
// ----------------------------------
requestMethod = 'GET';
endpoint = `/repos/${owner}/${repository}/actions/workflows`;
}
} else {
throw new NodeOperationError(this.getNode(), `The resource "${resource}" is not known!`, {
itemIndex: i,

View file

@ -85,3 +85,32 @@ export async function getRepositories(
const nextPaginationToken = page * per_page < responseData.total_count ? page + 1 : undefined;
return { results, paginationToken: nextPaginationToken };
}
export async function getWorkflows(
this: ILoadOptionsFunctions,
paginationToken?: string,
): Promise<INodeListSearchResult> {
const owner = this.getCurrentNodeParameter('owner', { extractValue: true });
const repository = this.getCurrentNodeParameter('repository', { extractValue: true });
const page = paginationToken ? +paginationToken : 1;
const per_page = 100;
const endpoint = `/repos/${owner}/${repository}/actions/workflows`;
let responseData: { workflows: Array<{ id: string; name: string }>; total_count: number } = {
workflows: [],
total_count: 0,
};
try {
responseData = await githubApiRequest.call(this, 'GET', endpoint, {}, { page, per_page });
} catch {
// will fail if the repository does not have any workflows
}
const results: INodeListSearchItems[] = responseData.workflows.map((workflow) => ({
name: workflow.name,
value: workflow.id,
}));
const nextPaginationToken = page * per_page < responseData.total_count ? page + 1 : undefined;
return { results, paginationToken: nextPaginationToken };
}