Compare commits
96 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
067ec2eb9c | ||
![]() |
2d332b32d9 | ||
![]() |
1d9ad2ba86 | ||
![]() |
a28e2177f7 | ||
![]() |
18fe0df691 | ||
![]() |
8e21a06d99 | ||
![]() |
2daf5473bb | ||
![]() |
928ff53adf | ||
![]() |
a71e95e6e5 | ||
![]() |
cb4a54b5cc | ||
![]() |
37e4524156 | ||
![]() |
9ac24ee051 | ||
![]() |
f28ccd559a | ||
![]() |
8e84a93d8e | ||
![]() |
d871dec1b7 | ||
![]() |
b133e1a197 | ||
![]() |
9346a037b9 | ||
![]() |
89facbcddd | ||
![]() |
53fef35638 | ||
![]() |
bfe496a09b | ||
![]() |
ff774c2e8e | ||
![]() |
08a6d1078c | ||
![]() |
e9bcc919bf | ||
![]() |
04f4693c85 | ||
![]() |
2a58a0a4c4 | ||
![]() |
d911843648 | ||
![]() |
c80d178410 | ||
![]() |
9fb4dca39b | ||
![]() |
0dd444d50b | ||
![]() |
f3bf418997 | ||
![]() |
676027245f | ||
![]() |
6c5039f1ba | ||
![]() |
807be59f25 | ||
![]() |
8e9896ec2e | ||
![]() |
110c2dbac8 | ||
![]() |
f55ec4bd8a | ||
![]() |
06c9bf420e | ||
![]() |
3c9bc53a79 | ||
![]() |
de7a35dfe9 | ||
![]() |
92638c2e97 | ||
![]() |
63251e6a9a | ||
![]() |
59844c33fd | ||
![]() |
d36dd2ece1 | ||
![]() |
1fdb94739b | ||
![]() |
8a18f4c44f | ||
![]() |
c9c47c5519 | ||
![]() |
6be8b55daa | ||
![]() |
f2dc2f5530 | ||
![]() |
42842e7aec | ||
![]() |
49d9f77d1b | ||
![]() |
d06a89564f | ||
![]() |
58a8510d49 | ||
![]() |
8055d6555e | ||
![]() |
39620d3510 | ||
![]() |
6d19711926 | ||
![]() |
0b362dd435 | ||
![]() |
9485731e7d | ||
![]() |
1449fb0f84 | ||
![]() |
e548dd49ca | ||
![]() |
35863ee6e9 | ||
![]() |
0784a2d4d0 | ||
![]() |
75d5c0e356 | ||
![]() |
a2dd6d76a8 | ||
![]() |
bdc6b59857 | ||
![]() |
34e95f1e89 | ||
![]() |
6a92cfc573 | ||
![]() |
9f759d70b6 | ||
![]() |
43e957e8d3 | ||
![]() |
ae316f60e4 | ||
![]() |
1ac423ba56 | ||
![]() |
b43490dd76 | ||
![]() |
f586e81dd1 | ||
![]() |
8a6d8a7d8c | ||
![]() |
45d607f1a0 | ||
![]() |
d84abaa229 | ||
![]() |
3fd1d4d9b3 | ||
![]() |
078b8efb56 | ||
![]() |
5066995f72 | ||
![]() |
577fe3dba8 | ||
![]() |
d96f4999bc | ||
![]() |
6e80ff4eb6 | ||
![]() |
3f8f022d48 | ||
![]() |
93a2e2151e | ||
![]() |
663a1ed9d4 | ||
![]() |
4f46c55c85 | ||
![]() |
9701c98af9 | ||
![]() |
aabf2a1c79 | ||
![]() |
29539b090e | ||
![]() |
1c80677ac3 | ||
![]() |
ad419855e9 | ||
![]() |
30b75943f3 | ||
![]() |
41a67b402d | ||
![]() |
caa104b1cc | ||
![]() |
94085f2bc8 | ||
![]() |
d39c962314 | ||
![]() |
706fb0f063 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -125,3 +125,6 @@ dist
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# MacOS finder preferences
|
||||
.DS_store
|
||||
|
@@ -4,7 +4,7 @@ WORKDIR /automatisch
|
||||
|
||||
RUN \
|
||||
apk --no-cache add --virtual build-dependencies python3 build-base && \
|
||||
yarn global add @automatisch/cli@0.7.0 --network-timeout 1000000 && \
|
||||
yarn global add @automatisch/cli@0.8.0 --network-timeout 1000000 && \
|
||||
rm -rf /usr/local/share/.cache/ && \
|
||||
apk del build-dependencies
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM automatischio/automatisch:0.7.0
|
||||
FROM automatischio/automatisch:0.8.0
|
||||
WORKDIR /automatisch
|
||||
|
||||
RUN apk add --no-cache openssl dos2unix
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "0.7.0",
|
||||
"version": "0.8.0",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"command": {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@automatisch/backend",
|
||||
"version": "0.7.0",
|
||||
"version": "0.8.0",
|
||||
"license": "See LICENSE file",
|
||||
"description": "The open source Zapier alternative. Build workflow automation without spending time and money.",
|
||||
"scripts": {
|
||||
@@ -22,7 +22,7 @@
|
||||
"prebuild": "rm -rf ./dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@automatisch/web": "^0.7.0",
|
||||
"@automatisch/web": "^0.8.0",
|
||||
"@bull-board/express": "^3.10.1",
|
||||
"@graphql-tools/graphql-file-loader": "^7.3.4",
|
||||
"@graphql-tools/load": "^7.5.2",
|
||||
@@ -30,6 +30,7 @@
|
||||
"@sentry/node": "^7.42.0",
|
||||
"@sentry/tracing": "^7.42.0",
|
||||
"@types/luxon": "^2.3.1",
|
||||
"@types/xmlrpc": "^1.3.7",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"axios": "0.24.0",
|
||||
"bcrypt": "^5.0.1",
|
||||
@@ -49,6 +50,8 @@
|
||||
"graphql-type-json": "^0.3.2",
|
||||
"handlebars": "^4.7.7",
|
||||
"http-errors": "~1.6.3",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.1",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"knex": "^2.4.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
@@ -62,7 +65,8 @@
|
||||
"pg": "^8.7.1",
|
||||
"php-serialize": "^4.0.2",
|
||||
"stripe": "^11.13.0",
|
||||
"winston": "^3.7.1"
|
||||
"winston": "^3.7.1",
|
||||
"xmlrpc": "^1.3.2"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
@@ -100,7 +104,7 @@
|
||||
"url": "https://github.com/automatisch/automatisch/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@automatisch/types": "^0.7.0",
|
||||
"@automatisch/types": "^0.8.0",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/bull": "^3.15.8",
|
||||
"@types/cors": "^2.8.12",
|
||||
|
@@ -2,7 +2,7 @@ import qs from 'qs';
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
export default defineAction({
|
||||
name: 'Translate Text',
|
||||
name: 'Translate text',
|
||||
key: 'translateText',
|
||||
description: 'Translates text from one language to another.',
|
||||
arguments: [
|
||||
@@ -20,7 +20,7 @@ export default defineAction({
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
description: 'Language to translate the text to.',
|
||||
variables: false,
|
||||
variables: true,
|
||||
value: '',
|
||||
options: [
|
||||
{ label: 'Bulgarian', value: 'BG' },
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
export default defineAction({
|
||||
name: 'Delay For',
|
||||
name: 'Delay for',
|
||||
key: 'delayFor',
|
||||
description:
|
||||
'Delays the execution of the next action by a specified amount of time.',
|
||||
@@ -13,7 +13,7 @@ export default defineAction({
|
||||
required: true,
|
||||
value: null,
|
||||
description: 'Delay for unit, e.g. minutes, hours, days, weeks.',
|
||||
variables: false,
|
||||
variables: true,
|
||||
options: [
|
||||
{
|
||||
label: 'Minutes',
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
export default defineAction({
|
||||
name: 'Delay Until',
|
||||
name: 'Delay until',
|
||||
key: 'delayUntil',
|
||||
description:
|
||||
'Delays the execution of the next action until a specified date.',
|
||||
|
@@ -11,7 +11,7 @@ export default defineAction({
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
description: 'Pick a channel to send the message to.',
|
||||
variables: false,
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
|
@@ -19,8 +19,8 @@ export default {
|
||||
|
||||
channels.data = response.data
|
||||
.filter((channel: IJSONObject) => {
|
||||
// filter in text channels only
|
||||
return channel.type === 0;
|
||||
// filter in text channels and announcement channels only
|
||||
return channel.type === 0 || channel.type === 5;
|
||||
})
|
||||
.map((channel: IJSONObject) => {
|
||||
return {
|
||||
|
@@ -20,12 +20,14 @@ export default defineTrigger({
|
||||
],
|
||||
|
||||
async testRun($) {
|
||||
if (!isEmpty($.lastExecutionStep?.dataOut)) {
|
||||
const lastExecutionStep = await $.getLastExecutionStep();
|
||||
|
||||
if (!isEmpty(lastExecutionStep?.dataOut)) {
|
||||
$.pushTriggerItem({
|
||||
raw: $.lastExecutionStep.dataOut,
|
||||
raw: lastExecutionStep.dataOut,
|
||||
meta: {
|
||||
internalId: '',
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -35,20 +37,15 @@ export default defineTrigger({
|
||||
name: $.flow.id,
|
||||
type: 'POST',
|
||||
url: $.webhookUrl,
|
||||
filters: [$.step.parameters.filters]
|
||||
filters: [$.step.parameters.filters],
|
||||
};
|
||||
|
||||
const { data } = await $.http.post(
|
||||
`/v2/public/api/webhooks`,
|
||||
payload
|
||||
);
|
||||
const { data } = await $.http.post(`/v2/public/api/webhooks`, payload);
|
||||
|
||||
await $.flow.setRemoteWebhookId(data.id);
|
||||
},
|
||||
|
||||
async unregisterHook($) {
|
||||
await $.http.delete(
|
||||
`/v2/public/api/webhooks/${$.flow.remoteWebhookId}`
|
||||
);
|
||||
await $.http.delete(`/v2/public/api/webhooks/${$.flow.remoteWebhookId}`);
|
||||
},
|
||||
});
|
||||
|
@@ -11,7 +11,7 @@ export default defineAction({
|
||||
key: 'repo',
|
||||
type: 'dropdown' as const,
|
||||
required: false,
|
||||
variables: false,
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
|
@@ -6,7 +6,7 @@ import actions from './actions';
|
||||
import dynamicData from './dynamic-data';
|
||||
|
||||
export default defineApp({
|
||||
name: 'Github',
|
||||
name: 'GitHub',
|
||||
key: 'github',
|
||||
baseUrl: 'https://github.com',
|
||||
apiBaseUrl: 'https://api.github.com',
|
||||
|
2
packages/backend/src/apps/gitlab/assets/favicon.svg
Normal file
2
packages/backend/src/apps/gitlab/assets/favicon.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<!-- https://about.gitlab.com/images/press/logo/svg/gitlab-logo-500.svg -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 380 380"><defs><style>.cls-1{fill:#e24329;}.cls-2{fill:#fc6d26;}.cls-3{fill:#fca326;}</style></defs><g id="LOGO"><path class="cls-1" d="M282.83,170.73l-.27-.69-26.14-68.22a6.81,6.81,0,0,0-2.69-3.24,7,7,0,0,0-8,.43,7,7,0,0,0-2.32,3.52l-17.65,54H154.29l-17.65-54A6.86,6.86,0,0,0,134.32,99a7,7,0,0,0-8-.43,6.87,6.87,0,0,0-2.69,3.24L97.44,170l-.26.69a48.54,48.54,0,0,0,16.1,56.1l.09.07.24.17,39.82,29.82,19.7,14.91,12,9.06a8.07,8.07,0,0,0,9.76,0l12-9.06,19.7-14.91,40.06-30,.1-.08A48.56,48.56,0,0,0,282.83,170.73Z"/><path class="cls-2" d="M282.83,170.73l-.27-.69a88.3,88.3,0,0,0-35.15,15.8L190,229.25c19.55,14.79,36.57,27.64,36.57,27.64l40.06-30,.1-.08A48.56,48.56,0,0,0,282.83,170.73Z"/><path class="cls-3" d="M153.43,256.89l19.7,14.91,12,9.06a8.07,8.07,0,0,0,9.76,0l12-9.06,19.7-14.91S209.55,244,190,229.25C170.45,244,153.43,256.89,153.43,256.89Z"/><path class="cls-2" d="M132.58,185.84A88.19,88.19,0,0,0,97.44,170l-.26.69a48.54,48.54,0,0,0,16.1,56.1l.09.07.24.17,39.82,29.82s17-12.85,36.57-27.64Z"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
24
packages/backend/src/apps/gitlab/auth/generate-auth-url.ts
Normal file
24
packages/backend/src/apps/gitlab/auth/generate-auth-url.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import { URL, URLSearchParams } from 'url';
|
||||
import getBaseUrl from '../common/get-base-url';
|
||||
|
||||
export default async function generateAuthUrl($: IGlobalVariable) {
|
||||
// ref: https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow
|
||||
|
||||
const scopes = ['api', 'read_user'];
|
||||
|
||||
const searchParams = new URLSearchParams({
|
||||
client_id: $.auth.data.clientId as string,
|
||||
redirect_uri: $.auth.data.oAuthRedirectUrl as string,
|
||||
scope: scopes.join(' '),
|
||||
response_type: 'code',
|
||||
state: Date.now().toString(),
|
||||
});
|
||||
|
||||
const baseUrl = getBaseUrl($);
|
||||
const path = `/oauth/authorize?${searchParams.toString()}`;
|
||||
|
||||
await $.auth.set({
|
||||
url: new URL(path, baseUrl).toString(),
|
||||
});
|
||||
}
|
63
packages/backend/src/apps/gitlab/auth/index.ts
Normal file
63
packages/backend/src/apps/gitlab/auth/index.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import generateAuthUrl from './generate-auth-url';
|
||||
import verifyCredentials from './verify-credentials';
|
||||
import isStillVerified from './is-still-verified';
|
||||
import refreshToken from './refresh-token';
|
||||
|
||||
export default {
|
||||
fields: [
|
||||
{
|
||||
key: 'oAuthRedirectUrl',
|
||||
label: 'OAuth Redirect URL',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: true,
|
||||
value: '{WEB_APP_URL}/app/gitlab/connections/add',
|
||||
placeholder: null,
|
||||
description:
|
||||
'When asked to input an OAuth callback or redirect URL in Gitlab OAuth, enter the URL above.',
|
||||
docUrl: 'https://automatisch.io/docs/gitlab#oauth-redirect-url',
|
||||
clickToCopy: true,
|
||||
},
|
||||
{
|
||||
key: 'instanceUrl',
|
||||
label: 'Gitlab instance URL',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
readOnly: false,
|
||||
value: 'https://gitlab.com',
|
||||
placeholder: 'https://gitlab.com',
|
||||
description: 'Your Gitlab instance URL. Default is https://gitlab.com.',
|
||||
docUrl: 'https://automatisch.io/docs/gitlab#oauth-redirect-url',
|
||||
clickToCopy: true,
|
||||
},
|
||||
{
|
||||
key: 'clientId',
|
||||
label: 'Client ID',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description: null,
|
||||
docUrl: 'https://automatisch.io/docs/gitlab#client-id',
|
||||
clickToCopy: false,
|
||||
},
|
||||
{
|
||||
key: 'clientSecret',
|
||||
label: 'Client Secret',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description: null,
|
||||
docUrl: 'https://automatisch.io/docs/gitlab#client-secret',
|
||||
clickToCopy: false,
|
||||
},
|
||||
],
|
||||
|
||||
generateAuthUrl,
|
||||
refreshToken,
|
||||
verifyCredentials,
|
||||
isStillVerified,
|
||||
};
|
@@ -0,0 +1,9 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import getCurrentUser from '../common/get-current-user';
|
||||
|
||||
const isStillVerified = async ($: IGlobalVariable) => {
|
||||
const user = await getCurrentUser($);
|
||||
return !!user.id;
|
||||
};
|
||||
|
||||
export default isStillVerified;
|
24
packages/backend/src/apps/gitlab/auth/refresh-token.ts
Normal file
24
packages/backend/src/apps/gitlab/auth/refresh-token.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import { URLSearchParams } from 'url';
|
||||
|
||||
const refreshToken = async ($: IGlobalVariable) => {
|
||||
// ref: https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow
|
||||
|
||||
const params = new URLSearchParams({
|
||||
grant_type: 'refresh_token',
|
||||
client_id: $.auth.data.clientId as string,
|
||||
client_secret: $.auth.data.clientSecret as string,
|
||||
refresh_token: $.auth.data.refreshToken as string,
|
||||
});
|
||||
|
||||
const { data } = await $.http.post('/oauth/token', params.toString());
|
||||
|
||||
await $.auth.set({
|
||||
accessToken: data.access_token,
|
||||
expiresIn: data.expires_in,
|
||||
tokenType: data.token_type,
|
||||
refreshToken: data.refresh_token,
|
||||
});
|
||||
};
|
||||
|
||||
export default refreshToken;
|
41
packages/backend/src/apps/gitlab/auth/verify-credentials.ts
Normal file
41
packages/backend/src/apps/gitlab/auth/verify-credentials.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import getCurrentUser from '../common/get-current-user';
|
||||
|
||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
||||
// ref: https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow
|
||||
|
||||
const response = await $.http.post(
|
||||
'/oauth/token',
|
||||
{
|
||||
client_id: $.auth.data.clientId,
|
||||
client_secret: $.auth.data.clientSecret,
|
||||
code: $.auth.data.code,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: $.auth.data.oAuthRedirectUrl,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = response.data;
|
||||
|
||||
$.auth.data.accessToken = data.access_token;
|
||||
|
||||
const currentUser = await getCurrentUser($);
|
||||
|
||||
await $.auth.set({
|
||||
clientId: $.auth.data.clientId,
|
||||
clientSecret: $.auth.data.clientSecret,
|
||||
accessToken: data.access_token,
|
||||
refreshToken: data.refresh_token,
|
||||
scope: data.scope,
|
||||
tokenType: data.token_type,
|
||||
userId: currentUser.id,
|
||||
screenName: `${currentUser.username} @ ${$.auth.data.instanceUrl}`,
|
||||
});
|
||||
};
|
||||
|
||||
export default verifyCredentials;
|
11
packages/backend/src/apps/gitlab/common/add-auth-header.ts
Normal file
11
packages/backend/src/apps/gitlab/common/add-auth-header.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { TBeforeRequest } from '@automatisch/types';
|
||||
|
||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
||||
if ($.auth.data?.accessToken) {
|
||||
requestConfig.headers = requestConfig.headers || {};
|
||||
requestConfig.headers.Authorization = `Bearer ${$.auth.data.accessToken}`;
|
||||
}
|
||||
return requestConfig;
|
||||
};
|
||||
|
||||
export default addAuthHeader;
|
15
packages/backend/src/apps/gitlab/common/get-base-url.ts
Normal file
15
packages/backend/src/apps/gitlab/common/get-base-url.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const getBaseUrl = ($: IGlobalVariable): string => {
|
||||
if ($.auth.data.instanceUrl) {
|
||||
return $.auth.data.instanceUrl as string;
|
||||
}
|
||||
|
||||
if ($.app.apiBaseUrl) {
|
||||
return $.app.apiBaseUrl;
|
||||
}
|
||||
|
||||
return $.app.baseUrl;
|
||||
};
|
||||
|
||||
export default getBaseUrl;
|
11
packages/backend/src/apps/gitlab/common/get-current-user.ts
Normal file
11
packages/backend/src/apps/gitlab/common/get-current-user.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
|
||||
const getCurrentUser = async ($: IGlobalVariable): Promise<IJSONObject> => {
|
||||
// ref: https://docs.gitlab.com/ee/api/users.html#list-current-user
|
||||
|
||||
const response = await $.http.get('/api/v4/user');
|
||||
const currentUser = response.data;
|
||||
return currentUser;
|
||||
};
|
||||
|
||||
export default getCurrentUser;
|
33
packages/backend/src/apps/gitlab/common/paginate-all.ts
Normal file
33
packages/backend/src/apps/gitlab/common/paginate-all.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
import type { AxiosResponse } from 'axios';
|
||||
import parseLinkHeader from '../../../helpers/parse-header-link';
|
||||
|
||||
type TResponse = {
|
||||
data: IJSONObject[];
|
||||
error?: IJSONObject;
|
||||
};
|
||||
|
||||
export default async function paginateAll(
|
||||
$: IGlobalVariable,
|
||||
request: Promise<AxiosResponse>
|
||||
) {
|
||||
const response = await request;
|
||||
|
||||
const aggregatedResponse: TResponse = {
|
||||
data: [...response.data],
|
||||
};
|
||||
|
||||
let links = parseLinkHeader(response.headers.link);
|
||||
|
||||
while (links.next) {
|
||||
const nextPageResponse = await $.http.request({
|
||||
...response.config,
|
||||
url: links.next.uri,
|
||||
});
|
||||
|
||||
aggregatedResponse.data.push(...nextPageResponse.data);
|
||||
links = parseLinkHeader(nextPageResponse.headers.link);
|
||||
}
|
||||
|
||||
return aggregatedResponse;
|
||||
}
|
13
packages/backend/src/apps/gitlab/common/set-base-url.ts
Normal file
13
packages/backend/src/apps/gitlab/common/set-base-url.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { TBeforeRequest } from '@automatisch/types';
|
||||
|
||||
const setBaseUrl: TBeforeRequest = ($, requestConfig) => {
|
||||
if ($.auth.data.instanceUrl) {
|
||||
requestConfig.baseURL = $.auth.data.instanceUrl as string;
|
||||
} else if ($.app.apiBaseUrl) {
|
||||
requestConfig.baseURL = $.app.apiBaseUrl as string;
|
||||
}
|
||||
|
||||
return requestConfig;
|
||||
};
|
||||
|
||||
export default setBaseUrl;
|
3
packages/backend/src/apps/gitlab/dynamic-data/index.ts
Normal file
3
packages/backend/src/apps/gitlab/dynamic-data/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import listProjects from './list-projects';
|
||||
|
||||
export default [listProjects];
|
@@ -0,0 +1,33 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import paginateAll from '../../common/paginate-all';
|
||||
|
||||
export default {
|
||||
name: 'List projects',
|
||||
key: 'listProjects',
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
// ref:
|
||||
// - https://docs.gitlab.com/ee/api/projects.html#list-all-projects
|
||||
// - https://docs.gitlab.com/ee/api/rest/index.html#keyset-based-pagination
|
||||
const firstPageRequest = $.http.get('/api/v4/projects', {
|
||||
params: {
|
||||
simple: true,
|
||||
pagination: 'keyset',
|
||||
membership: true,
|
||||
order_by: 'id',
|
||||
sort: 'asc',
|
||||
},
|
||||
});
|
||||
|
||||
const response = await paginateAll($, firstPageRequest);
|
||||
|
||||
response.data = response.data.map((repo: { name: string; id: number }) => {
|
||||
return {
|
||||
value: repo.id,
|
||||
name: repo.name,
|
||||
};
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
};
|
1
packages/backend/src/apps/gitlab/index.d.ts
vendored
Normal file
1
packages/backend/src/apps/gitlab/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
|
21
packages/backend/src/apps/gitlab/index.ts
Normal file
21
packages/backend/src/apps/gitlab/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import defineApp from '../../helpers/define-app';
|
||||
import addAuthHeader from './common/add-auth-header';
|
||||
import setBaseUrl from './common/set-base-url';
|
||||
import auth from './auth';
|
||||
import triggers from './triggers';
|
||||
import dynamicData from './dynamic-data';
|
||||
|
||||
export default defineApp({
|
||||
name: 'GitLab',
|
||||
key: 'gitlab',
|
||||
baseUrl: 'https://gitlab.com',
|
||||
apiBaseUrl: 'https://gitlab.com',
|
||||
iconUrl: '{BASE_URL}/apps/gitlab/assets/favicon.svg',
|
||||
authDocUrl: 'https://automatisch.io/docs/apps/gitlab/connection',
|
||||
primaryColor: 'FC6D26',
|
||||
supportsConnections: true,
|
||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||
auth,
|
||||
triggers,
|
||||
dynamicData,
|
||||
});
|
@@ -0,0 +1,27 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
// confidential_issues_events has the same event data as issues_events
|
||||
import data from './issue_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Confidential issue event',
|
||||
description:
|
||||
'Confidential issue event (triggered when a new confidential issue is created or an existing issue is updated, closed, or reopened)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#issue-events',
|
||||
key: GITLAB_EVENT_TYPE.confidential_issues_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.confidential_issues_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,159 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#issue-events
|
||||
|
||||
export default {
|
||||
object_kind: 'issue',
|
||||
event_type: 'issue',
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
project: {
|
||||
id: 1,
|
||||
name: 'Gitlab Test',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
web_url: 'http://example.com/gitlabhq/gitlab-test',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
git_http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
namespace: 'GitlabHQ',
|
||||
visibility_level: 20,
|
||||
path_with_namespace: 'gitlabhq/gitlab-test',
|
||||
default_branch: 'master',
|
||||
ci_config_path: null,
|
||||
homepage: 'http://example.com/gitlabhq/gitlab-test',
|
||||
url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
},
|
||||
object_attributes: {
|
||||
id: 301,
|
||||
title: 'New API: create/update/delete file',
|
||||
assignee_ids: [51],
|
||||
assignee_id: 51,
|
||||
author_id: 51,
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
updated_by_id: 1,
|
||||
last_edited_at: null,
|
||||
last_edited_by_id: null,
|
||||
relative_position: 0,
|
||||
description: 'Create new API for manipulations with repository',
|
||||
milestone_id: null,
|
||||
state_id: 1,
|
||||
confidential: false,
|
||||
discussion_locked: true,
|
||||
due_date: null,
|
||||
moved_to_id: null,
|
||||
duplicated_to_id: null,
|
||||
time_estimate: 0,
|
||||
total_time_spent: 0,
|
||||
time_change: 0,
|
||||
human_total_time_spent: null,
|
||||
human_time_estimate: null,
|
||||
human_time_change: null,
|
||||
weight: null,
|
||||
iid: 23,
|
||||
url: 'http://example.com/diaspora/issues/23',
|
||||
state: 'opened',
|
||||
action: 'open',
|
||||
severity: 'high',
|
||||
escalation_status: 'triggered',
|
||||
escalation_policy: {
|
||||
id: 18,
|
||||
name: 'Engineering On-call',
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
id: 206,
|
||||
title: 'API',
|
||||
color: '#ffffff',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'API related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
},
|
||||
repository: {
|
||||
name: 'Gitlab Test',
|
||||
url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
homepage: 'http://example.com/gitlabhq/gitlab-test',
|
||||
},
|
||||
assignees: [
|
||||
{
|
||||
name: 'User1',
|
||||
username: 'user1',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
},
|
||||
],
|
||||
assignee: {
|
||||
name: 'User1',
|
||||
username: 'user1',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
id: 206,
|
||||
title: 'API',
|
||||
color: '#ffffff',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'API related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
changes: {
|
||||
updated_by_id: {
|
||||
previous: null,
|
||||
current: 1,
|
||||
},
|
||||
updated_at: {
|
||||
previous: '2017-09-15 16:50:55 UTC',
|
||||
current: '2017-09-15 16:52:00 UTC',
|
||||
},
|
||||
labels: {
|
||||
previous: [
|
||||
{
|
||||
id: 206,
|
||||
title: 'API',
|
||||
color: '#ffffff',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'API related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
current: [
|
||||
{
|
||||
id: 205,
|
||||
title: 'Platform',
|
||||
color: '#123123',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'Platform related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
@@ -0,0 +1,27 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
// confidential_note_events has the same event data as note_events
|
||||
import data from './note_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Confidential comment event',
|
||||
description:
|
||||
'Confidential comment event (triggered when a new confidential comment is made on commits, merge requests, issues, and code snippets)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#comment-events',
|
||||
key: GITLAB_EVENT_TYPE.confidential_note_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.confidential_note_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,74 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#comment-events
|
||||
|
||||
export default {
|
||||
object_kind: 'note',
|
||||
event_type: 'note',
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
project_id: 5,
|
||||
project: {
|
||||
id: 5,
|
||||
name: 'Gitlab Test',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
web_url: 'http://example.com/gitlabhq/gitlab-test',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
git_http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
namespace: 'GitlabHQ',
|
||||
visibility_level: 20,
|
||||
path_with_namespace: 'gitlabhq/gitlab-test',
|
||||
default_branch: 'master',
|
||||
homepage: 'http://example.com/gitlabhq/gitlab-test',
|
||||
url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
},
|
||||
repository: {
|
||||
name: 'Gitlab Test',
|
||||
url: 'http://example.com/gitlab-org/gitlab-test.git',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
homepage: 'http://example.com/gitlab-org/gitlab-test',
|
||||
},
|
||||
object_attributes: {
|
||||
id: 1243,
|
||||
note: 'This is a commit comment. How does this work?',
|
||||
noteable_type: 'Commit',
|
||||
author_id: 1,
|
||||
created_at: '2015-05-17 18:08:09 UTC',
|
||||
updated_at: '2015-05-17 18:08:09 UTC',
|
||||
project_id: 5,
|
||||
attachment: null,
|
||||
line_code: 'bec9703f7a456cd2b4ab5fb3220ae016e3e394e3_0_1',
|
||||
commit_id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
|
||||
noteable_id: null,
|
||||
system: false,
|
||||
st_diff: {
|
||||
diff: '--- /dev/null\n+++ b/six\n@@ -0,0 +1 @@\n+Subproject commit 409f37c4f05865e4fb208c771485f211a22c4c2d\n',
|
||||
new_path: 'six',
|
||||
old_path: 'six',
|
||||
a_mode: '0',
|
||||
b_mode: '160000',
|
||||
new_file: true,
|
||||
renamed_file: false,
|
||||
deleted_file: false,
|
||||
},
|
||||
url: 'http://example.com/gitlab-org/gitlab-test/commit/cfe32cf61b73a0d5e9f13e774abde7ff789b1660#note_1243',
|
||||
},
|
||||
commit: {
|
||||
id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
|
||||
message:
|
||||
'Add submodule\n\nSigned-off-by: Example User \u003cuser@example.com.com\u003e\n',
|
||||
timestamp: '2014-02-27T10:06:20+02:00',
|
||||
url: 'http://example.com/gitlab-org/gitlab-test/commit/cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
|
||||
author: {
|
||||
name: 'Example User',
|
||||
email: 'user@example.com',
|
||||
},
|
||||
},
|
||||
};
|
@@ -0,0 +1,45 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#deployment-events
|
||||
|
||||
export default {
|
||||
object_kind: 'deployment',
|
||||
status: 'success',
|
||||
status_changed_at: '2021-04-28 21:50:00 +0200',
|
||||
deployment_id: 15,
|
||||
deployable_id: 796,
|
||||
deployable_url:
|
||||
'http://10.126.0.2:3000/root/test-deployment-webhooks/-/jobs/796',
|
||||
environment: 'staging',
|
||||
environment_slug: 'staging',
|
||||
environment_external_url: 'https://staging.example.com',
|
||||
project: {
|
||||
id: 30,
|
||||
name: 'test-deployment-webhooks',
|
||||
description: '',
|
||||
web_url: 'http://10.126.0.2:3000/root/test-deployment-webhooks',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'ssh://vlad@10.126.0.2:2222/root/test-deployment-webhooks.git',
|
||||
git_http_url: 'http://10.126.0.2:3000/root/test-deployment-webhooks.git',
|
||||
namespace: 'Administrator',
|
||||
visibility_level: 0,
|
||||
path_with_namespace: 'root/test-deployment-webhooks',
|
||||
default_branch: 'master',
|
||||
ci_config_path: '',
|
||||
homepage: 'http://10.126.0.2:3000/root/test-deployment-webhooks',
|
||||
url: 'ssh://vlad@10.126.0.2:2222/root/test-deployment-webhooks.git',
|
||||
ssh_url: 'ssh://vlad@10.126.0.2:2222/root/test-deployment-webhooks.git',
|
||||
http_url: 'http://10.126.0.2:3000/root/test-deployment-webhooks.git',
|
||||
},
|
||||
short_sha: '279484c0',
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
user_url: 'http://10.126.0.2:3000/root',
|
||||
commit_url:
|
||||
'http://10.126.0.2:3000/root/test-deployment-webhooks/-/commit/279484c09fbe69ededfced8c1bb6e6d24616b468',
|
||||
commit_title: 'Add new file',
|
||||
};
|
@@ -0,0 +1,26 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './deployment_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Deployment event',
|
||||
description:
|
||||
'Deployment event (triggered when a deployment starts, succeeds, fails or is canceled)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#deployment-events',
|
||||
key: GITLAB_EVENT_TYPE.deployment_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.deployment_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,38 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#feature-flag-events
|
||||
|
||||
export default {
|
||||
object_kind: 'feature_flag',
|
||||
project: {
|
||||
id: 1,
|
||||
name: 'Gitlab Test',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
web_url: 'http://example.com/gitlabhq/gitlab-test',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
git_http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
namespace: 'GitlabHQ',
|
||||
visibility_level: 20,
|
||||
path_with_namespace: 'gitlabhq/gitlab-test',
|
||||
default_branch: 'master',
|
||||
ci_config_path: null,
|
||||
homepage: 'http://example.com/gitlabhq/gitlab-test',
|
||||
url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
},
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
user_url: 'http://example.com/root',
|
||||
object_attributes: {
|
||||
id: 6,
|
||||
name: 'test-feature-flag',
|
||||
description: 'test-feature-flag-description',
|
||||
active: true,
|
||||
},
|
||||
};
|
@@ -0,0 +1,26 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './feature_flag_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Feature flag event',
|
||||
description:
|
||||
'Feature flag event (triggered when a feature flag is turned on or off)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#feature-flag-events',
|
||||
key: GITLAB_EVENT_TYPE.feature_flag_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.feature_flag_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
29
packages/backend/src/apps/gitlab/triggers/index.ts
Normal file
29
packages/backend/src/apps/gitlab/triggers/index.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import confidentialIssueEvent from './confidential-issue-event';
|
||||
import confidentialNoteEvent from './confidential-note-event';
|
||||
import deploymentEvent from './deployment-event';
|
||||
import featureFlagEvent from './feature-flag-event';
|
||||
import issueEvent from './issue-event';
|
||||
import jobEvent from './job-event';
|
||||
import mergeRequestEvent from './merge-request-event';
|
||||
import noteEvent from './note-event';
|
||||
import pipelineEvent from './pipeline-event';
|
||||
import pushEvent from './push-event';
|
||||
import releaseEvent from './release-event';
|
||||
import tagPushEvent from './tag-push-event';
|
||||
import wikiPageEvent from './wiki-page-event';
|
||||
|
||||
export default [
|
||||
confidentialIssueEvent,
|
||||
confidentialNoteEvent,
|
||||
deploymentEvent,
|
||||
featureFlagEvent,
|
||||
issueEvent,
|
||||
jobEvent,
|
||||
mergeRequestEvent,
|
||||
noteEvent,
|
||||
pipelineEvent,
|
||||
pushEvent,
|
||||
releaseEvent,
|
||||
tagPushEvent,
|
||||
wikiPageEvent,
|
||||
];
|
@@ -0,0 +1,26 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './issue_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Issue event',
|
||||
description:
|
||||
'Issue event (triggered when a new issue is created or an existing issue is updated, closed, or reopened)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#issue-events',
|
||||
key: GITLAB_EVENT_TYPE.issues_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.issues_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,159 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#issue-events
|
||||
|
||||
export default {
|
||||
object_kind: 'issue',
|
||||
event_type: 'issue',
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
project: {
|
||||
id: 1,
|
||||
name: 'Gitlab Test',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
web_url: 'http://example.com/gitlabhq/gitlab-test',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
git_http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
namespace: 'GitlabHQ',
|
||||
visibility_level: 20,
|
||||
path_with_namespace: 'gitlabhq/gitlab-test',
|
||||
default_branch: 'master',
|
||||
ci_config_path: null,
|
||||
homepage: 'http://example.com/gitlabhq/gitlab-test',
|
||||
url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
},
|
||||
object_attributes: {
|
||||
id: 301,
|
||||
title: 'New API: create/update/delete file',
|
||||
assignee_ids: [51],
|
||||
assignee_id: 51,
|
||||
author_id: 51,
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
updated_by_id: 1,
|
||||
last_edited_at: null,
|
||||
last_edited_by_id: null,
|
||||
relative_position: 0,
|
||||
description: 'Create new API for manipulations with repository',
|
||||
milestone_id: null,
|
||||
state_id: 1,
|
||||
confidential: false,
|
||||
discussion_locked: true,
|
||||
due_date: null,
|
||||
moved_to_id: null,
|
||||
duplicated_to_id: null,
|
||||
time_estimate: 0,
|
||||
total_time_spent: 0,
|
||||
time_change: 0,
|
||||
human_total_time_spent: null,
|
||||
human_time_estimate: null,
|
||||
human_time_change: null,
|
||||
weight: null,
|
||||
iid: 23,
|
||||
url: 'http://example.com/diaspora/issues/23',
|
||||
state: 'opened',
|
||||
action: 'open',
|
||||
severity: 'high',
|
||||
escalation_status: 'triggered',
|
||||
escalation_policy: {
|
||||
id: 18,
|
||||
name: 'Engineering On-call',
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
id: 206,
|
||||
title: 'API',
|
||||
color: '#ffffff',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'API related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
},
|
||||
repository: {
|
||||
name: 'Gitlab Test',
|
||||
url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
homepage: 'http://example.com/gitlabhq/gitlab-test',
|
||||
},
|
||||
assignees: [
|
||||
{
|
||||
name: 'User1',
|
||||
username: 'user1',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
},
|
||||
],
|
||||
assignee: {
|
||||
name: 'User1',
|
||||
username: 'user1',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
id: 206,
|
||||
title: 'API',
|
||||
color: '#ffffff',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'API related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
changes: {
|
||||
updated_by_id: {
|
||||
previous: null,
|
||||
current: 1,
|
||||
},
|
||||
updated_at: {
|
||||
previous: '2017-09-15 16:50:55 UTC',
|
||||
current: '2017-09-15 16:52:00 UTC',
|
||||
},
|
||||
labels: {
|
||||
previous: [
|
||||
{
|
||||
id: 206,
|
||||
title: 'API',
|
||||
color: '#ffffff',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'API related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
current: [
|
||||
{
|
||||
id: 205,
|
||||
title: 'Platform',
|
||||
color: '#123123',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'Platform related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
25
packages/backend/src/apps/gitlab/triggers/job-event/index.ts
Normal file
25
packages/backend/src/apps/gitlab/triggers/job-event/index.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './job_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Job event',
|
||||
description: 'Job event (triggered when the status of a job changes)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#job-events',
|
||||
key: GITLAB_EVENT_TYPE.job_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.job_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,60 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#job-events
|
||||
|
||||
export default {
|
||||
object_kind: 'build',
|
||||
ref: 'gitlab-script-trigger',
|
||||
tag: false,
|
||||
before_sha: '2293ada6b400935a1378653304eaf6221e0fdb8f',
|
||||
sha: '2293ada6b400935a1378653304eaf6221e0fdb8f',
|
||||
build_id: 1977,
|
||||
build_name: 'test',
|
||||
build_stage: 'test',
|
||||
build_status: 'created',
|
||||
build_created_at: '2021-02-23T02:41:37.886Z',
|
||||
build_started_at: null,
|
||||
build_finished_at: null,
|
||||
build_duration: null,
|
||||
build_queued_duration: 1095.588715, // duration in seconds
|
||||
build_allow_failure: false,
|
||||
build_failure_reason: 'script_failure',
|
||||
retries_count: 2, // the second retry of this job
|
||||
pipeline_id: 2366,
|
||||
project_id: 380,
|
||||
project_name: 'gitlab-org/gitlab-test',
|
||||
user: {
|
||||
id: 3,
|
||||
name: 'User',
|
||||
email: 'user@gitlab.com',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon',
|
||||
},
|
||||
commit: {
|
||||
id: 2366,
|
||||
name: 'Build pipeline',
|
||||
sha: '2293ada6b400935a1378653304eaf6221e0fdb8f',
|
||||
message: 'test\n',
|
||||
author_name: 'User',
|
||||
author_email: 'user@gitlab.com',
|
||||
status: 'created',
|
||||
duration: null,
|
||||
started_at: null,
|
||||
finished_at: null,
|
||||
},
|
||||
repository: {
|
||||
name: 'gitlab_test',
|
||||
description: 'Atque in sunt eos similique dolores voluptatem.',
|
||||
homepage: 'http://192.168.64.1:3005/gitlab-org/gitlab-test',
|
||||
git_ssh_url: 'git@192.168.64.1:gitlab-org/gitlab-test.git',
|
||||
git_http_url: 'http://192.168.64.1:3005/gitlab-org/gitlab-test.git',
|
||||
visibility_level: 20,
|
||||
},
|
||||
runner: {
|
||||
active: true,
|
||||
runner_type: 'project_type',
|
||||
is_shared: false,
|
||||
id: 380987,
|
||||
description: 'shared-runners-manager-6.gitlab.com',
|
||||
tags: ['linux', 'docker'],
|
||||
},
|
||||
environment: null,
|
||||
};
|
89
packages/backend/src/apps/gitlab/triggers/lib.ts
Normal file
89
packages/backend/src/apps/gitlab/triggers/lib.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
import Crypto from 'crypto';
|
||||
import { GITLAB_EVENT_TYPE } from './types';
|
||||
import appConfig from '../../../config/app';
|
||||
|
||||
export const projectArgumentDescriptor = {
|
||||
label: 'Project',
|
||||
key: 'projectId',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
description: 'Pick a project to receive events from',
|
||||
variables: false,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listProjects',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const getTestRunFn =
|
||||
(eventData: IJSONObject) => ($: IGlobalVariable) => {
|
||||
/*
|
||||
Not fetching actual events from gitlab and using static event data from documentation
|
||||
as there is no way to filter out events of one category using gitlab event types,
|
||||
filtering is very limited and uses different grouping than what is applicable when creating a webhook.
|
||||
|
||||
ref:
|
||||
- https://docs.gitlab.com/ee/api/events.html#target-types
|
||||
- https://docs.gitlab.com/ee/api/projects.html#add-project-hook
|
||||
*/
|
||||
|
||||
if (!eventData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dataItem = {
|
||||
raw: eventData,
|
||||
meta: {
|
||||
// there is no distinct id on gitlab event object thus creating it
|
||||
internalId: Crypto.randomUUID(),
|
||||
},
|
||||
};
|
||||
|
||||
$.pushTriggerItem(dataItem);
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
export const getRegisterHookFn =
|
||||
(eventType: GITLAB_EVENT_TYPE) => async ($: IGlobalVariable) => {
|
||||
// ref: https://docs.gitlab.com/ee/api/projects.html#add-project-hook
|
||||
|
||||
const subscriptionPayload = {
|
||||
url: $.webhookUrl,
|
||||
token: appConfig.webhookSecretKey,
|
||||
enable_ssl_verification: true,
|
||||
[eventType]: true,
|
||||
};
|
||||
|
||||
if (
|
||||
['wildcard', 'regex'].includes(
|
||||
$.step.parameters.branch_filter_strategy as string
|
||||
)
|
||||
) {
|
||||
subscriptionPayload.branch_filter_strategy = $.step.parameters
|
||||
.branch_filter_strategy as string;
|
||||
subscriptionPayload.push_events_branch_filter = $.step.parameters
|
||||
.push_events_branch_filter as string;
|
||||
}
|
||||
|
||||
const { data } = await $.http.post(
|
||||
`/api/v4/projects/${$.step.parameters.projectId}/hooks`,
|
||||
subscriptionPayload
|
||||
);
|
||||
|
||||
await $.flow.setRemoteWebhookId(data.id.toString());
|
||||
};
|
||||
|
||||
export const unregisterHook = async ($: IGlobalVariable) => {
|
||||
// ref: https://docs.gitlab.com/ee/api/projects.html#delete-project-hook
|
||||
await $.http.delete(
|
||||
`/api/v4/projects/${$.step.parameters.projectId}/hooks/${$.flow.remoteWebhookId}`
|
||||
);
|
||||
};
|
@@ -0,0 +1,26 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './merge_request_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Merge request event',
|
||||
description:
|
||||
'Merge request event (triggered when merge request is created, updated, or closed)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#merge-request-events',
|
||||
key: GITLAB_EVENT_TYPE.merge_requests_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.merge_requests_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,208 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#merge-request-events
|
||||
|
||||
export default {
|
||||
object_kind: 'merge_request',
|
||||
event_type: 'merge_request',
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
project: {
|
||||
id: 1,
|
||||
name: 'Gitlab Test',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
web_url: 'http://example.com/gitlabhq/gitlab-test',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
git_http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
namespace: 'GitlabHQ',
|
||||
visibility_level: 20,
|
||||
path_with_namespace: 'gitlabhq/gitlab-test',
|
||||
default_branch: 'master',
|
||||
ci_config_path: '',
|
||||
homepage: 'http://example.com/gitlabhq/gitlab-test',
|
||||
url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
},
|
||||
repository: {
|
||||
name: 'Gitlab Test',
|
||||
url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
homepage: 'http://example.com/gitlabhq/gitlab-test',
|
||||
},
|
||||
object_attributes: {
|
||||
id: 99,
|
||||
iid: 1,
|
||||
target_branch: 'master',
|
||||
source_branch: 'ms-viewport',
|
||||
source_project_id: 14,
|
||||
author_id: 51,
|
||||
assignee_ids: [6],
|
||||
assignee_id: 6,
|
||||
reviewer_ids: [6],
|
||||
title: 'MS-Viewport',
|
||||
created_at: '2013-12-03T17:23:34Z',
|
||||
updated_at: '2013-12-03T17:23:34Z',
|
||||
last_edited_at: '2013-12-03T17:23:34Z',
|
||||
last_edited_by_id: 1,
|
||||
milestone_id: null,
|
||||
state_id: 1,
|
||||
state: 'opened',
|
||||
blocking_discussions_resolved: true,
|
||||
work_in_progress: false,
|
||||
first_contribution: true,
|
||||
merge_status: 'unchecked',
|
||||
target_project_id: 14,
|
||||
description: '',
|
||||
total_time_spent: 1800,
|
||||
time_change: 30,
|
||||
human_total_time_spent: '30m',
|
||||
human_time_change: '30s',
|
||||
human_time_estimate: '30m',
|
||||
url: 'http://example.com/diaspora/merge_requests/1',
|
||||
source: {
|
||||
name: 'Awesome Project',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
web_url: 'http://example.com/awesome_space/awesome_project',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:awesome_space/awesome_project.git',
|
||||
git_http_url: 'http://example.com/awesome_space/awesome_project.git',
|
||||
namespace: 'Awesome Space',
|
||||
visibility_level: 20,
|
||||
path_with_namespace: 'awesome_space/awesome_project',
|
||||
default_branch: 'master',
|
||||
homepage: 'http://example.com/awesome_space/awesome_project',
|
||||
url: 'http://example.com/awesome_space/awesome_project.git',
|
||||
ssh_url: 'git@example.com:awesome_space/awesome_project.git',
|
||||
http_url: 'http://example.com/awesome_space/awesome_project.git',
|
||||
},
|
||||
target: {
|
||||
name: 'Awesome Project',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
web_url: 'http://example.com/awesome_space/awesome_project',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:awesome_space/awesome_project.git',
|
||||
git_http_url: 'http://example.com/awesome_space/awesome_project.git',
|
||||
namespace: 'Awesome Space',
|
||||
visibility_level: 20,
|
||||
path_with_namespace: 'awesome_space/awesome_project',
|
||||
default_branch: 'master',
|
||||
homepage: 'http://example.com/awesome_space/awesome_project',
|
||||
url: 'http://example.com/awesome_space/awesome_project.git',
|
||||
ssh_url: 'git@example.com:awesome_space/awesome_project.git',
|
||||
http_url: 'http://example.com/awesome_space/awesome_project.git',
|
||||
},
|
||||
last_commit: {
|
||||
id: 'da1560886d4f094c3e6c9ef40349f7d38b5d27d7',
|
||||
message: 'fixed readme',
|
||||
title: 'Update file README.md',
|
||||
timestamp: '2012-01-03T23:36:29+02:00',
|
||||
url: 'http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7',
|
||||
author: {
|
||||
name: 'GitLab dev user',
|
||||
email: 'gitlabdev@dv6700.(none)',
|
||||
},
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
id: 206,
|
||||
title: 'API',
|
||||
color: '#ffffff',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'API related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
action: 'open',
|
||||
detailed_merge_status: 'mergeable',
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
id: 206,
|
||||
title: 'API',
|
||||
color: '#ffffff',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'API related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
changes: {
|
||||
updated_by_id: {
|
||||
previous: null,
|
||||
current: 1,
|
||||
},
|
||||
updated_at: {
|
||||
previous: '2017-09-15 16:50:55 UTC',
|
||||
current: '2017-09-15 16:52:00 UTC',
|
||||
},
|
||||
labels: {
|
||||
previous: [
|
||||
{
|
||||
id: 206,
|
||||
title: 'API',
|
||||
color: '#ffffff',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'API related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
current: [
|
||||
{
|
||||
id: 205,
|
||||
title: 'Platform',
|
||||
color: '#123123',
|
||||
project_id: 14,
|
||||
created_at: '2013-12-03T17:15:43Z',
|
||||
updated_at: '2013-12-03T17:15:43Z',
|
||||
template: false,
|
||||
description: 'Platform related issues',
|
||||
type: 'ProjectLabel',
|
||||
group_id: 41,
|
||||
},
|
||||
],
|
||||
},
|
||||
last_edited_at: {
|
||||
previous: null,
|
||||
current: '2023-03-15 00:00:10 UTC',
|
||||
},
|
||||
last_edited_by_id: {
|
||||
previous: null,
|
||||
current: 3278533,
|
||||
},
|
||||
},
|
||||
assignees: [
|
||||
{
|
||||
id: 6,
|
||||
name: 'User1',
|
||||
username: 'user1',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
},
|
||||
],
|
||||
reviewers: [
|
||||
{
|
||||
id: 6,
|
||||
name: 'User1',
|
||||
username: 'user1',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
},
|
||||
],
|
||||
};
|
@@ -0,0 +1,26 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './note_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Comment event',
|
||||
description:
|
||||
'Comment event (triggered when a new comment is made on commits, merge requests, issues, and code snippets)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#comment-events',
|
||||
key: GITLAB_EVENT_TYPE.note_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.note_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,74 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#comment-events
|
||||
|
||||
export default {
|
||||
object_kind: 'note',
|
||||
event_type: 'note',
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
project_id: 5,
|
||||
project: {
|
||||
id: 5,
|
||||
name: 'Gitlab Test',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
web_url: 'http://example.com/gitlabhq/gitlab-test',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
git_http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
namespace: 'GitlabHQ',
|
||||
visibility_level: 20,
|
||||
path_with_namespace: 'gitlabhq/gitlab-test',
|
||||
default_branch: 'master',
|
||||
homepage: 'http://example.com/gitlabhq/gitlab-test',
|
||||
url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
ssh_url: 'git@example.com:gitlabhq/gitlab-test.git',
|
||||
http_url: 'http://example.com/gitlabhq/gitlab-test.git',
|
||||
},
|
||||
repository: {
|
||||
name: 'Gitlab Test',
|
||||
url: 'http://example.com/gitlab-org/gitlab-test.git',
|
||||
description: 'Aut reprehenderit ut est.',
|
||||
homepage: 'http://example.com/gitlab-org/gitlab-test',
|
||||
},
|
||||
object_attributes: {
|
||||
id: 1243,
|
||||
note: 'This is a commit comment. How does this work?',
|
||||
noteable_type: 'Commit',
|
||||
author_id: 1,
|
||||
created_at: '2015-05-17 18:08:09 UTC',
|
||||
updated_at: '2015-05-17 18:08:09 UTC',
|
||||
project_id: 5,
|
||||
attachment: null,
|
||||
line_code: 'bec9703f7a456cd2b4ab5fb3220ae016e3e394e3_0_1',
|
||||
commit_id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
|
||||
noteable_id: null,
|
||||
system: false,
|
||||
st_diff: {
|
||||
diff: '--- /dev/null\n+++ b/six\n@@ -0,0 +1 @@\n+Subproject commit 409f37c4f05865e4fb208c771485f211a22c4c2d\n',
|
||||
new_path: 'six',
|
||||
old_path: 'six',
|
||||
a_mode: '0',
|
||||
b_mode: '160000',
|
||||
new_file: true,
|
||||
renamed_file: false,
|
||||
deleted_file: false,
|
||||
},
|
||||
url: 'http://example.com/gitlab-org/gitlab-test/commit/cfe32cf61b73a0d5e9f13e774abde7ff789b1660#note_1243',
|
||||
},
|
||||
commit: {
|
||||
id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
|
||||
message:
|
||||
'Add submodule\n\nSigned-off-by: Example User \u003cuser@example.com.com\u003e\n',
|
||||
timestamp: '2014-02-27T10:06:20+02:00',
|
||||
url: 'http://example.com/gitlab-org/gitlab-test/commit/cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
|
||||
author: {
|
||||
name: 'Example User',
|
||||
email: 'user@example.com',
|
||||
},
|
||||
},
|
||||
};
|
@@ -0,0 +1,26 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './pipeline_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Pipeline event',
|
||||
description:
|
||||
'Pipeline event (triggered when the status of a pipeline changes)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#pipeline-events',
|
||||
key: GITLAB_EVENT_TYPE.pipeline_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.pipeline_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,254 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#pipeline-events
|
||||
|
||||
export default {
|
||||
object_kind: 'pipeline',
|
||||
object_attributes: {
|
||||
id: 31,
|
||||
iid: 3,
|
||||
ref: 'master',
|
||||
tag: false,
|
||||
sha: 'bcbb5ec396a2c0f828686f14fac9b80b780504f2',
|
||||
before_sha: 'bcbb5ec396a2c0f828686f14fac9b80b780504f2',
|
||||
source: 'merge_request_event',
|
||||
status: 'success',
|
||||
stages: ['build', 'test', 'deploy'],
|
||||
created_at: '2016-08-12 15:23:28 UTC',
|
||||
finished_at: '2016-08-12 15:26:29 UTC',
|
||||
duration: 63,
|
||||
variables: [
|
||||
{
|
||||
key: 'NESTOR_PROD_ENVIRONMENT',
|
||||
value: 'us-west-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
merge_request: {
|
||||
id: 1,
|
||||
iid: 1,
|
||||
title: 'Test',
|
||||
source_branch: 'test',
|
||||
source_project_id: 1,
|
||||
target_branch: 'master',
|
||||
target_project_id: 1,
|
||||
state: 'opened',
|
||||
merge_status: 'can_be_merged',
|
||||
detailed_merge_status: 'mergeable',
|
||||
url: 'http://192.168.64.1:3005/gitlab-org/gitlab-test/merge_requests/1',
|
||||
},
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon',
|
||||
email: 'user_email@gitlab.com',
|
||||
},
|
||||
project: {
|
||||
id: 1,
|
||||
name: 'Gitlab Test',
|
||||
description: 'Atque in sunt eos similique dolores voluptatem.',
|
||||
web_url: 'http://192.168.64.1:3005/gitlab-org/gitlab-test',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@192.168.64.1:gitlab-org/gitlab-test.git',
|
||||
git_http_url: 'http://192.168.64.1:3005/gitlab-org/gitlab-test.git',
|
||||
namespace: 'Gitlab Org',
|
||||
visibility_level: 20,
|
||||
path_with_namespace: 'gitlab-org/gitlab-test',
|
||||
default_branch: 'master',
|
||||
},
|
||||
commit: {
|
||||
id: 'bcbb5ec396a2c0f828686f14fac9b80b780504f2',
|
||||
message: 'test\n',
|
||||
timestamp: '2016-08-12T17:23:21+02:00',
|
||||
url: 'http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2',
|
||||
author: {
|
||||
name: 'User',
|
||||
email: 'user@gitlab.com',
|
||||
},
|
||||
},
|
||||
source_pipeline: {
|
||||
project: {
|
||||
id: 41,
|
||||
web_url: 'https://gitlab.example.com/gitlab-org/upstream-project',
|
||||
path_with_namespace: 'gitlab-org/upstream-project',
|
||||
},
|
||||
pipeline_id: 30,
|
||||
job_id: 3401,
|
||||
},
|
||||
builds: [
|
||||
{
|
||||
id: 380,
|
||||
stage: 'deploy',
|
||||
name: 'production',
|
||||
status: 'skipped',
|
||||
created_at: '2016-08-12 15:23:28 UTC',
|
||||
started_at: null,
|
||||
finished_at: null,
|
||||
duration: null,
|
||||
queued_duration: null,
|
||||
failure_reason: null,
|
||||
when: 'manual',
|
||||
manual: true,
|
||||
allow_failure: false,
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
runner: null,
|
||||
artifacts_file: {
|
||||
filename: null,
|
||||
size: null,
|
||||
},
|
||||
environment: {
|
||||
name: 'production',
|
||||
action: 'start',
|
||||
deployment_tier: 'production',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 377,
|
||||
stage: 'test',
|
||||
name: 'test-image',
|
||||
status: 'success',
|
||||
created_at: '2016-08-12 15:23:28 UTC',
|
||||
started_at: '2016-08-12 15:26:12 UTC',
|
||||
finished_at: '2016-08-12 15:26:29 UTC',
|
||||
duration: 17.0,
|
||||
queued_duration: 196.0,
|
||||
failure_reason: null,
|
||||
when: 'on_success',
|
||||
manual: false,
|
||||
allow_failure: false,
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
runner: {
|
||||
id: 380987,
|
||||
description: 'shared-runners-manager-6.gitlab.com',
|
||||
active: true,
|
||||
runner_type: 'instance_type',
|
||||
is_shared: true,
|
||||
tags: ['linux', 'docker', 'shared-runner'],
|
||||
},
|
||||
artifacts_file: {
|
||||
filename: null,
|
||||
size: null,
|
||||
},
|
||||
environment: null,
|
||||
},
|
||||
{
|
||||
id: 378,
|
||||
stage: 'test',
|
||||
name: 'test-build',
|
||||
status: 'failed',
|
||||
created_at: '2016-08-12 15:23:28 UTC',
|
||||
started_at: '2016-08-12 15:26:12 UTC',
|
||||
finished_at: '2016-08-12 15:26:29 UTC',
|
||||
duration: 17.0,
|
||||
queued_duration: 196.0,
|
||||
failure_reason: 'script_failure',
|
||||
when: 'on_success',
|
||||
manual: false,
|
||||
allow_failure: false,
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
runner: {
|
||||
id: 380987,
|
||||
description: 'shared-runners-manager-6.gitlab.com',
|
||||
active: true,
|
||||
runner_type: 'instance_type',
|
||||
is_shared: true,
|
||||
tags: ['linux', 'docker'],
|
||||
},
|
||||
artifacts_file: {
|
||||
filename: null,
|
||||
size: null,
|
||||
},
|
||||
environment: null,
|
||||
},
|
||||
{
|
||||
id: 376,
|
||||
stage: 'build',
|
||||
name: 'build-image',
|
||||
status: 'success',
|
||||
created_at: '2016-08-12 15:23:28 UTC',
|
||||
started_at: '2016-08-12 15:24:56 UTC',
|
||||
finished_at: '2016-08-12 15:25:26 UTC',
|
||||
duration: 17.0,
|
||||
queued_duration: 196.0,
|
||||
failure_reason: null,
|
||||
when: 'on_success',
|
||||
manual: false,
|
||||
allow_failure: false,
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
runner: {
|
||||
id: 380987,
|
||||
description: 'shared-runners-manager-6.gitlab.com',
|
||||
active: true,
|
||||
runner_type: 'instance_type',
|
||||
is_shared: true,
|
||||
tags: ['linux', 'docker'],
|
||||
},
|
||||
artifacts_file: {
|
||||
filename: null,
|
||||
size: null,
|
||||
},
|
||||
environment: null,
|
||||
},
|
||||
{
|
||||
id: 379,
|
||||
stage: 'deploy',
|
||||
name: 'staging',
|
||||
status: 'created',
|
||||
created_at: '2016-08-12 15:23:28 UTC',
|
||||
started_at: null,
|
||||
finished_at: null,
|
||||
duration: null,
|
||||
queued_duration: null,
|
||||
failure_reason: null,
|
||||
when: 'on_success',
|
||||
manual: false,
|
||||
allow_failure: false,
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
runner: null,
|
||||
artifacts_file: {
|
||||
filename: null,
|
||||
size: null,
|
||||
},
|
||||
environment: {
|
||||
name: 'staging',
|
||||
action: 'start',
|
||||
deployment_tier: 'staging',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
@@ -0,0 +1,62 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './push_event';
|
||||
|
||||
export const branchFilterStrategyArgumentDescriptor = {
|
||||
label: 'What type of filter to use?',
|
||||
key: 'branch_filter_strategy',
|
||||
type: 'dropdown' as const,
|
||||
description: 'Defaults to including all branches',
|
||||
required: true,
|
||||
variables: false,
|
||||
value: 'all_branches',
|
||||
options: [
|
||||
{
|
||||
label: 'All branches',
|
||||
value: 'all_branches',
|
||||
},
|
||||
{
|
||||
label: 'Wildcard pattern (ex: *-stable)',
|
||||
value: 'wildcard',
|
||||
},
|
||||
{
|
||||
label: 'Regular expression (ex: ^(feature|hotfix)/)',
|
||||
value: 'regex',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const pushEventsBranchFilterArgumentDescriptor = {
|
||||
label: 'Filter value',
|
||||
key: 'push_events_branch_filter',
|
||||
description: 'Leave empty when using "all branches"',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: false,
|
||||
};
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Push event',
|
||||
description: 'Push event (triggered when you push to the repository)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#push-events',
|
||||
key: GITLAB_EVENT_TYPE.push_events,
|
||||
type: 'webhook',
|
||||
arguments: [
|
||||
projectArgumentDescriptor,
|
||||
branchFilterStrategyArgumentDescriptor,
|
||||
pushEventsBranchFilterArgumentDescriptor,
|
||||
],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.push_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,75 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#push-events
|
||||
|
||||
export default {
|
||||
object_kind: 'push',
|
||||
event_name: 'push',
|
||||
before: '95790bf891e76fee5e1747ab589903a6a1f80f22',
|
||||
after: 'da1560886d4f094c3e6c9ef40349f7d38b5d27d7',
|
||||
ref: 'refs/heads/master',
|
||||
checkout_sha: 'da1560886d4f094c3e6c9ef40349f7d38b5d27d7',
|
||||
user_id: 4,
|
||||
user_name: 'John Smith',
|
||||
user_username: 'jsmith',
|
||||
user_email: 'john@example.com',
|
||||
user_avatar:
|
||||
'https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80',
|
||||
project_id: 15,
|
||||
project: {
|
||||
id: 15,
|
||||
name: 'Diaspora',
|
||||
description: '',
|
||||
web_url: 'http://example.com/mike/diaspora',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:mike/diaspora.git',
|
||||
git_http_url: 'http://example.com/mike/diaspora.git',
|
||||
namespace: 'Mike',
|
||||
visibility_level: 0,
|
||||
path_with_namespace: 'mike/diaspora',
|
||||
default_branch: 'master',
|
||||
homepage: 'http://example.com/mike/diaspora',
|
||||
url: 'git@example.com:mike/diaspora.git',
|
||||
ssh_url: 'git@example.com:mike/diaspora.git',
|
||||
http_url: 'http://example.com/mike/diaspora.git',
|
||||
},
|
||||
repository: {
|
||||
name: 'Diaspora',
|
||||
url: 'git@example.com:mike/diaspora.git',
|
||||
description: '',
|
||||
homepage: 'http://example.com/mike/diaspora',
|
||||
git_http_url: 'http://example.com/mike/diaspora.git',
|
||||
git_ssh_url: 'git@example.com:mike/diaspora.git',
|
||||
visibility_level: 0,
|
||||
},
|
||||
commits: [
|
||||
{
|
||||
id: 'b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327',
|
||||
message:
|
||||
'Update Catalan translation to e38cb41.\n\nSee https://gitlab.com/gitlab-org/gitlab for more information',
|
||||
title: 'Update Catalan translation to e38cb41.',
|
||||
timestamp: '2011-12-12T14:27:31+02:00',
|
||||
url: 'http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327',
|
||||
author: {
|
||||
name: 'Jordi Mallach',
|
||||
email: 'jordi@softcatala.org',
|
||||
},
|
||||
added: ['CHANGELOG'],
|
||||
modified: ['app/controller/application.rb'],
|
||||
removed: [],
|
||||
},
|
||||
{
|
||||
id: 'da1560886d4f094c3e6c9ef40349f7d38b5d27d7',
|
||||
message: 'fixed readme',
|
||||
title: 'fixed readme',
|
||||
timestamp: '2012-01-03T23:36:29+02:00',
|
||||
url: 'http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7',
|
||||
author: {
|
||||
name: 'GitLab dev user',
|
||||
email: 'gitlabdev@dv6700.(none)',
|
||||
},
|
||||
added: ['CHANGELOG'],
|
||||
modified: ['app/controller/application.rb'],
|
||||
removed: [],
|
||||
},
|
||||
],
|
||||
total_commits_count: 4,
|
||||
};
|
@@ -0,0 +1,25 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './release_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Release event',
|
||||
description: 'Release event (triggered when a release is created or updated)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#release-events',
|
||||
key: GITLAB_EVENT_TYPE.releases_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.releases_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,72 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#release-events
|
||||
|
||||
export default {
|
||||
object_kind: 'release',
|
||||
id: 1,
|
||||
created_at: '2020-11-02 12:55:12 UTC',
|
||||
description: 'v1.1 has been released',
|
||||
name: 'v1.1',
|
||||
released_at: '2020-11-02 12:55:12 UTC',
|
||||
tag: 'v1.1',
|
||||
project: {
|
||||
id: 2,
|
||||
name: 'release-webhook-example',
|
||||
description: '',
|
||||
web_url: 'https://example.com/gitlab-org/release-webhook-example',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'ssh://git@example.com/gitlab-org/release-webhook-example.git',
|
||||
git_http_url: 'https://example.com/gitlab-org/release-webhook-example.git',
|
||||
namespace: 'Gitlab',
|
||||
visibility_level: 0,
|
||||
path_with_namespace: 'gitlab-org/release-webhook-example',
|
||||
default_branch: 'master',
|
||||
ci_config_path: null,
|
||||
homepage: 'https://example.com/gitlab-org/release-webhook-example',
|
||||
url: 'ssh://git@example.com/gitlab-org/release-webhook-example.git',
|
||||
ssh_url: 'ssh://git@example.com/gitlab-org/release-webhook-example.git',
|
||||
http_url: 'https://example.com/gitlab-org/release-webhook-example.git',
|
||||
},
|
||||
url: 'https://example.com/gitlab-org/release-webhook-example/-/releases/v1.1',
|
||||
action: 'create',
|
||||
assets: {
|
||||
count: 5,
|
||||
links: [
|
||||
{
|
||||
id: 1,
|
||||
external: true, // deprecated in GitLab 15.9, will be removed in GitLab 16.0.
|
||||
link_type: 'other',
|
||||
name: 'Changelog',
|
||||
url: 'https://example.net/changelog',
|
||||
},
|
||||
],
|
||||
sources: [
|
||||
{
|
||||
format: 'zip',
|
||||
url: 'https://example.com/gitlab-org/release-webhook-example/-/archive/v1.1/release-webhook-example-v1.1.zip',
|
||||
},
|
||||
{
|
||||
format: 'tar.gz',
|
||||
url: 'https://example.com/gitlab-org/release-webhook-example/-/archive/v1.1/release-webhook-example-v1.1.tar.gz',
|
||||
},
|
||||
{
|
||||
format: 'tar.bz2',
|
||||
url: 'https://example.com/gitlab-org/release-webhook-example/-/archive/v1.1/release-webhook-example-v1.1.tar.bz2',
|
||||
},
|
||||
{
|
||||
format: 'tar',
|
||||
url: 'https://example.com/gitlab-org/release-webhook-example/-/archive/v1.1/release-webhook-example-v1.1.tar',
|
||||
},
|
||||
],
|
||||
},
|
||||
commit: {
|
||||
id: 'ee0a3fb31ac16e11b9dbb596ad16d4af654d08f8',
|
||||
message: 'Release v1.1',
|
||||
title: 'Release v1.1',
|
||||
timestamp: '2020-10-31T14:58:32+11:00',
|
||||
url: 'https://example.com/gitlab-org/release-webhook-example/-/commit/ee0a3fb31ac16e11b9dbb596ad16d4af654d08f8',
|
||||
author: {
|
||||
name: 'Example User',
|
||||
email: 'user@example.com',
|
||||
},
|
||||
},
|
||||
};
|
@@ -0,0 +1,26 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './tag_push_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Tag event',
|
||||
description:
|
||||
'Tag event (triggered when you create or delete tags in the repository)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#tag-events',
|
||||
key: GITLAB_EVENT_TYPE.tag_push_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.tag_push_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,43 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#tag-events
|
||||
|
||||
export default {
|
||||
object_kind: 'tag_push',
|
||||
event_name: 'tag_push',
|
||||
before: '0000000000000000000000000000000000000000',
|
||||
after: '82b3d5ae55f7080f1e6022629cdb57bfae7cccc7',
|
||||
ref: 'refs/tags/v1.0.0',
|
||||
checkout_sha: '82b3d5ae55f7080f1e6022629cdb57bfae7cccc7',
|
||||
user_id: 1,
|
||||
user_name: 'John Smith',
|
||||
user_avatar:
|
||||
'https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80',
|
||||
project_id: 1,
|
||||
project: {
|
||||
id: 1,
|
||||
name: 'Example',
|
||||
description: '',
|
||||
web_url: 'http://example.com/jsmith/example',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:jsmith/example.git',
|
||||
git_http_url: 'http://example.com/jsmith/example.git',
|
||||
namespace: 'Jsmith',
|
||||
visibility_level: 0,
|
||||
path_with_namespace: 'jsmith/example',
|
||||
default_branch: 'master',
|
||||
homepage: 'http://example.com/jsmith/example',
|
||||
url: 'git@example.com:jsmith/example.git',
|
||||
ssh_url: 'git@example.com:jsmith/example.git',
|
||||
http_url: 'http://example.com/jsmith/example.git',
|
||||
},
|
||||
repository: {
|
||||
name: 'Example',
|
||||
url: 'ssh://git@example.com/jsmith/example.git',
|
||||
description: '',
|
||||
homepage: 'http://example.com/jsmith/example',
|
||||
git_http_url: 'http://example.com/jsmith/example.git',
|
||||
git_ssh_url: 'git@example.com:jsmith/example.git',
|
||||
visibility_level: 0,
|
||||
},
|
||||
commits: [],
|
||||
total_commits_count: 0,
|
||||
};
|
24
packages/backend/src/apps/gitlab/triggers/types.ts
Normal file
24
packages/backend/src/apps/gitlab/triggers/types.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export enum GITLAB_EVENT_TYPE {
|
||||
// ref: https://docs.gitlab.com/ee/api/projects.html#add-project-hook
|
||||
confidential_issues_events = 'confidential_issues_events',
|
||||
confidential_note_events = 'confidential_note_events',
|
||||
deployment_events = 'deployment_events',
|
||||
feature_flag_events = 'feature_flag_events',
|
||||
issues_events = 'issues_events',
|
||||
job_events = 'job_events',
|
||||
merge_requests_events = 'merge_requests_events',
|
||||
note_events = 'note_events',
|
||||
pipeline_events = 'pipeline_events',
|
||||
push_events = 'push_events',
|
||||
releases_events = 'releases_events',
|
||||
tag_push_events = 'tag_push_events',
|
||||
wiki_page_events = 'wiki_page_events',
|
||||
}
|
||||
|
||||
export type EventDescriptor = {
|
||||
name: string;
|
||||
description: string;
|
||||
info?: string;
|
||||
type: GITLAB_EVENT_TYPE;
|
||||
data: any;
|
||||
};
|
@@ -0,0 +1,26 @@
|
||||
import { IRawTrigger } from '@automatisch/types';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import { GITLAB_EVENT_TYPE } from '../types';
|
||||
import {
|
||||
getRegisterHookFn,
|
||||
getTestRunFn,
|
||||
projectArgumentDescriptor,
|
||||
unregisterHook,
|
||||
} from '../lib';
|
||||
|
||||
import data from './wiki_page_event';
|
||||
|
||||
export const triggerDescriptor: IRawTrigger = {
|
||||
name: 'Wiki page event',
|
||||
description:
|
||||
'Wiki page event (triggered when a wiki page is created, updated, or deleted)',
|
||||
// info: 'https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#wiki-page-events',
|
||||
key: GITLAB_EVENT_TYPE.wiki_page_events,
|
||||
type: 'webhook',
|
||||
arguments: [projectArgumentDescriptor],
|
||||
testRun: getTestRunFn(data),
|
||||
registerHook: getRegisterHookFn(GITLAB_EVENT_TYPE.wiki_page_events),
|
||||
unregisterHook,
|
||||
};
|
||||
|
||||
export default defineTrigger(triggerDescriptor);
|
@@ -0,0 +1,48 @@
|
||||
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#wiki-page-events
|
||||
|
||||
export default {
|
||||
object_kind: 'wiki_page',
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
avatar_url:
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
|
||||
email: 'admin@example.com',
|
||||
},
|
||||
project: {
|
||||
id: 1,
|
||||
name: 'awesome-project',
|
||||
description: 'This is awesome',
|
||||
web_url: 'http://example.com/root/awesome-project',
|
||||
avatar_url: null,
|
||||
git_ssh_url: 'git@example.com:root/awesome-project.git',
|
||||
git_http_url: 'http://example.com/root/awesome-project.git',
|
||||
namespace: 'root',
|
||||
visibility_level: 0,
|
||||
path_with_namespace: 'root/awesome-project',
|
||||
default_branch: 'master',
|
||||
homepage: 'http://example.com/root/awesome-project',
|
||||
url: 'git@example.com:root/awesome-project.git',
|
||||
ssh_url: 'git@example.com:root/awesome-project.git',
|
||||
http_url: 'http://example.com/root/awesome-project.git',
|
||||
},
|
||||
wiki: {
|
||||
web_url: 'http://example.com/root/awesome-project/-/wikis/home',
|
||||
git_ssh_url: 'git@example.com:root/awesome-project.wiki.git',
|
||||
git_http_url: 'http://example.com/root/awesome-project.wiki.git',
|
||||
path_with_namespace: 'root/awesome-project.wiki',
|
||||
default_branch: 'master',
|
||||
},
|
||||
object_attributes: {
|
||||
title: 'Awesome',
|
||||
content: 'awesome content goes here',
|
||||
format: 'markdown',
|
||||
message: 'adding an awesome page to the wiki',
|
||||
slug: 'awesome',
|
||||
url: 'http://example.com/root/awesome-project/-/wikis/awesome',
|
||||
action: 'create',
|
||||
diff_url:
|
||||
'http://example.com/root/awesome-project/-/wikis/home/diff?version_id=78ee4a6705abfbff4f4132c6646dbaae9c8fb6ec',
|
||||
},
|
||||
};
|
@@ -1,7 +1,7 @@
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
|
||||
export default {
|
||||
name: 'List Folders',
|
||||
name: 'List folders',
|
||||
key: 'listFolders',
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
@@ -22,6 +22,7 @@ export default {
|
||||
|
||||
if ($.step.parameters.driveId) {
|
||||
params.includeItemsFromAllDrives = true;
|
||||
params.corpora = 'drive';
|
||||
}
|
||||
|
||||
do {
|
||||
|
@@ -2,7 +2,7 @@ import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import newFilesInFolder from './new-files-in-folder';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'New Files in Folder',
|
||||
name: 'New files in folder',
|
||||
key: 'newFilesInFolder',
|
||||
pollInterval: 15,
|
||||
description:
|
||||
|
@@ -19,6 +19,7 @@ const newFilesInFolder = async ($: IGlobalVariable) => {
|
||||
|
||||
if ($.step.parameters.driveId) {
|
||||
params.includeItemsFromAllDrives = true;
|
||||
params.corpora = 'drive';
|
||||
}
|
||||
|
||||
do {
|
||||
|
@@ -2,7 +2,7 @@ import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import newFiles from './new-files';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'New Files',
|
||||
name: 'New files',
|
||||
key: 'newFiles',
|
||||
pollInterval: 15,
|
||||
description: 'Triggers when any new file is added (inside of any folder).',
|
||||
|
@@ -13,6 +13,7 @@ const newFiles = async ($: IGlobalVariable) => {
|
||||
|
||||
if ($.step.parameters.driveId) {
|
||||
params.includeItemsFromAllDrives = true;
|
||||
params.corpora = 'drive';
|
||||
}
|
||||
|
||||
do {
|
||||
|
@@ -2,7 +2,7 @@ import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import newFolders from './new-folders';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'New Folders',
|
||||
name: 'New folders',
|
||||
key: 'newFolders',
|
||||
pollInterval: 15,
|
||||
description:
|
||||
|
@@ -20,6 +20,7 @@ const newFolders = async ($: IGlobalVariable) => {
|
||||
|
||||
if ($.step.parameters.driveId) {
|
||||
params.includeItemsFromAllDrives = true;
|
||||
params.corpora = 'drive';
|
||||
}
|
||||
|
||||
do {
|
||||
|
@@ -2,7 +2,7 @@ import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import updatedFiles from './updated-files';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'Updated Files',
|
||||
name: 'Updated files',
|
||||
key: 'updatedFiles',
|
||||
pollInterval: 15,
|
||||
description:
|
||||
|
@@ -24,6 +24,7 @@ const updatedFiles = async ($: IGlobalVariable) => {
|
||||
|
||||
if ($.step.parameters.driveId) {
|
||||
params.includeItemsFromAllDrives = true;
|
||||
params.corpora = 'drive';
|
||||
}
|
||||
|
||||
do {
|
||||
|
@@ -2,7 +2,7 @@ import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import newFormResponses from './new-form-responses';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'New Form Responses',
|
||||
name: 'New form responses',
|
||||
key: 'newFormResponses',
|
||||
pollInterval: 15,
|
||||
description: 'Triggers when a new form response is submitted.',
|
||||
|
@@ -0,0 +1,145 @@
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
type TSheetsResponse = {
|
||||
sheets: {
|
||||
properties: {
|
||||
sheetId: string;
|
||||
title: string;
|
||||
};
|
||||
}[];
|
||||
};
|
||||
|
||||
export default defineAction({
|
||||
name: 'Create spreadsheet row',
|
||||
key: 'createSpreadsheetRow',
|
||||
description: 'Creates a new row in a specified spreadsheet.',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Drive',
|
||||
key: 'driveId',
|
||||
type: 'dropdown' as const,
|
||||
required: false,
|
||||
description:
|
||||
'The Google Drive where your spreadsheet resides. If nothing is selected, then your personal Google Drive will be used.',
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listDrives',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Spreadsheet',
|
||||
key: 'spreadsheetId',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
dependsOn: ['parameters.driveId'],
|
||||
description: 'The spreadsheets in your Google Drive.',
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listSpreadsheets',
|
||||
},
|
||||
{
|
||||
name: 'parameters.driveId',
|
||||
value: '{parameters.driveId}',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Worksheet',
|
||||
key: 'worksheetId',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
dependsOn: ['parameters.spreadsheetId'],
|
||||
description: 'The worksheets in your selected spreadsheet.',
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listWorksheets',
|
||||
},
|
||||
{
|
||||
name: 'parameters.spreadsheetId',
|
||||
value: '{parameters.spreadsheetId}',
|
||||
},
|
||||
],
|
||||
},
|
||||
additionalFields: {
|
||||
type: 'query',
|
||||
name: 'getDynamicFields',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listSheetHeaders',
|
||||
},
|
||||
{
|
||||
name: 'parameters.worksheetId',
|
||||
value: '{parameters.worksheetId}',
|
||||
},
|
||||
{
|
||||
name: 'parameters.spreadsheetId',
|
||||
value: '{parameters.spreadsheetId}',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
const {
|
||||
data: { sheets },
|
||||
} = await $.http.get<TSheetsResponse>(
|
||||
`/v4/spreadsheets/${$.step.parameters.spreadsheetId}`
|
||||
);
|
||||
|
||||
const selectedSheet = sheets.find(
|
||||
(sheet) => sheet.properties.sheetId === $.step.parameters.worksheetId
|
||||
);
|
||||
|
||||
const sheetName = selectedSheet.properties.title;
|
||||
|
||||
const range = sheetName;
|
||||
|
||||
const dataValues = Object.entries($.step.parameters)
|
||||
.filter((entry: [string, string]) => entry[0].startsWith('header-'))
|
||||
.map((value) => value[1]);
|
||||
|
||||
const values = [dataValues];
|
||||
|
||||
const params = {
|
||||
valueInputOption: 'USER_ENTERED',
|
||||
insertDataOption: 'INSERT_ROWS',
|
||||
includeValuesInResponse: true,
|
||||
};
|
||||
|
||||
const body = {
|
||||
majorDimension: 'ROWS',
|
||||
range,
|
||||
values,
|
||||
};
|
||||
|
||||
const { data } = await $.http.post(
|
||||
`/v4/spreadsheets/${$.step.parameters.spreadsheetId}/values/${range}:append`,
|
||||
body,
|
||||
{ params }
|
||||
);
|
||||
|
||||
$.setActionItem({
|
||||
raw: data,
|
||||
});
|
||||
},
|
||||
});
|
@@ -0,0 +1,105 @@
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
type THeaders = {
|
||||
__id: string;
|
||||
header: string;
|
||||
}[];
|
||||
|
||||
export default defineAction({
|
||||
name: 'Create spreadsheet',
|
||||
key: 'createSpreadsheet',
|
||||
description:
|
||||
'Create a blank spreadsheet or duplicate an existing spreadsheet. Optionally, provide headers.',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Title',
|
||||
key: 'title',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
description: '',
|
||||
variables: true,
|
||||
},
|
||||
{
|
||||
label: 'Spreadsheet to copy',
|
||||
key: 'spreadsheetId',
|
||||
type: 'dropdown' as const,
|
||||
required: false,
|
||||
description: 'Choose a spreadsheet to copy its data.',
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listSpreadsheets',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Headers',
|
||||
key: 'headers',
|
||||
type: 'dynamic' as const,
|
||||
required: false,
|
||||
description:
|
||||
'These headers are ignored if "Spreadsheet to Copy" is selected.',
|
||||
fields: [
|
||||
{
|
||||
label: 'Header',
|
||||
key: 'header',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
variables: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
if ($.step.parameters.spreadsheetId) {
|
||||
const body = { name: $.step.parameters.title };
|
||||
|
||||
const { data } = await $.http.post(
|
||||
`https://www.googleapis.com/drive/v3/files/${$.step.parameters.spreadsheetId}/copy`,
|
||||
body
|
||||
);
|
||||
|
||||
$.setActionItem({
|
||||
raw: data,
|
||||
});
|
||||
} else {
|
||||
const headers = $.step.parameters.headers as THeaders;
|
||||
const values = headers.map((entry) => entry.header);
|
||||
|
||||
const spreadsheetBody = {
|
||||
properties: {
|
||||
title: $.step.parameters.title,
|
||||
},
|
||||
sheets: [
|
||||
{
|
||||
data: [
|
||||
{
|
||||
startRow: 0,
|
||||
startColumn: 0,
|
||||
rowData: [
|
||||
{
|
||||
values: values.map((header) => ({
|
||||
userEnteredValue: { stringValue: header },
|
||||
})),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { data } = await $.http.post('/v4/spreadsheets', spreadsheetBody);
|
||||
|
||||
$.setActionItem({
|
||||
raw: data,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
@@ -0,0 +1,191 @@
|
||||
import { IJSONObject } from '@automatisch/types';
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
type THeaders = {
|
||||
__id: string;
|
||||
header: string;
|
||||
}[];
|
||||
|
||||
type TSheetsResponse = {
|
||||
sheets: {
|
||||
properties: {
|
||||
sheetId: string;
|
||||
title: string;
|
||||
};
|
||||
}[];
|
||||
};
|
||||
|
||||
type TBody = {
|
||||
requests: IJSONObject[];
|
||||
};
|
||||
|
||||
export default defineAction({
|
||||
name: 'Create worksheet',
|
||||
key: 'createWorksheet',
|
||||
description:
|
||||
'Create a blank worksheet with a title. Optionally, provide headers.',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Drive',
|
||||
key: 'driveId',
|
||||
type: 'dropdown' as const,
|
||||
required: false,
|
||||
description:
|
||||
'The Google Drive where your spreadsheet resides. If nothing is selected, then your personal Google Drive will be used.',
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listDrives',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Spreadsheet',
|
||||
key: 'spreadsheetId',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
dependsOn: ['parameters.driveId'],
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listSpreadsheets',
|
||||
},
|
||||
{
|
||||
name: 'parameters.driveId',
|
||||
value: '{parameters.driveId}',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Title',
|
||||
key: 'title',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
description: '',
|
||||
variables: true,
|
||||
},
|
||||
{
|
||||
label: 'Headers',
|
||||
key: 'headers',
|
||||
type: 'dynamic' as const,
|
||||
required: false,
|
||||
fields: [
|
||||
{
|
||||
label: 'Header',
|
||||
key: 'header',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
variables: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Overwrite',
|
||||
key: 'overwrite',
|
||||
type: 'dropdown' as const,
|
||||
required: false,
|
||||
value: false,
|
||||
description:
|
||||
'If a worksheet with the specified title exists, its content would be lost. Please, use with caution.',
|
||||
variables: true,
|
||||
options: [
|
||||
{
|
||||
label: 'Yes',
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
label: 'No',
|
||||
value: 'false',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
const {
|
||||
data: { sheets },
|
||||
} = await $.http.get<TSheetsResponse>(
|
||||
`/v4/spreadsheets/${$.step.parameters.spreadsheetId}`
|
||||
);
|
||||
const selectedSheet = sheets.find(
|
||||
(sheet) => sheet.properties.title === $.step.parameters.title
|
||||
);
|
||||
const headers = $.step.parameters.headers as THeaders;
|
||||
const values = headers.map((entry) => entry.header);
|
||||
|
||||
const body: TBody = {
|
||||
requests: [
|
||||
{
|
||||
addSheet: {
|
||||
properties: {
|
||||
title: $.step.parameters.title,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if ($.step.parameters.overwrite === 'true' && selectedSheet) {
|
||||
body.requests.unshift({
|
||||
deleteSheet: {
|
||||
sheetId: selectedSheet.properties.sheetId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const { data } = await $.http.post(
|
||||
`https://sheets.googleapis.com/v4/spreadsheets/${$.step.parameters.spreadsheetId}:batchUpdate`,
|
||||
body
|
||||
);
|
||||
|
||||
if (values.length) {
|
||||
const body = {
|
||||
requests: [
|
||||
{
|
||||
updateCells: {
|
||||
rows: [
|
||||
{
|
||||
values: values.map((header) => ({
|
||||
userEnteredValue: { stringValue: header },
|
||||
})),
|
||||
},
|
||||
],
|
||||
fields: '*',
|
||||
start: {
|
||||
sheetId:
|
||||
data.replies[data.replies.length - 1].addSheet.properties
|
||||
.sheetId,
|
||||
rowIndex: 0,
|
||||
columnIndex: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { data: response } = await $.http.post(
|
||||
`https://sheets.googleapis.com/v4/spreadsheets/${$.step.parameters.spreadsheetId}:batchUpdate`,
|
||||
body
|
||||
);
|
||||
|
||||
$.setActionItem({
|
||||
raw: response,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
$.setActionItem({
|
||||
raw: data,
|
||||
});
|
||||
},
|
||||
});
|
5
packages/backend/src/apps/google-sheets/actions/index.ts
Normal file
5
packages/backend/src/apps/google-sheets/actions/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import createSpreadsheet from './create-spreadsheet';
|
||||
import createSpreadsheetRow from './create-spreadsheet-row';
|
||||
import createWorksheet from './create-worksheet';
|
||||
|
||||
export default [createSpreadsheet, createSpreadsheetRow, createWorksheet];
|
@@ -1,4 +1,5 @@
|
||||
import listDrives from './list-drives';
|
||||
import listSpreadsheets from './list-spreadsheets';
|
||||
import listWorksheets from './list-worksheets';
|
||||
|
||||
export default [listDrives, listSpreadsheets];
|
||||
export default [listDrives, listSpreadsheets, listWorksheets];
|
||||
|
@@ -22,6 +22,7 @@ export default {
|
||||
|
||||
if ($.step.parameters.driveId) {
|
||||
params.includeItemsFromAllDrives = true;
|
||||
params.corpora = 'drive';
|
||||
}
|
||||
|
||||
do {
|
||||
|
@@ -0,0 +1,42 @@
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
|
||||
export default {
|
||||
name: 'List worksheets',
|
||||
key: 'listWorksheets',
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
const spreadsheetId = $.step.parameters.spreadsheetId as string;
|
||||
|
||||
const worksheets: {
|
||||
data: IJSONObject[];
|
||||
} = {
|
||||
data: [],
|
||||
};
|
||||
|
||||
if (!spreadsheetId) {
|
||||
return worksheets;
|
||||
}
|
||||
|
||||
const params: Record<string, unknown> = {
|
||||
pageToken: undefined as unknown as string,
|
||||
};
|
||||
|
||||
do {
|
||||
const { data } = await $.http.get(`/v4/spreadsheets/${spreadsheetId}`, {
|
||||
params,
|
||||
});
|
||||
params.pageToken = data.nextPageToken;
|
||||
|
||||
if (data.sheets?.length) {
|
||||
for (const sheet of data.sheets) {
|
||||
worksheets.data.push({
|
||||
value: sheet.properties.sheetId,
|
||||
name: sheet.properties.title,
|
||||
});
|
||||
}
|
||||
}
|
||||
} while (params.pageToken);
|
||||
|
||||
return worksheets;
|
||||
},
|
||||
};
|
@@ -0,0 +1,3 @@
|
||||
import listSheetHeaders from './list-sheet-headers';
|
||||
|
||||
export default [listSheetHeaders];
|
@@ -0,0 +1,71 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
type TSheetsResponse = {
|
||||
sheets: {
|
||||
properties: {
|
||||
sheetId: string;
|
||||
title: string;
|
||||
};
|
||||
}[];
|
||||
};
|
||||
|
||||
type TSheetsValueResponse = {
|
||||
majorDimension: string;
|
||||
range: string;
|
||||
values: string[][];
|
||||
};
|
||||
|
||||
const hasValue = (value: any) => value !== null && value !== undefined;
|
||||
|
||||
export default {
|
||||
name: 'List Sheet Headers',
|
||||
key: 'listSheetHeaders',
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
if (!hasValue($.step.parameters.spreadsheetId) || !hasValue($.step.parameters.worksheetId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
data: { sheets },
|
||||
} = await $.http.get<TSheetsResponse>(
|
||||
`/v4/spreadsheets/${$.step.parameters.spreadsheetId}`
|
||||
);
|
||||
|
||||
const selectedSheet = sheets.find(
|
||||
(sheet) => sheet.properties.sheetId === $.step.parameters.worksheetId
|
||||
);
|
||||
|
||||
if (!selectedSheet) return;
|
||||
|
||||
const sheetName = selectedSheet.properties.title;
|
||||
|
||||
const range = `${sheetName}!1:1`;
|
||||
|
||||
const params: Record<string, unknown> = {
|
||||
majorDimension: 'ROWS',
|
||||
};
|
||||
|
||||
const { data } = await $.http.get<TSheetsValueResponse>(
|
||||
`/v4/spreadsheets/${$.step.parameters.spreadsheetId}/values/${range}`,
|
||||
{
|
||||
params,
|
||||
}
|
||||
);
|
||||
|
||||
if (!data.values) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = data.values[0].map((item: string, index: number) => ({
|
||||
label: item,
|
||||
key: `header-${index}`,
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
value: item,
|
||||
variables: true,
|
||||
}));
|
||||
|
||||
return result;
|
||||
},
|
||||
};
|
@@ -2,7 +2,9 @@ import defineApp from '../../helpers/define-app';
|
||||
import addAuthHeader from './common/add-auth-header';
|
||||
import auth from './auth';
|
||||
import triggers from './triggers';
|
||||
import actions from './actions';
|
||||
import dynamicData from './dynamic-data';
|
||||
import dynamicFields from './dynamic-fields';
|
||||
|
||||
export default defineApp({
|
||||
name: 'Google Sheets',
|
||||
@@ -16,5 +18,7 @@ export default defineApp({
|
||||
beforeRequest: [addAuthHeader],
|
||||
auth,
|
||||
triggers,
|
||||
actions,
|
||||
dynamicData,
|
||||
dynamicFields,
|
||||
});
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import newSpreadsheets from './new-spreadsheets';
|
||||
import newWorksheets from './new-worksheets';
|
||||
import newSpreadsheetRows from './new-spreadsheet-rows';
|
||||
|
||||
export default [newSpreadsheets, newWorksheets];
|
||||
export default [newSpreadsheets, newWorksheets, newSpreadsheetRows];
|
||||
|
@@ -0,0 +1,82 @@
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import newSpreadsheetRows from './new-spreadsheet-rows';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'New spreadsheet rows',
|
||||
key: 'newSpreadsheetRows',
|
||||
pollInterval: 15,
|
||||
description:
|
||||
'Triggers when a new row is added to the bottom of a spreadsheet.',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Drive',
|
||||
key: 'driveId',
|
||||
type: 'dropdown' as const,
|
||||
required: false,
|
||||
description:
|
||||
'The Google Drive where your spreadsheet resides. If nothing is selected, then your personal Google Drive will be used.',
|
||||
variables: false,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listDrives',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Spreadsheet',
|
||||
key: 'spreadsheetId',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
dependsOn: ['parameters.driveId'],
|
||||
description: 'The spreadsheets in your Google Drive.',
|
||||
variables: false,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listSpreadsheets',
|
||||
},
|
||||
{
|
||||
name: 'parameters.driveId',
|
||||
value: '{parameters.driveId}',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Worksheet',
|
||||
key: 'worksheetId',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
dependsOn: ['parameters.spreadsheetId'],
|
||||
description:
|
||||
'The worksheets in your selected spreadsheet. You must have column headers.',
|
||||
variables: false,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listWorksheets',
|
||||
},
|
||||
{
|
||||
name: 'parameters.spreadsheetId',
|
||||
value: '{parameters.spreadsheetId}',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
await newSpreadsheetRows($);
|
||||
},
|
||||
});
|
@@ -0,0 +1,46 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
type TSheetsResponse = {
|
||||
sheets: {
|
||||
properties: {
|
||||
sheetId: string;
|
||||
title: string;
|
||||
};
|
||||
}[];
|
||||
};
|
||||
|
||||
const newSpreadsheetRows = async ($: IGlobalVariable) => {
|
||||
const {
|
||||
data: { sheets },
|
||||
} = await $.http.get<TSheetsResponse>(
|
||||
`/v4/spreadsheets/${$.step.parameters.spreadsheetId}`
|
||||
);
|
||||
|
||||
const selectedSheet = sheets.find(
|
||||
(sheet) => sheet.properties.sheetId === $.step.parameters.worksheetId
|
||||
);
|
||||
|
||||
if (!selectedSheet) return;
|
||||
|
||||
const sheetName = selectedSheet.properties.title;
|
||||
|
||||
const range = sheetName;
|
||||
|
||||
const { data } = await $.http.get(
|
||||
`v4/spreadsheets/${$.step.parameters.spreadsheetId}/values/${range}`
|
||||
);
|
||||
|
||||
if (data.values?.length) {
|
||||
for (let index = data.values.length - 1; index > 0; index--) {
|
||||
const value = data.values[index];
|
||||
$.pushTriggerItem({
|
||||
raw: { row: value },
|
||||
meta: {
|
||||
internalId: index.toString(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default newSpreadsheetRows;
|
@@ -1,8 +1,8 @@
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import newSpreadsheets from './new-spreadsheets'
|
||||
import newSpreadsheets from './new-spreadsheets';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'New Spreadsheets',
|
||||
name: 'New spreadsheets',
|
||||
key: 'newSpreadsheets',
|
||||
pollInterval: 15,
|
||||
description: 'Triggers when you create a new spreadsheet.',
|
||||
@@ -12,7 +12,8 @@ export default defineTrigger({
|
||||
key: 'driveId',
|
||||
type: 'dropdown' as const,
|
||||
required: false,
|
||||
description: 'The Google Drive where your spreadsheet resides. If nothing is selected, then your personal Google Drive will be used.',
|
||||
description:
|
||||
'The Google Drive where your spreadsheet resides. If nothing is selected, then your personal Google Drive will be used.',
|
||||
variables: false,
|
||||
source: {
|
||||
type: 'query',
|
||||
@@ -30,4 +31,4 @@ export default defineTrigger({
|
||||
async run($) {
|
||||
await newSpreadsheets($);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@@ -13,6 +13,7 @@ const newSpreadsheets = async ($: IGlobalVariable) => {
|
||||
|
||||
if ($.step.parameters.driveId) {
|
||||
params.includeItemsFromAllDrives = true;
|
||||
params.corpora = 'drive';
|
||||
}
|
||||
|
||||
do {
|
||||
|
@@ -2,7 +2,7 @@ import defineTrigger from '../../../../helpers/define-trigger';
|
||||
import newWorksheets from './new-worksheets';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'New Worksheets',
|
||||
name: 'New worksheets',
|
||||
key: 'newWorksheets',
|
||||
pollInterval: 15,
|
||||
description: 'Triggers when you create a new worksheet in a spreadsheet.',
|
||||
|
@@ -6,15 +6,17 @@ type TMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
||||
type THeaderEntry = {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
};
|
||||
|
||||
type THeaderEntries = THeaderEntry[];
|
||||
|
||||
function isPossiblyTextBased(contentType: string) {
|
||||
if (!contentType) return false;
|
||||
|
||||
return contentType.startsWith('application/json')
|
||||
|| contentType.startsWith('text/');
|
||||
return (
|
||||
contentType.startsWith('application/json') ||
|
||||
contentType.startsWith('text/')
|
||||
);
|
||||
}
|
||||
|
||||
function throwIfFileSizeExceedsLimit(contentLength: string) {
|
||||
@@ -28,7 +30,7 @@ function throwIfFileSizeExceedsLimit(contentLength: string) {
|
||||
}
|
||||
|
||||
export default defineAction({
|
||||
name: 'Custom Request',
|
||||
name: 'Custom request',
|
||||
key: 'customRequest',
|
||||
description: 'Makes a custom HTTP request by providing raw details.',
|
||||
arguments: [
|
||||
@@ -69,10 +71,12 @@ export default defineAction({
|
||||
type: 'dynamic' as const,
|
||||
required: false,
|
||||
description: 'Add or remove headers as needed',
|
||||
value: [{
|
||||
key: 'Content-Type',
|
||||
value: 'application/json'
|
||||
}],
|
||||
value: [
|
||||
{
|
||||
key: 'Content-Type',
|
||||
value: 'application/json',
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
label: 'Key',
|
||||
@@ -80,7 +84,7 @@ export default defineAction({
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
description: 'Header key',
|
||||
variables: false,
|
||||
variables: true,
|
||||
},
|
||||
{
|
||||
label: 'Value',
|
||||
@@ -89,9 +93,9 @@ export default defineAction({
|
||||
required: true,
|
||||
description: 'Header value',
|
||||
variables: true,
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
@@ -100,25 +104,30 @@ export default defineAction({
|
||||
const url = $.step.parameters.url as string;
|
||||
const headers = $.step.parameters.headers as THeaderEntries;
|
||||
|
||||
const headersObject: Record<string, string> = headers.reduce((result, entry) => {
|
||||
const key = entry.key?.toLowerCase();
|
||||
const value = entry.value;
|
||||
const headersObject: Record<string, string> = headers.reduce(
|
||||
(result, entry) => {
|
||||
const key = entry.key?.toLowerCase();
|
||||
const value = entry.value;
|
||||
|
||||
if (key && value) {
|
||||
return {
|
||||
...result,
|
||||
[entry.key?.toLowerCase()]: entry.value
|
||||
if (key && value) {
|
||||
return {
|
||||
...result,
|
||||
[entry.key?.toLowerCase()]: entry.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
return result;
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
let contentType = headersObject['content-type'];
|
||||
|
||||
// in case HEAD request is not supported by the URL
|
||||
try {
|
||||
const metadataResponse = await $.http.head(url, { headers: headersObject });
|
||||
const metadataResponse = await $.http.head(url, {
|
||||
headers: headersObject,
|
||||
});
|
||||
contentType = metadataResponse.headers['content-type'];
|
||||
|
||||
throwIfFileSizeExceedsLimit(metadataResponse.headers['content-length']);
|
||||
|
3
packages/backend/src/apps/mattermost/actions/index.ts
Normal file
3
packages/backend/src/apps/mattermost/actions/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import sendMessageToChannel from './send-a-message-to-channel';
|
||||
|
||||
export default [sendMessageToChannel];
|
@@ -0,0 +1,42 @@
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
import postMessage from './post-message';
|
||||
|
||||
export default defineAction({
|
||||
name: 'Send a message to channel',
|
||||
key: 'sendMessageToChannel',
|
||||
description: 'Sends a message to a channel you specify.',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Channel',
|
||||
key: 'channel',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
description: 'Pick a channel to send the message to.',
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listChannels',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Message text',
|
||||
key: 'message',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
description: 'The content of your new message.',
|
||||
variables: true,
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
const message = await postMessage($);
|
||||
|
||||
return message;
|
||||
},
|
||||
});
|
@@ -0,0 +1,27 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
type TData = {
|
||||
channel_id: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
const postMessage = async ($: IGlobalVariable) => {
|
||||
const { parameters } = $.step;
|
||||
const channel_id = parameters.channel as string;
|
||||
const message = parameters.message as string;
|
||||
|
||||
const data: TData = {
|
||||
channel_id,
|
||||
message,
|
||||
};
|
||||
|
||||
const response = await $.http.post('/api/v4/posts', data);
|
||||
|
||||
const actionData = {
|
||||
raw: response?.data,
|
||||
};
|
||||
|
||||
$.setActionItem(actionData);
|
||||
};
|
||||
|
||||
export default postMessage;
|
6
packages/backend/src/apps/mattermost/assets/favicon.svg
Normal file
6
packages/backend/src/apps/mattermost/assets/favicon.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<path d="M6.79123171,86.9648684 C25.2351716,32.4823178 76.783459,-1.43234143 131.421839,0.0464773399 L131.421839,0.0464773399 L113.909757,20.739032 C81.4957329,26.5997669 53.5072568,48.7337413 42.5072761,81.2287969 C26.140539,129.576353 53.572705,182.545803 103.779303,199.543648 C153.985902,216.538377 207.952658,191.12264 224.319395,142.7782 C235.283535,110.390667 226.589826,75.9306053 204.563374,51.5978814 L204.563374,51.5978814 L203.21701,24.4290666 C247.371203,56.4768925 267.622761,114.633895 249.208429,169.029181 C226.546194,235.970273 153.909545,271.865521 86.9684532,249.204844 C20.0273609,226.542609 -15.8694453,153.905961 6.79123171,86.9648684 Z M165.185344,11.9237762 C165.839826,11.6401671 166.594039,11.5793938 167.321762,11.8256038 C168.035459,12.0671391 168.585536,12.5580009 168.936152,13.1595015 L168.936152,13.1595015 L169.007833,13.2763734 L169.071723,13.4103864 C169.240019,13.7313945 169.383381,14.0991514 169.450388,14.5510559 C169.582343,15.4417519 169.641535,17.5358595 169.665634,19.6808502 L169.671365,20.2662434 C169.677102,20.9486534 169.679633,21.6256073 169.680171,22.2599793 L169.680173,22.7924325 C169.678741,24.5267431 169.663874,25.8268542 169.663874,25.8268542 L169.663874,25.8268542 L170.167202,44.7600977 L170.910507,66.6151379 L171.837691,104.59538 C171.837691,104.59538 171.83785,104.602367 171.838064,104.616156 L171.838772,104.677745 C171.838883,104.691349 171.838983,104.706608 171.839058,104.723498 L171.839105,104.844231 C171.832023,107.013302 171.387173,122.892918 160.122454,133.928662 C148.009853,145.795053 133.131285,144.708923 123.451177,141.433394 C113.771069,138.154749 101.293828,129.979951 98.8800345,113.195592 C96.8283098,98.9302108 104.41287,86.9390787 106.734401,83.6627102 L106.889339,83.4459953 C107.205256,83.0081712 107.389865,82.7777388 107.389865,82.7777388 L107.389865,82.7777388 L131.197445,53.1717559 L145.064682,36.2627333 L156.965355,21.5275276 C156.965355,21.5275276 158.715313,19.1834331 160.51647,16.874806 L160.876881,16.4142586 C161.477025,15.6498178 162.070275,14.9069442 162.593713,14.2737698 L162.898895,13.907734 C163.342593,13.3805415 163.71955,12.9564826 163.983901,12.6998055 C164.292443,12.4006135 164.608776,12.205827 164.918876,12.0546727 L164.918876,12.0546727 L165.146386,11.9393591 Z" fill="#0058CC"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,18 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import { URL, URLSearchParams } from 'url';
|
||||
import getBaseUrl from '../common/get-base-url';
|
||||
|
||||
export default async function generateAuthUrl($: IGlobalVariable) {
|
||||
const searchParams = new URLSearchParams({
|
||||
client_id: $.auth.data.clientId as string,
|
||||
redirect_uri: $.auth.data.oAuthRedirectUrl as string,
|
||||
response_type: 'code',
|
||||
});
|
||||
|
||||
const baseUrl = getBaseUrl($);
|
||||
const path = `/oauth/authorize?${searchParams.toString()}`;
|
||||
|
||||
await $.auth.set({
|
||||
url: new URL(path, baseUrl).toString(),
|
||||
});
|
||||
}
|
57
packages/backend/src/apps/mattermost/auth/index.ts
Normal file
57
packages/backend/src/apps/mattermost/auth/index.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import generateAuthUrl from './generate-auth-url';
|
||||
import verifyCredentials from './verify-credentials';
|
||||
import isStillVerified from './is-still-verified';
|
||||
|
||||
export default {
|
||||
fields: [
|
||||
{
|
||||
key: 'oAuthRedirectUrl',
|
||||
label: 'OAuth Redirect URL',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: true,
|
||||
value: '{WEB_APP_URL}/app/mattermost/connections/add',
|
||||
placeholder: null,
|
||||
description:
|
||||
'When asked to input an OAuth callback or redirect URL in Mattermost OAuth, enter the URL above.',
|
||||
clickToCopy: true,
|
||||
},
|
||||
{
|
||||
key: 'instanceUrl',
|
||||
label: 'Mattermost instance URL',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description: 'Your Mattermost instance URL',
|
||||
clickToCopy: true,
|
||||
},
|
||||
{
|
||||
key: 'clientId',
|
||||
label: 'Client id',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description: null,
|
||||
clickToCopy: false,
|
||||
},
|
||||
{
|
||||
key: 'clientSecret',
|
||||
label: 'Client secret',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description: null,
|
||||
clickToCopy: false,
|
||||
},
|
||||
],
|
||||
|
||||
generateAuthUrl,
|
||||
verifyCredentials,
|
||||
isStillVerified,
|
||||
};
|
@@ -0,0 +1,9 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import getCurrentUser from '../common/get-current-user';
|
||||
|
||||
const isStillVerified = async ($: IGlobalVariable) => {
|
||||
const user = await getCurrentUser($);
|
||||
return !!user.id;
|
||||
};
|
||||
|
||||
export default isStillVerified;
|
@@ -0,0 +1,44 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import getCurrentUser from '../common/get-current-user';
|
||||
|
||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
||||
const oauthRedirectUrlField = $.app.auth.fields.find(
|
||||
(field) => field.key == 'oAuthRedirectUrl'
|
||||
);
|
||||
const redirectUri = oauthRedirectUrlField.value as string;
|
||||
const params = {
|
||||
client_id: $.auth.data.clientId,
|
||||
client_secret: $.auth.data.clientSecret,
|
||||
code: $.auth.data.code,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: redirectUri,
|
||||
};
|
||||
const headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded', // This is not documented yet required
|
||||
};
|
||||
const response = await $.http.post('/oauth/access_token', null, {
|
||||
params,
|
||||
headers,
|
||||
});
|
||||
|
||||
const {
|
||||
data: { access_token, refresh_token, scope, token_type },
|
||||
} = response;
|
||||
|
||||
$.auth.data.accessToken = response.data.access_token;
|
||||
|
||||
const currentUser = await getCurrentUser($);
|
||||
|
||||
await $.auth.set({
|
||||
clientId: $.auth.data.clientId,
|
||||
clientSecret: $.auth.data.clientSecret,
|
||||
accessToken: access_token,
|
||||
refreshToken: refresh_token,
|
||||
scope: scope,
|
||||
tokenType: token_type,
|
||||
userId: currentUser.id,
|
||||
screenName: currentUser.username,
|
||||
});
|
||||
};
|
||||
|
||||
export default verifyCredentials;
|
@@ -0,0 +1,12 @@
|
||||
import { TBeforeRequest } from '@automatisch/types';
|
||||
|
||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
||||
if ($.auth.data?.accessToken) {
|
||||
requestConfig.headers = requestConfig.headers || {};
|
||||
requestConfig.headers.Authorization = `Bearer ${$.auth.data.accessToken}`;
|
||||
}
|
||||
|
||||
return requestConfig;
|
||||
};
|
||||
|
||||
export default addAuthHeader;
|
@@ -0,0 +1,11 @@
|
||||
import { TBeforeRequest } from '@automatisch/types';
|
||||
|
||||
const addXRequestedWithHeader: TBeforeRequest = ($, requestConfig) => {
|
||||
// This is not documented yet required
|
||||
// ref. https://forum.mattermost.com/t/solved-invalid-or-expired-session-please-login-again/6772
|
||||
requestConfig.headers = requestConfig.headers || {};
|
||||
requestConfig.headers['X-Requested-With'] = `XMLHttpRequest`;
|
||||
return requestConfig;
|
||||
};
|
||||
|
||||
export default addXRequestedWithHeader;
|
@@ -0,0 +1,7 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const getBaseUrl = ($: IGlobalVariable): string => {
|
||||
return $.auth.data.instanceUrl as string;
|
||||
};
|
||||
|
||||
export default getBaseUrl;
|
@@ -0,0 +1,9 @@
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
|
||||
const getCurrentUser = async ($: IGlobalVariable): Promise<IJSONObject> => {
|
||||
const response = await $.http.get('/api/v4/users/me');
|
||||
const currentUser = response.data;
|
||||
return currentUser;
|
||||
};
|
||||
|
||||
export default getCurrentUser;
|
@@ -0,0 +1,9 @@
|
||||
import { TBeforeRequest } from '@automatisch/types';
|
||||
|
||||
const setBaseUrl: TBeforeRequest = ($, requestConfig) => {
|
||||
requestConfig.baseURL = $.auth.data.instanceUrl as string;
|
||||
|
||||
return requestConfig;
|
||||
};
|
||||
|
||||
export default setBaseUrl;
|
@@ -0,0 +1,3 @@
|
||||
import listChannels from './list-channels';
|
||||
|
||||
export default [listChannels];
|
@@ -0,0 +1,36 @@
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
|
||||
type TChannel = {
|
||||
id: string;
|
||||
display_name: string;
|
||||
};
|
||||
|
||||
type TResponse = {
|
||||
data: TChannel[];
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'List channels',
|
||||
key: 'listChannels',
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
const channels: {
|
||||
data: IJSONObject[];
|
||||
error: IJSONObject | null;
|
||||
} = {
|
||||
data: [],
|
||||
error: null,
|
||||
};
|
||||
|
||||
const response: TResponse = await $.http.get('/api/v4/users/me/channels'); // this endpoint will return only channels user joined, there is no endpoint to list all channels available for user
|
||||
|
||||
for (const channel of response.data) {
|
||||
channels.data.push({
|
||||
value: channel.id as string,
|
||||
name: (channel.display_name as string) || (channel.id as string), // it's possible for channel to not have any name thus falling back to using id
|
||||
});
|
||||
}
|
||||
|
||||
return channels;
|
||||
},
|
||||
};
|
0
packages/backend/src/apps/mattermost/index.d.ts
vendored
Normal file
0
packages/backend/src/apps/mattermost/index.d.ts
vendored
Normal file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user