-
-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
48946f4
commit fc53116
Showing
5 changed files
with
310 additions
and
1 deletion.
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,218 @@ | ||
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 fs = require('fs'); | ||
const path = require('path'); | ||
async function ensureDiscussionCategory() { | ||
// Get all discussion categories | ||
const { data: categories } = await github.rest.discussions.listRepoCategories({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo | ||
}); | ||
// Look for "App Voting" category | ||
let category = categories.find(c => c.name === "App Voting"); | ||
// Create category if it doesn't exist | ||
if (!category) { | ||
const { data: newCategory } = await github.rest.discussions.createRepoCategory({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
name: "App Voting", | ||
description: "Vote for community apps", | ||
format: "discussion" | ||
}); | ||
category = newCategory; | ||
} | ||
return category.id; | ||
} | ||
async function createDiscussion(content) { | ||
// Parse the frontmatter manually | ||
const frontmatterMatch = content.match(/---\n([\s\S]*?)\n---/); | ||
if (!frontmatterMatch) return; | ||
const frontmatter = frontmatterMatch[1]; | ||
// Parse the simple YAML format manually | ||
const appData = {}; | ||
frontmatter.split('\n').forEach(line => { | ||
const match = line.match(/^(\w+):\s*"?([^"]*)"?$/); | ||
if (match) { | ||
appData[match[1]] = match[2]; | ||
} | ||
}); | ||
if (!appData.name || !appData.author) { | ||
console.log('Missing required fields in frontmatter'); | ||
return; | ||
} | ||
// Check if discussion already exists - FIXED API CALL | ||
const { data: existingDiscussions } = await github.rest.search.discussionsQuery({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
query: `repo:${context.repo.owner}/${context.repo.repo} "${appData.name} by ${appData.author}" in:title` | ||
}); | ||
const existingDiscussion = existingDiscussions.items?.find(d => | ||
d.title === `Vote: ${appData.name} by ${appData.author}` | ||
); | ||
const categoryId = await ensureDiscussionCategory(); | ||
if (!existingDiscussion) { | ||
// Create a discussion - FIXED API CALL | ||
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: categoryId | ||
}); | ||
console.log(`Created discussion for ${appData.name}`); | ||
} else { | ||
console.log(`Discussion already exists for ${appData.name}`); | ||
} | ||
} | ||
// Get the changed files from the PR | ||
const { data: files } = await github.rest.pulls.listFiles({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
pull_number: context.issue.number | ||
}); | ||
// Find new app submissions | ||
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(); | ||
await createDiscussion(content); | ||
} | ||
- name: Create Discussions for Existing Apps | ||
if: github.event_name == 'workflow_dispatch' && inputs.createForExisting | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
async function ensureDiscussionCategory() { | ||
const { data: categories } = await github.rest.discussions.listRepoCategories({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo | ||
}); | ||
let category = categories.find(c => c.name === "App Voting"); | ||
if (!category) { | ||
const { data: newCategory } = await github.rest.discussions.createRepoCategory({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
name: "App Voting", | ||
description: "Vote for community apps", | ||
format: "discussion" | ||
}); | ||
category = newCategory; | ||
} | ||
return category.id; | ||
} | ||
async function createDiscussion(content) { | ||
// Parse the frontmatter manually | ||
const frontmatterMatch = content.match(/---\n([\s\S]*?)\n---/); | ||
if (!frontmatterMatch) return; | ||
const frontmatter = frontmatterMatch[1]; | ||
// Parse the simple YAML format manually | ||
const appData = {}; | ||
frontmatter.split('\n').forEach(line => { | ||
const match = line.match(/^(\w+):\s*"?([^"]*)"?$/); | ||
if (match) { | ||
appData[match[1]] = match[2]; | ||
} | ||
}); | ||
if (!appData.name || !appData.author) { | ||
console.log('Missing required fields in frontmatter'); | ||
return; | ||
} | ||
// Check if discussion already exists - FIXED API CALL | ||
const { data: existingDiscussions } = await github.rest.search.discussionsQuery({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
query: `repo:${context.repo.owner}/${context.repo.repo} "${appData.name} by ${appData.author}" in:title` | ||
}); | ||
const existingDiscussion = existingDiscussions.items?.find(d => | ||
d.title === `Vote: ${appData.name} by ${appData.author}` | ||
); | ||
const categoryId = await ensureDiscussionCategory(); | ||
if (!existingDiscussion) { | ||
// Create a discussion - FIXED API CALL | ||
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: categoryId | ||
}); | ||
console.log(`Created discussion for ${appData.name}`); | ||
} else { | ||
console.log(`Discussion already exists for ${appData.name}`); | ||
} | ||
} | ||
// Get all existing app files | ||
const appsDir = 'src/content/apps'; | ||
const files = fs.readdirSync(appsDir) | ||
.filter(file => file.endsWith('.md') && file !== '_template.md'); | ||
for (const file of files) { | ||
const content = fs.readFileSync(path.join(appsDir, file), 'utf8'); | ||
await createDiscussion(content); | ||
} |
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,59 @@ | ||
name: Update Vote Counts | ||
|
||
on: | ||
schedule: | ||
- cron: '0 */6 * * *' # Run every 6 hours | ||
workflow_dispatch: # Allow manual triggers | ||
|
||
jobs: | ||
update-votes: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
contents: write | ||
discussions: read | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Update Vote Counts | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
const fs = require('fs').promises; | ||
const path = require('path'); | ||
const yaml = require('js-yaml'); | ||
// Get all discussions in the Flutter of the Year category | ||
const discussions = await github.paginate(github.rest.discussions.listForRepo, { | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
category_id: process.env.DISCUSSION_CATEGORY_ID | ||
}); | ||
// Create votes.json with the current vote counts | ||
const votes = {}; | ||
for (const discussion of discussions) { | ||
if (discussion.title.startsWith('Vote: ')) { | ||
const appName = discussion.title.replace('Vote: ', '').split(' by ')[0]; | ||
// Count thumbs up reactions | ||
const reactions = await github.rest.reactions.listForDiscussion({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
discussion_number: discussion.number | ||
}); | ||
votes[appName] = reactions.data.filter(r => r.content === '+1').length; | ||
} | ||
} | ||
// Write the votes to a JSON file | ||
await fs.writeFile( | ||
'src/data/votes.json', | ||
JSON.stringify(votes, null, 2) | ||
); | ||
// Commit and push the changes | ||
const date = new Date().toISOString(); | ||
await exec.exec('git', ['config', 'user.name', 'github-actions[bot]']); | ||
await exec.exec('git', ['config', 'user.email', 'github-actions[bot]@users.noreply.github.com']); | ||
await exec.exec('git', ['add', 'src/data/votes.json']); | ||
await exec.exec('git', ['commit', '-m', `Update vote counts - ${date}`]); | ||
await exec.exec('git', ['push']); |
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 @@ | ||
{} |
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
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,15 @@ | ||
export interface VoteData { | ||
[appName: string]: number; | ||
} | ||
|
||
export function getVotes(): VoteData { | ||
try { | ||
// During build time, this file will be created by GitHub Actions | ||
// We import it as a module to get the data | ||
const votes = import.meta.glob('/src/data/votes.json', { eager: true }); | ||
return Object.values(votes)[0] as VoteData || {}; | ||
} catch (error) { | ||
console.error('Error reading votes:', error); | ||
return {}; | ||
} | ||
} |