-
-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add asyncapi events scheduling automation (#308)
- Loading branch information
Showing
32 changed files
with
2,989 additions
and
241 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }}'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
155
.github/workflows/create-event-helpers/calendar/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
75
.github/workflows/create-event-helpers/issues_templates/ad-hoc.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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._ |
Oops, something went wrong.