mirror of
https://github.com/langgenius/dify.git
synced 2026-04-05 05:09:19 +08:00
172 lines
5.8 KiB
YAML
172 lines
5.8 KiB
YAML
name: Trigger i18n Sync on Push
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'web/i18n/en-US/*.json'
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
concurrency:
|
|
group: trigger-i18n-sync-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
trigger:
|
|
if: github.repository == 'langgenius/dify'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Detect changed files and build structured change set
|
|
id: detect
|
|
shell: bash
|
|
run: |
|
|
BASE_SHA="${{ github.event.before }}"
|
|
if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then
|
|
BASE_SHA=$(git rev-parse HEAD~1 2>/dev/null || true)
|
|
fi
|
|
HEAD_SHA="${{ github.sha }}"
|
|
|
|
if [ -n "$BASE_SHA" ]; then
|
|
CHANGED_FILES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" -- 'web/i18n/en-US/*.json' 2>/dev/null | sed -n 's@^.*/@@p' | sed 's/\.json$//' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
|
|
else
|
|
CHANGED_FILES=$(find web/i18n/en-US -maxdepth 1 -type f -name '*.json' -print | sed -n 's@^.*/@@p' | sed 's/\.json$//' | sort | tr '\n' ' ' | sed 's/[[:space:]]*$//')
|
|
fi
|
|
|
|
export BASE_SHA HEAD_SHA CHANGED_FILES
|
|
node <<'NODE'
|
|
const { execFileSync } = require('node:child_process')
|
|
const fs = require('node:fs')
|
|
const path = require('node:path')
|
|
|
|
const repoRoot = process.cwd()
|
|
const baseSha = process.env.BASE_SHA || ''
|
|
const headSha = process.env.HEAD_SHA || ''
|
|
const files = (process.env.CHANGED_FILES || '').split(/\s+/).filter(Boolean)
|
|
|
|
const englishPath = fileStem => path.join(repoRoot, 'web', 'i18n', 'en-US', `${fileStem}.json`)
|
|
|
|
const readCurrentJson = (fileStem) => {
|
|
const filePath = englishPath(fileStem)
|
|
if (!fs.existsSync(filePath))
|
|
return null
|
|
|
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
}
|
|
|
|
const readBaseJson = (fileStem) => {
|
|
if (!baseSha)
|
|
return null
|
|
|
|
try {
|
|
const relativePath = `web/i18n/en-US/${fileStem}.json`
|
|
const content = execFileSync('git', ['show', `${baseSha}:${relativePath}`], { encoding: 'utf8' })
|
|
return JSON.parse(content)
|
|
}
|
|
catch (error) {
|
|
return null
|
|
}
|
|
}
|
|
|
|
const compareJson = (beforeValue, afterValue) => JSON.stringify(beforeValue) === JSON.stringify(afterValue)
|
|
|
|
const changes = {}
|
|
|
|
for (const fileStem of files) {
|
|
const beforeJson = readBaseJson(fileStem) || {}
|
|
const afterJson = readCurrentJson(fileStem) || {}
|
|
const added = {}
|
|
const updated = {}
|
|
const deleted = []
|
|
|
|
for (const [key, value] of Object.entries(afterJson)) {
|
|
if (!(key in beforeJson)) {
|
|
added[key] = value
|
|
continue
|
|
}
|
|
|
|
if (!compareJson(beforeJson[key], value)) {
|
|
updated[key] = {
|
|
before: beforeJson[key],
|
|
after: value,
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const key of Object.keys(beforeJson)) {
|
|
if (!(key in afterJson))
|
|
deleted.push(key)
|
|
}
|
|
|
|
changes[fileStem] = {
|
|
fileDeleted: readCurrentJson(fileStem) === null,
|
|
added,
|
|
updated,
|
|
deleted,
|
|
}
|
|
}
|
|
|
|
fs.writeFileSync(
|
|
'/tmp/i18n-changes.json',
|
|
JSON.stringify({
|
|
baseSha,
|
|
headSha,
|
|
files,
|
|
changes,
|
|
})
|
|
)
|
|
NODE
|
|
|
|
if [ -n "$CHANGED_FILES" ]; then
|
|
echo "has_changes=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "has_changes=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
echo "base_sha=$BASE_SHA" >> "$GITHUB_OUTPUT"
|
|
echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT"
|
|
echo "changed_files=$CHANGED_FILES" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Trigger i18n sync workflow
|
|
if: steps.detect.outputs.has_changes == 'true'
|
|
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
|
env:
|
|
BASE_SHA: ${{ steps.detect.outputs.base_sha }}
|
|
HEAD_SHA: ${{ steps.detect.outputs.head_sha }}
|
|
CHANGED_FILES: ${{ steps.detect.outputs.changed_files }}
|
|
with:
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
script: |
|
|
const fs = require('fs')
|
|
|
|
const changesJson = fs.readFileSync('/tmp/i18n-changes.json', 'utf8')
|
|
const changesBase64 = Buffer.from(changesJson).toString('base64')
|
|
const maxEmbeddedChangesChars = 48000
|
|
const changesEmbedded = changesBase64.length <= maxEmbeddedChangesChars
|
|
|
|
if (!changesEmbedded) {
|
|
console.log(`Structured change set too large to embed safely (${changesBase64.length} chars). Downstream workflow will regenerate it from git history.`)
|
|
}
|
|
|
|
await github.rest.repos.createDispatchEvent({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
event_type: 'i18n-sync',
|
|
client_payload: {
|
|
changed_files: process.env.CHANGED_FILES,
|
|
changes_base64: changesEmbedded ? changesBase64 : '',
|
|
changes_embedded: changesEmbedded,
|
|
sync_mode: 'incremental',
|
|
base_sha: process.env.BASE_SHA,
|
|
head_sha: process.env.HEAD_SHA,
|
|
},
|
|
})
|