diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 6ced1c77..cec6fb51 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -8,6 +8,9 @@ services: volumes: - ..:/workspace:cached command: sleep infinity + ports: + - '3000:3000' + - '3001:3001' postgres: image: 'postgres:14.5-alpine' environment: diff --git a/.gitignore b/.gitignore index ba7f9dc3..3f9eca91 100644 --- a/.gitignore +++ b/.gitignore @@ -125,3 +125,6 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* + +# MacOS finder preferences +.DS_store diff --git a/packages/backend/bin/database/seed-user.ts b/packages/backend/bin/database/seed-user.ts index 0ce56315..a741d415 100644 --- a/packages/backend/bin/database/seed-user.ts +++ b/packages/backend/bin/database/seed-user.ts @@ -1,3 +1,6 @@ import { createUser } from './utils'; -createUser(); +(async () => { + await createUser(); + process.exit(); +})(); diff --git a/packages/backend/src/apps/gitlab/assets/favicon.svg b/packages/backend/src/apps/gitlab/assets/favicon.svg new file mode 100644 index 00000000..b1108696 --- /dev/null +++ b/packages/backend/src/apps/gitlab/assets/favicon.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/packages/backend/src/apps/gitlab/auth/generate-auth-url.ts b/packages/backend/src/apps/gitlab/auth/generate-auth-url.ts new file mode 100644 index 00000000..6845d1c9 --- /dev/null +++ b/packages/backend/src/apps/gitlab/auth/generate-auth-url.ts @@ -0,0 +1,24 @@ +import { IGlobalVariable } from '@automatisch/types'; +import { URLSearchParams } from '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()}`, + }); + + const url = `${ + $.auth.data.oInstanceUrl + }/oauth/authorize?${searchParams.toString()}`; + + await $.auth.set({ + url, + }); +} diff --git a/packages/backend/src/apps/gitlab/auth/index.ts b/packages/backend/src/apps/gitlab/auth/index.ts new file mode 100644 index 00000000..e8fe83cd --- /dev/null +++ b/packages/backend/src/apps/gitlab/auth/index.ts @@ -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: 'oInstanceUrl', + 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: '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: '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, +}; diff --git a/packages/backend/src/apps/gitlab/auth/is-still-verified.ts b/packages/backend/src/apps/gitlab/auth/is-still-verified.ts new file mode 100644 index 00000000..befb7694 --- /dev/null +++ b/packages/backend/src/apps/gitlab/auth/is-still-verified.ts @@ -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; diff --git a/packages/backend/src/apps/gitlab/auth/refresh-token.ts b/packages/backend/src/apps/gitlab/auth/refresh-token.ts new file mode 100644 index 00000000..b57f292b --- /dev/null +++ b/packages/backend/src/apps/gitlab/auth/refresh-token.ts @@ -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; diff --git a/packages/backend/src/apps/gitlab/auth/verify-credentials.ts b/packages/backend/src/apps/gitlab/auth/verify-credentials.ts new file mode 100644 index 00000000..e5832113 --- /dev/null +++ b/packages/backend/src/apps/gitlab/auth/verify-credentials.ts @@ -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( + `${$.auth.data.oInstanceUrl}/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, + }); +}; + +export default verifyCredentials; diff --git a/packages/backend/src/apps/gitlab/common/add-auth-header.ts b/packages/backend/src/apps/gitlab/common/add-auth-header.ts new file mode 100644 index 00000000..3af3e250 --- /dev/null +++ b/packages/backend/src/apps/gitlab/common/add-auth-header.ts @@ -0,0 +1,14 @@ +import { TBeforeRequest } from '@automatisch/types'; + +const addAuthHeader: TBeforeRequest = ($, requestConfig) => { + if ($.auth.data.oInstanceUrl) { + requestConfig.baseURL = $.auth.data.oInstanceUrl as string; + } + + if (requestConfig.headers && $.auth.data?.accessToken) { + requestConfig.headers.Authorization = `Bearer ${$.auth.data.accessToken}`; + } + return requestConfig; +}; + +export default addAuthHeader; diff --git a/packages/backend/src/apps/gitlab/common/get-current-user.ts b/packages/backend/src/apps/gitlab/common/get-current-user.ts new file mode 100644 index 00000000..f1a98387 --- /dev/null +++ b/packages/backend/src/apps/gitlab/common/get-current-user.ts @@ -0,0 +1,11 @@ +import { IGlobalVariable, IJSONObject } from '@automatisch/types'; + +const getCurrentUser = async ($: IGlobalVariable): Promise => { + // ref: https://docs.gitlab.com/ee/api/users.html#list-current-user + + const response = await $.http.get(`${$.auth.data.oInstanceUrl}/api/v4/user`); + const currentUser = response.data; + return currentUser; +}; + +export default getCurrentUser; diff --git a/packages/backend/src/apps/gitlab/common/paginate-all.ts b/packages/backend/src/apps/gitlab/common/paginate-all.ts new file mode 100644 index 00000000..664489ab --- /dev/null +++ b/packages/backend/src/apps/gitlab/common/paginate-all.ts @@ -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 +) { + 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; +} diff --git a/packages/backend/src/apps/gitlab/dynamic-data/index.ts b/packages/backend/src/apps/gitlab/dynamic-data/index.ts new file mode 100644 index 00000000..27787b4b --- /dev/null +++ b/packages/backend/src/apps/gitlab/dynamic-data/index.ts @@ -0,0 +1,3 @@ +import listProjects from './list-projects'; + +export default [listProjects]; diff --git a/packages/backend/src/apps/gitlab/dynamic-data/list-projects/index.ts b/packages/backend/src/apps/gitlab/dynamic-data/list-projects/index.ts new file mode 100644 index 00000000..b3ac5aa6 --- /dev/null +++ b/packages/backend/src/apps/gitlab/dynamic-data/list-projects/index.ts @@ -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', + 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; + }, +}; diff --git a/packages/backend/src/apps/gitlab/index.ts b/packages/backend/src/apps/gitlab/index.ts new file mode 100644 index 00000000..f7c0b59f --- /dev/null +++ b/packages/backend/src/apps/gitlab/index.ts @@ -0,0 +1,20 @@ +import defineApp from '../../helpers/define-app'; +import addAuthHeader from './common/add-auth-header'; +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/api/v4', + iconUrl: '{BASE_URL}/apps/gitlab/assets/favicon.svg', + authDocUrl: 'https://automatisch.io/docs/apps/gitlab/connection', + primaryColor: '000000', + supportsConnections: true, + beforeRequest: [addAuthHeader], + auth, + triggers, + dynamicData, +}); diff --git a/packages/backend/src/apps/gitlab/triggers/confidential-issue-event/index.ts b/packages/backend/src/apps/gitlab/triggers/confidential-issue-event/index.ts new file mode 100644 index 00000000..81249e29 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/confidential-issue-event/index.ts @@ -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 './issues_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Confidential issue events', + description: + 'Confidential issue events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/confidential-issue-event/issues_events.ts b/packages/backend/src/apps/gitlab/triggers/confidential-issue-event/issues_events.ts new file mode 100644 index 00000000..75a243b3 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/confidential-issue-event/issues_events.ts @@ -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, + }, + ], + }, + }, +}; diff --git a/packages/backend/src/apps/gitlab/triggers/confidential-note-event/index.ts b/packages/backend/src/apps/gitlab/triggers/confidential-note-event/index.ts new file mode 100644 index 00000000..856f0ad7 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/confidential-note-event/index.ts @@ -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_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Confidential comment events', + description: + 'Confidential comment events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/confidential-note-event/note_events.ts b/packages/backend/src/apps/gitlab/triggers/confidential-note-event/note_events.ts new file mode 100644 index 00000000..593188f2 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/confidential-note-event/note_events.ts @@ -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', + }, + }, +}; diff --git a/packages/backend/src/apps/gitlab/triggers/deployment-event/deployment_events.ts b/packages/backend/src/apps/gitlab/triggers/deployment-event/deployment_events.ts new file mode 100644 index 00000000..0c2d2858 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/deployment-event/deployment_events.ts @@ -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', +}; diff --git a/packages/backend/src/apps/gitlab/triggers/deployment-event/index.ts b/packages/backend/src/apps/gitlab/triggers/deployment-event/index.ts new file mode 100644 index 00000000..48def28b --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/deployment-event/index.ts @@ -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_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Deployment events', + description: + 'Deployment events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/feature-flag-event/feature_flag_events.ts b/packages/backend/src/apps/gitlab/triggers/feature-flag-event/feature_flag_events.ts new file mode 100644 index 00000000..bff89088 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/feature-flag-event/feature_flag_events.ts @@ -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, + }, +}; diff --git a/packages/backend/src/apps/gitlab/triggers/feature-flag-event/index.ts b/packages/backend/src/apps/gitlab/triggers/feature-flag-event/index.ts new file mode 100644 index 00000000..a9cabbcd --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/feature-flag-event/index.ts @@ -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_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Feature flag events', + description: + 'Feature flag events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/index.ts b/packages/backend/src/apps/gitlab/triggers/index.ts new file mode 100644 index 00000000..f8621d3b --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/index.ts @@ -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, +]; diff --git a/packages/backend/src/apps/gitlab/triggers/issue-event/index.ts b/packages/backend/src/apps/gitlab/triggers/issue-event/index.ts new file mode 100644 index 00000000..b52f92cb --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/issue-event/index.ts @@ -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 './issues_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Issue events', + description: + 'Issue events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/issue-event/issues_events.ts b/packages/backend/src/apps/gitlab/triggers/issue-event/issues_events.ts new file mode 100644 index 00000000..75a243b3 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/issue-event/issues_events.ts @@ -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, + }, + ], + }, + }, +}; diff --git a/packages/backend/src/apps/gitlab/triggers/job-event/index.ts b/packages/backend/src/apps/gitlab/triggers/job-event/index.ts new file mode 100644 index 00000000..9eb7824b --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/job-event/index.ts @@ -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_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Job events', + description: 'Job events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/job-event/job_events.ts b/packages/backend/src/apps/gitlab/triggers/job-event/job_events.ts new file mode 100644 index 00000000..bc23866d --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/job-event/job_events.ts @@ -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, +}; diff --git a/packages/backend/src/apps/gitlab/triggers/lib.ts b/packages/backend/src/apps/gitlab/triggers/lib.ts new file mode 100644 index 00000000..6b1a5ede --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/lib.ts @@ -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}`); + }; + +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}` + ); +}; diff --git a/packages/backend/src/apps/gitlab/triggers/merge-request-event/index.ts b/packages/backend/src/apps/gitlab/triggers/merge-request-event/index.ts new file mode 100644 index 00000000..fc06c098 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/merge-request-event/index.ts @@ -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_requests_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Merge request events', + description: + 'Merge request events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/merge-request-event/merge_requests_events.ts b/packages/backend/src/apps/gitlab/triggers/merge-request-event/merge_requests_events.ts new file mode 100644 index 00000000..e0f3f48f --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/merge-request-event/merge_requests_events.ts @@ -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', + }, + ], +}; diff --git a/packages/backend/src/apps/gitlab/triggers/note-event/index.ts b/packages/backend/src/apps/gitlab/triggers/note-event/index.ts new file mode 100644 index 00000000..177231cc --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/note-event/index.ts @@ -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_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Comment events', + description: + 'Comment events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/note-event/note_events.ts b/packages/backend/src/apps/gitlab/triggers/note-event/note_events.ts new file mode 100644 index 00000000..593188f2 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/note-event/note_events.ts @@ -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', + }, + }, +}; diff --git a/packages/backend/src/apps/gitlab/triggers/pipeline-event/index.ts b/packages/backend/src/apps/gitlab/triggers/pipeline-event/index.ts new file mode 100644 index 00000000..e5d7cadc --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/pipeline-event/index.ts @@ -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_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Pipeline events', + description: + 'Pipeline events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/pipeline-event/pipeline_events.ts b/packages/backend/src/apps/gitlab/triggers/pipeline-event/pipeline_events.ts new file mode 100644 index 00000000..4a29b41b --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/pipeline-event/pipeline_events.ts @@ -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', + }, + }, + ], +}; diff --git a/packages/backend/src/apps/gitlab/triggers/push-event/index.ts b/packages/backend/src/apps/gitlab/triggers/push-event/index.ts new file mode 100644 index 00000000..c2916fb3 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/push-event/index.ts @@ -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_events'; + +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 events', + description: 'Push events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/push-event/push_events.ts b/packages/backend/src/apps/gitlab/triggers/push-event/push_events.ts new file mode 100644 index 00000000..2951c153 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/push-event/push_events.ts @@ -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, +}; diff --git a/packages/backend/src/apps/gitlab/triggers/release-event/index.ts b/packages/backend/src/apps/gitlab/triggers/release-event/index.ts new file mode 100644 index 00000000..565dae14 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/release-event/index.ts @@ -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 './releases_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Release events', + description: + 'Release events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/release-event/releases_events.ts b/packages/backend/src/apps/gitlab/triggers/release-event/releases_events.ts new file mode 100644 index 00000000..90c758b3 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/release-event/releases_events.ts @@ -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', + }, + }, +}; diff --git a/packages/backend/src/apps/gitlab/triggers/tag-push-event/index.ts b/packages/backend/src/apps/gitlab/triggers/tag-push-event/index.ts new file mode 100644 index 00000000..6b4525be --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/tag-push-event/index.ts @@ -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_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Tag events', + description: + 'Tag events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/tag-push-event/tag_push_events.ts b/packages/backend/src/apps/gitlab/triggers/tag-push-event/tag_push_events.ts new file mode 100644 index 00000000..8dd94cfc --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/tag-push-event/tag_push_events.ts @@ -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, +}; diff --git a/packages/backend/src/apps/gitlab/triggers/types.ts b/packages/backend/src/apps/gitlab/triggers/types.ts new file mode 100644 index 00000000..38456fd0 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/types.ts @@ -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; +}; diff --git a/packages/backend/src/apps/gitlab/triggers/wiki-page-event/index.ts b/packages/backend/src/apps/gitlab/triggers/wiki-page-event/index.ts new file mode 100644 index 00000000..d7d0b4da --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/wiki-page-event/index.ts @@ -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_events'; + +export const triggerDescriptor: IRawTrigger = { + name: 'Wiki page events', + description: + 'Wiki page events (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); diff --git a/packages/backend/src/apps/gitlab/triggers/wiki-page-event/wiki_page_events.ts b/packages/backend/src/apps/gitlab/triggers/wiki-page-event/wiki_page_events.ts new file mode 100644 index 00000000..3058eea2 --- /dev/null +++ b/packages/backend/src/apps/gitlab/triggers/wiki-page-event/wiki_page_events.ts @@ -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', + }, +}; diff --git a/packages/types/index.d.ts b/packages/types/index.d.ts index 1dfcd3c0..2e531bf2 100644 --- a/packages/types/index.d.ts +++ b/packages/types/index.d.ts @@ -4,7 +4,13 @@ import type { Request } from 'express'; // Type definitions for automatisch -export type IJSONValue = string | number | boolean | IJSONObject | IJSONArray; +export type IJSONValue = + | string + | number + | boolean + | null + | IJSONObject + | IJSONArray; export type IJSONArray = Array; export interface IJSONObject { [x: string]: IJSONValue; @@ -338,7 +344,7 @@ export type TPaymentPlan = { name: string; limit: string; productId: string; -} +}; export type TSubscription = { status: string; @@ -354,28 +360,28 @@ export type TSubscription = { title: string; action: BillingCardAction; }; -} +}; type TBillingCardAction = TBillingTextCardAction | TBillingLinkCardAction; type TBillingTextCardAction = { type: 'text'; text: string; -} +}; type TBillingLinkCardAction = { type: 'link'; text: string; src: string; -} +}; type TInvoice = { - id: number - amount: number - currency: string - payout_date: string - receipt_url: string -} + id: number; + amount: number; + currency: string; + payout_date: string; + receipt_url: string; +}; declare module 'axios' { interface AxiosResponse {