Automatically create or update a meeting issue using .ics recurrence, timezone info, and agenda topics from the issue log and pull requests.
Meetings should be conducted the same way, with an opinion on the structure needed to support healthy and productive conversations.
Upon invocation, the action will:
- read and validate action input
- read the recurring
.ics- find the next meeting occurrence date and useful timezone info
-
⚠️ The recurrence does not know about any moved instances - read the location from the meeting, often a zoom, slack huddle, or teams link
- find all issues and pull requests labeled with the specified agenda label (default:
agenda) and add them to the upcoming meeting agenda - create an issue for the next meeting, or update the existing issue for that meeting with the latest agenda items
- output the issue url, location, and next meeting date for further use by downstream actions
- Download the
.icsassociated with the recurring meeting series. - Place the
.icsfile at the root of your repository, or specify a different path using theMEETING_PATHinput.- By default, the action will look for
meeting.icsat the root of the repo.
- By default, the action will look for
Add the action to your repo as the following:
name: Create Meeting
on:
workflow_dispatch:
schedule:
# Run every day at 12:00 UTC so the next meeting issue stays current.
- cron: "0 12 * * *"
jobs:
create-meeting:
runs-on: ubuntu-latest
concurrency:
group: create-meeting-${{ github.repository }}
cancel-in-progress: false
permissions:
contents: read
pull-requests: read
issues: write
steps:
- uses: actions/checkout@v4 # use an immutable SHA in production
- uses: target/create-meeting-issue@v1 # use an immutable SHA in production
id: create-meeting
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}| Name | Required | Default | Description |
|---|---|---|---|
GITHUB_TOKEN |
✅ | A token with pull-request read access and issues write to the repository, used to create or update the meeting issue. |
|
MEETING_PATH |
✅ | meeting.ics |
The path to the recurring meeting.ics file. |
TIMEZONES |
✅ | Etc/UTC |
The comma-separated timezones to display for the next meeting. For example, America/Chicago,Asia/Kolkata. Use TZ Identifiers from this list. |
SLACK_CHANNEL |
The slack channel to mention within the issue body. This input is not used in any workflow dispatch logic mentioned later, that is a separate process governed by a webhook originating in Slack. |
||
DRY_RUN |
false |
If true, only outputs the issue body instead of creating or updating the issue. | |
AGENDA_LABEL |
agenda |
The label used to identify agenda items to include in the meeting. | |
ORG_WIDE |
false |
If true, searches for agenda items across the entire organization instead of just the repository. |
| Name | Example | Description |
|---|---|---|
ISSUE_URL |
https://github.com/octocat/example/issues/16 |
The url of the issue created or updated. |
NEXT_MEETING_DATE |
1/15/2025 |
The next meeting date from the .ics file. |
LOCATION |
https://example.zoom.us/j/foo |
The meeting location from the .ics file. |
The daily schedule removes the need to time the workflow just before a meeting. The first run creates an issue titled for the next meeting date. Later runs for that occurrence update the same issue, so newly labeled agenda items appear without creating duplicates. The concurrency group is suggested because the action's lookup-then-create operation cannot be made atomic by the action itself; without it, overlapping scheduled and manual runs can create duplicates. After the meeting passes, the calendar advances and the action creates an issue for the next occurrence.
Run workflow directly within the Actions > Create Meeting Workflow screen.
Optionally, you can compose this action together with a messaging solution, such as slack-github-action to inform folks about the upcoming meeting and agenda.
name: Create Meeting
on:
workflow_dispatch:
schedule:
- cron: "0 12 * * *"
jobs:
create-meeting:
runs-on: ubuntu-latest
concurrency:
group: create-meeting-${{ github.repository }}
cancel-in-progress: false
permissions:
pull-requests: read
issues: write
outputs:
ISSUE_URL: ${{ steps.create-meeting.outputs.ISSUE_URL }}
LOCATION: ${{ steps.create-meeting.outputs.LOCATION }}
NEXT_MEETING_DATE: ${{ steps.create-meeting.outputs.NEXT_MEETING_DATE }}
steps:
- uses: actions/checkout@v4 # use an immutable SHA in production
- uses: target/create-meeting-issue@v1 # use an immutable SHA in production
id: create-meeting
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# this is unaffiliated boilerplate and should be tailored to your needs
# using https://github.com/slackapi/slack-github-action/tree/main?tab=readme-ov-file#technique-1-slack-workflow-builder is a pretty lightweight way to do this
notify-slack:
runs-on: ubuntu-latest
needs: create-meeting
# Avoid sending a message after every daily refresh. Run this job when the
# workflow is manually invoked, or replace this with your desired cadence.
if: github.event_name == 'workflow_dispatch'
permissions: {} # no extra permissions needed
steps:
- uses: slackapi/slack-github-action@v2.0.0 # use an immutable SHA in production
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: webhook-trigger
payload: |
issue_url: ${{ needs.create-meeting.outputs.ISSUE_URL }}
location: ${{ needs.create-meeting.outputs.LOCATION }}
next_meeting_date: ${{ needs.create-meeting.outputs.NEXT_MEETING_DATE }}Warning
GitHub may omit output like location if it thinks it contains a secret, such as a pre-authorized webinar link. If you encounter this, you can combine the steps into a single job, but it does provide more permissions to subsequent steps in the job. Consult security resources as prudent. See this GitHub discussion for status and potential workarounds.
Ensure you have the following tools:
nvm use
corepack enable
corepack install
pnpm install
pnpm dev
Run pnpm package prior to pushing new versions.
This action uses ncc to emit JavaScript - at least until:
- GH Actions support Node 22
- Node.js supports
--experimental-strip-typeswithin node_modules
If node22 is unblocked first, the action.yml line can be uncommented and TypeScript compilation can be evaluated for removal.