From fe3bdb715e963fe133d20b73bfe782c708658be2 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Fri, 19 Apr 2024 22:39:35 -0300 Subject: [PATCH 01/21] New app/package --- components/gitlab_developer_app/common/constants.mjs | 1 + .../gitlab_developer_app/gitlab_developer_app.app.mjs | 11 +++-------- components/gitlab_developer_app/package.json | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) create mode 100644 components/gitlab_developer_app/common/constants.mjs diff --git a/components/gitlab_developer_app/common/constants.mjs b/components/gitlab_developer_app/common/constants.mjs new file mode 100644 index 0000000000000..df0a42f880c03 --- /dev/null +++ b/components/gitlab_developer_app/common/constants.mjs @@ -0,0 +1 @@ +export * from "../../gitlab/common/constants.mjs"; diff --git a/components/gitlab_developer_app/gitlab_developer_app.app.mjs b/components/gitlab_developer_app/gitlab_developer_app.app.mjs index 662e8957603da..f0acf0cef2a71 100644 --- a/components/gitlab_developer_app/gitlab_developer_app.app.mjs +++ b/components/gitlab_developer_app/gitlab_developer_app.app.mjs @@ -1,11 +1,6 @@ +import common from "../gitlab/gitlab.app.mjs"; + export default { - type: "app", + ...common, app: "gitlab_developer_app", - propDefinitions: {}, - methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); - }, - }, }; diff --git a/components/gitlab_developer_app/package.json b/components/gitlab_developer_app/package.json index 93b55e1faf2e3..fc297c11657ab 100644 --- a/components/gitlab_developer_app/package.json +++ b/components/gitlab_developer_app/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/gitlab_developer_app", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream GitLab (Developer App) Components", "main": "gitlab_developer_app.app.mjs", "keywords": [ From 1ffc93897b0927bce7a2207a31e9c1365bbda27c Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Sat, 20 Apr 2024 14:54:45 -0300 Subject: [PATCH 02/21] Creating actions reusing Gitlab actions --- .../actions/create-branch/create-branch.mjs | 23 +++ .../actions/create-epic/create-epic.mjs | 23 +++ .../actions/create-issue/create-issue.mjs | 23 +++ .../actions/get-issue/get-issue.mjs | 23 +++ .../get-repo-branch/get-repo-branch.mjs | 23 +++ .../actions/list-commits/list-commits.mjs | 23 +++ .../list-repo-branches/list-repo-branches.mjs | 23 +++ .../actions/search-issues/search-issues.mjs | 23 +++ .../actions/update-epic/update-epic.mjs | 23 +++ .../actions/update-issue/update-issue.mjs | 23 +++ .../sources/common/base.mjs | 107 ++++++++++++++ .../sources/common/hook-events.mjs | 10 ++ .../new-audit-event/common-queries.mjs | 43 ++++++ .../new-audit-event/new-audit-event.mjs | 134 ++++++++++++++++++ .../sources/new-branch/new-branch.mjs | 43 ++++++ .../new-commit-comment/new-commit-comment.mjs | 55 +++++++ .../sources/new-commit/new-commit.mjs | 83 +++++++++++ .../sources/new-issue/new-issue.mjs | 55 +++++++ .../sources/new-mention/new-mention.mjs | 81 +++++++++++ .../new-merge-request/new-merge-request.mjs | 55 +++++++ .../sources/new-milestone/new-milestone.mjs | 94 ++++++++++++ .../sources/new-project/new-project.mjs | 89 ++++++++++++ .../new-review-request/new-review-request.mjs | 80 +++++++++++ 23 files changed, 1159 insertions(+) create mode 100644 components/gitlab_developer_app/actions/create-branch/create-branch.mjs create mode 100644 components/gitlab_developer_app/actions/create-epic/create-epic.mjs create mode 100644 components/gitlab_developer_app/actions/create-issue/create-issue.mjs create mode 100644 components/gitlab_developer_app/actions/get-issue/get-issue.mjs create mode 100644 components/gitlab_developer_app/actions/get-repo-branch/get-repo-branch.mjs create mode 100644 components/gitlab_developer_app/actions/list-commits/list-commits.mjs create mode 100644 components/gitlab_developer_app/actions/list-repo-branches/list-repo-branches.mjs create mode 100644 components/gitlab_developer_app/actions/search-issues/search-issues.mjs create mode 100644 components/gitlab_developer_app/actions/update-epic/update-epic.mjs create mode 100644 components/gitlab_developer_app/actions/update-issue/update-issue.mjs create mode 100644 components/gitlab_developer_app/sources/common/base.mjs create mode 100644 components/gitlab_developer_app/sources/common/hook-events.mjs create mode 100644 components/gitlab_developer_app/sources/new-audit-event/common-queries.mjs create mode 100644 components/gitlab_developer_app/sources/new-audit-event/new-audit-event.mjs create mode 100644 components/gitlab_developer_app/sources/new-branch/new-branch.mjs create mode 100644 components/gitlab_developer_app/sources/new-commit-comment/new-commit-comment.mjs create mode 100644 components/gitlab_developer_app/sources/new-commit/new-commit.mjs create mode 100644 components/gitlab_developer_app/sources/new-issue/new-issue.mjs create mode 100644 components/gitlab_developer_app/sources/new-mention/new-mention.mjs create mode 100644 components/gitlab_developer_app/sources/new-merge-request/new-merge-request.mjs create mode 100644 components/gitlab_developer_app/sources/new-milestone/new-milestone.mjs create mode 100644 components/gitlab_developer_app/sources/new-project/new-project.mjs create mode 100644 components/gitlab_developer_app/sources/new-review-request/new-review-request.mjs diff --git a/components/gitlab_developer_app/actions/create-branch/create-branch.mjs b/components/gitlab_developer_app/actions/create-branch/create-branch.mjs new file mode 100644 index 0000000000000..24cbd0339eceb --- /dev/null +++ b/components/gitlab_developer_app/actions/create-branch/create-branch.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/create-branch/create-branch.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-create-branch", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/actions/create-epic/create-epic.mjs b/components/gitlab_developer_app/actions/create-epic/create-epic.mjs new file mode 100644 index 0000000000000..ee4921af6634f --- /dev/null +++ b/components/gitlab_developer_app/actions/create-epic/create-epic.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/create-epic/create-epic.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-create-epic", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/actions/create-issue/create-issue.mjs b/components/gitlab_developer_app/actions/create-issue/create-issue.mjs new file mode 100644 index 0000000000000..bc6c88e02ca01 --- /dev/null +++ b/components/gitlab_developer_app/actions/create-issue/create-issue.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/create-issue/create-issue.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-create-issue", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/actions/get-issue/get-issue.mjs b/components/gitlab_developer_app/actions/get-issue/get-issue.mjs new file mode 100644 index 0000000000000..b1ad77a0f7a04 --- /dev/null +++ b/components/gitlab_developer_app/actions/get-issue/get-issue.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/get-issue/get-issue.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-get-issue", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/actions/get-repo-branch/get-repo-branch.mjs b/components/gitlab_developer_app/actions/get-repo-branch/get-repo-branch.mjs new file mode 100644 index 0000000000000..4aa8ebfb8590b --- /dev/null +++ b/components/gitlab_developer_app/actions/get-repo-branch/get-repo-branch.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/get-repo-branch/get-repo-branch.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-get-repo-branch", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/actions/list-commits/list-commits.mjs b/components/gitlab_developer_app/actions/list-commits/list-commits.mjs new file mode 100644 index 0000000000000..c0f7c4b347d70 --- /dev/null +++ b/components/gitlab_developer_app/actions/list-commits/list-commits.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/list-commits/list-commits.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-list-commits", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/actions/list-repo-branches/list-repo-branches.mjs b/components/gitlab_developer_app/actions/list-repo-branches/list-repo-branches.mjs new file mode 100644 index 0000000000000..04563191f6f1e --- /dev/null +++ b/components/gitlab_developer_app/actions/list-repo-branches/list-repo-branches.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/list-repo-branches/list-repo-branches.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-list-repo-branches", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/actions/search-issues/search-issues.mjs b/components/gitlab_developer_app/actions/search-issues/search-issues.mjs new file mode 100644 index 0000000000000..19dd825b2f16f --- /dev/null +++ b/components/gitlab_developer_app/actions/search-issues/search-issues.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/search-issues/search-issues.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-search-issues", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/actions/update-epic/update-epic.mjs b/components/gitlab_developer_app/actions/update-epic/update-epic.mjs new file mode 100644 index 0000000000000..e568d36d449b1 --- /dev/null +++ b/components/gitlab_developer_app/actions/update-epic/update-epic.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/update-epic/update-epic.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-update-epic", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/actions/update-issue/update-issue.mjs b/components/gitlab_developer_app/actions/update-issue/update-issue.mjs new file mode 100644 index 0000000000000..9e0a466ab85fb --- /dev/null +++ b/components/gitlab_developer_app/actions/update-issue/update-issue.mjs @@ -0,0 +1,23 @@ +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/actions/update-issue/update-issue.mjs"; + +const { + name, description, type, ...others +} = common; + +const { // eslint-disable-next-line no-unused-vars + gitlab, ...props +} = others.props; + +export default { + ...others, + key: "gitlab_developer_app-update-issue", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, + }, +}; diff --git a/components/gitlab_developer_app/sources/common/base.mjs b/components/gitlab_developer_app/sources/common/base.mjs new file mode 100644 index 0000000000000..43549e4d39096 --- /dev/null +++ b/components/gitlab_developer_app/sources/common/base.mjs @@ -0,0 +1,107 @@ +import gitlab from "../../gitlab.app.mjs"; + +export default { + props: { + gitlab, + db: "$.service.db", + http: { + type: "$.interface.http", + customResponse: true, + }, + projectId: { + propDefinition: [ + gitlab, + "projectId", + ], + }, + }, + hooks: { + /** + * This method should be implemented in every source component + */ + async activate() { + // await this.activateHook(eventType); + throw new Error("activate() hook not implemented"); + }, + async deactivate() { + const hookId = this.getHookId(); + await this.gitlab.deleteProjectHook(this.projectId, hookId); + console.log( + `Deleted webhook for project ID ${this.projectId}. + (Hook ID: ${hookId})`, + ); + }, + }, + methods: { + _buildHookOpts(eventType) { + if (Array.isArray(eventType)) { + return eventType.reduce((prev, e) => ({ + ...prev, + [e]: true, + }), {}); + } + return { + [eventType]: true, + }; + }, + getHookId() { + return this.db.get("hookId"); + }, + setHookId(hookId) { + this.db.set("hookId", hookId); + }, + getToken() { + return this.db.get("token"); + }, + setToken(token) { + this.db.set("token", token); + }, + async activateHook(eventType) { + const data = this._buildHookOpts(eventType); + data.url = this.http.endpoint; + const { + hookId, + token, + } = await this.gitlab.createProjectHook(this.projectId, { + data, + }); + console.log( + `Created "${eventType}" webhook for project ID ${this.projectId}. + (Hook ID: ${hookId}, endpoint: ${data.url})`, + ); + this.setHookId(hookId); + this.setToken(token); + }, + emitEvent() { + throw new Error("emitEvent is not implemented"); + }, + isValidSource(headers) { + const token = headers["x-gitlab-token"]; + const expectedToken = this.getToken(); + return token === expectedToken; + }, + isValidEvent(headers) { + // Reject any calls not made by the proper Gitlab webhook. + if (!this.isValidSource(headers)) { + this.http.respond({ + status: 404, + }); + return false; + } + // Acknowledge the event back to Gitlab. + this.http.respond({ + status: 200, + }); + return true; + }, + }, + async run(event) { + const { + headers, + body, + } = event; + if (this.isValidEvent(headers)) { + await this.emitEvent(body); + } + }, +}; diff --git a/components/gitlab_developer_app/sources/common/hook-events.mjs b/components/gitlab_developer_app/sources/common/hook-events.mjs new file mode 100644 index 0000000000000..57b00434d81d2 --- /dev/null +++ b/components/gitlab_developer_app/sources/common/hook-events.mjs @@ -0,0 +1,10 @@ +const eventTypes = { + PUSH_EVENT: "push_event", + NOTE_EVENTS: "note_events", + ISSUES_EVENTS: "issues_events", + MERGE_REQUESTS_EVENTS: "merge_requests_events", +}; + +export { + eventTypes, +}; diff --git a/components/gitlab_developer_app/sources/new-audit-event/common-queries.mjs b/components/gitlab_developer_app/sources/new-audit-event/common-queries.mjs new file mode 100644 index 0000000000000..ee4a49c18bc6b --- /dev/null +++ b/components/gitlab_developer_app/sources/new-audit-event/common-queries.mjs @@ -0,0 +1,43 @@ +export function create_destination(destination, groupPath) { return ` + mutation { + externalAuditEventDestinationCreate(input: + { + destinationUrl: "${destination}", + groupPath: "${groupPath}", + clientMutationId: "PipeDream destination" + }) + { + clientMutationId, + errors + externalAuditEventDestination { + destinationUrl + group { + name + } + } + } + }`;} + +export function list_destinations(groupPath) { return ` + query { + group(fullPath: "${groupPath}") { + id, + externalAuditEventDestinations { + nodes { + destinationUrl, + id + } + } + } + }`;} + +export function delete_destination(destinationId) { return ` + mutation { + externalAuditEventDestinationDestroy(input: + { + id: "${destinationId}" + }) + { + errors + } + }`;} diff --git a/components/gitlab_developer_app/sources/new-audit-event/new-audit-event.mjs b/components/gitlab_developer_app/sources/new-audit-event/new-audit-event.mjs new file mode 100644 index 0000000000000..1c0e8fb51c9d9 --- /dev/null +++ b/components/gitlab_developer_app/sources/new-audit-event/new-audit-event.mjs @@ -0,0 +1,134 @@ +import gitlab from "../../gitlab.app.mjs"; +import base from "../common/base.mjs"; +import fetch from "node-fetch"; +import { + create_destination, + list_destinations, + delete_destination, +} from "./common-queries.mjs"; + +export default { + ...base, + key: "gitlab-new-audit-event", + name: "New Audit Event (Instant)", + description: "Emit new event when a new audit event is created", + version: "0.1.2", + dedupe: "unique", + type: "source", + props: { + gitlab, + http: { + // doesn't include base because base has a project, which we don't need + type: "$.interface.http", + customResponse: true, + }, + groupPath: { + propDefinition: [ + gitlab, + "groupPath", + ], + }, + }, + hooks: { + ...base.hooks, + async activate() { + console.log("Activating streaming audit events."); + console.log(`Event destination: ${this.http.endpoint}`); + console.log(`Group name: ${this.groupPath}`); + + // the variable must be named "query" to work with JSON.stringify and GraphQL + const query = create_destination(this.http.endpoint, this.groupPath); + + try { + await fetch(`https://${this._getBaseApiUrl()}/api/graphql`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": `Bearer ${this.gitlab.$auth.oauth_access_token}`, + }, + body: JSON.stringify({ + query, + }), + }) + .then((r) => r.json()); + + } catch (err) { + console.log(`Error thrown during activation: ${JSON.stringify(err)}`); + } + }, + async deactivate() { + console.log("Deactivating streaming audit events."); + console.log(`Event destiniation: ${this.http.endpoint}`); + console.log(`Group name: ${this.groupPath}`); + + // the variable must be named "query" to work with JSON.stringify and GraphQL + var query = list_destinations(this.groupPath); + + try { + + const data = await fetch(`https://${this._getBaseApiUrl()}/api/graphql`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": `Bearer ${this.gitlab.$auth.oauth_access_token}`, + }, + body: JSON.stringify({ + query, + }), + }) + .then((r) => r.json()); + console.log("Group list received."); + console.log(`Received: ${JSON.stringify(data)}`); + + const todelete = data.data.group.externalAuditEventDestinations + .nodes.filter((item) => item.destinationUrl == this.http.endpoint)[0].id; + console.log(`Deleting object ID: ${JSON.stringify(todelete)}`); + + query = delete_destination(todelete); + + await fetch(`https://${this._getBaseApiUrl()}/api/graphql`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": `Bearer ${this.gitlab.$auth.oauth_access_token}`, + }, + body: JSON.stringify({ + query, + }), + }) + .then((r) => r.json()); + + console.log("Done deactivating!"); + + } catch (err) { + console.log(`Error thrown during deactivation: ${JSON.stringify(err)}`); + } + }, + }, + methods: { + ...base.methods, + generateMeta(event) { + const id = event.id; + return { + id, + summary: `New Audit Event: ${id}`, + ts: +new Date(), + }; + }, + emitEvent(event) { + const meta = this.generateMeta(event); + this.$emit(event, meta); + }, + isValidSource() { + // GitLab doesn't currently send a x-gitlab-token + // with streaming audit events + return true; + }, + isValidEvent() { + return true; + }, + }, +}; diff --git a/components/gitlab_developer_app/sources/new-branch/new-branch.mjs b/components/gitlab_developer_app/sources/new-branch/new-branch.mjs new file mode 100644 index 0000000000000..0478322fabc8b --- /dev/null +++ b/components/gitlab_developer_app/sources/new-branch/new-branch.mjs @@ -0,0 +1,43 @@ +import base from "../common/base.mjs"; +import { eventTypes } from "../common/hook-events.mjs"; + +export default { + ...base, + key: "gitlab-new-branch", + name: "New Branch (Instant)", + description: "Emit new event when a new branch is created", + version: "0.1.1", + dedupe: "unique", + type: "source", + hooks: { + ...base.hooks, + async activate() { + await this.activateHook(eventTypes.PUSH_EVENT); + }, + }, + methods: { + ...base.methods, + isNewBranch(branch) { + // Logic based on https://gitlab.com/gitlab-org/gitlab-foss/-/issues/31723. + const { before } = branch; + const expectedBeforeValue = "0000000000000000000000000000000000000000"; + return before === expectedBeforeValue; + }, + generateMeta(branch) { + const id = branch.ref; + return { + id, + summary: `New Branch: ${id}`, + ts: +new Date(), + }; + }, + emitEvent(event) { + // Gitlab doesn't offer a specific hook for "new branch" events, + // but such event can be deduced from the payload of "push" events. + if (this.isNewBranch(event)) { + const meta = this.generateMeta(event); + this.$emit(event, meta); + } + }, + }, +}; diff --git a/components/gitlab_developer_app/sources/new-commit-comment/new-commit-comment.mjs b/components/gitlab_developer_app/sources/new-commit-comment/new-commit-comment.mjs new file mode 100644 index 0000000000000..a0a8b9462c42c --- /dev/null +++ b/components/gitlab_developer_app/sources/new-commit-comment/new-commit-comment.mjs @@ -0,0 +1,55 @@ +import base from "../common/base.mjs"; +import { eventTypes } from "../common/hook-events.mjs"; + +export default { + ...base, + key: "gitlab-new-commit-comment", + name: "New Commit Comment (Instant)", + description: "Emit new event when a commit receives a comment", + version: "0.1.1", + dedupe: "unique", + type: "source", + hooks: { + ...base.hooks, + async activate() { + await this.activateHook(eventTypes.NOTE_EVENTS); + }, + }, + methods: { + ...base.methods, + isCommentOnCommit(commit) { + const noteableType = commit.object_attributes?.noteable_type; + const expectedNoteableType = "Commit"; + return noteableType === expectedNoteableType; + }, + generateMeta({ + user, comment, + }) { + const { + name, + username, + } = user; + const { + id, + created_at: createdAt, + commit_id: commitId, + } = comment; + return { + id, + summary: `New comment by ${name} (${username}) on commit ${commitId}`, + ts: +new Date(createdAt), + }; + }, + async emitEvent(event) { + // Gitlab doesn't offer a specific hook for "commit comments" events, + // but such event can be deduced from the payload of "note" events. + if (this.isCommentOnCommit(event)) { + const meta = this.generateMeta({ + user: event.user, + comment: event.object_attributes, + }); + this.$emit(event, meta); + } + }, + }, +}; diff --git a/components/gitlab_developer_app/sources/new-commit/new-commit.mjs b/components/gitlab_developer_app/sources/new-commit/new-commit.mjs new file mode 100644 index 0000000000000..965d8ffb21939 --- /dev/null +++ b/components/gitlab_developer_app/sources/new-commit/new-commit.mjs @@ -0,0 +1,83 @@ +import gitlab from "../../gitlab.app.mjs"; +import base from "../common/base.mjs"; +import { eventTypes } from "../common/hook-events.mjs"; + +export default { + ...base, + key: "gitlab-new-commit", + name: "New Commit (Instant)", + description: "Emit new event when a new commit is pushed to a branch", + version: "0.1.2", + dedupe: "unique", + type: "source", + props: { + ...base.props, + refName: { + propDefinition: [ + gitlab, + "branch", + (c) => ({ + projectId: c.projectId, + }), + ], + optional: true, + }, + }, + hooks: { + ...base.hooks, + async activate() { + await this.activateHook(eventTypes.PUSH_EVENT); + }, + }, + methods: { + ...base.methods, + isEventForThisBranch(branch) { + return !this.refName || branch === this.refName; + }, + generateMeta(commit) { + const { + id, + message, + shortId, + committedDate, + } = commit; + return { + id, + summary: `New commit: ${message} (${shortId})`, + ts: +new Date(committedDate), + }; + }, + async emitEvent(event) { + const refName = event.ref.split("refs/heads/").pop(); + if (!this.isEventForThisBranch(refName)) { + return; + } + + // Gitlab "push events" are only provisioned with at most + // 20 commit objects (which also lack information when compared + // to the Commits API). The amount of new commits is specified + // in a separate variable called `total_commits_count`, which + // we'll use to keep track of the commits that we need to emit + // downstream. + // See https://gitlab.com/help/user/project/integrations/webhooks#push-events + const { total_commits_count: totalCommitsCount } = event; + if (totalCommitsCount <= 0) return; + + const commits = await this.gitlab.listCommits(this.projectId, { + params: { + ref_name: refName, + per_page: Math.min(50, totalCommitsCount), + }, + }); + + // We need to collect all the relevant commits, sort + // them in reverse order (since the Gitlab API sorts them + // from most to least recent) and emit an event for each + // one of them. + commits.reverse().forEach((commit) => { + const meta = this.generateMeta(commit); + this.$emit(commit, meta); + }); + }, + }, +}; diff --git a/components/gitlab_developer_app/sources/new-issue/new-issue.mjs b/components/gitlab_developer_app/sources/new-issue/new-issue.mjs new file mode 100644 index 0000000000000..c4c512e6cd5be --- /dev/null +++ b/components/gitlab_developer_app/sources/new-issue/new-issue.mjs @@ -0,0 +1,55 @@ +import base from "../common/base.mjs"; +import { eventTypes } from "../common/hook-events.mjs"; + +export default { + ...base, + key: "gitlab-new-issue", + name: "New Issue (Instant)", + description: "Emit new event when an issue is created in a project", + version: "0.1.1", + dedupe: "unique", + type: "source", + hooks: { + ...base.hooks, + async activate() { + await this.activateHook(eventTypes.ISSUES_EVENTS); + }, + }, + methods: { + ...base.methods, + isNewIssue(issue) { + const { previous } = issue.changes.updated_at; + return previous === undefined || previous === null; + }, + generateMeta({ + user, issue, + }) { + const { + name, + username, + } = user; + const { + id, + iid, + created_at: createdAt, + title, + } = issue; + return { + id, + summary: `New issue by ${name} (${username}): #${iid} ${title}`, + ts: +new Date(createdAt), + }; + }, + async emitEvent(event) { + // Gitlab doesn't offer a specific hook for "new issue" events, + // but such event can be deduced from the payload of "issues" events. + if (this.isNewIssue(event)) { + const meta = this.generateMeta({ + user: event.user, + issue: event.object_attributes, + }); + this.$emit(event, meta); + } + }, + }, +}; diff --git a/components/gitlab_developer_app/sources/new-mention/new-mention.mjs b/components/gitlab_developer_app/sources/new-mention/new-mention.mjs new file mode 100644 index 0000000000000..e9f8efb6168d9 --- /dev/null +++ b/components/gitlab_developer_app/sources/new-mention/new-mention.mjs @@ -0,0 +1,81 @@ +import gitlab from "../../gitlab.app.mjs"; +import base from "../common/base.mjs"; +import { eventTypes } from "../common/hook-events.mjs"; + +export default { + ...base, + key: "gitlab-new-mention", + name: "New Mention (Instant)", + description: "Emit new event when you are @mentioned in a new commit, comment, issue or pull request", + version: "0.1.1", + dedupe: "unique", + type: "source", + props: { + ...base.props, + username: { + propDefinition: [ + gitlab, + "assignee", + (c) => ({ + projectId: c.projectId, + }), + ], + label: "Username", + description: "The GitLab Username whose mentions will emit events", + withLabel: true, + }, + }, + hooks: { + ...base.hooks, + async activate() { + await this.activateHook([ + eventTypes.ISSUES_EVENTS, + eventTypes.NOTE_EVENTS, + ]); + }, + }, + methods: { + ...base.methods, + isUserMentioned(mention) { + const pattern = new RegExp(`\\B@${this.username.label}\\b`); + const groomedAttributes = { + ...mention, + // We want to exclude some fields, since they do not map + // to the content being updated, and could result in false + // positives (e.g. if a URL contains `@someuser` in its path). + url: "", + }; + const changedSummary = JSON.stringify(groomedAttributes); + return pattern.test(changedSummary); + }, + generateMeta({ + user, mention, + }) { + const { + id, + created_at: createdAt, + } = mention; + const { username } = user; + return { + id, + summary: `New mention of ${this.username.label} by ${username}`, + ts: +new Date(createdAt), + }; + }, + async emitEvent(event) { + const { + user, + object_attributes: mention, + } = event; + // Gitlab doesn't offer a specific hook for "new label" events, + // but such event can be deduced from the payload of "issues" events. + if (this.isUserMentioned(mention)) { + const meta = this.generateMeta({ + user, + mention, + }); + this.$emit(event, meta); + } + }, + }, +}; diff --git a/components/gitlab_developer_app/sources/new-merge-request/new-merge-request.mjs b/components/gitlab_developer_app/sources/new-merge-request/new-merge-request.mjs new file mode 100644 index 0000000000000..96d46cf4d6db0 --- /dev/null +++ b/components/gitlab_developer_app/sources/new-merge-request/new-merge-request.mjs @@ -0,0 +1,55 @@ +import base from "../common/base.mjs"; +import { eventTypes } from "../common/hook-events.mjs"; + +export default { + ...base, + key: "gitlab-new-merge-request", + name: "New Merge Request (Instant)", + description: "Emit new event when a merge request is created", + version: "0.1.1", + dedupe: "unique", + type: "source", + hooks: { + ...base.hooks, + async activate() { + await this.activateHook(eventTypes.MERGE_REQUESTS_EVENTS); + }, + }, + methods: { + ...base.methods, + isNewMergeRequest(event) { + const { action } = event.object_attributes; + const expectedAction = "open"; + return action === expectedAction; + }, + generateMeta({ + user, mergeRequest, + }) { + const { + name, + username, + } = user; + const { + id, + created_at: createdAt, + title, + } = mergeRequest; + return { + id, + summary: `New Merge Request: "${title}" by ${name} (${username})`, + ts: +new Date(createdAt), + }; + }, + async emitEvent(event) { + // Gitlab doesn't offer a specific hook for "new merge request" events, + // but such event can be deduced from the payload of "merge request" events. + if (this.isNewMergeRequest(event)) { + const meta = this.generateMeta({ + user: event.user, + mergeRequest: event.object_attributes, + }); + this.$emit(event, meta); + } + }, + }, +}; diff --git a/components/gitlab_developer_app/sources/new-milestone/new-milestone.mjs b/components/gitlab_developer_app/sources/new-milestone/new-milestone.mjs new file mode 100644 index 0000000000000..88e785fc74cee --- /dev/null +++ b/components/gitlab_developer_app/sources/new-milestone/new-milestone.mjs @@ -0,0 +1,94 @@ +import gitlab from "../../gitlab.app.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; + +export default { + key: "gitlab-new-milestone", + name: "New Milestone", + description: "Emit new event when a milestone is created in a project", + version: "0.1.2", + dedupe: "greatest", + type: "source", + props: { + gitlab, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + projectId: { + propDefinition: [ + gitlab, + "projectId", + ], + }, + }, + hooks: { + async activate() { + const milestones = await this.gitlab.listMilestones(this.projectId, { + params: { + max: 1, + }, + }); + if (milestones.length > 0) { + const lastProcessedMilestoneTime = milestones[0].created_at; + this.db.set("lastProcessedMilestoneTime", lastProcessedMilestoneTime); + console.log(`Polling GitLab milestones created after ${lastProcessedMilestoneTime}`); + } + }, + }, + methods: { + _getLastProcessedMilestoneTime() { + return this.db.get("lastProcessedMilestoneTime") || 0; + }, + _setLastProcessedMilestoneTime(lastProcessedMilestoneTime) { + this.db.set("lastProcessedMilestoneTime", lastProcessedMilestoneTime); + }, + generateMeta(data) { + const { + id, + created_at: createdAt, + title, + } = data; + return { + id, + summary: `New milestone: ${title}`, + ts: +new Date(createdAt), + }; + }, + }, + async run() { + let lastProcessedMilestoneTime = this._getLastProcessedMilestoneTime(); + const newOrUpdatedMilestones = await this.gitlab.listMilestones(this.projectId, { + params: { + updated_after: lastProcessedMilestoneTime, + }, + }); + + const milestones = newOrUpdatedMilestones.filter( + ({ created_at }) => Date.parse(created_at) > Date.parse(lastProcessedMilestoneTime), + ); + + if (milestones.length === 0) { + console.log("No new GitLab milestones detected"); + return; + } + + console.log(`Detected ${milestones.length} new milestones`); + + // We store the most recent milestone ID in the DB so that + // we don't process it (and previous milestones) in future runs. + lastProcessedMilestoneTime = milestones[0].created_at; + this._setLastProcessedMilestoneTime(lastProcessedMilestoneTime); + + // We need to sort the retrieved milestones + // in reverse order (since the Gitlab API sorts them + // from most to least recent) and emit an event for each + // one of them. + milestones.reverse().forEach((milestone) => { + const meta = this.generateMeta(milestone); + this.$emit(milestone, meta); + }); + }, +}; diff --git a/components/gitlab_developer_app/sources/new-project/new-project.mjs b/components/gitlab_developer_app/sources/new-project/new-project.mjs new file mode 100644 index 0000000000000..2ea4c3f07327b --- /dev/null +++ b/components/gitlab_developer_app/sources/new-project/new-project.mjs @@ -0,0 +1,89 @@ +import gitlab from "../../gitlab.app.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; + +export default { + key: "gitlab-new-project", + name: "New Project", + description: "Emit new event when a project (i.e. repository) is created", + version: "0.1.2", + dedupe: "greatest", + type: "source", + props: { + gitlab, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + hooks: { + async activate() { + const projects = await this.gitlab.listProjects({ + params: { + owned: true, + per_page: 1, + }, + }); + if (projects.length > 0) { + const lastProcessedProjectId = projects[0].id; + this._setLastProcessedProjectId(lastProcessedProjectId); + console.log(`Polling GitLab projects created after ID ${lastProcessedProjectId}`); + } + }, + }, + methods: { + _getLastProcessedProjectId() { + return this.db.get("lastProcessedProjectId"); + }, + _setLastProcessedProjectId(lastProcessedProjectId) { + this.db.set("lastProcessedProjectId", lastProcessedProjectId); + }, + generateMeta(data) { + const { + id, + created_at: createdAt, + name, + } = data; + return { + id, + summary: `New project: ${name}`, + ts: +new Date(createdAt), + }; + }, + }, + async run() { + // We use the ID of the last processed project so that we + // don't emit events for them (i.e. we only want to emit events + // for new projects). + let lastProcessedProjectId = this._getLastProcessedProjectId(); + const projects = await this.gitlab.listProjects({ + params: { + id_after: lastProcessedProjectId, + owned: true, + }, + }); + + if (projects.length === 0) { + console.log("No new GitLab projects detected"); + return; + } + + console.log(`Detected ${projects.length} new projects`); + + // We store the most recent project ID in the DB so that + // we don't process it (and previous projects) in future runs. + lastProcessedProjectId = projects[0].id; + this._setLastProcessedProjectId(lastProcessedProjectId); + + // We need to sort the retrieved projects + // in reverse order (since the Gitlab API sorts them + // from most to least recent) and emit an event for each + // one of them. + projects.reverse().forEach((project) => { + const meta = this.generateMeta(project); + this.$emit(project, meta); + }); + }, +}; diff --git a/components/gitlab_developer_app/sources/new-review-request/new-review-request.mjs b/components/gitlab_developer_app/sources/new-review-request/new-review-request.mjs new file mode 100644 index 0000000000000..79b18649e2d4f --- /dev/null +++ b/components/gitlab_developer_app/sources/new-review-request/new-review-request.mjs @@ -0,0 +1,80 @@ +import base from "../common/base.mjs"; +import { eventTypes } from "../common/hook-events.mjs"; + +export default { + ...base, + key: "gitlab-new-review-request", + name: "New Review Request (Instant)", + description: "Emit new event when a reviewer is added to a merge request", + version: "0.1.1", + dedupe: "unique", + type: "source", + hooks: { + ...base.hooks, + async activate() { + await this.activateHook([ + eventTypes.MERGE_REQUESTS_EVENTS, + eventTypes.PUSH_EVENT, + ]); + }, + }, + methods: { + ...base.methods, + getNewReviewers(event) { + const { + action, + title, + } = event.object_attributes; + + // When a merge request is first created, any assignees + // in it are interpreted as new review requests. + if (action === "open" || action === "reopen") { + const { assignees = [] } = event; + return assignees; + } + + // Gitlab API provides any merge request update diff + // as part of their response. We can check the presence of + // the `assignees` attribute within those changes to verify + // if there are new review requests. + const { assignees } = event.changes; + if (!assignees) { + console.log(`No new assignees in merge request "${title}"`); + return []; + } + + // If the assignees of the merge request changed, we need to compute + // the difference in order to extract the new reviewers. + const previousAssignees = new Set(assignees.previous.map((a) => a.username)); + const newAssignees = assignees.current.filter((a) => !previousAssignees.has(a.username)); + if (newAssignees.length > 0) { + console.log(`Assignees added to merge request "${title}": ${newAssignees.map((a) => a.username).join(", ")}`); + } + return newAssignees; + }, + generateMeta(event, reviewer) { + const { + id, + title, + updated_at: updatedAt, + } = event.object_attributes; + const ts = +new Date(updatedAt); + return { + id: `${id}-${ts}-${reviewer.username}`, + summary: `New reviewer for "${title}": ${reviewer.username}`, + ts, + }; + }, + async emitEvent(event) { + // Gitlab doesn't offer a specific hook for "new merge request reviewers" events, + // but such event can be deduced from the payload of "merge request" events. + this.getNewReviewers(event).forEach((reviewer) => { + const meta = this.generateMeta(event, reviewer); + this.$emit({ + ...event, + reviewer, + }, meta); + }); + }, + }, +}; From f1022d68791ef705d7cde2ee5e18fffa4e8580eb Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Sat, 20 Apr 2024 14:59:03 -0300 Subject: [PATCH 03/21] Package update --- components/gitlab_developer_app/package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/gitlab_developer_app/package.json b/components/gitlab_developer_app/package.json index fc297c11657ab..499cffbd21914 100644 --- a/components/gitlab_developer_app/package.json +++ b/components/gitlab_developer_app/package.json @@ -9,6 +9,11 @@ ], "homepage": "https://pipedream.com/apps/gitlab_developer_app", "author": "Pipedream (https://pipedream.com/)", + "dependencies": { + "@pipedream/platform": "^1.6.4", + "lodash": "^4.17.21", + "uuid": "^8.3.2" + }, "publishConfig": { "access": "public" } From 723b691ca19fbce0c8471a29c69299881d39b680 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Sat, 20 Apr 2024 14:59:39 -0300 Subject: [PATCH 04/21] pnpm --- pnpm-lock.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bd7ac3e8ab84..de8bac0038481 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3171,7 +3171,14 @@ importers: uuid: 8.3.2 components/gitlab_developer_app: - specifiers: {} + specifiers: + '@pipedream/platform': ^1.6.4 + lodash: ^4.17.21 + uuid: ^8.3.2 + dependencies: + '@pipedream/platform': 1.6.4 + lodash: 4.17.21 + uuid: 8.3.2 components/givebutter: specifiers: {} From 8cf54e53312a6b61c91974c81e7a3e31f3acebcf Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Sat, 20 Apr 2024 21:52:37 -0300 Subject: [PATCH 05/21] Mapping propDefinitions to new app --- .../actions/create-epic/create-epic.mjs | 6 ++-- .../gitlab_developer_app/common/utils.mjs | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 components/gitlab_developer_app/common/utils.mjs diff --git a/components/gitlab_developer_app/actions/create-epic/create-epic.mjs b/components/gitlab_developer_app/actions/create-epic/create-epic.mjs index ee4921af6634f..b56c7ad7452b4 100644 --- a/components/gitlab_developer_app/actions/create-epic/create-epic.mjs +++ b/components/gitlab_developer_app/actions/create-epic/create-epic.mjs @@ -1,13 +1,11 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/create-epic/create-epic.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, diff --git a/components/gitlab_developer_app/common/utils.mjs b/components/gitlab_developer_app/common/utils.mjs new file mode 100644 index 0000000000000..336ad9e7eb1cc --- /dev/null +++ b/components/gitlab_developer_app/common/utils.mjs @@ -0,0 +1,35 @@ +export function adjustPropDefinitions(props, app) { + return Object.fromEntries( + Object.entries(props).map(([ + key, + { + propDefinition, ...otherValues + }, + ]) => { + if (propDefinition) { + const [ + , ...otherDefs + ] = propDefinition; + return [ + key, + { + propDefinition: [ + app, + ...otherDefs, + ], + ...otherValues, + }, + ]; + } + return [ + key, + otherValues.type === "app" + ? null + : otherValues, + ]; + }) + .filter(([ + , value, + ]) => value), + ); +} From 21fc2d7327d14c7828b665d2f0798135ecbd37be Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Sat, 20 Apr 2024 21:58:41 -0300 Subject: [PATCH 06/21] Adjusting actions' propDefinitions --- .../actions/create-branch/create-branch.mjs | 7 +++---- .../actions/create-issue/create-issue.mjs | 7 +++---- .../gitlab_developer_app/actions/get-issue/get-issue.mjs | 7 +++---- .../actions/get-repo-branch/get-repo-branch.mjs | 7 +++---- .../actions/list-commits/list-commits.mjs | 7 +++---- .../actions/list-repo-branches/list-repo-branches.mjs | 7 +++---- .../actions/search-issues/search-issues.mjs | 7 +++---- .../actions/update-epic/update-epic.mjs | 7 +++---- .../actions/update-issue/update-issue.mjs | 7 +++---- 9 files changed, 27 insertions(+), 36 deletions(-) diff --git a/components/gitlab_developer_app/actions/create-branch/create-branch.mjs b/components/gitlab_developer_app/actions/create-branch/create-branch.mjs index 24cbd0339eceb..b2226dce7f8af 100644 --- a/components/gitlab_developer_app/actions/create-branch/create-branch.mjs +++ b/components/gitlab_developer_app/actions/create-branch/create-branch.mjs @@ -1,13 +1,12 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/create-branch/create-branch.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, diff --git a/components/gitlab_developer_app/actions/create-issue/create-issue.mjs b/components/gitlab_developer_app/actions/create-issue/create-issue.mjs index bc6c88e02ca01..6d69fab7737f8 100644 --- a/components/gitlab_developer_app/actions/create-issue/create-issue.mjs +++ b/components/gitlab_developer_app/actions/create-issue/create-issue.mjs @@ -1,13 +1,12 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/create-issue/create-issue.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, diff --git a/components/gitlab_developer_app/actions/get-issue/get-issue.mjs b/components/gitlab_developer_app/actions/get-issue/get-issue.mjs index b1ad77a0f7a04..ecdae4575d656 100644 --- a/components/gitlab_developer_app/actions/get-issue/get-issue.mjs +++ b/components/gitlab_developer_app/actions/get-issue/get-issue.mjs @@ -1,13 +1,12 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/get-issue/get-issue.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, diff --git a/components/gitlab_developer_app/actions/get-repo-branch/get-repo-branch.mjs b/components/gitlab_developer_app/actions/get-repo-branch/get-repo-branch.mjs index 4aa8ebfb8590b..18135cd745cf2 100644 --- a/components/gitlab_developer_app/actions/get-repo-branch/get-repo-branch.mjs +++ b/components/gitlab_developer_app/actions/get-repo-branch/get-repo-branch.mjs @@ -1,13 +1,12 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/get-repo-branch/get-repo-branch.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, diff --git a/components/gitlab_developer_app/actions/list-commits/list-commits.mjs b/components/gitlab_developer_app/actions/list-commits/list-commits.mjs index c0f7c4b347d70..0454ffe6910ac 100644 --- a/components/gitlab_developer_app/actions/list-commits/list-commits.mjs +++ b/components/gitlab_developer_app/actions/list-commits/list-commits.mjs @@ -1,13 +1,12 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/list-commits/list-commits.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, diff --git a/components/gitlab_developer_app/actions/list-repo-branches/list-repo-branches.mjs b/components/gitlab_developer_app/actions/list-repo-branches/list-repo-branches.mjs index 04563191f6f1e..4a2ad20cae132 100644 --- a/components/gitlab_developer_app/actions/list-repo-branches/list-repo-branches.mjs +++ b/components/gitlab_developer_app/actions/list-repo-branches/list-repo-branches.mjs @@ -1,13 +1,12 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/list-repo-branches/list-repo-branches.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, diff --git a/components/gitlab_developer_app/actions/search-issues/search-issues.mjs b/components/gitlab_developer_app/actions/search-issues/search-issues.mjs index 19dd825b2f16f..8c5033594c30f 100644 --- a/components/gitlab_developer_app/actions/search-issues/search-issues.mjs +++ b/components/gitlab_developer_app/actions/search-issues/search-issues.mjs @@ -1,13 +1,12 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/search-issues/search-issues.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, diff --git a/components/gitlab_developer_app/actions/update-epic/update-epic.mjs b/components/gitlab_developer_app/actions/update-epic/update-epic.mjs index e568d36d449b1..2ea00e29e0669 100644 --- a/components/gitlab_developer_app/actions/update-epic/update-epic.mjs +++ b/components/gitlab_developer_app/actions/update-epic/update-epic.mjs @@ -1,13 +1,12 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/update-epic/update-epic.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, diff --git a/components/gitlab_developer_app/actions/update-issue/update-issue.mjs b/components/gitlab_developer_app/actions/update-issue/update-issue.mjs index 9e0a466ab85fb..c920fa14d3294 100644 --- a/components/gitlab_developer_app/actions/update-issue/update-issue.mjs +++ b/components/gitlab_developer_app/actions/update-issue/update-issue.mjs @@ -1,13 +1,12 @@ import app from "../../gitlab_developer_app.app.mjs"; import common from "../../../gitlab/actions/update-issue/update-issue.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + const { name, description, type, ...others } = common; - -const { // eslint-disable-next-line no-unused-vars - gitlab, ...props -} = others.props; +const props = adjustPropDefinitions(others.props, app); export default { ...others, From ec7552d2a90632cde076f69b74aff23981789fc1 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Sat, 20 Apr 2024 22:08:45 -0300 Subject: [PATCH 07/21] Adjusting sources to use mapped propDefinitions --- .../sources/common/base.mjs | 107 ------------- .../sources/common/hook-events.mjs | 10 -- .../new-audit-event/common-queries.mjs | 43 ------ .../new-audit-event/new-audit-event.mjs | 145 ++---------------- .../sources/new-branch/new-branch.mjs | 56 ++----- .../new-commit-comment/new-commit-comment.mjs | 68 ++------ .../sources/new-commit/new-commit.mjs | 94 ++---------- .../sources/new-issue/new-issue.mjs | 68 ++------ .../sources/new-mention/new-mention.mjs | 92 ++--------- .../new-merge-request/new-merge-request.mjs | 68 ++------ .../sources/new-milestone/new-milestone.mjs | 105 ++----------- .../sources/new-project/new-project.mjs | 100 ++---------- .../new-review-request/new-review-request.mjs | 93 ++--------- 13 files changed, 165 insertions(+), 884 deletions(-) delete mode 100644 components/gitlab_developer_app/sources/common/base.mjs delete mode 100644 components/gitlab_developer_app/sources/common/hook-events.mjs delete mode 100644 components/gitlab_developer_app/sources/new-audit-event/common-queries.mjs diff --git a/components/gitlab_developer_app/sources/common/base.mjs b/components/gitlab_developer_app/sources/common/base.mjs deleted file mode 100644 index 43549e4d39096..0000000000000 --- a/components/gitlab_developer_app/sources/common/base.mjs +++ /dev/null @@ -1,107 +0,0 @@ -import gitlab from "../../gitlab.app.mjs"; - -export default { - props: { - gitlab, - db: "$.service.db", - http: { - type: "$.interface.http", - customResponse: true, - }, - projectId: { - propDefinition: [ - gitlab, - "projectId", - ], - }, - }, - hooks: { - /** - * This method should be implemented in every source component - */ - async activate() { - // await this.activateHook(eventType); - throw new Error("activate() hook not implemented"); - }, - async deactivate() { - const hookId = this.getHookId(); - await this.gitlab.deleteProjectHook(this.projectId, hookId); - console.log( - `Deleted webhook for project ID ${this.projectId}. - (Hook ID: ${hookId})`, - ); - }, - }, - methods: { - _buildHookOpts(eventType) { - if (Array.isArray(eventType)) { - return eventType.reduce((prev, e) => ({ - ...prev, - [e]: true, - }), {}); - } - return { - [eventType]: true, - }; - }, - getHookId() { - return this.db.get("hookId"); - }, - setHookId(hookId) { - this.db.set("hookId", hookId); - }, - getToken() { - return this.db.get("token"); - }, - setToken(token) { - this.db.set("token", token); - }, - async activateHook(eventType) { - const data = this._buildHookOpts(eventType); - data.url = this.http.endpoint; - const { - hookId, - token, - } = await this.gitlab.createProjectHook(this.projectId, { - data, - }); - console.log( - `Created "${eventType}" webhook for project ID ${this.projectId}. - (Hook ID: ${hookId}, endpoint: ${data.url})`, - ); - this.setHookId(hookId); - this.setToken(token); - }, - emitEvent() { - throw new Error("emitEvent is not implemented"); - }, - isValidSource(headers) { - const token = headers["x-gitlab-token"]; - const expectedToken = this.getToken(); - return token === expectedToken; - }, - isValidEvent(headers) { - // Reject any calls not made by the proper Gitlab webhook. - if (!this.isValidSource(headers)) { - this.http.respond({ - status: 404, - }); - return false; - } - // Acknowledge the event back to Gitlab. - this.http.respond({ - status: 200, - }); - return true; - }, - }, - async run(event) { - const { - headers, - body, - } = event; - if (this.isValidEvent(headers)) { - await this.emitEvent(body); - } - }, -}; diff --git a/components/gitlab_developer_app/sources/common/hook-events.mjs b/components/gitlab_developer_app/sources/common/hook-events.mjs deleted file mode 100644 index 57b00434d81d2..0000000000000 --- a/components/gitlab_developer_app/sources/common/hook-events.mjs +++ /dev/null @@ -1,10 +0,0 @@ -const eventTypes = { - PUSH_EVENT: "push_event", - NOTE_EVENTS: "note_events", - ISSUES_EVENTS: "issues_events", - MERGE_REQUESTS_EVENTS: "merge_requests_events", -}; - -export { - eventTypes, -}; diff --git a/components/gitlab_developer_app/sources/new-audit-event/common-queries.mjs b/components/gitlab_developer_app/sources/new-audit-event/common-queries.mjs deleted file mode 100644 index ee4a49c18bc6b..0000000000000 --- a/components/gitlab_developer_app/sources/new-audit-event/common-queries.mjs +++ /dev/null @@ -1,43 +0,0 @@ -export function create_destination(destination, groupPath) { return ` - mutation { - externalAuditEventDestinationCreate(input: - { - destinationUrl: "${destination}", - groupPath: "${groupPath}", - clientMutationId: "PipeDream destination" - }) - { - clientMutationId, - errors - externalAuditEventDestination { - destinationUrl - group { - name - } - } - } - }`;} - -export function list_destinations(groupPath) { return ` - query { - group(fullPath: "${groupPath}") { - id, - externalAuditEventDestinations { - nodes { - destinationUrl, - id - } - } - } - }`;} - -export function delete_destination(destinationId) { return ` - mutation { - externalAuditEventDestinationDestroy(input: - { - id: "${destinationId}" - }) - { - errors - } - }`;} diff --git a/components/gitlab_developer_app/sources/new-audit-event/new-audit-event.mjs b/components/gitlab_developer_app/sources/new-audit-event/new-audit-event.mjs index 1c0e8fb51c9d9..22342654d28a9 100644 --- a/components/gitlab_developer_app/sources/new-audit-event/new-audit-event.mjs +++ b/components/gitlab_developer_app/sources/new-audit-event/new-audit-event.mjs @@ -1,134 +1,21 @@ -import gitlab from "../../gitlab.app.mjs"; -import base from "../common/base.mjs"; -import fetch from "node-fetch"; -import { - create_destination, - list_destinations, - delete_destination, -} from "./common-queries.mjs"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-audit-event/new-audit-event.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); export default { - ...base, - key: "gitlab-new-audit-event", - name: "New Audit Event (Instant)", - description: "Emit new event when a new audit event is created", - version: "0.1.2", - dedupe: "unique", - type: "source", + ...others, + key: "gitlab_developer_app-new-audit-event", + version: "0.0.1", + name, + description, + type, props: { - gitlab, - http: { - // doesn't include base because base has a project, which we don't need - type: "$.interface.http", - customResponse: true, - }, - groupPath: { - propDefinition: [ - gitlab, - "groupPath", - ], - }, - }, - hooks: { - ...base.hooks, - async activate() { - console.log("Activating streaming audit events."); - console.log(`Event destination: ${this.http.endpoint}`); - console.log(`Group name: ${this.groupPath}`); - - // the variable must be named "query" to work with JSON.stringify and GraphQL - const query = create_destination(this.http.endpoint, this.groupPath); - - try { - await fetch(`https://${this._getBaseApiUrl()}/api/graphql`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": `Bearer ${this.gitlab.$auth.oauth_access_token}`, - }, - body: JSON.stringify({ - query, - }), - }) - .then((r) => r.json()); - - } catch (err) { - console.log(`Error thrown during activation: ${JSON.stringify(err)}`); - } - }, - async deactivate() { - console.log("Deactivating streaming audit events."); - console.log(`Event destiniation: ${this.http.endpoint}`); - console.log(`Group name: ${this.groupPath}`); - - // the variable must be named "query" to work with JSON.stringify and GraphQL - var query = list_destinations(this.groupPath); - - try { - - const data = await fetch(`https://${this._getBaseApiUrl()}/api/graphql`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": `Bearer ${this.gitlab.$auth.oauth_access_token}`, - }, - body: JSON.stringify({ - query, - }), - }) - .then((r) => r.json()); - console.log("Group list received."); - console.log(`Received: ${JSON.stringify(data)}`); - - const todelete = data.data.group.externalAuditEventDestinations - .nodes.filter((item) => item.destinationUrl == this.http.endpoint)[0].id; - console.log(`Deleting object ID: ${JSON.stringify(todelete)}`); - - query = delete_destination(todelete); - - await fetch(`https://${this._getBaseApiUrl()}/api/graphql`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": `Bearer ${this.gitlab.$auth.oauth_access_token}`, - }, - body: JSON.stringify({ - query, - }), - }) - .then((r) => r.json()); - - console.log("Done deactivating!"); - - } catch (err) { - console.log(`Error thrown during deactivation: ${JSON.stringify(err)}`); - } - }, - }, - methods: { - ...base.methods, - generateMeta(event) { - const id = event.id; - return { - id, - summary: `New Audit Event: ${id}`, - ts: +new Date(), - }; - }, - emitEvent(event) { - const meta = this.generateMeta(event); - this.$emit(event, meta); - }, - isValidSource() { - // GitLab doesn't currently send a x-gitlab-token - // with streaming audit events - return true; - }, - isValidEvent() { - return true; - }, + gitlab: app, + ...props, }, }; diff --git a/components/gitlab_developer_app/sources/new-branch/new-branch.mjs b/components/gitlab_developer_app/sources/new-branch/new-branch.mjs index 0478322fabc8b..6314096a56a84 100644 --- a/components/gitlab_developer_app/sources/new-branch/new-branch.mjs +++ b/components/gitlab_developer_app/sources/new-branch/new-branch.mjs @@ -1,43 +1,21 @@ -import base from "../common/base.mjs"; -import { eventTypes } from "../common/hook-events.mjs"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-branch/new-branch.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); export default { - ...base, - key: "gitlab-new-branch", - name: "New Branch (Instant)", - description: "Emit new event when a new branch is created", - version: "0.1.1", - dedupe: "unique", - type: "source", - hooks: { - ...base.hooks, - async activate() { - await this.activateHook(eventTypes.PUSH_EVENT); - }, - }, - methods: { - ...base.methods, - isNewBranch(branch) { - // Logic based on https://gitlab.com/gitlab-org/gitlab-foss/-/issues/31723. - const { before } = branch; - const expectedBeforeValue = "0000000000000000000000000000000000000000"; - return before === expectedBeforeValue; - }, - generateMeta(branch) { - const id = branch.ref; - return { - id, - summary: `New Branch: ${id}`, - ts: +new Date(), - }; - }, - emitEvent(event) { - // Gitlab doesn't offer a specific hook for "new branch" events, - // but such event can be deduced from the payload of "push" events. - if (this.isNewBranch(event)) { - const meta = this.generateMeta(event); - this.$emit(event, meta); - } - }, + ...others, + key: "gitlab_developer_app-new-branch", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, }, }; diff --git a/components/gitlab_developer_app/sources/new-commit-comment/new-commit-comment.mjs b/components/gitlab_developer_app/sources/new-commit-comment/new-commit-comment.mjs index a0a8b9462c42c..e150550caa4de 100644 --- a/components/gitlab_developer_app/sources/new-commit-comment/new-commit-comment.mjs +++ b/components/gitlab_developer_app/sources/new-commit-comment/new-commit-comment.mjs @@ -1,55 +1,21 @@ -import base from "../common/base.mjs"; -import { eventTypes } from "../common/hook-events.mjs"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-commit-comment/new-commit-comment.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); export default { - ...base, - key: "gitlab-new-commit-comment", - name: "New Commit Comment (Instant)", - description: "Emit new event when a commit receives a comment", - version: "0.1.1", - dedupe: "unique", - type: "source", - hooks: { - ...base.hooks, - async activate() { - await this.activateHook(eventTypes.NOTE_EVENTS); - }, - }, - methods: { - ...base.methods, - isCommentOnCommit(commit) { - const noteableType = commit.object_attributes?.noteable_type; - const expectedNoteableType = "Commit"; - return noteableType === expectedNoteableType; - }, - generateMeta({ - user, comment, - }) { - const { - name, - username, - } = user; - const { - id, - created_at: createdAt, - commit_id: commitId, - } = comment; - return { - id, - summary: `New comment by ${name} (${username}) on commit ${commitId}`, - ts: +new Date(createdAt), - }; - }, - async emitEvent(event) { - // Gitlab doesn't offer a specific hook for "commit comments" events, - // but such event can be deduced from the payload of "note" events. - if (this.isCommentOnCommit(event)) { - const meta = this.generateMeta({ - user: event.user, - comment: event.object_attributes, - }); - this.$emit(event, meta); - } - }, + ...others, + key: "gitlab_developer_app-new-commit-comment", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, }, }; diff --git a/components/gitlab_developer_app/sources/new-commit/new-commit.mjs b/components/gitlab_developer_app/sources/new-commit/new-commit.mjs index 965d8ffb21939..0829809b1c2f0 100644 --- a/components/gitlab_developer_app/sources/new-commit/new-commit.mjs +++ b/components/gitlab_developer_app/sources/new-commit/new-commit.mjs @@ -1,83 +1,21 @@ -import gitlab from "../../gitlab.app.mjs"; -import base from "../common/base.mjs"; -import { eventTypes } from "../common/hook-events.mjs"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-commit/new-commit.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); export default { - ...base, - key: "gitlab-new-commit", - name: "New Commit (Instant)", - description: "Emit new event when a new commit is pushed to a branch", - version: "0.1.2", - dedupe: "unique", - type: "source", + ...others, + key: "gitlab_developer_app-new-commit", + version: "0.0.1", + name, + description, + type, props: { - ...base.props, - refName: { - propDefinition: [ - gitlab, - "branch", - (c) => ({ - projectId: c.projectId, - }), - ], - optional: true, - }, - }, - hooks: { - ...base.hooks, - async activate() { - await this.activateHook(eventTypes.PUSH_EVENT); - }, - }, - methods: { - ...base.methods, - isEventForThisBranch(branch) { - return !this.refName || branch === this.refName; - }, - generateMeta(commit) { - const { - id, - message, - shortId, - committedDate, - } = commit; - return { - id, - summary: `New commit: ${message} (${shortId})`, - ts: +new Date(committedDate), - }; - }, - async emitEvent(event) { - const refName = event.ref.split("refs/heads/").pop(); - if (!this.isEventForThisBranch(refName)) { - return; - } - - // Gitlab "push events" are only provisioned with at most - // 20 commit objects (which also lack information when compared - // to the Commits API). The amount of new commits is specified - // in a separate variable called `total_commits_count`, which - // we'll use to keep track of the commits that we need to emit - // downstream. - // See https://gitlab.com/help/user/project/integrations/webhooks#push-events - const { total_commits_count: totalCommitsCount } = event; - if (totalCommitsCount <= 0) return; - - const commits = await this.gitlab.listCommits(this.projectId, { - params: { - ref_name: refName, - per_page: Math.min(50, totalCommitsCount), - }, - }); - - // We need to collect all the relevant commits, sort - // them in reverse order (since the Gitlab API sorts them - // from most to least recent) and emit an event for each - // one of them. - commits.reverse().forEach((commit) => { - const meta = this.generateMeta(commit); - this.$emit(commit, meta); - }); - }, + gitlab: app, + ...props, }, }; diff --git a/components/gitlab_developer_app/sources/new-issue/new-issue.mjs b/components/gitlab_developer_app/sources/new-issue/new-issue.mjs index c4c512e6cd5be..d9addfda12927 100644 --- a/components/gitlab_developer_app/sources/new-issue/new-issue.mjs +++ b/components/gitlab_developer_app/sources/new-issue/new-issue.mjs @@ -1,55 +1,21 @@ -import base from "../common/base.mjs"; -import { eventTypes } from "../common/hook-events.mjs"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-issue/new-issue.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); export default { - ...base, - key: "gitlab-new-issue", - name: "New Issue (Instant)", - description: "Emit new event when an issue is created in a project", - version: "0.1.1", - dedupe: "unique", - type: "source", - hooks: { - ...base.hooks, - async activate() { - await this.activateHook(eventTypes.ISSUES_EVENTS); - }, - }, - methods: { - ...base.methods, - isNewIssue(issue) { - const { previous } = issue.changes.updated_at; - return previous === undefined || previous === null; - }, - generateMeta({ - user, issue, - }) { - const { - name, - username, - } = user; - const { - id, - iid, - created_at: createdAt, - title, - } = issue; - return { - id, - summary: `New issue by ${name} (${username}): #${iid} ${title}`, - ts: +new Date(createdAt), - }; - }, - async emitEvent(event) { - // Gitlab doesn't offer a specific hook for "new issue" events, - // but such event can be deduced from the payload of "issues" events. - if (this.isNewIssue(event)) { - const meta = this.generateMeta({ - user: event.user, - issue: event.object_attributes, - }); - this.$emit(event, meta); - } - }, + ...others, + key: "gitlab_developer_app-new-issue", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, }, }; diff --git a/components/gitlab_developer_app/sources/new-mention/new-mention.mjs b/components/gitlab_developer_app/sources/new-mention/new-mention.mjs index e9f8efb6168d9..5b6cb41365d29 100644 --- a/components/gitlab_developer_app/sources/new-mention/new-mention.mjs +++ b/components/gitlab_developer_app/sources/new-mention/new-mention.mjs @@ -1,81 +1,21 @@ -import gitlab from "../../gitlab.app.mjs"; -import base from "../common/base.mjs"; -import { eventTypes } from "../common/hook-events.mjs"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-mention/new-mention.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); export default { - ...base, - key: "gitlab-new-mention", - name: "New Mention (Instant)", - description: "Emit new event when you are @mentioned in a new commit, comment, issue or pull request", - version: "0.1.1", - dedupe: "unique", - type: "source", + ...others, + key: "gitlab_developer_app-new-mention", + version: "0.0.1", + name, + description, + type, props: { - ...base.props, - username: { - propDefinition: [ - gitlab, - "assignee", - (c) => ({ - projectId: c.projectId, - }), - ], - label: "Username", - description: "The GitLab Username whose mentions will emit events", - withLabel: true, - }, - }, - hooks: { - ...base.hooks, - async activate() { - await this.activateHook([ - eventTypes.ISSUES_EVENTS, - eventTypes.NOTE_EVENTS, - ]); - }, - }, - methods: { - ...base.methods, - isUserMentioned(mention) { - const pattern = new RegExp(`\\B@${this.username.label}\\b`); - const groomedAttributes = { - ...mention, - // We want to exclude some fields, since they do not map - // to the content being updated, and could result in false - // positives (e.g. if a URL contains `@someuser` in its path). - url: "", - }; - const changedSummary = JSON.stringify(groomedAttributes); - return pattern.test(changedSummary); - }, - generateMeta({ - user, mention, - }) { - const { - id, - created_at: createdAt, - } = mention; - const { username } = user; - return { - id, - summary: `New mention of ${this.username.label} by ${username}`, - ts: +new Date(createdAt), - }; - }, - async emitEvent(event) { - const { - user, - object_attributes: mention, - } = event; - // Gitlab doesn't offer a specific hook for "new label" events, - // but such event can be deduced from the payload of "issues" events. - if (this.isUserMentioned(mention)) { - const meta = this.generateMeta({ - user, - mention, - }); - this.$emit(event, meta); - } - }, + gitlab: app, + ...props, }, }; diff --git a/components/gitlab_developer_app/sources/new-merge-request/new-merge-request.mjs b/components/gitlab_developer_app/sources/new-merge-request/new-merge-request.mjs index 96d46cf4d6db0..d473a02d5af05 100644 --- a/components/gitlab_developer_app/sources/new-merge-request/new-merge-request.mjs +++ b/components/gitlab_developer_app/sources/new-merge-request/new-merge-request.mjs @@ -1,55 +1,21 @@ -import base from "../common/base.mjs"; -import { eventTypes } from "../common/hook-events.mjs"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-merge-request/new-merge-request.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); export default { - ...base, - key: "gitlab-new-merge-request", - name: "New Merge Request (Instant)", - description: "Emit new event when a merge request is created", - version: "0.1.1", - dedupe: "unique", - type: "source", - hooks: { - ...base.hooks, - async activate() { - await this.activateHook(eventTypes.MERGE_REQUESTS_EVENTS); - }, - }, - methods: { - ...base.methods, - isNewMergeRequest(event) { - const { action } = event.object_attributes; - const expectedAction = "open"; - return action === expectedAction; - }, - generateMeta({ - user, mergeRequest, - }) { - const { - name, - username, - } = user; - const { - id, - created_at: createdAt, - title, - } = mergeRequest; - return { - id, - summary: `New Merge Request: "${title}" by ${name} (${username})`, - ts: +new Date(createdAt), - }; - }, - async emitEvent(event) { - // Gitlab doesn't offer a specific hook for "new merge request" events, - // but such event can be deduced from the payload of "merge request" events. - if (this.isNewMergeRequest(event)) { - const meta = this.generateMeta({ - user: event.user, - mergeRequest: event.object_attributes, - }); - this.$emit(event, meta); - } - }, + ...others, + key: "gitlab_developer_app-new-merge-request", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, }, }; diff --git a/components/gitlab_developer_app/sources/new-milestone/new-milestone.mjs b/components/gitlab_developer_app/sources/new-milestone/new-milestone.mjs index 88e785fc74cee..2c291c5406aeb 100644 --- a/components/gitlab_developer_app/sources/new-milestone/new-milestone.mjs +++ b/components/gitlab_developer_app/sources/new-milestone/new-milestone.mjs @@ -1,94 +1,21 @@ -import gitlab from "../../gitlab.app.mjs"; -import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-milestone/new-milestone.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); export default { - key: "gitlab-new-milestone", - name: "New Milestone", - description: "Emit new event when a milestone is created in a project", - version: "0.1.2", - dedupe: "greatest", - type: "source", + ...others, + key: "gitlab_developer_app-new-milestone", + version: "0.0.1", + name, + description, + type, props: { - gitlab, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, - }, - }, - projectId: { - propDefinition: [ - gitlab, - "projectId", - ], - }, - }, - hooks: { - async activate() { - const milestones = await this.gitlab.listMilestones(this.projectId, { - params: { - max: 1, - }, - }); - if (milestones.length > 0) { - const lastProcessedMilestoneTime = milestones[0].created_at; - this.db.set("lastProcessedMilestoneTime", lastProcessedMilestoneTime); - console.log(`Polling GitLab milestones created after ${lastProcessedMilestoneTime}`); - } - }, - }, - methods: { - _getLastProcessedMilestoneTime() { - return this.db.get("lastProcessedMilestoneTime") || 0; - }, - _setLastProcessedMilestoneTime(lastProcessedMilestoneTime) { - this.db.set("lastProcessedMilestoneTime", lastProcessedMilestoneTime); - }, - generateMeta(data) { - const { - id, - created_at: createdAt, - title, - } = data; - return { - id, - summary: `New milestone: ${title}`, - ts: +new Date(createdAt), - }; - }, - }, - async run() { - let lastProcessedMilestoneTime = this._getLastProcessedMilestoneTime(); - const newOrUpdatedMilestones = await this.gitlab.listMilestones(this.projectId, { - params: { - updated_after: lastProcessedMilestoneTime, - }, - }); - - const milestones = newOrUpdatedMilestones.filter( - ({ created_at }) => Date.parse(created_at) > Date.parse(lastProcessedMilestoneTime), - ); - - if (milestones.length === 0) { - console.log("No new GitLab milestones detected"); - return; - } - - console.log(`Detected ${milestones.length} new milestones`); - - // We store the most recent milestone ID in the DB so that - // we don't process it (and previous milestones) in future runs. - lastProcessedMilestoneTime = milestones[0].created_at; - this._setLastProcessedMilestoneTime(lastProcessedMilestoneTime); - - // We need to sort the retrieved milestones - // in reverse order (since the Gitlab API sorts them - // from most to least recent) and emit an event for each - // one of them. - milestones.reverse().forEach((milestone) => { - const meta = this.generateMeta(milestone); - this.$emit(milestone, meta); - }); + gitlab: app, + ...props, }, }; diff --git a/components/gitlab_developer_app/sources/new-project/new-project.mjs b/components/gitlab_developer_app/sources/new-project/new-project.mjs index 2ea4c3f07327b..65ff7e274316f 100644 --- a/components/gitlab_developer_app/sources/new-project/new-project.mjs +++ b/components/gitlab_developer_app/sources/new-project/new-project.mjs @@ -1,89 +1,21 @@ -import gitlab from "../../gitlab.app.mjs"; -import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-project/new-project.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; + +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); export default { - key: "gitlab-new-project", - name: "New Project", - description: "Emit new event when a project (i.e. repository) is created", - version: "0.1.2", - dedupe: "greatest", - type: "source", + ...others, + key: "gitlab_developer_app-new-project", + version: "0.0.1", + name, + description, + type, props: { - gitlab, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, - }, - }, - }, - hooks: { - async activate() { - const projects = await this.gitlab.listProjects({ - params: { - owned: true, - per_page: 1, - }, - }); - if (projects.length > 0) { - const lastProcessedProjectId = projects[0].id; - this._setLastProcessedProjectId(lastProcessedProjectId); - console.log(`Polling GitLab projects created after ID ${lastProcessedProjectId}`); - } - }, - }, - methods: { - _getLastProcessedProjectId() { - return this.db.get("lastProcessedProjectId"); - }, - _setLastProcessedProjectId(lastProcessedProjectId) { - this.db.set("lastProcessedProjectId", lastProcessedProjectId); - }, - generateMeta(data) { - const { - id, - created_at: createdAt, - name, - } = data; - return { - id, - summary: `New project: ${name}`, - ts: +new Date(createdAt), - }; - }, - }, - async run() { - // We use the ID of the last processed project so that we - // don't emit events for them (i.e. we only want to emit events - // for new projects). - let lastProcessedProjectId = this._getLastProcessedProjectId(); - const projects = await this.gitlab.listProjects({ - params: { - id_after: lastProcessedProjectId, - owned: true, - }, - }); - - if (projects.length === 0) { - console.log("No new GitLab projects detected"); - return; - } - - console.log(`Detected ${projects.length} new projects`); - - // We store the most recent project ID in the DB so that - // we don't process it (and previous projects) in future runs. - lastProcessedProjectId = projects[0].id; - this._setLastProcessedProjectId(lastProcessedProjectId); - - // We need to sort the retrieved projects - // in reverse order (since the Gitlab API sorts them - // from most to least recent) and emit an event for each - // one of them. - projects.reverse().forEach((project) => { - const meta = this.generateMeta(project); - this.$emit(project, meta); - }); + gitlab: app, + ...props, }, }; diff --git a/components/gitlab_developer_app/sources/new-review-request/new-review-request.mjs b/components/gitlab_developer_app/sources/new-review-request/new-review-request.mjs index 79b18649e2d4f..5993904c01646 100644 --- a/components/gitlab_developer_app/sources/new-review-request/new-review-request.mjs +++ b/components/gitlab_developer_app/sources/new-review-request/new-review-request.mjs @@ -1,80 +1,21 @@ -import base from "../common/base.mjs"; -import { eventTypes } from "../common/hook-events.mjs"; +import app from "../../gitlab_developer_app.app.mjs"; +import common from "../../../gitlab/sources/new-review-request/new-review-request.mjs"; +import { adjustPropDefinitions } from "../../common/utils.mjs"; -export default { - ...base, - key: "gitlab-new-review-request", - name: "New Review Request (Instant)", - description: "Emit new event when a reviewer is added to a merge request", - version: "0.1.1", - dedupe: "unique", - type: "source", - hooks: { - ...base.hooks, - async activate() { - await this.activateHook([ - eventTypes.MERGE_REQUESTS_EVENTS, - eventTypes.PUSH_EVENT, - ]); - }, - }, - methods: { - ...base.methods, - getNewReviewers(event) { - const { - action, - title, - } = event.object_attributes; - - // When a merge request is first created, any assignees - // in it are interpreted as new review requests. - if (action === "open" || action === "reopen") { - const { assignees = [] } = event; - return assignees; - } +const { + name, description, type, ...others +} = common; +const props = adjustPropDefinitions(others.props, app); - // Gitlab API provides any merge request update diff - // as part of their response. We can check the presence of - // the `assignees` attribute within those changes to verify - // if there are new review requests. - const { assignees } = event.changes; - if (!assignees) { - console.log(`No new assignees in merge request "${title}"`); - return []; - } - - // If the assignees of the merge request changed, we need to compute - // the difference in order to extract the new reviewers. - const previousAssignees = new Set(assignees.previous.map((a) => a.username)); - const newAssignees = assignees.current.filter((a) => !previousAssignees.has(a.username)); - if (newAssignees.length > 0) { - console.log(`Assignees added to merge request "${title}": ${newAssignees.map((a) => a.username).join(", ")}`); - } - return newAssignees; - }, - generateMeta(event, reviewer) { - const { - id, - title, - updated_at: updatedAt, - } = event.object_attributes; - const ts = +new Date(updatedAt); - return { - id: `${id}-${ts}-${reviewer.username}`, - summary: `New reviewer for "${title}": ${reviewer.username}`, - ts, - }; - }, - async emitEvent(event) { - // Gitlab doesn't offer a specific hook for "new merge request reviewers" events, - // but such event can be deduced from the payload of "merge request" events. - this.getNewReviewers(event).forEach((reviewer) => { - const meta = this.generateMeta(event, reviewer); - this.$emit({ - ...event, - reviewer, - }, meta); - }); - }, +export default { + ...others, + key: "gitlab_developer_app-new-review-request", + version: "0.0.1", + name, + description, + type, + props: { + gitlab: app, + ...props, }, }; From 6900332e60394ea97af636640952e929d5df2171 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Sat, 20 Apr 2024 22:13:12 -0300 Subject: [PATCH 08/21] Removing unused file --- components/gitlab_developer_app/common/constants.mjs | 1 - 1 file changed, 1 deletion(-) delete mode 100644 components/gitlab_developer_app/common/constants.mjs diff --git a/components/gitlab_developer_app/common/constants.mjs b/components/gitlab_developer_app/common/constants.mjs deleted file mode 100644 index df0a42f880c03..0000000000000 --- a/components/gitlab_developer_app/common/constants.mjs +++ /dev/null @@ -1 +0,0 @@ -export * from "../../gitlab/common/constants.mjs"; From ca6be9ec4d14f91901971c7484bdf64d5e15b6c0 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Tue, 23 Apr 2024 18:04:23 -0300 Subject: [PATCH 09/21] Fixing import error for sources --- components/gitlab_developer_app/common/utils.mjs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/gitlab_developer_app/common/utils.mjs b/components/gitlab_developer_app/common/utils.mjs index 336ad9e7eb1cc..d42df055ddeb0 100644 --- a/components/gitlab_developer_app/common/utils.mjs +++ b/components/gitlab_developer_app/common/utils.mjs @@ -2,10 +2,15 @@ export function adjustPropDefinitions(props, app) { return Object.fromEntries( Object.entries(props).map(([ key, - { - propDefinition, ...otherValues - }, + prop, ]) => { + if (typeof prop === "string") return [ + key, + prop, + ]; + const { + propDefinition, ...otherValues + } = prop; if (propDefinition) { const [ , ...otherDefs From 07be7c3d8669fa5140e68aa08d2ac03f013fc016 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Wed, 24 Apr 2024 09:49:00 -0300 Subject: [PATCH 10/21] Updating list projects --- components/gitlab/gitlab.app.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/gitlab/gitlab.app.mjs b/components/gitlab/gitlab.app.mjs index f4e12ff593df2..004b91833decd 100644 --- a/components/gitlab/gitlab.app.mjs +++ b/components/gitlab/gitlab.app.mjs @@ -273,7 +273,7 @@ export default { }, listProjects(opts = {}) { return this._makeRequest({ - path: `/users/${this._userId()}/projects`, + path: "/projects", ...opts, }); }, From 19b5358b09d2023108d9b6681bc65418a44290fb Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Wed, 24 Apr 2024 09:55:17 -0300 Subject: [PATCH 11/21] Gitlab version bumps --- components/gitlab/actions/create-branch/create-branch.mjs | 2 +- components/gitlab/actions/create-epic/create-epic.mjs | 2 +- components/gitlab/actions/create-issue/create-issue.mjs | 2 +- components/gitlab/actions/get-issue/get-issue.mjs | 2 +- components/gitlab/actions/get-repo-branch/get-repo-branch.mjs | 2 +- components/gitlab/actions/list-commits/list-commits.mjs | 2 +- .../gitlab/actions/list-repo-branches/list-repo-branches.mjs | 2 +- components/gitlab/actions/search-issues/search-issues.mjs | 2 +- components/gitlab/actions/update-epic/update-epic.mjs | 2 +- components/gitlab/actions/update-issue/update-issue.mjs | 2 +- components/gitlab/package.json | 2 +- components/gitlab/sources/new-audit-event/new-audit-event.mjs | 2 +- components/gitlab/sources/new-branch/new-branch.mjs | 2 +- .../gitlab/sources/new-commit-comment/new-commit-comment.mjs | 2 +- components/gitlab/sources/new-commit/new-commit.mjs | 2 +- components/gitlab/sources/new-issue/new-issue.mjs | 2 +- components/gitlab/sources/new-mention/new-mention.mjs | 2 +- .../gitlab/sources/new-merge-request/new-merge-request.mjs | 2 +- components/gitlab/sources/new-milestone/new-milestone.mjs | 2 +- components/gitlab/sources/new-project/new-project.mjs | 2 +- .../gitlab/sources/new-review-request/new-review-request.mjs | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/components/gitlab/actions/create-branch/create-branch.mjs b/components/gitlab/actions/create-branch/create-branch.mjs index 0688604201ddb..74f062235e62f 100644 --- a/components/gitlab/actions/create-branch/create-branch.mjs +++ b/components/gitlab/actions/create-branch/create-branch.mjs @@ -4,7 +4,7 @@ export default { key: "gitlab-create-branch", name: "Create Branch", description: "Create a new branch in the repository. [See the documentation](https://docs.gitlab.com/ee/api/branches.html#create-repository-branch)", - version: "0.3.1", + version: "0.3.2", type: "action", props: { gitlab, diff --git a/components/gitlab/actions/create-epic/create-epic.mjs b/components/gitlab/actions/create-epic/create-epic.mjs index 68faebd3c2c68..2db03a3142bf1 100644 --- a/components/gitlab/actions/create-epic/create-epic.mjs +++ b/components/gitlab/actions/create-epic/create-epic.mjs @@ -5,7 +5,7 @@ export default { key: "gitlab-create-epic", name: "Create Epic", description: "Creates a new epic. [See the documentation](https://docs.gitlab.com/ee/api/epics.html#new-epic)", - version: "0.0.3", + version: "0.0.4", type: "action", props: { gitlab, diff --git a/components/gitlab/actions/create-issue/create-issue.mjs b/components/gitlab/actions/create-issue/create-issue.mjs index 9f40ca22a9771..10f2d00a02380 100644 --- a/components/gitlab/actions/create-issue/create-issue.mjs +++ b/components/gitlab/actions/create-issue/create-issue.mjs @@ -5,7 +5,7 @@ export default { key: "gitlab-create-issue", name: "Create issue", description: "Creates a new issue. [See the documentation](https://docs.gitlab.com/ee/api/issues.html#new-issue)", - version: "0.2.1", + version: "0.2.2", type: "action", props: { gitlab, diff --git a/components/gitlab/actions/get-issue/get-issue.mjs b/components/gitlab/actions/get-issue/get-issue.mjs index e3f31291c1cf2..fd1b99c3e11c9 100644 --- a/components/gitlab/actions/get-issue/get-issue.mjs +++ b/components/gitlab/actions/get-issue/get-issue.mjs @@ -4,7 +4,7 @@ export default { key: "gitlab-get-issue", name: "Get Issue", description: "Gets a single issue from repository. [See the documentation](https://docs.gitlab.com/ee/api/issues.html#single-project-issue)", - version: "0.2.1", + version: "0.2.2", type: "action", props: { gitlab, diff --git a/components/gitlab/actions/get-repo-branch/get-repo-branch.mjs b/components/gitlab/actions/get-repo-branch/get-repo-branch.mjs index 4f14f3110b929..c2488b99b4593 100644 --- a/components/gitlab/actions/get-repo-branch/get-repo-branch.mjs +++ b/components/gitlab/actions/get-repo-branch/get-repo-branch.mjs @@ -4,7 +4,7 @@ export default { key: "gitlab-get-repo-branch", name: "Get Repo Branch", description: "Get a single project repository branch. [See the documentation](https://docs.gitlab.com/ee/api/branches.html#get-single-repository-branch)", - version: "0.2.1", + version: "0.2.2", type: "action", props: { gitlab, diff --git a/components/gitlab/actions/list-commits/list-commits.mjs b/components/gitlab/actions/list-commits/list-commits.mjs index 311501a881987..96df8562c49ac 100644 --- a/components/gitlab/actions/list-commits/list-commits.mjs +++ b/components/gitlab/actions/list-commits/list-commits.mjs @@ -5,7 +5,7 @@ export default { key: "gitlab-list-commits", name: "List Commits", description: "List commits in a repository branch. [See the documentation](https://docs.gitlab.com/ee/api/commits.html#list-repository-commits)", - version: "0.0.2", + version: "0.0.3", type: "action", props: { gitlab, diff --git a/components/gitlab/actions/list-repo-branches/list-repo-branches.mjs b/components/gitlab/actions/list-repo-branches/list-repo-branches.mjs index b8b4fc5e5fd26..c0ce31e6eb9ef 100644 --- a/components/gitlab/actions/list-repo-branches/list-repo-branches.mjs +++ b/components/gitlab/actions/list-repo-branches/list-repo-branches.mjs @@ -4,7 +4,7 @@ export default { key: "gitlab-list-repo-branches", name: "List Repo Branches", description: "Get a list of repository branches from a project. [See the documentation](https://docs.gitlab.com/ee/api/branches.html#list-repository-branches)", - version: "0.2.1", + version: "0.2.2", type: "action", props: { gitlab, diff --git a/components/gitlab/actions/search-issues/search-issues.mjs b/components/gitlab/actions/search-issues/search-issues.mjs index 68762679e40d5..a00dbe4326ccf 100644 --- a/components/gitlab/actions/search-issues/search-issues.mjs +++ b/components/gitlab/actions/search-issues/search-issues.mjs @@ -6,7 +6,7 @@ export default { key: "gitlab-search-issues", name: "Search Issues", description: "Search for issues in a repository with a query. [See the documentation](https://docs.gitlab.com/ee/api/issues.html#list-issues)", - version: "0.0.2", + version: "0.0.3", type: "action", props: { gitlab, diff --git a/components/gitlab/actions/update-epic/update-epic.mjs b/components/gitlab/actions/update-epic/update-epic.mjs index 1b11a5fce1b8e..28790327db6c9 100644 --- a/components/gitlab/actions/update-epic/update-epic.mjs +++ b/components/gitlab/actions/update-epic/update-epic.mjs @@ -5,7 +5,7 @@ export default { key: "gitlab-update-epic", name: "Update Epic", description: "Updates an epic. [See the documentation](https://docs.gitlab.com/ee/api/epics.html#update-epic)", - version: "0.0.2", + version: "0.0.3", type: "action", props: { gitlab, diff --git a/components/gitlab/actions/update-issue/update-issue.mjs b/components/gitlab/actions/update-issue/update-issue.mjs index 131d43fd42a8b..ed3ca6763b930 100644 --- a/components/gitlab/actions/update-issue/update-issue.mjs +++ b/components/gitlab/actions/update-issue/update-issue.mjs @@ -5,7 +5,7 @@ export default { key: "gitlab-update-issue", name: "Update Issue", description: "Updates an existing project issue. [See the documentation](https://docs.gitlab.com/ee/api/issues.html#edit-issue)", - version: "0.0.1", + version: "0.0.2", type: "action", props: { gitlab, diff --git a/components/gitlab/package.json b/components/gitlab/package.json index 76c9df65285e8..dd16f0abc1e39 100644 --- a/components/gitlab/package.json +++ b/components/gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/gitlab", - "version": "0.5.5", + "version": "0.5.6", "description": "Pipedream Gitlab Components", "main": "gitlab.app.mjs", "keywords": [ diff --git a/components/gitlab/sources/new-audit-event/new-audit-event.mjs b/components/gitlab/sources/new-audit-event/new-audit-event.mjs index 1c0e8fb51c9d9..4388dc8373d3b 100644 --- a/components/gitlab/sources/new-audit-event/new-audit-event.mjs +++ b/components/gitlab/sources/new-audit-event/new-audit-event.mjs @@ -12,7 +12,7 @@ export default { key: "gitlab-new-audit-event", name: "New Audit Event (Instant)", description: "Emit new event when a new audit event is created", - version: "0.1.2", + version: "0.1.3", dedupe: "unique", type: "source", props: { diff --git a/components/gitlab/sources/new-branch/new-branch.mjs b/components/gitlab/sources/new-branch/new-branch.mjs index 0478322fabc8b..e1e9040b745d8 100644 --- a/components/gitlab/sources/new-branch/new-branch.mjs +++ b/components/gitlab/sources/new-branch/new-branch.mjs @@ -6,7 +6,7 @@ export default { key: "gitlab-new-branch", name: "New Branch (Instant)", description: "Emit new event when a new branch is created", - version: "0.1.1", + version: "0.1.2", dedupe: "unique", type: "source", hooks: { diff --git a/components/gitlab/sources/new-commit-comment/new-commit-comment.mjs b/components/gitlab/sources/new-commit-comment/new-commit-comment.mjs index a0a8b9462c42c..e2a57aac30206 100644 --- a/components/gitlab/sources/new-commit-comment/new-commit-comment.mjs +++ b/components/gitlab/sources/new-commit-comment/new-commit-comment.mjs @@ -6,7 +6,7 @@ export default { key: "gitlab-new-commit-comment", name: "New Commit Comment (Instant)", description: "Emit new event when a commit receives a comment", - version: "0.1.1", + version: "0.1.2", dedupe: "unique", type: "source", hooks: { diff --git a/components/gitlab/sources/new-commit/new-commit.mjs b/components/gitlab/sources/new-commit/new-commit.mjs index 965d8ffb21939..0ed0991b993b8 100644 --- a/components/gitlab/sources/new-commit/new-commit.mjs +++ b/components/gitlab/sources/new-commit/new-commit.mjs @@ -7,7 +7,7 @@ export default { key: "gitlab-new-commit", name: "New Commit (Instant)", description: "Emit new event when a new commit is pushed to a branch", - version: "0.1.2", + version: "0.1.3", dedupe: "unique", type: "source", props: { diff --git a/components/gitlab/sources/new-issue/new-issue.mjs b/components/gitlab/sources/new-issue/new-issue.mjs index c4c512e6cd5be..e995c1c7280eb 100644 --- a/components/gitlab/sources/new-issue/new-issue.mjs +++ b/components/gitlab/sources/new-issue/new-issue.mjs @@ -6,7 +6,7 @@ export default { key: "gitlab-new-issue", name: "New Issue (Instant)", description: "Emit new event when an issue is created in a project", - version: "0.1.1", + version: "0.1.2", dedupe: "unique", type: "source", hooks: { diff --git a/components/gitlab/sources/new-mention/new-mention.mjs b/components/gitlab/sources/new-mention/new-mention.mjs index e9f8efb6168d9..947144dd1be73 100644 --- a/components/gitlab/sources/new-mention/new-mention.mjs +++ b/components/gitlab/sources/new-mention/new-mention.mjs @@ -7,7 +7,7 @@ export default { key: "gitlab-new-mention", name: "New Mention (Instant)", description: "Emit new event when you are @mentioned in a new commit, comment, issue or pull request", - version: "0.1.1", + version: "0.1.2", dedupe: "unique", type: "source", props: { diff --git a/components/gitlab/sources/new-merge-request/new-merge-request.mjs b/components/gitlab/sources/new-merge-request/new-merge-request.mjs index 96d46cf4d6db0..6c3fe2aa6bcec 100644 --- a/components/gitlab/sources/new-merge-request/new-merge-request.mjs +++ b/components/gitlab/sources/new-merge-request/new-merge-request.mjs @@ -6,7 +6,7 @@ export default { key: "gitlab-new-merge-request", name: "New Merge Request (Instant)", description: "Emit new event when a merge request is created", - version: "0.1.1", + version: "0.1.2", dedupe: "unique", type: "source", hooks: { diff --git a/components/gitlab/sources/new-milestone/new-milestone.mjs b/components/gitlab/sources/new-milestone/new-milestone.mjs index 88e785fc74cee..7396e789ca804 100644 --- a/components/gitlab/sources/new-milestone/new-milestone.mjs +++ b/components/gitlab/sources/new-milestone/new-milestone.mjs @@ -5,7 +5,7 @@ export default { key: "gitlab-new-milestone", name: "New Milestone", description: "Emit new event when a milestone is created in a project", - version: "0.1.2", + version: "0.1.3", dedupe: "greatest", type: "source", props: { diff --git a/components/gitlab/sources/new-project/new-project.mjs b/components/gitlab/sources/new-project/new-project.mjs index 2ea4c3f07327b..2b128aeca9bb5 100644 --- a/components/gitlab/sources/new-project/new-project.mjs +++ b/components/gitlab/sources/new-project/new-project.mjs @@ -5,7 +5,7 @@ export default { key: "gitlab-new-project", name: "New Project", description: "Emit new event when a project (i.e. repository) is created", - version: "0.1.2", + version: "0.1.3", dedupe: "greatest", type: "source", props: { diff --git a/components/gitlab/sources/new-review-request/new-review-request.mjs b/components/gitlab/sources/new-review-request/new-review-request.mjs index 79b18649e2d4f..fbe838354aff2 100644 --- a/components/gitlab/sources/new-review-request/new-review-request.mjs +++ b/components/gitlab/sources/new-review-request/new-review-request.mjs @@ -6,7 +6,7 @@ export default { key: "gitlab-new-review-request", name: "New Review Request (Instant)", description: "Emit new event when a reviewer is added to a merge request", - version: "0.1.1", + version: "0.1.2", dedupe: "unique", type: "source", hooks: { From 915b5bc398eb6c0f6cf780578aab29c17acbb3b5 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Wed, 24 Apr 2024 10:27:58 -0300 Subject: [PATCH 12/21] package newline --- components/gitlab_developer_app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/gitlab_developer_app/package.json b/components/gitlab_developer_app/package.json index 499cffbd21914..b42abd5326b4f 100644 --- a/components/gitlab_developer_app/package.json +++ b/components/gitlab_developer_app/package.json @@ -17,4 +17,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} From e6c2d0b760c6e963aca98cf1f919d6fe5daaf6c1 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Wed, 24 Apr 2024 23:38:29 -0300 Subject: [PATCH 13/21] Description update --- components/gitlab/gitlab.app.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/gitlab/gitlab.app.mjs b/components/gitlab/gitlab.app.mjs index 004b91833decd..612de4213e4bb 100644 --- a/components/gitlab/gitlab.app.mjs +++ b/components/gitlab/gitlab.app.mjs @@ -78,7 +78,7 @@ export default { epicIid: { type: "string", label: "Epic Internal ID", - description: "The internal ID of a project's epic", + description: "The internal ID of a project's epic. [This feature is restricted to Gitlab's Premium and Ultimate tiers.](https://docs.gitlab.com/ee/api/epics.html)", async options({ page, groupId, }) { From 6de10eaafb49619271681bdef5ff6ac943cedd43 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Thu, 25 Apr 2024 17:39:58 -0300 Subject: [PATCH 14/21] Making username required --- components/gitlab/sources/new-mention/new-mention.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/gitlab/sources/new-mention/new-mention.mjs b/components/gitlab/sources/new-mention/new-mention.mjs index 947144dd1be73..b027ab406f2eb 100644 --- a/components/gitlab/sources/new-mention/new-mention.mjs +++ b/components/gitlab/sources/new-mention/new-mention.mjs @@ -20,6 +20,7 @@ export default { projectId: c.projectId, }), ], + optional: false, label: "Username", description: "The GitLab Username whose mentions will emit events", withLabel: true, From f8a946ee8bd02afa17e6fd0bd23144a3246adb59 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Mon, 29 Apr 2024 19:38:13 -0300 Subject: [PATCH 15/21] Fix labels and parentId optional --- components/gitlab/actions/create-epic/create-epic.mjs | 1 + components/gitlab/gitlab.app.mjs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/gitlab/actions/create-epic/create-epic.mjs b/components/gitlab/actions/create-epic/create-epic.mjs index 2db03a3142bf1..4f5618c99a451 100644 --- a/components/gitlab/actions/create-epic/create-epic.mjs +++ b/components/gitlab/actions/create-epic/create-epic.mjs @@ -24,6 +24,7 @@ export default { }), ], label: "Parent ID", + optional: true, }, title: { propDefinition: [ diff --git a/components/gitlab/gitlab.app.mjs b/components/gitlab/gitlab.app.mjs index 612de4213e4bb..2aa67e526600f 100644 --- a/components/gitlab/gitlab.app.mjs +++ b/components/gitlab/gitlab.app.mjs @@ -125,7 +125,7 @@ export default { page: page + 1, }, }); - return response.data.map((label) => label.name); + return response?.map?.((label) => label.name); }, }, assignee: { From df7054c732ab5476dea163e063a5d9dabc0bc52f Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Tue, 30 Apr 2024 00:05:16 -0300 Subject: [PATCH 16/21] Fixing 'new milstone' --- .../sources/new-milestone/new-milestone.mjs | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/components/gitlab/sources/new-milestone/new-milestone.mjs b/components/gitlab/sources/new-milestone/new-milestone.mjs index 7396e789ca804..8d8e07c66f260 100644 --- a/components/gitlab/sources/new-milestone/new-milestone.mjs +++ b/components/gitlab/sources/new-milestone/new-milestone.mjs @@ -24,23 +24,9 @@ export default { ], }, }, - hooks: { - async activate() { - const milestones = await this.gitlab.listMilestones(this.projectId, { - params: { - max: 1, - }, - }); - if (milestones.length > 0) { - const lastProcessedMilestoneTime = milestones[0].created_at; - this.db.set("lastProcessedMilestoneTime", lastProcessedMilestoneTime); - console.log(`Polling GitLab milestones created after ${lastProcessedMilestoneTime}`); - } - }, - }, methods: { _getLastProcessedMilestoneTime() { - return this.db.get("lastProcessedMilestoneTime") || 0; + return this.db.get("lastProcessedMilestoneTime"); }, _setLastProcessedMilestoneTime(lastProcessedMilestoneTime) { this.db.set("lastProcessedMilestoneTime", lastProcessedMilestoneTime); @@ -59,7 +45,9 @@ export default { }, }, async run() { - let lastProcessedMilestoneTime = this._getLastProcessedMilestoneTime(); + const isoDateNow = new Date().toISOString() + .slice(0, -5) + "Z"; + let lastProcessedMilestoneTime = this._getLastProcessedMilestoneTime() ?? isoDateNow; const newOrUpdatedMilestones = await this.gitlab.listMilestones(this.projectId, { params: { updated_after: lastProcessedMilestoneTime, @@ -72,6 +60,9 @@ export default { if (milestones.length === 0) { console.log("No new GitLab milestones detected"); + if (!this._getLastProcessedMilestoneTime()) { + this._setLastProcessedMilestoneTime(lastProcessedMilestoneTime); + } return; } From 55bb59d9db17e8c5fb4ce666811206f553d75e0b Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Tue, 30 Apr 2024 03:00:56 -0300 Subject: [PATCH 17/21] Adjusting 'new review request' --- .../sources/new-review-request/new-review-request.mjs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/gitlab/sources/new-review-request/new-review-request.mjs b/components/gitlab/sources/new-review-request/new-review-request.mjs index fbe838354aff2..86feb54c5b2fa 100644 --- a/components/gitlab/sources/new-review-request/new-review-request.mjs +++ b/components/gitlab/sources/new-review-request/new-review-request.mjs @@ -37,16 +37,16 @@ export default { // as part of their response. We can check the presence of // the `assignees` attribute within those changes to verify // if there are new review requests. - const { assignees } = event.changes; - if (!assignees) { + const { reviewers } = event.changes; + if (!reviewers) { console.log(`No new assignees in merge request "${title}"`); return []; } // If the assignees of the merge request changed, we need to compute // the difference in order to extract the new reviewers. - const previousAssignees = new Set(assignees.previous.map((a) => a.username)); - const newAssignees = assignees.current.filter((a) => !previousAssignees.has(a.username)); + const previousAssignees = new Set(reviewers.previous.map((a) => a.username)); + const newAssignees = reviewers.current.filter((a) => !previousAssignees.has(a.username)); if (newAssignees.length > 0) { console.log(`Assignees added to merge request "${title}": ${newAssignees.map((a) => a.username).join(", ")}`); } From 8579c065586281de33b05cbe61a62e2773f8c6ea Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Tue, 30 Apr 2024 03:19:08 -0300 Subject: [PATCH 18/21] Update issue: fixing labels on request --- components/gitlab/actions/update-issue/update-issue.mjs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/gitlab/actions/update-issue/update-issue.mjs b/components/gitlab/actions/update-issue/update-issue.mjs index ed3ca6763b930..8d5fb4b3c86ac 100644 --- a/components/gitlab/actions/update-issue/update-issue.mjs +++ b/components/gitlab/actions/update-issue/update-issue.mjs @@ -75,14 +75,17 @@ export default { }, }, async run({ $ }) { + const labels = Array.isArray(this.labels) + ? this.labels.join() + : this.labels; const data = lodash.pickBy({ title: this.title, description: this.description, assignee_ids: this.assignee_ids, state_event: this.stateEvent, discussion_locked: this.discussionLocked, + labels, }); - data.labels = data.labels?.join(); const response = await this.gitlab.editIssue(this.projectId, this.issueIid, { data, }); From 458466896a12b52ccf73118345459e149e1abce8 Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Tue, 30 Apr 2024 03:37:43 -0300 Subject: [PATCH 19/21] Replacing node-fetch with axios --- .../sources/new-audit-event/new-audit-event.mjs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/components/gitlab/sources/new-audit-event/new-audit-event.mjs b/components/gitlab/sources/new-audit-event/new-audit-event.mjs index 4388dc8373d3b..74dedcab77a48 100644 --- a/components/gitlab/sources/new-audit-event/new-audit-event.mjs +++ b/components/gitlab/sources/new-audit-event/new-audit-event.mjs @@ -1,6 +1,5 @@ import gitlab from "../../gitlab.app.mjs"; import base from "../common/base.mjs"; -import fetch from "node-fetch"; import { create_destination, list_destinations, @@ -40,18 +39,16 @@ export default { const query = create_destination(this.http.endpoint, this.groupPath); try { - await fetch(`https://${this._getBaseApiUrl()}/api/graphql`, { + await this.gitlab._makeRequest({ + url: `https://${this._getBaseApiUrl()}/api/graphql`, method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json", "Authorization": `Bearer ${this.gitlab.$auth.oauth_access_token}`, }, - body: JSON.stringify({ - query, - }), - }) - .then((r) => r.json()); + data: query, + }); } catch (err) { console.log(`Error thrown during activation: ${JSON.stringify(err)}`); From 816ddb81e54408b85db73b251d2f39c0bd76ab7c Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Fri, 3 May 2024 15:05:22 -0300 Subject: [PATCH 20/21] Splittin group path and group id --- .../actions/create-epic/create-epic.mjs | 14 +++++----- .../actions/update-epic/update-epic.mjs | 26 +++++++++---------- components/gitlab/gitlab.app.mjs | 22 ++++++++++++++-- 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/components/gitlab/actions/create-epic/create-epic.mjs b/components/gitlab/actions/create-epic/create-epic.mjs index 4f5618c99a451..39d5fb483133c 100644 --- a/components/gitlab/actions/create-epic/create-epic.mjs +++ b/components/gitlab/actions/create-epic/create-epic.mjs @@ -9,18 +9,18 @@ export default { type: "action", props: { gitlab, - groupPath: { + groupId: { propDefinition: [ gitlab, - "groupPath", + "groupId", ], }, parent_id: { propDefinition: [ gitlab, "epicIid", - (c) => ({ - groupId: c.groupPath, + ({ groupId }) => ({ + groupId, }), ], label: "Parent ID", @@ -37,8 +37,8 @@ export default { propDefinition: [ gitlab, "groupLabels", - (c) => ({ - groupId: c.groupPath, + ({ groupId }) => ({ + groupId, }), ], }, @@ -116,7 +116,7 @@ export default { ])); data.labels = data.labels?.join(); - const response = await this.gitlab.createEpic(this.groupPath, { + const response = await this.gitlab.createEpic(this.groupId, { data, }); $.export("$summary", `Created epic ${this.title}`); diff --git a/components/gitlab/actions/update-epic/update-epic.mjs b/components/gitlab/actions/update-epic/update-epic.mjs index 28790327db6c9..6bad6a71fbbab 100644 --- a/components/gitlab/actions/update-epic/update-epic.mjs +++ b/components/gitlab/actions/update-epic/update-epic.mjs @@ -9,18 +9,18 @@ export default { type: "action", props: { gitlab, - groupPath: { + groupId: { propDefinition: [ gitlab, - "groupPath", + "groupId", ], }, epicIid: { propDefinition: [ gitlab, "epicIid", - (c) => ({ - groupId: c.groupPath, + ({ groupId }) => ({ + groupId, }), ], }, @@ -28,8 +28,8 @@ export default { propDefinition: [ gitlab, "groupLabels", - (c) => ({ - groupId: c.groupPath, + ({ groupId }) => ({ + groupId, }), ], label: "Add labels", @@ -51,8 +51,8 @@ export default { propDefinition: [ gitlab, "groupLabels", - (c) => ({ - groupPath: c.groupPath, + ({ groupId }) => ({ + groupId, }), ], description: "Comma-separated label names for an issue. Set to an empty string to unassign all labels.", @@ -61,8 +61,8 @@ export default { propDefinition: [ gitlab, "epicIid", - (c) => ({ - groupPath: c.groupPath, + ({ groupId }) => ({ + groupId, }), ], label: "Parent Id", @@ -73,8 +73,8 @@ export default { propDefinition: [ gitlab, "groupLabels", - (c) => ({ - groupPath: c.groupPath, + ({ groupId }) => ({ + groupId, }), ], label: "Remove labels", @@ -163,7 +163,7 @@ export default { ])); data.labels = data.labels?.join(); - const response = await this.gitlab.updateEpic(this.groupPath, this.epicIid, { + const response = await this.gitlab.updateEpic(this.groupId, this.epicIid, { data, }); $.export("$summary", `Updated epic ${this.epicIid}`); diff --git a/components/gitlab/gitlab.app.mjs b/components/gitlab/gitlab.app.mjs index 2aa67e526600f..cc25a96e4a420 100644 --- a/components/gitlab/gitlab.app.mjs +++ b/components/gitlab/gitlab.app.mjs @@ -23,10 +23,28 @@ export default { })); }, }, - groupPath: { + groupId: { type: "string", label: "Group ID", - description: "The group path, as displayed in the main group page. You must be an Owner of this group", + description: "Select a Group or use a custom Group ID. You must be an Owner of this group", + async options({ page }) { + const response = await this.listGroups({ + params: { + min_access_level: 50, // owner role + top_level_only: true, // only can use on root groups + page: page + 1, + }, + }); + return response.map((group) => ({ + label: group.full_path, + value: group.id, + })); + }, + }, + groupPath: { + type: "string", + label: "Group Path", + description: "Select a Group or use a custom Group Path, as displayed in the main group page. You must be an Owner of this group", async options({ page }) { const response = await this.listGroups({ params: { From ed1190223ae2a0af43252d94cf10835285b0ce4b Mon Sep 17 00:00:00 2001 From: GTFalcao Date: Fri, 3 May 2024 15:19:37 -0300 Subject: [PATCH 21/21] Adding error treatment for source --- .../gitlab/sources/new-merge-request/new-merge-request.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/gitlab/sources/new-merge-request/new-merge-request.mjs b/components/gitlab/sources/new-merge-request/new-merge-request.mjs index 6c3fe2aa6bcec..f2187b68e420e 100644 --- a/components/gitlab/sources/new-merge-request/new-merge-request.mjs +++ b/components/gitlab/sources/new-merge-request/new-merge-request.mjs @@ -18,7 +18,7 @@ export default { methods: { ...base.methods, isNewMergeRequest(event) { - const { action } = event.object_attributes; + const action = event?.object_attributes?.action; const expectedAction = "open"; return action === expectedAction; },