Feature: swapwithmaster behave like DWM #108
This file contains hidden or 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
name: Close Unauthorized Issues | |
on: | |
workflow_dispatch: | |
issues: | |
types: [opened] | |
jobs: | |
close-unauthorized-issues: | |
runs-on: ubuntu-latest | |
permissions: | |
issues: write | |
steps: | |
# XXX: This *could* be done in Bash by abusing GitHub's own tool to interact with its API | |
# but that's too much of a hack, and we'll be adding a layer of abstraction. github-script | |
# is a workflow that eases interaction with GitHub API in the workflow run context. | |
- name: "Close 'unauthorized' issues" | |
uses: actions/github-script@v7 | |
with: | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
script: | | |
const ALLOWED_USERS = ['vaxerski', 'fufexan', 'NotAShelf']; | |
const CLOSING_COMMENT = 'Users are no longer allowed to open issues themselves, please open a discussion instead.\n\nPlease see the [wiki](https://wiki.hyprland.org/Contributing-and-Debugging/Issue-Guidelines/) on why this is the case.\n\nWe are volunteers, and we need your cooperation to make the best software we can. Thank you for understanding! ❤️\n\n[Open a discussion here](https://github.com/hyprwm/Hyprland/discussions)'; | |
async function closeUnauthorizedIssue(issueNumber, userName) { | |
if (ALLOWED_USERS.includes(userName)) { | |
console.log(`Issue #${issueNumber} - Created by authorized user ${userName}`); | |
return; | |
} | |
console.log(`Issue #${issueNumber} - Unauthorized, closing`); | |
await github.rest.issues.update({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: issueNumber, | |
state: 'closed', | |
state_reason: 'not_planned' | |
}); | |
await github.rest.issues.createComment({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: issueNumber, | |
body: CLOSING_COMMENT | |
}); | |
} | |
if (context.eventName === 'issues' && context.payload.action === 'opened') { | |
// Direct access to the issue that triggered the workflow | |
const issue = context.payload.issue; | |
// Skip if this is a PR | |
if (issue.pull_request) { | |
console.log(`Issue #${issue.number} - Skipping, this is a pull request`); | |
return; | |
} | |
// Process the single issue that triggered the workflow | |
await closeUnauthorizedIssue(issue.number, issue.user.login); | |
} else { | |
// For manual runs, we need to handle pagination | |
async function* fetchAllOpenIssues() { | |
let page = 1; | |
let hasNextPage = true; | |
while (hasNextPage) { | |
const response = await github.rest.issues.listForRepo({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
state: 'open', | |
per_page: 100, | |
page: page | |
}); | |
if (response.data.length === 0) { | |
hasNextPage = false; | |
} else { | |
for (const issue of response.data) { | |
yield issue; | |
} | |
page++; | |
} | |
} | |
} | |
// Process issues one by one | |
for await (const issue of fetchAllOpenIssues()) { | |
try { | |
// Skip pull requests | |
if (issue.pull_request) { | |
console.log(`Issue #${issue.number} - Skipping, this is a pull request`); | |
continue; | |
} | |
await closeUnauthorizedIssue(issue.number, issue.user.login); | |
} catch (error) { | |
console.error(`Error processing issue #${issue.number}: ${error.message}`); | |
} | |
} | |
} |