name: Validate filenames on: pull_request_target: paths: - "ct/*.sh" - "install/*.sh" - "json/*.json" jobs: check-files: name: Check changed files runs-on: ubuntu-latest permissions: pull-requests: write steps: - name: Get pull request information if: github.event_name == 'pull_request_target' uses: actions/github-script@v7 id: pr with: script: | const { data: pullRequest } = await github.rest.pulls.get({ ...context.repo, pull_number: context.payload.pull_request.number, }); return pullRequest; - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # Ensure the full history is fetched for accurate diffing ref: ${{ github.event_name == 'pull_request_target' && fromJSON(steps.pr.outputs.result).merge_commit_sha || '' }} - name: Get changed files id: changed-files run: | if ${{ github.event_name == 'pull_request_target' }}; then echo "files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ steps.pr.outputs.result && fromJSON(steps.pr.outputs.result).merge_commit_sha }} | xargs)" >> $GITHUB_OUTPUT else echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | xargs)" >> $GITHUB_OUTPUT fi - name: "Validate filenames in ct and install directory" if: always() && steps.changed-files.outputs.files != '' id: check-scripts run: | CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^(ct|install)/.*\.sh$' || true; }) NON_COMPLIANT_FILES="" for FILE in $CHANGED_FILES; do BASENAME=$(echo "$(basename "${FILE%.*}")") if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" fi done if [ -n "$NON_COMPLIANT_FILES" ]; then echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT echo "Non-compliant filenames found, change to lowercase:" for FILE in $NON_COMPLIANT_FILES; do echo "$FILE" done exit 1 fi - name: "Validate filenames in json directory." if: always() && steps.changed-files.outputs.files != '' id: check-json run: | CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^json/.*\.json$' || true; }) NON_COMPLIANT_FILES="" for FILE in $CHANGED_FILES; do BASENAME=$(echo "$(basename "${FILE%.*}")") if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" fi done if [ -n "$NON_COMPLIANT_FILES" ]; then echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT echo "Non-compliant filenames found, change to lowercase:" for FILE in $NON_COMPLIANT_FILES; do echo "$FILE" done exit 1 fi - name: Post results and comment if: always() && steps.check-scripts.outputs.files != '' && steps.check-json.outputs.files != '' && github.event_name == 'pull_request_target' uses: actions/github-script@v7 with: script: | const result = "${{ job.status }}" === "success" ? "success" : "failure"; const nonCompliantFiles = { script: "${{ steps.check-scripts.outputs.files }}", JSON: "${{ steps.check-json.outputs.files }}", }; const issueNumber = context.payload.pull_request ? context.payload.pull_request.number : null; const commentIdentifier = "validate-filenames"; let newCommentBody = `\n### Filename validation\n\n`; if (result === "failure") { newCommentBody += ":x: We found issues in the following changed files:\n\n"; for (const [check, files] of Object.entries(nonCompliantFiles)) { if (files) { newCommentBody += `**${check.charAt(0).toUpperCase() + check.slice(1)} filename invalid:**\n${files .trim() .split(" ") .map((file) => `- ${file}`) .join("\n")}\n\n`; } } newCommentBody += "Please change the filenames to lowercase and use only alphanumeric characters and dashes.\n"; } else { newCommentBody += `:rocket: All files passed filename validation!\n`; } newCommentBody += `\n\n`; if (issueNumber) { const { data: comments } = await github.rest.issues.listComments({ ...context.repo, issue_number: issueNumber, }); const existingComment = comments.find( (comment) => comment.user.login === "github-actions[bot]", ); if (existingComment) { if (existingComment.body.includes(commentIdentifier)) { const re = new RegExp(String.raw`[\s\S]*?`, ""); newCommentBody = existingComment.body.replace(re, newCommentBody); } else { newCommentBody = existingComment.body + '\n\n---\n\n' + newCommentBody; } await github.rest.issues.updateComment({ ...context.repo, comment_id: existingComment.id, body: newCommentBody, }); } else { await github.rest.issues.createComment({ ...context.repo, issue_number: issueNumber, body: newCommentBody, }); } }