Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions components/vercel/deployment-ready.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const vercel = require("https://github.com/PipedreamHQ/pipedream/components/vercel/vercel.app.js");

module.exports = {
name: "Deployment Ready (Instant)",
description: "Triggers when a new deployment is ready",
version: "0.0.1",
dedupe: "unique",
props: {
vercel,
projectName: {
propDefinition: [
vercel,
"projectName",
],
},
http: "$.interface.http",
db: "$.service.db",
},
hooks: {
async activate() {
const events = [
"deployment-ready",
];
const hookParams = {
url: this.http.endpoint,
events,
};
const opts = {
projectName: this.projectName,
hookParams,
};
const { hookId } = await this.vercel.createHook(opts);
console.log(
`Created "deployment-ready" webhook for project ${this.projectName}.
(Hook ID: ${hookId}, endpoint: ${hookParams.url})`,
);
this.db.set("hookId", hookId);
},
async deactivate() {
const hookId = this.db.get("hookId");
const opts = {
hookId,
};
await this.vercel.deleteHook(opts);
console.log(
`Deleted webhook for project ${this.projectName}.
(Hook ID: ${hookId})`,
);
},
},
methods: {
generateMeta(body) {
const { createdAt } = body;
const {
deploymentId,
name,
} = body.payload;
const summary = `Deployment ready: ${name}`;
return {
id: deploymentId,
summary,
ts: createdAt,
};
},
},
async run(event) {
// Acknowledge the event back to Vercel.
this.http.respond({
status: 200,
});

const { body } = event;
const opts = {
body,
projectName: this.projectName,
};
if (this.vercel.isEventForThisProject(opts)) {
const meta = this.generateMeta(body);
this.$emit(body, meta);
}
},
};
82 changes: 82 additions & 0 deletions components/vercel/new-deployment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const vercel = require("https://github.com/PipedreamHQ/pipedream/components/vercel/vercel.app.js");

module.exports = {
name: "New Deployment (Instant)",
description: "Triggers when a new deployment is created",
version: "0.0.1",
dedupe: "unique",
props: {
vercel,
projectName: {
propDefinition: [
vercel,
"projectName",
],
},
http: "$.interface.http",
db: "$.service.db",
},
hooks: {
async activate() {
const events = [
"deployment",
];
const hookParams = {
url: this.http.endpoint,
events,
};
const opts = {
projectName: this.projectName,
hookParams,
};
const { hookId } = await this.vercel.createHook(opts);
console.log(
`Created "deployment" webhook for project ${this.projectName}.
(Hook ID: ${hookId}, endpoint: ${hookParams.url})`,
);
this.db.set("hookId", hookId);
},
async deactivate() {
const hookId = this.db.get("hookId");
const opts = {
hookId,
};
await this.vercel.deleteHook(opts);
console.log(
`Deleted webhook for project ${this.projectName}.
(Hook ID: ${hookId})`,
);
},
},
methods: {
generateMeta(body) {
const { createdAt } = body;
const {
deploymentId,
name,
} = body.payload;
const summary = `New deployment: ${name}`;
return {
id: deploymentId,
summary,
ts: createdAt,
};
},
},
async run(event) {
// Acknowledge the event back to Vercel.
this.http.respond({
status: 200,
});

const { body } = event;
const opts = {
body,
projectName: this.projectName,
};
if (this.vercel.isEventForThisProject(opts)) {
const meta = this.generateMeta(body);
this.$emit(body, meta);
}
},
};
123 changes: 123 additions & 0 deletions components/vercel/vercel.app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
const axios = require("axios");

module.exports = {
type: "app",
app: "zeit",
propDefinitions: {
projectName: {
type: "string",
label: "Project Name",
description: "The name of the project",
async options(context) {
const { from = 0 } = context.prevContext;
const url = this._userProjectsEndpoint();
const params = {
from,
};

const {
data,
next,
} = await this._propDefinitionsOptions(url, params, context);

const options = data.map((project) => project.name);
return {
options,
context: {
from: next,
},
};
},
},
},
methods: {
_apiUrl() {
return "https://api.vercel.com";
},
_hooksEndpointUrl() {
const baseUrl = this._apiUrl();
return `${baseUrl}/v1/integrations/webhooks`;
},
_hookEndpointUrl(hookId) {
const baseUrl = this._apiUrl();
return `${baseUrl}/v1/integrations/webhooks/${hookId}`;
},
_userProjectsEndpoint() {
const baseUrl = this._apiUrl();
return `${baseUrl}/v4/projects/`;
},
_authToken() {
return this.$auth.oauth_access_token;
},
_makeRequestConfig() {
const authToken = this._authToken();
const headers = {
"Authorization": `Bearer ${authToken}`,
"User-Agent": "@PipedreamHQ/pipedream v0.1",
};
return {
headers,
};
},
async _propDefinitionsOptions(url, params, { page }) {
const baseRequestConfig = this._makeRequestConfig();
const requestConfig = {
...baseRequestConfig,
params,
};
const { data } = await axios.get(url, requestConfig);
const {
projects,
pagination,
} = data;

// When retrieving items from subsequent pages, the Vercel API
// response has as its first element the same one that was provided
// as the last element in the previous page.
const effectiveData = page !== 0
? projects.slice(1)
: projects;

return {
data: effectiveData,
next: pagination.next,
};
},
async createHook(opts) {
const {
projectName,
hookParams,
} = opts;
const url = this._hooksEndpointUrl();
const name = `Pipedream - Hook for project ${projectName}`;
const requestData = {
...hookParams,
name,
};
const requestConfig = this._makeRequestConfig();
const { data } = await axios.post(url, requestData, requestConfig);
return {
hookId: data.id,
};
},
deleteHook(opts) {
const { hookId } = opts;
const url = this._hookEndpointUrl(hookId);
const requestConfig = this._makeRequestConfig();
return axios.delete(url, requestConfig);
},
isEventForThisProject(opts) {
// Vercel webhooks cannot be linked to a particular project,
// but they are rather called for an event on any of the projects
// under an account.
// As a consequence, we need to make sure we're only capturing and
// processing the events related to this particualr project.
const {
body,
projectName,
} = opts;
const { name } = body.payload;
return projectName === name;
},
},
};