diff --git a/.github/workflows/pr-automation.yml b/.github/workflows/pr-automation.yml index f9f6d2736b..527b040443 100644 --- a/.github/workflows/pr-automation.yml +++ b/.github/workflows/pr-automation.yml @@ -34,16 +34,16 @@ jobs: exit 1 fi - # Reads the PR description to retrieve /ok-to-test slash command + # Reads the PR description to retrieve the /ok-to-test or, if that's absent, the /test command - name: Get tags + uses: actions/github-script@v7 id: getTags env: - PR_BODY: ${{ github.event.pull_request.body }} - run: | - REGEX='/ok-to-test tags="([^"]*)"'; - if [[ $PR_BODY =~ $REGEX ]]; then - echo "tags=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT - fi + NODE_PATH: "${{ github.workspace }}/.github/workflows/scripts" + with: + script: | + const testTagParser = require("test-tag-parser.js") + core.setOutput("tags", testTagParser.parseTags({core, context})) # Parses the retrieved /ok-to-test slash command to retrieve tags - name: Parse tags @@ -112,7 +112,7 @@ jobs: - name: Stop the workflow run if tags are incorrect if: steps.checkTags.outputs.outcome == 'failure' run: exit 1 - + # In case of a run with all test cases, allocate a larger matrix - name: Check if @tag.All is present in tags id: checkAll diff --git a/.github/workflows/scripts/test-tag-parser.js b/.github/workflows/scripts/test-tag-parser.js new file mode 100644 index 0000000000..87298c2a3e --- /dev/null +++ b/.github/workflows/scripts/test-tag-parser.js @@ -0,0 +1,47 @@ +function parseTags({core, context}) { + const body = context.payload.pull_request.body; + + // "/ok-to-test" matcher. Takes precedence over the "/test" matcher. + const strictMatch = body.match(/\/ok-to-test tags="(.+?)"/)?.[1]; + if (strictMatch) { + return strictMatch; + } + + // "/test" matcher. + const allTags = require(process.env.GITHUB_WORKSPACE + "/app/client/cypress/tags.js").Tag; + const config = body.match(/^\/test\s+(.*)$/m)?.[1] ?? ""; + const concreteTags = []; + + for (const [rawTag] of config.matchAll(/\w+/g)) { + console.log("Given: '" + rawTag + "'"); + + // See if there is exact case-insensitive match. + const exactTagMatch = allTags.find(t => t.toLowerCase() === "@tag." + rawTag); + if (exactTagMatch) { + console.log("\tMatch found:", exactTagMatch); + concreteTags.push(exactTagMatch); + continue; + } + + // See if there is a singular/plural match (very rudimentary language skills). + const countedMatch = allTags.find(t => t.toLowerCase().replace(/s$/, "") === "@tag." + rawTag.replace(/s$/, "")); + if (countedMatch) { + console.log("\tMatch found:", countedMatch); + concreteTags.push(countedMatch); + continue; + } + + // More smart matchers? + + // No match, fail. + core.setFailed("\tNo match found for tag:", rawTag); + + // We still process the rest, so we report all invalid tags in the input in a single run. + } + + return concreteTags.join(", "); +} + +module.exports = { + parseTags, +}