diff --git a/.github/scripts/pr-title.ts b/.github/scripts/pr-title.ts new file mode 100644 index 00000000000..1788e5324e3 --- /dev/null +++ b/.github/scripts/pr-title.ts @@ -0,0 +1,75 @@ +import * as core from "@actions/core"; +import * as github from "@actions/github"; + +const PREFIXES = ["ability", "balance", "bug", "docs", "feature", "item", "localize", "move", "other"] as const; + +const LOCALES = ["es", "fr", "de", "it", "zh_CN", "zh_TW", "pt_BR", "ko"]; + +const validEvent = ["pull_request"]; + +async function run() { + try { + const authToken = core.getInput("github_token", { required: true }); + const eventName = github.context.eventName; + core.info(`Event name: ${eventName}`); + if (!validEvent.includes(eventName)) { + core.setFailed(`Invalid event: ${eventName}`); + return; + } + + const client = github.getOctokit(authToken); + // The pull request info on the context isn't up to date. When + // the user updates the title and re-runs the workflow, it would + // be outdated. Therefore fetch the pull request via the REST API + // to ensure we use the current title. + const { data: pullRequest } = await client.rest.pulls.get({ + owner: github.context.payload.pull_request!.base.user.login, + repo: github.context.payload.pull_request!.base.repo.name, + pull_number: github.context.payload.pull_request!.number, + }); + + const title = pullRequest.title; + // const title = "poop(asd): asdasdasd"; + core.info(`Pull Request title: "${title}"`); + + + + const info = ` +Terminology: feat(ui): Add new feature + ^ ^ ^ + | | |__ Subject + | |_______ Scope + |____________ Prefix +`; + + core.info(info.trim()); + + // Check if title pass regex + const regex = RegExp(/^[a-zA-Z]+(\([a-zA-Z]+\))?: .+/); + if (!regex.test(title)) { + core.setFailed(`Pull Request title "${title}" failed to match - 'Prefix(Scrope): Subject'`); + return; + } + + // Check if title starts with an allowed prefix + core.info(`Allowed prefixes: ${PREFIXES}`); + if (!PREFIXES.some((prefix) => title.startsWith(prefix))) { + core.setFailed(`Pull Request title "${title}" did not match any of the prefixes - ${PREFIXES}`); + return; + } + + // Check if title has an allowed scope + if (title.startsWith("localize")) { + core.info(`Allowed locale scopes: ${LOCALES}`); + const scope = regex.exec(title); + if (!scope || !LOCALES.includes(scope[1])) { + core.setFailed(`Pull Request title "${title}" did not match any of the locale scope - (${LOCALES})`); + return; + } + } + } catch (error) { + core.setFailed(error.message); + } +} + +run(); diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 00000000000..9c507b83349 --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,21 @@ +name: PR Title Validation +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - run: npm i --no-save @actions/core @actions/github tsx + + - name: Lint PR + run: npx tsx ./.github/scripts/pr-title.ts + env: + INPUT_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file