Repository navigation
Translation tracker: auto close issue on PR merged and closed and translation coverage - #1582
aashishpanthi wants to merge 12 commits into
Conversation
We now look at the title, body, comments, cross references to pull out the issue number(s)
|
Note: This branches off the stub-file-generation PR. So, #1473 should be merged first, then this. |
…es changed/added in the PR to ensure the correct translations have been added
| name: Translation Auto-Close | ||
|
|
||
| on: | ||
| pull_request: |
There was a problem hiding this comment.
Hi @aashishpanthi , I see one blocker here for which I'm not very sure.
For any PR opened from a fork (which is how virtually all external translation contributors submit), GitHub downgrades GITHUB_TOKEN to read-only regardless of the permissions: block. This workflow needs issues: write to remove labels, edit the body, comment, and close/reopen, all of those API calls (removeLabel, issues.update, createComment) will return 403 for fork PRs.
The whole motivation of the PR ("real contributors" not using linking keywords) implies fork-based PRs, so as written the feature might work only for maintainers pushing branches inside the repo.
Can we test this on a fork?
cc: @ksen0 do you have any views here?
There was a problem hiding this comment.
Sorry for the very delayed response, but I created a new GitHub account just to try the new changes. As you can see, aap009#15
Here, the write on issues is working. In the workflow file, I changed the workflow trigger from pull_request to pull_request_target. Exactly this.
Let me know if any problems arise.
There was a problem hiding this comment.
Thanks @Divyansh013 for the excellent point, this is an important concern to deal with. @aashishpanthi you're right that technically pull_request_target would be able to access the elevated permissions afaik and I believe this is reasonable in this case.
We have many GHA workflows across the p5 projects so maintenance can be an issue. This is the most specialized one. Ideally, it should be as least-privileged as possible at every step. In this case, no fork-controlled code is executed without a manual merge; the code that is checked out and run is just the website main branch. If this is compromised, then that is a big problem overall. As long as merging is subject to manual review, this is ok.
(If merging becomes automated / skips human review, or if reviewer misses something on a non-translation PR that changes the files in this rather complex workflow and creates higher risk, that could cause a severe problem. But this is generally true, that's why it takes so long to review/merge things - because there's high potential risk for more complex PRs)
I think this is well-constructed as is but introduces a nontrivial supply chain surface to add to the security handbook, draft here: processing/p5.js#9318, eg, you could propose something like:
- T-x Malicious PR from a fork. Can link to https://docs.github.com/en/actions/reference/security/secure-use#good-practices and note the mitigation that untrusted code must never be run or influence execution. So even if
pull_request_targetis used, any subsequent execution must be conditional on human review. - please feel free to comment on Perminder's PR with any other additions that help cover the GHA of translation. He's worked on auditing actions in the main p5.js repo but this is more complex than anything there
I think it's also worth adding a warning in the GHA itself as a comment, after line 26 that actions must never checkout untrusted code (eg from an unmerged fork), never use ${{ github.event.pull_request.title }} (or any untrusted text: commit message, body, branch name) in a run:, and never delete this comment. Such a warning also helps reviewer flag risky workflow changes.
| const { getLanguageDisplayName, getTranslationPath } = require('./utils'); | ||
|
|
||
| // List all files changed in a merged PR (paginated). | ||
| async function listPullRequestFiles(octokit, owner, repo, pullNumber) { |
There was a problem hiding this comment.
This function returns every file including status: "removed"/"renamed", and neither identifyLanguagesFromFiles nor the verifiedLanguages filter checks status:
const verifiedLanguages = languages.filter((lang) => {
const paths = expectedPaths.get(lang);
if (!paths || paths.length === 0) return false;
return paths.some((p) => changedFileNames.includes(p)); // matches removed files too
});
A PR that deletes src/content/examples/es/foo.mdx would strike Spanish, remove lang-es, and potentially close the tracker issue - the opposite of the truth. Filter to file.status === 'added' || 'modified' (or exclude removed) before deriving languages and verifying paths.
There was a problem hiding this comment.
I resolved it, now we check if the file was updated, added, or deleted.
|
Also, latest update: I have added the translation coverage to this PR. A detailed description is found above in PR description. But it can be dispatched from GitHub Actions. See one here. |
|
Hi @aashishpanthi ! Sorry for the wait. For this PR:
|
ksen0
left a comment
There was a problem hiding this comment.
Many thanks for this excellent work! Some hardening comments as well, I can rereview promptly when done
| node-version: '22' | ||
|
|
||
| - name: Install translation tracker dependencies | ||
| run: cd .github/actions/translation-tracker && npm install |
There was a problem hiding this comment.
Needs package.json and lockfile then npm ci not npm install because this is a live supply chain surface in a privileged context, and then is not reproducible.
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 |
There was a problem hiding this comment.
In general, SHA-pin rather than tag-pin actions, eg https://github.com/processing/p5.js/tree/main/.github/workflows
There was a problem hiding this comment.
cc @perminder-17 @Vaivaswat2244 Please flag anything I might be missing for GHA hygiene? Also if this inspires any edits to Perminder's handbook PR, please do comment there too: processing/p5.js#9318 (Note: this will ultimately target main but due to branch divergence and for review sanity it's targeting v1 for now.)
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| GITHUB_REPOSITORY: ${{ github.repository }} | ||
| PR_NUMBER: ${{ github.event.pull_request.number }} | ||
| run: node .github/actions/translation-tracker/auto-close.js |
There was a problem hiding this comment.
I think probably a good idea to do
concurrency:
group: translation-auto-close
cancel-in-progress: false
to queue them up. In practice some stewards merge multiple items in a row. May also be worth testing concurrent merges of different languages for same file? So they should result in sensible issue body update
| node-version: '22' | ||
|
|
||
| - name: Install translation tracker dependencies | ||
| run: cd .github/actions/translation-tracker && npm install |
There was a problem hiding this comment.
Same as above: Needs package.json and lockfile then npm ci not npm install because this is a live supply chain surface in a privileged context, and then is not reproducible.

Summary
Extends the translation tracker with:
lang-*label, and close the issue when nothing remains.public/translation-status/coverage.json(served as/translation-status/coverage.json).Addresses #1404.
Auto-close issue
How an issue is found
Relying on
Resolves #123did not worked well with real contributors: most translation PRs either use no linking keyword or mention the issue somewhere other than the body. So any#123is treated as a candidate, and it is looked for in:#123" during review)https://github.com/<owner>/<repo>/issues/123linksHow false positives are avoided
Matching every
#123is deliberately greedy, so candidates are filtered:owner/repo#123cross-repo references and#123abcare not matched; numbers are capped at five digits because color codes are six digits and we are in four digits, we'll reach six digits in years (needs attention)needs translationlabelHow an issue is updated
Which languages a PR translated is derived from its changed file paths, for example
src/content/examples/es/...means Spanish. For each such language, the action removes thelang-<code>label and strikes that language's line in the issue body. The issue is closed only when nolang-*labels are left.One tracker issue often covers several languages for the same English file, which creates a wrinkle: GitHub closes an issue natively the instant a PR saying
Fixes #123is merged, even when only one of four languages was done. The action detects this and reopens the issue, leaving a comment naming the languages still working.Translation coverage
translation-coverage.yml— runs on push tomainfor content changes, or via Actions → Translation Coverage → Run workflow..github/actions/translation-tracker/coverage.js— filesystem-only scan (present/missing/stub). Andd excludesreference.coverage.jsonas a public file for the visualization.languages,content_typeswhich can be dispatched from web.Test plan
coverage.jsonupdates quickly. See here/translation-status/coverage.jsonis publicly reachable after deploy.