[pull] main from Stirling-Tools:main #298
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: Check Properties Files on PR | |
| on: | |
| pull_request_target: | |
| types: [opened, synchronize, reopened] | |
| paths: | |
| - "app/core/src/main/resources/messages_*.properties" | |
| branches: | |
| - main | |
| # cancel in-progress jobs if a new job is triggered | |
| # This is useful to avoid running multiple builds for the same branch if a new commit is pushed | |
| # or a pull request is updated. | |
| # It helps to save resources and time by ensuring that only the latest commit is built and tested | |
| # This is particularly useful for long-running jobs that may take a while to complete. | |
| # The `group` is set to a combination of the workflow name, event name, and branch name. | |
| # This ensures that jobs are grouped by the workflow and branch, allowing for cancellation of | |
| # in-progress jobs when a new commit is pushed to the same branch or a new pull request is opened. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref_name || github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read # Allow read access to repository content | |
| jobs: | |
| check-files: | |
| if: github.event_name == 'pull_request_target' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write # Allow posting comments on issues/PRs | |
| pull-requests: write # Allow writing to pull requests | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout main branch first | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - name: Setup GitHub App Bot | |
| id: setup-bot | |
| uses: ./.github/actions/setup-bot | |
| with: | |
| app-id: ${{ secrets.GH_APP_ID }} | |
| private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} | |
| - name: Get PR data | |
| id: get-pr-data | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| with: | |
| github-token: ${{ steps.setup-bot.outputs.token }} | |
| script: | | |
| const prNumber = context.payload.pull_request.number; | |
| const repoOwner = context.payload.repository.owner.login; | |
| const repoName = context.payload.repository.name; | |
| const branch = context.payload.pull_request.head.ref; | |
| console.log(`PR Number: ${prNumber}`); | |
| console.log(`Repo Owner: ${repoOwner}`); | |
| console.log(`Repo Name: ${repoName}`); | |
| console.log(`Branch: ${branch}`); | |
| core.setOutput("pr_number", prNumber); | |
| core.setOutput("repo_owner", repoOwner); | |
| core.setOutput("repo_name", repoName); | |
| core.setOutput("branch", branch); | |
| continue-on-error: true | |
| - name: Fetch PR changed files | |
| id: fetch-pr-changes | |
| env: | |
| GH_TOKEN: ${{ steps.setup-bot.outputs.token }} | |
| run: | | |
| echo "Fetching PR changed files..." | |
| echo "Getting list of changed files from PR..." | |
| # Check if PR number exists | |
| if [ -z "${{ steps.get-pr-data.outputs.pr_number }}" ]; then | |
| echo "Error: PR number is empty" | |
| exit 1 | |
| fi | |
| # Get changed files and filter for properties files, handle case where no matches are found | |
| gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^app/core/src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$' > changed_files.txt || echo "No matching properties files found in PR" | |
| # Check if any files were found | |
| if [ ! -s changed_files.txt ]; then | |
| echo "No properties files changed in this PR" | |
| echo "Workflow will exit early as no relevant files to check" | |
| exit 0 | |
| fi | |
| echo "Found $(wc -l < changed_files.txt) matching properties files" | |
| - name: Determine reference file test | |
| id: determine-file | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| with: | |
| github-token: ${{ steps.setup-bot.outputs.token }} | |
| script: | | |
| const fs = require("fs"); | |
| const path = require("path"); | |
| const prNumber = ${{ steps.get-pr-data.outputs.pr_number }}; | |
| const repoOwner = "${{ steps.get-pr-data.outputs.repo_owner }}"; | |
| const repoName = "${{ steps.get-pr-data.outputs.repo_name }}"; | |
| const prRepoOwner = "${{ github.event.pull_request.head.repo.owner.login }}"; | |
| const prRepoName = "${{ github.event.pull_request.head.repo.name }}"; | |
| const branch = "${{ steps.get-pr-data.outputs.branch }}"; | |
| console.log(`Determining reference file for PR #${prNumber}`); | |
| // Validate inputs | |
| const validateInput = (input, regex, name) => { | |
| if (!regex.test(input)) { | |
| throw new Error(`Invalid ${name}: ${input}`); | |
| } | |
| }; | |
| validateInput(repoOwner, /^[a-zA-Z0-9_-]+$/, "repository owner"); | |
| validateInput(repoName, /^[a-zA-Z0-9._-]+$/, "repository name"); | |
| validateInput(branch, /^[a-zA-Z0-9._/-]+$/, "branch name"); | |
| // Get the list of changed files in the PR | |
| const { data: files } = await github.rest.pulls.listFiles({ | |
| owner: repoOwner, | |
| repo: repoName, | |
| pull_number: prNumber, | |
| }); | |
| // Filter for relevant files based on the PR changes | |
| const changedFiles = files | |
| .filter(file => | |
| file.status !== "removed" && | |
| /^app\/core\/src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file.filename) | |
| ) | |
| .map(file => file.filename); | |
| console.log("Changed files:", changedFiles); | |
| // Create a temporary directory for PR files | |
| const tempDir = "pr-branch"; | |
| if (!fs.existsSync(tempDir)) { | |
| fs.mkdirSync(tempDir, { recursive: true }); | |
| } | |
| // Download and save each changed file | |
| for (const file of changedFiles) { | |
| const { data: fileContent } = await github.rest.repos.getContent({ | |
| owner: prRepoOwner, | |
| repo: prRepoName, | |
| path: file, | |
| ref: branch, | |
| }); | |
| const content = Buffer.from(fileContent.content, "base64").toString("utf-8"); | |
| const filePath = path.join(tempDir, file); | |
| const dirPath = path.dirname(filePath); | |
| if (!fs.existsSync(dirPath)) { | |
| fs.mkdirSync(dirPath, { recursive: true }); | |
| } | |
| fs.writeFileSync(filePath, content); | |
| console.log(`Saved file: ${filePath}`); | |
| } | |
| // Output the list of changed files for further processing | |
| const fileList = changedFiles.join(" "); | |
| core.exportVariable("FILES_LIST", fileList); | |
| console.log("Files saved and listed in FILES_LIST."); | |
| // Determine reference file | |
| let referenceFilePath; | |
| if (changedFiles.includes("app/core/src/main/resources/messages_en_GB.properties")) { | |
| console.log("Using PR branch reference file."); | |
| const { data: fileContent } = await github.rest.repos.getContent({ | |
| owner: prRepoOwner, | |
| repo: prRepoName, | |
| path: "app/core/src/main/resources/messages_en_GB.properties", | |
| ref: branch, | |
| }); | |
| referenceFilePath = "pr-branch-messages_en_GB.properties"; | |
| const content = Buffer.from(fileContent.content, "base64").toString("utf-8"); | |
| fs.writeFileSync(referenceFilePath, content); | |
| } else { | |
| console.log("Using main branch reference file."); | |
| const { data: fileContent } = await github.rest.repos.getContent({ | |
| owner: repoOwner, | |
| repo: repoName, | |
| path: "app/core/src/main/resources/messages_en_GB.properties", | |
| ref: "main", | |
| }); | |
| referenceFilePath = "main-branch-messages_en_GB.properties"; | |
| const content = Buffer.from(fileContent.content, "base64").toString("utf-8"); | |
| fs.writeFileSync(referenceFilePath, content); | |
| } | |
| console.log(`Reference file path: ${referenceFilePath}`); | |
| core.exportVariable("REFERENCE_FILE", referenceFilePath); | |
| - name: Run Python script to check files | |
| id: run-check | |
| run: | | |
| echo "Running Python script to check files..." | |
| python .github/scripts/check_language_properties.py \ | |
| --actor ${{ github.event.pull_request.user.login }} \ | |
| --reference-file "${REFERENCE_FILE}" \ | |
| --branch "pr-branch" \ | |
| --files "${FILES_LIST[@]}" > result.txt | |
| continue-on-error: true # Continue the job even if this step fails | |
| - name: Capture output | |
| id: capture-output | |
| run: | | |
| if [ -f result.txt ] && [ -s result.txt ]; then | |
| echo "Test, capturing output..." | |
| SCRIPT_OUTPUT=$(cat result.txt) | |
| echo "SCRIPT_OUTPUT<<EOF" >> $GITHUB_ENV | |
| echo "$SCRIPT_OUTPUT" >> $GITHUB_ENV | |
| echo "EOF" >> $GITHUB_ENV | |
| echo "${SCRIPT_OUTPUT}" | |
| # Determine job failure based on script output | |
| if [[ "$SCRIPT_OUTPUT" == *"❌"* ]]; then | |
| echo "FAIL_JOB=true" >> $GITHUB_ENV | |
| else | |
| echo "FAIL_JOB=false" >> $GITHUB_ENV | |
| fi | |
| else | |
| echo "No update found." | |
| echo "SCRIPT_OUTPUT=" >> $GITHUB_ENV | |
| echo "FAIL_JOB=false" >> $GITHUB_ENV | |
| fi | |
| - name: Post comment on PR | |
| if: env.SCRIPT_OUTPUT != '' | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| with: | |
| github-token: ${{ steps.setup-bot.outputs.token }} | |
| script: | | |
| const { GITHUB_REPOSITORY, SCRIPT_OUTPUT } = process.env; | |
| const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/'); | |
| const issueNumber = context.issue.number; | |
| // Find existing comment | |
| const comments = await github.rest.issues.listComments({ | |
| owner: repoOwner, | |
| repo: repoName, | |
| issue_number: issueNumber | |
| }); | |
| const comment = comments.data.find(c => c.body.includes("## 🚀 Translation Verification Summary")); | |
| // Only update or create comments by the action user | |
| const expectedActor = "${{ steps.setup-bot.outputs.app-slug }}[bot]"; | |
| if (comment && comment.user.login === expectedActor) { | |
| // Update existing comment | |
| await github.rest.issues.updateComment({ | |
| owner: repoOwner, | |
| repo: repoName, | |
| comment_id: comment.id, | |
| body: `## 🚀 Translation Verification Summary\n\n\n${SCRIPT_OUTPUT}\n` | |
| }); | |
| console.log("Updated existing comment."); | |
| } else if (!comment) { | |
| // Create new comment if no existing comment is found | |
| await github.rest.issues.createComment({ | |
| owner: repoOwner, | |
| repo: repoName, | |
| issue_number: issueNumber, | |
| body: `## 🚀 Translation Verification Summary\n\n\n${SCRIPT_OUTPUT}\n` | |
| }); | |
| console.log("Created new comment."); | |
| } else { | |
| console.log("Comment update attempt denied. Actor does not match."); | |
| } | |
| - name: Fail job if errors found | |
| if: env.FAIL_JOB == 'true' | |
| run: | | |
| echo "Failing the job because errors were detected." | |
| exit 1 | |
| - name: Cleanup temporary files | |
| if: always() | |
| run: | | |
| echo "Cleaning up temporary files..." | |
| rm -rf pr-branch | |
| rm -f pr-branch-messages_en_GB.properties main-branch-messages_en_GB.properties changed_files.txt result.txt | |
| echo "Cleanup complete." | |
| continue-on-error: true # Ensure cleanup runs even if previous steps fail |