Convert BetterFormattingRedux toolbar from manual DOM to Svelte 5 #41
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: Auto-close PRs modifying restricted files | |
| permissions: write-all | |
| on: | |
| pull_request_target: | |
| types: [opened, synchronize, reopened] | |
| jobs: | |
| check-restricted-changes: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Get list of changed files | |
| id: changed-files | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| // Get the list of changed files using GitHub API | |
| const { data: files } = await github.rest.pulls.listFiles({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.payload.pull_request.number | |
| }); | |
| const changedFiles = files.map(file => file.filename); | |
| console.log('Changed files:', changedFiles); | |
| // Check for restricted patterns | |
| let restrictedMatched = false; | |
| let matchedFiles = ''; | |
| // Define restricted patterns (customize these as needed) | |
| const restrictedPatterns = [ | |
| '*.plugin.js' | |
| ]; | |
| for (const file of changedFiles) { | |
| console.log('Checking file:', file); | |
| for (const pattern of restrictedPatterns) { | |
| // Convert glob pattern to regex | |
| const regexPattern = pattern.replace(/\*/g, '.*'); | |
| const regex = new RegExp(regexPattern + '$'); | |
| if (regex.test(file)) { | |
| console.log('File ' + file + ' matches restricted pattern: ' + pattern); | |
| restrictedMatched = true; | |
| matchedFiles += '- ' + file + ' (matches pattern: ' + pattern + ')\n'; | |
| break; | |
| } | |
| } | |
| } | |
| // Set outputs | |
| core.setOutput('restricted_matched', restrictedMatched.toString()); | |
| core.setOutput('matched_files', matchedFiles); | |
| - name: Close PR if restricted files are modified | |
| if: steps.changed-files.outputs.restricted_matched == 'true' | |
| uses: actions/github-script@v7 | |
| env: | |
| RESTRICTED_MATCHED: ${{ steps.changed-files.outputs.restricted_matched }} | |
| MATCHED_FILES: ${{ steps.changed-files.outputs.matched_files }} | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| console.log('=== DEBUG: Starting second step ==='); | |
| // Use environment variables to safely access step outputs | |
| const restrictedMatched = process.env.RESTRICTED_MATCHED === 'true'; | |
| const matchedFiles = process.env.MATCHED_FILES || ''; | |
| console.log('Restricted matched:', restrictedMatched); | |
| console.log('Matched files:', matchedFiles); | |
| const pr = context.payload.pull_request; | |
| const author = pr.user.login; | |
| console.log('=== DEBUG: Building message ==='); | |
| let message = 'π€ **Automated message** - @' + author + ' This pull request has been automatically closed because it modifies restricted files.\n\n'; | |
| message += 'π« **Restricted file patterns detected**\n\n'; | |
| message += 'The following files match restricted patterns:\n'; | |
| // Add backticks for proper markdown formatting | |
| const formattedFiles = matchedFiles.replace(/- ([^\s]+) \(matches pattern: ([^)]+)\)/g, '- `$1` (matches pattern: `$2`)'); | |
| message += formattedFiles + '\n'; | |
| message += 'These are compiled/built plugin files that are automatically generated from source code. '; | |
| message += 'Modifying these files directly is not allowed.\n\n'; | |
| message += '## How to contribute properly:\n\n'; | |
| message += '1. π Make your changes in the `src/plugins/` folder instead\n'; | |
| message += '2. π§ Use the build script to generate the plugin files: `bun run build`\n'; | |
| message += '3. π€ Submit a new pull request with only the source file changes from `src/`\n'; | |
| message += '4. β Do **NOT** include the generated files from `Plugins/` in your PR\n\n'; | |
| message += '## Additional resources:\n'; | |
| message += '- π [Contributing Guidelines](' + context.payload.repository.html_url + '/blob/master/CONTRIBUTING.md)\n'; | |
| message += '- ποΈ [Build Documentation](' + context.payload.repository.html_url + '/blob/master/README.md)\n\n'; | |
| message += 'Thank you for your interest in contributing! Please resubmit your PR following the guidelines above. π'; | |
| console.log('=== DEBUG: Message built successfully ==='); | |
| try { | |
| // First, let's check what permissions we have | |
| console.log('Checking permissions...'); | |
| console.log('PR author association:', pr.author_association); | |
| console.log('Repository owner:', context.repo.owner); | |
| console.log('PR author:', author); | |
| // Try to get current user to understand our permissions | |
| try { | |
| const { data: currentUser } = await github.rest.users.getAuthenticated(); | |
| console.log('Acting as user:', currentUser.login); | |
| console.log('User type:', currentUser.type); | |
| } catch (authError) { | |
| console.log('Failed to get authenticated user:', authError.message); | |
| } | |
| // Test what token we're actually using | |
| console.log('Using AUTO_CLOSE_TOKEN:', process.env.AUTO_CLOSE_TOKEN ? 'YES' : 'NO'); | |
| // Try a simple permission test first | |
| try { | |
| const { data: repo } = await github.rest.repos.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo | |
| }); | |
| console.log('Can read repo info: YES'); | |
| } catch (repoError) { | |
| console.log('Cannot read repo info:', repoError.message); | |
| } | |
| // Post comment explaining the closure | |
| console.log('Posting comment to PR #' + pr.number); | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| body: message | |
| }); | |
| console.log('Comment posted successfully'); | |
| // Close the pull request | |
| await github.rest.pulls.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr.number, | |
| state: 'closed' | |
| }); | |
| console.log('PR closed successfully'); | |
| // Add helpful labels | |
| const labels = ['auto-closed', 'invalid-files', 'restricted-patterns']; | |
| try { | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| labels: labels | |
| }); | |
| console.log('Labels added successfully'); | |
| } catch (error) { | |
| console.log('Note: Could not add labels. They may not exist in the repository.'); | |
| } | |
| console.log('Successfully closed PR #' + pr.number + ' due to restricted file modifications'); | |
| } catch (error) { | |
| console.log('Error details:', error.message); | |
| console.log('Error status:', error.status); | |
| console.log('PR author association:', pr.author_association); | |
| if (error.status === 403) { | |
| console.log('Permission denied - this is likely a PR from an outside contributor.'); | |
| console.log('The PR contains restricted files but cannot be auto-closed due to GitHub security restrictions.'); | |
| console.log('Repository maintainers should manually review and close this PR.'); | |
| console.log('PR #' + pr.number + ' by @' + author + ' modifies restricted files.'); | |
| console.log('Matched files:', matchedFiles); | |
| // Instead of throwing an error, let's exit gracefully with a summary | |
| console.log('SUMMARY: Auto-close blocked by permissions. Manual action required.'); | |
| core.setFailed('Manual review required: PR #' + pr.number + ' modifies restricted files but cannot be auto-closed due to GitHub permissions.'); | |
| } else { | |
| throw error; // Re-throw other errors | |
| } | |
| } |