Skip to content

Instantly share code, notes, and snippets.

@addeeandra
Last active July 27, 2020 04:55
Show Gist options
  • Save addeeandra/1e2f2889f76ca318dfdebf2a45f2e945 to your computer and use it in GitHub Desktop.
Save addeeandra/1e2f2889f76ca318dfdebf2a45f2e945 to your computer and use it in GitHub Desktop.
Git Kanban to Airtable Basic Hooks
<?php
/**
* Host this code on a server and point your github webhooks to this file.
* it's a single directional API for Github to Airtable. It excludes the Airtable to Github.
*
* What to prepare?
* 1. Make an airtable Base,
* 2. Make a special table on airtable for Github Kanban (ex. Report),
* 3. Enable 'project' on Github to get the Kanban view,
* 4. Host the code, point the project webhooks to this code,
* 5. Make an issue in Github + sync it to the Kanban .. it'll created / updated on airtable too.
*/
const GITHUB_TOKEN = 'your github api token';
const AIR_TOKEN = 'your airtable api token';
const AIR_BASE_ID = 'your airtable Base ID';
const AIR_TABLE_ID = 'your airtable Base > Table Name'; // ex. "Report"
// the 905xxx is based on your Github Card ID (haha, map it yourself with ur own)
const COLUMN_CONFIG = [
9050828 => '',
9050825 => 'TO DO', // To Do
9050831 => 'DOING', // In Progress
9050832 => 'DONE' // Done
];
function write_log($tag, $content) {
file_put_contents('logs.txt', '['.date('Y-m-d').']['.$tag.'] '.$content.PHP_EOL , FILE_APPEND | LOCK_EX);
}
// SETUP AIRTABLE CURL
function aircurl($url, $method = 'GET', $payload = null, $json = true) {
$headers = ['Authorization: Bearer ' . AIR_TOKEN];
// HEADERS : Content-Type
if (!is_null($payload) && $json) array_push($headers, 'Content-Type: application/json');
else if (!is_null($payload) && !$json) array_push($headers, 'Content-Type: application/x-www-form-urlencoded');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// METHOD
if ($method == 'POST') curl_setopt($ch, CURLOPT_POST, 1);
if (!in_array($method, ['POST', 'GET'])) curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
// PAYLOAD
if (!is_null($payload) && $json) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
else if (!is_null($payload)) curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
// RESPONSE
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
function gitcurl($url, $method = 'GET', $payload = null, $json = true) {
$headers = [
'Authorization: token ' . GITHUB_TOKEN,
'User-Agent: GitAir-Integrator'
];
// HEADERS : Content-Type
if (!is_null($payload) && $json) array_push($headers, 'Content-Type: application/json');
else if (!is_null($payload)) array_push($headers, 'Content-Type: application/x-www-form-urlencoded');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// METHOD
if ($method == 'POST') curl_setopt($ch, CURLOPT_POST, 1);
if (!in_array($method, ['POST', 'GET'])) curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
// PAYLOAD
if (!is_null($payload) && $json) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
else if (!is_null($payload)) curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
// RESPONSE
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
// GET BACKLOG RECORDS
function get_backlog_records() {
return aircurl("https://api.airtable.com/v0/${AIR_BASE_ID}/${AIR_TABLE_ID}?view=Grid");
}
function get_backlog_record_with_code($name) {
$raw_records = get_backlog_records();
$air_payload_records = json_decode($raw_records, true);
$records = $air_payload_records['records'];
$record = null;
foreach ($records as $rec) if ($rec['fields']['GitCode'] == $name) $record = $rec;
return $record;
}
function create_backlog_record_with($git_project_card) {
if (is_null($git_project_card['note'])) {
$content = json_decode(gitcurl($git_project_card['content_url']), 1);
$name = $content['title'];
$note = $content['body'];
} else {
$name = 'NO #'.$git_project_card['id'];
$note = $git_project_card['note'];
}
$gitcode = (string) $git_project_card['id'];
$creator = $git_project_card['creator']['login'];
$author = $creator;
$status = COLUMN_CONFIG[$git_project_card['column_id']] ?: null;
return aircurl("https://api.airtable.com/v0/${AIR_BASE_ID}/${AIR_TABLE_ID}", 'POST', [
'fields' => [
'Name' => $name,
'Notes' => $note,
'Status' => $status,
'GitCode' => $gitcode,
'GitAuthor' => $author
]
]);
}
function delete_backlog_record_with($git_project_card) {
$record = get_backlog_record_with_code($git_project_card['id']);
if (is_null($record)) return;
return aircurl("https://api.airtable.com/v0/${AIR_BASE_ID}/${AIR_TABLE_ID}/" . $record['id'], 'DELETE');
}
function update_backlog_record_with($git_project_card) {
$record = get_backlog_record_with_code($git_project_card['id']);
if (is_null($record)) {
return create_backlog_record_with($git_project_card);
}
if (is_null($git_project_card['note'])) {
$response = gitcurl($git_project_card['content_url']);
write_log('GIT RESPONSE', $response);
if (is_null($response)) {
$name = 'NO #'.$git_project_card['id'];
$note = $git_project_card['note'];
} else {
$content = json_decode($response, 1);
$name = $content['title'];
$note = $content['body'];
}
} else {
$name = 'NO #'.$git_project_card['id'];
$note = $git_project_card['note'];
}
$gitcode = (string) $git_project_card['id'];
$creator = $git_project_card['creator']['login'];
$author = $creator;
$status = COLUMN_CONFIG[$git_project_card['column_id']] ?: null;
return aircurl("https://api.airtable.com/v0/${AIR_BASE_ID}/${AIR_TABLE_ID}/" . $record['id'], 'PATCH', [
'fields' => [
'Name' => $name,
'Notes' => $note,
'Status' => $status,
'GitCode' => $gitcode,
'GitAuthor' => $author
]
]);
}
// LOG PAYLOAD
write_log('INIT HOOK', '--------------------------------------------------------------------');
write_log('GIT PAYLOAD', $_POST['payload']);
$git_payload = json_decode($_POST['payload'], true);
$git_action = $git_payload['action'];
$card = $git_payload['project_card'];
write_log('ACTION', $git_action);
switch ($git_action) {
case 'created':
write_log('AIR CREATE', create_backlog_record_with($card));
break;
case 'edited':
write_log('AIR EDITED', update_backlog_record_with($card));
break;
case 'moved':
write_log('AIR MOVED', update_backlog_record_with($card));
break;
case 'deleted':
write_log('AIR DELETE', delete_backlog_record_with($card));
break;
default:
break;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment