feat: workflow for automated translations merge (#21639)

* feat: workflow for automated translations merge

* feat: dismiss review on merge failure

* chore: parameterize weblate URL

* fix: remove unnecessary CHANGES_REQUESTED review flow

* feat: leave weblate locked on failures

* chore: remove unnecessary merge timeout comment

The review dismissal already communicates this

* chore: remove todo

* feat: save api call

* fix: quotes
This commit is contained in:
bo0tzz 2025-09-08 16:25:31 +02:00 committed by GitHub
parent 5a7042364b
commit 72ffa37dd9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 104 additions and 12 deletions

View file

@ -0,0 +1,87 @@
name: Merge translations
on:
workflow_call:
workflow_dispatch:
permissions: {}
env:
WEBLATE_HOST: 'https://hosted.weblate.org'
WEBLATE_COMPONENT: 'immich/immich'
jobs:
merge:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Find translation PR
id: find_pr
run: |
gh pr list --repo $GITHUB_REPOSITORY --author weblate --json number,mergeable | read PR
echo "$PR" | jq '
if length == 1 then
.[0].number
else
error("Expected exactly 1 entry, got \(length)")
end
' | read PR_NUMBER
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT
echo "$PR" | jq -e '.[0].mergeable == "MERGEABLE"' || (echo "PR is not mergeable" && exit 1)
- name: Generate a token
id: generate_token
uses: actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b # v2.1.1
with:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- name: Lock weblate
env:
WEBLATE_TOKEN: ${{ secrets.WEBLATE_TOKEN }}
run: |
curl -X POST -H "Authorization: Token $WEBLATE_TOKEN" "$WEBLATE_HOST/api/components/$WEBLATE_COMPONENT/lock/" -d lock=true
- name: Commit translations
env:
WEBLATE_TOKEN: ${{ secrets.WEBLATE_TOKEN }}
run: |
curl -X POST -H "Authorization: Token $WEBLATE_TOKEN" "$WEBLATE_HOST/api/components/$WEBLATE_COMPONENT/repository/" -d operation=commit
curl -X POST -H "Authorization: Token $WEBLATE_TOKEN" "$WEBLATE_HOST/api/components/$WEBLATE_COMPONENT/repository/" -d operation=push
- name: Merge PR
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
PR_NUMBER: ${{ steps.find_pr.outputs.PR_NUMBER }}
run: |
gh api -X POST "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews" --field event='APPROVE' --field body='Automatically merging translations PR' \
| jq '.id' | read REVIEW_ID
echo "REVIEW_ID=$REVIEW_ID" >> $GITHUB_OUTPUT
gh pr merge "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --auto --squash
- name: Wait for PR to merge
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
PR_NUMBER: ${{ steps.find_pr.outputs.PR_NUMBER }}
REVIEW_ID: ${{ steps.merge_pr.outputs.REVIEW_ID }}
run: |
for i in {1..10}; do
if gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --json merged | jq -e '.merged == true'; then
echo "PR merged"
exit 0
else
echo "PR not merged yet, waiting..."
sleep 6
fi
done
echo "PR did not merge in time"
gh api -X PUT "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews/$REVIEW_ID/dismissals" --field message='Merge attempt timed out' --field event='DISMISS'
gh pr merge "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --disable-auto
exit 1
- name: Unlock weblate
env:
WEBLATE_TOKEN: ${{ secrets.WEBLATE_TOKEN }}
run: |
curl -X POST -H "Authorization: Token $WEBLATE_TOKEN" "$WEBLATE_HOST/api/components/$WEBLATE_COMPONENT/lock/" -d lock=false

View file

@ -24,6 +24,15 @@ concurrency:
permissions: {}
jobs:
merge_translations:
uses: ./.github/workflows/merge-translations.yml
permissions:
pull-requests: write
secrets:
PUSH_O_MATIC_APP_ID: ${{ secrets.PUSH_O_MATIC_APP_ID }}
PUSH_O_MATIC_APP_KEY: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
WEBLATE_TOKEN: ${{ secrets.WEBLATE_TOKEN }}
bump_version:
runs-on: ubuntu-latest
outputs:

View file

@ -1,6 +1,7 @@
name: Weblate checks
on:
pull_request_review:
pull_request:
branches: [main]
@ -32,19 +33,14 @@ jobs:
permissions: {}
if: ${{ needs.pre-job.outputs.should_run == 'true' }}
steps:
- name: Check weblate lock
- name: Bot review status
env:
PR_NUMBER: ${{ github.event.pull_request.number || github.event.pull_request_review.pull_request.number }}
run: |
if [[ "false" = $(curl https://hosted.weblate.org/api/components/immich/immich/lock/ | jq .locked) ]]; then
exit 1
fi
- name: Find Pull Request
uses: juliangruber/find-pull-request-action@952b3bb1ddb2dcc0aa3479e98bb1c2d1a922f096 # v1.10.0
id: find-pr
with:
branch: chore/translations
- name: Fail if existing weblate PR
if: ${{ steps.find-pr.outputs.number }}
run: exit 1
# Then check for APPROVED by the bot, if absent fail
gh pr view "$PR_NUMBER" --json reviews | jq -e '.reviews | map(select(.author.login == "github-actions[bot]" and .state == "APPROVED")) | length > 0' \
|| (echo "The push-o-matic bot has not approved this PR yet" && exit 1)
success-check-lock:
name: Weblate Lock Check Success
needs: [enforce-lock]