Skip to content

Commit

Permalink
feat: add asyncapi events scheduling automation (#308)
Browse files Browse the repository at this point in the history
  • Loading branch information
derberg authored Apr 20, 2022
1 parent ab6dd11 commit 7536466
Show file tree
Hide file tree
Showing 32 changed files with 2,989 additions and 241 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/cancel-event.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Cancel event when issue was closed before it took place

on:
issues:
types:
- closed

jobs:

cancel_event:
env:
CALENDAR_ID: ${{ secrets.CALENDAR_ID }}
CALENDAR_SERVICE_ACCOUNT: ${{ secrets.CALENDAR_SERVICE_ACCOUNT }}
name: Remove event from calendar
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 16
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Install deps
run: npm install
working-directory: ./.github/workflows/create-event-helpers
- name: Remove Google Calendar entry
uses: actions/github-script@v4
with:
script: |
const { deleteEvent } = require('./.github/workflows/create-event-helpers/calendar/index.js');
deleteEvent('${{ github.event.issue.number }}', '${{ github.event.issue.closed_at }}');
39 changes: 39 additions & 0 deletions .github/workflows/create-event-ad-hoc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Schedule Ad Hoc Meeting

on:
workflow_dispatch:
inputs:
time:
description: 'Info about meeting hour in UTC time zone, like: 08 or 16. No PM or AM versions.'
required: true
date:
description: 'Date in a form like: 2022-04-05 where 04 is a month and 05 is a day number.'
required: true
name:
description: 'Provide short title for the meeting.'
required: true
desc:
description: 'Provide description that explains the purpose of the meeting'
required: true

jobs:

setup-ad-hoc:
uses: ./.github/workflows/create-event-workflow-reusable.yml
with:
time: ${{ github.event.inputs.time }}
date: ${{ github.event.inputs.date }}
meeting_name: ${{ github.event.inputs.name }}
meeting_desc: ${{ github.event.inputs.desc }}
host: lpgornicki@gmail.com
alternative_host: fmvilas@gmail.com
issue_template_path: .github/workflows/create-event-helpers/issues_templates/ad-hoc.md
create_zoom: true
secrets:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
ZOOM_API_KEY: ${{ secrets.ZOOM_API_KEY }}
ZOOM_API_SECRET: ${{ secrets.ZOOM_API_SECRET }}
STREAM_URL: ${{ secrets.STREAM_URL }}
STREAM_KEY: ${{ secrets.STREAM_KEY }}
CALENDAR_ID: ${{ secrets.CALENDAR_ID }}
CALENDAR_SERVICE_ACCOUNT: ${{ secrets.CALENDAR_SERVICE_ACCOUNT }}
33 changes: 33 additions & 0 deletions .github/workflows/create-event-community-meeting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Schedule Community Meeting

on:
workflow_dispatch:
inputs:
time:
description: 'Info about meeting hour in UTC time zone, like: 08 or 16. No PM or AM versions.'
required: true
date:
description: 'Date in a form like: 2022-04-05 where 04 is a month and 05 is a day number.'
required: true

jobs:

setup-community-meeting:
uses: ./.github/workflows/create-event-workflow-reusable.yml
with:
time: ${{ github.event.inputs.time }}
date: ${{ github.event.inputs.date }}
meeting_name: Community Meeting
meeting_desc: This is a community meeting to regularly talk in open about important topics around AsyncAPI Initiative.
host: lpgornicki@gmail.com
alternative_host: fmvilas@gmail.com
issue_template_path: .github/workflows/create-event-helpers/issues_templates/community.md
create_zoom: true
secrets:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
ZOOM_API_KEY: ${{ secrets.ZOOM_API_KEY }}
ZOOM_API_SECRET: ${{ secrets.ZOOM_API_SECRET }}
STREAM_URL: ${{ secrets.STREAM_URL }}
STREAM_KEY: ${{ secrets.STREAM_KEY }}
CALENDAR_ID: ${{ secrets.CALENDAR_ID }}
CALENDAR_SERVICE_ACCOUNT: ${{ secrets.CALENDAR_SERVICE_ACCOUNT }}
155 changes: 155 additions & 0 deletions .github/workflows/create-event-helpers/calendar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
const { google } = require('googleapis')
const core = require('@actions/core');

module.exports = { addEvent, deleteEvent, listEvents }

const auth = new google.auth.GoogleAuth({
scopes: ['https://www.googleapis.com/auth/calendar'],
credentials: JSON.parse(process.env.CALENDAR_SERVICE_ACCOUNT)
});

const calendar = google.calendar({ version: 'v3', auth });

/**
* Adds new single-occuring event
* All events are being linked to their GitHub issues
* @param {String} zoomUrl Zoom url of the meeting
* @param {String} startDate ex. 2022-04-05
* @param {String} startTime ex. 08 or 16
* @param {Number} issueNumber GitHub issue number of the event, to find event later
*/
async function addEvent(zoomUrl, startDate, startTime, issueNumber) {

const communityIssuesUrl = 'https://github.com/asyncapi/community/issues/';
const title = process.env.MEETING_NAME;
const suffix = process.env.MEETING_NAME_SUFFIX;
const description = process.env.MEETING_DESC;
const guest = process.env.GUEST;
const summary = suffix ? `${title} ${suffix}` : title;

try {

//helper to create end time which is always 1h later
const getEndTime = (startTime) => {
const time = Number(startTime);
if (time < 10) return '0' + (time + 1)

return (time + 1) + ''
}

//helper to build meeting description
//there is a use case that meeting has no connection over zoom available as it is pure live stream
const getDescription = (description, communityIssuesUrl, issueNumber, zoomUrl, guest) => {

const zoomDetails = zoomUrl && `<b>Zoom</b>: <a href="${zoomUrl}">Meeting Link</a>`;
const agendaDetails = `<b>Agenda and more options to join the meeting</b>: <a href="${communityIssuesUrl}${issueNumber}">GitHub Issue Link.</a>`;
const guestDetails = guest ? `<b>Special guest</b>: ${ guest }` : '';
return `${ description }<br><br>${ zoomDetails }<br><br>${ agendaDetails }<br><br>${ guestDetails }`
};

await calendar.events.insert({
calendarId: process.env.CALENDAR_ID,
requestBody: {
summary,
description: getDescription(description, communityIssuesUrl, issueNumber, zoomUrl, guest),
start: {
dateTime: `${ startDate }T${ startTime }:00:00Z`
},
end: {
dateTime: `${ startDate }T${ getEndTime(startTime) }:00:00Z`
},
location: zoomUrl,
extendedProperties: {
private: {
'ISSUE_ID': `${issueNumber}`
}
}
}
})

core.info('Event created')
} catch (error) {
core.setFailed(`Faild creating event in Google Calendar: ${ JSON.stringify(error) }`)
}
}

/**
* Deletes a single-occuring event from issue number
* @param {Number} issueNumber GitHub issue number of the meeting to delete
* @param {Number} closeDate Date when issue was closed
*/
async function deleteEvent(issueNumber, closeDate) {
let events

try {
events = (await calendar.events.list({
calendarId: process.env.CALENDAR_ID,
privateExtendedProperty: `ISSUE_ID=${issueNumber}`
})).data;
} catch (error) {
return core.setFailed(`Failed to fetch events for issue numer ${ issueNumber }: ${ JSON.stringify(error) }`)
}

const eventsItems = events.items;

if (eventsItems.length > 0) {

const meetingId = eventsItems[0].id;
const eventStartDate = new Date(eventsItems[0].start.dateTime);
const issueCloseDate = new Date(closeDate);

try {
//in case of issue was closed after the event, we do not remove it from calendar
if (eventStartDate.getTime() < issueCloseDate.getTime()) return core.info('Event not removed as related issue was closed after the event took place.');

await calendar.events.delete({
calendarId: process.env.CALENDAR_ID,
eventId: meetingId
})

core.info('Event deleted from calendar')
} catch (error) {
core.setFailed(`Failed to delete event for issue number ${ issueNumber }: ${ JSON.stringify(error) }`)
}
} else {
core.info('Event not found in calendar')
}
}

/**
* Lists all events including single-occuring and recurring
*/
async function listEvents() {

let eventsItems;

try {
//this runs always on friday midnight
const currentTime = new Date(Date.now()).toISOString();
//we check moday
const timeIn2Days = new Date(Date.parse(currentTime) + 2 * 24 * 60 * 60 * 1000).toISOString();
//till friday
const timeIn8Days = new Date(Date.parse(currentTime) + 8 * 24 * 60 * 60 * 1000).toISOString();

const eventsList = await calendar.events.list({
calendarId: process.env.CALENDAR_ID,
timeMax: timeIn8Days,
timeMin: timeIn2Days
})

eventsItems = eventsList.data.items.map((e) => {
return {
title: e.summary,
issueId: e.extendedProperties.private.ISSUE_ID,
date: new Date(e.start.dateTime).toUTCString()
}
})

core.info(`List of all events: ${ JSON.stringify(eventsList.data, null, 4) }`)
} catch (error) {
return core.setFailed(`Faild fetching events from Google Calendar API: ${ JSON.stringify(error) }`)
}

return eventsItems;

}
75 changes: 75 additions & 0 deletions .github/workflows/create-event-helpers/issues_templates/ad-hoc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: "{{ env.MEETING_NAME }}, {{ env.FULL_DATE | date('H:mm [UTC] dddd MMMM Do YYYY') }}"
---

<table>
<tr>
<th>Meeting Info</th>
<th>Details</th>
</tr>
<tr>
<td>Purpose</td>
<td>{{ env.MEETING_DESC }}</td>
</tr>
<tr>
<td>Time</td>
<td><strong>{{ env.FULL_DATE | date('H') }}:00 UTC</strong> | Translate to your time zone with the <a href="https://dateful.com/convert/coordinated-universal-time-utc?t={{ env.FULL_DATE | date('kk') }}&d={{ env.DATE_ONLY }}">time zone converter</a>.</td>
</tr>
<tr>
<th>Meeting Place</th>
<th>Link</th>
</tr>
<tr>
<td>Zoom</td>
<td><a href="{{ env.ZOOM_LINK }}">Join live</a>.</td>
</tr>
<tr>
<td>YouTube</td>
<td><a href="https://www.youtube.com/asyncapi">Watch live and interact through live chat</a>.</td>
</tr>
<tr>
<td>Twitch</td>
<td><a href="https://www.twitch.tv/asyncapi">Watch live</a>.</td>
</tr>
<tr>
<td>Twitter</td>
<td><a href="https://twitter.com/AsyncAPISpec">Watch live</a>.</td>
</tr>
<tr>
<td>LinkedIn</td>
<td><a href="https://www.linkedin.com/company/asyncapi">Watch live</a>.</td>
</tr>
<tr>
<th>More Info</th>
<th>Details</th>
</tr>
<tr>
<td>Meeting Recordings</td>
<td><a href="https://www.youtube.com/asyncapi">YouTube Playlist</a>.</td>
</tr>
<tr>
<td>AsyncAPI Initiative Calendar</td>
<td><a href="https://calendar.google.com/calendar/embed?src=c_q9tseiglomdsj6njuhvbpts11c%40group.calendar.google.com&ctz=UTC">Public URL</a>.</td>
</tr>
<tr>
<td>iCal File</td>
<td><a href="https://calendar.google.com/calendar/ical/c_q9tseiglomdsj6njuhvbpts11c%40group.calendar.google.com/public/basic.ics">Add to your calendar</a>.</td>
</tr>
<tr>
<td>Newsletter</td>
<td><a href="https://www.asyncapi.com/newsletter">Subscribe to get weekly updates on upcoming meetings</a>.</td>
</tr>
</table>


## Agenda

> Don't wait for the meeting to discuss topics that already have issues. Feel free to comment on them earlier.
1. Q&A
1. _Place for your topic_
1. Q&A

## Notes

_Add notes here after the meeting._
Loading

0 comments on commit 7536466

Please sign in to comment.