Skip to content

Create GitHub Discussions #12

Create GitHub Discussions

Create GitHub Discussions #12

name: Create GitHub Discussions
on:
pull_request:
types: [opened]
paths:
- 'src/content/apps/**'
workflow_dispatch:
inputs:
createForExisting:
description: 'Create discussions for existing apps'
required: true
default: 'true'
type: boolean
jobs:
create-discussion:
runs-on: ubuntu-latest
permissions:
discussions: write
pull-requests: read
contents: read
steps:
- uses: actions/checkout@v4
- name: Create Discussion for PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const { data: categories } = await github.rest.repos.listDiscussionCategories({
owner: context.repo.owner,
repo: context.repo.repo
});
let category = categories.find(c => c.name === "app-votes");
if (!category) {
const { data: newCategory } = await github.rest.repos.createDiscussionCategory({
owner: context.repo.owner,
repo: context.repo.repo,
name: "app-votes",
description: "Vote for community apps",
format: "discussion"
});
category = newCategory;
}
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
const appFiles = files.filter(file =>
file.status === 'added' &&
file.filename.startsWith('src/content/apps/') &&
!file.filename.endsWith('_template.md')
);
for (const file of appFiles) {
const content = Buffer.from((await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: file.filename,
ref: context.payload.pull_request.head.sha
})).data.content, 'base64').toString();
const frontmatterMatch = content.match(/---\n([\s\S]*?)\n---/);
if (!frontmatterMatch) continue;
const frontmatter = frontmatterMatch[1];
const appData = {};
frontmatter.split('\n').forEach(line => {
const match = line.match(/^(\w+):\s*(?:"([^"]*)"|'([^']*)'|([^"'\s].*))\s*$/);
if (match) {
appData[match[1]] = match[2] || match[3] || match[4];
}
});
try {
if (!appData.name || !appData.author) {
console.log(`Skipping file ${file.filename || file.path}: Missing required fields in frontmatter`);
continue;
}
const query = `query($searchQuery: String!) {
search(query: $searchQuery, type: DISCUSSION, first: 10) {
nodes {
... on Discussion {
title
}
}
}
}`;
const searchResult = await github.graphql(query, {
searchQuery: `repo:${context.repo.owner}/${context.repo.repo} "${appData.name} by ${appData.author}" in:title`
});
const existingDiscussion = searchResult.search.nodes.find(node =>
node.title === `Vote: ${appData.name} by ${appData.author}`
);
if (!existingDiscussion) {
await github.rest.discussions.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Vote: ${appData.name} by ${appData.author}`,
body: `🗳️ **Vote for this app by giving it a 👍 reaction!**\n\n${appData.description}`,
category_id: category.id
});
console.log(`Created discussion for ${appData.name}`);
} else {
console.log(`Discussion already exists for ${appData.name}`);
}
} catch (error) {
console.error(`Error processing ${file.filename || file.path}:`, error);
continue;
}
}
- name: Create Discussions for Existing Apps
if: github.event_name == 'workflow_dispatch' && github.event.inputs.createForExisting == 'true'
uses: actions/github-script@v7
with:
script: |
const { data: categories } = await github.rest.repos.listDiscussionCategories({
owner: context.repo.owner,
repo: context.repo.repo
});
let category = categories.find(c => c.name === "app-votes");
if (!category) {
const { data: newCategory } = await github.rest.repos.createDiscussionCategory({
owner: context.repo.owner,
repo: context.repo.repo,
name: "app-votes",
description: "Vote for community apps",
format: "discussion"
});
category = newCategory;
}
const { data: contents } = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: 'src/content/apps'
});
for (const file of contents) {
if (file.type !== 'file' || file.name.endsWith('_template.md')) continue;
const content = Buffer.from((await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: file.path
})).data.content, 'base64').toString();
const frontmatterMatch = content.match(/---\n([\s\S]*?)\n---/);
if (!frontmatterMatch) continue;
const frontmatter = frontmatterMatch[1];
const appData = {};
frontmatter.split('\n').forEach(line => {
const match = line.match(/^(\w+):\s*(?:"([^"]*)"|'([^']*)'|([^"'\s].*))\s*$/);
if (match) {
appData[match[1]] = match[2] || match[3] || match[4];
}
});
try {
if (!appData.name || !appData.author) {
console.log(`Skipping file ${file.filename || file.path}: Missing required fields in frontmatter`);
continue;
}
const query = `query($searchQuery: String!) {
search(query: $searchQuery, type: DISCUSSION, first: 10) {
nodes {
... on Discussion {
title
}
}
}
}`;
const searchResult = await github.graphql(query, {
searchQuery: `repo:${context.repo.owner}/${context.repo.repo} "${appData.name} by ${appData.author}" in:title`
});
const existingDiscussion = searchResult.search.nodes.find(node =>
node.title === `Vote: ${appData.name} by ${appData.author}`
);
if (!existingDiscussion) {
await github.rest.discussions.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Vote: ${appData.name} by ${appData.author}`,
body: `🗳️ **Vote for this app by giving it a 👍 reaction!**\n\n${appData.description}`,
category_id: category.id
});
console.log(`Created discussion for ${appData.name}`);
} else {
console.log(`Discussion already exists for ${appData.name}`);
}
} catch (error) {
console.error(`Error processing ${file.filename || file.path}:`, error);
continue;
}
}