This project sets up an integration between GitHub and Asana to automate task creation in Asana based on GitHub issue events. The integration uses GitHub webhooks to trigger the creation of tasks in Asana whenever an issue is opened or reopened in a GitHub repository.
The integration aims to streamline task management by creating Asana tasks for new or reopened GitHub issues, ensuring that important tasks are tracked and managed efficiently in Asana.
Before setting up the integration, ensure you have the following:
Navigate to Asana Developer Console:
Create a Personal Access Token:
Initialize a New Node.js Project:
mkdir github-to-asana
cd github-to-asana
npm init -y
npm install express body-parser axios asana localtunnel dotenv
Create the Webhook Server Script (index.js
):
require("dotenv").config();
const express = require("express");
const localtunnel = require("localtunnel");
const bodyParser = require("body-parser");
const Asana = require("asana");
const validateWebhookPayload = require("./validateWebhookPayload");
let client = Asana.ApiClient.instance;
let token = client.authentications["token"];
token.accessToken = process.env.ASANA_ACCESS_TOKEN;
const app = express();
app.use(
bodyParser.json({
verify: (req, res, buf, encoding) => {
if (buf && buf.length) {
req.rawBody = buf.toString(encoding || "utf8");
}
},
})
);
const PORT = 3000;
app.listen(PORT, async () => {
console.log("Server running on port ", PORT);
const tunnel = await localtunnel({
port: PORT,
subdomain: "webhook-integration-828",
});
console.log(`LocalTunnel URL: ${tunnel.url}`);
tunnel.on("close", () => {
console.log("Tunnel closed");
});
});
app.get("/", (req, res) => {
res.send("Working");
});
app.post("/new-issue", validateWebhookPayload, (req, res) => {
try {
const payload = req.body;
console.log("Received webhook:", payload);
res.status(200).send("Webhook received");
if (payload.action === "opened" || payload.action === "reopened") {
let tasksApiInstance = new Asana.TasksApi();
let body = {
data: {
name: payload.issue.title,
notes: `${payload.issue.body}\n\nLink to issue: ${payload.issue.url}`,
workspace: "1208126540134411",
projects: "1208128739940832",
id: payload.issue.url,
due_on: "2024-09-01",
assignee: "me",
},
};
let opts = {
opt_fields: "name,id,notes,assignee,assignee.name",
};
tasksApiInstance.createTask(body, opts).then(
(result) => {
console.log(
"API called successfully. Returned data: " +
JSON.stringify(result.data, null, 2)
);
},
(error) => {
console.error(error.response.body);
}
);
}
} catch (err) {
console.log(err);
}
});
Create a Validation Middleware (validateWebhookPayload.js
):
require("dotenv").config();
const crypto = require("crypto");
const sigHeaderName = "X-Hub-Signature-256";
const sigHashAlg = "sha256";
function validateWebhookPayload(req, res, next) {
if (req.method === "POST") {
if (!req.rawBody) {
return next("Request body empty");
}
const secret = process.env.PAYLOAD_VALIDATION_SECRET;
const sig = Buffer.from(req.get(sigHeaderName) || "", "utf8");
const hmac = crypto.createHmac(sigHashAlg, secret);
const digest = Buffer.from(
sigHashAlg + "=" + hmac.update(req.rawBody).digest("hex"),
"utf8"
);
if (sig.length !== digest.length || !crypto.timingSafeEqual(digest, sig)) {
return next(
`Request body digest (${digest}) did not match ${sigHeaderName} (${sig})`
);
}
}
return next();
}
module.exports = validateWebhookPayload;
Create a .env
File:
ASANA_ACCESS_TOKEN=your_asana_access_token
PAYLOAD_VALIDATION_SECRET=your_github_webhook_secret
Navigate to Your GitHub Repository:
Add a Webhook:
http://webhook-integration-828.localtunnel.me/new-issue
).application/json
.PAYLOAD_VALIDATION_SECRET
from your .env
file.Save the Webhook.
Create or Reopen an Issue:
Verify Task Creation:
Monitor Server Logs:
Handle Errors:
This README provides comprehensive instructions for setting up and configuring the GitHub to Asana integration, including details about the validation middleware. Let me know if there are any more details you’d like to include!