forked from home-assistant/frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fetch nightly translations during build (home-assistant#13724)
Co-authored-by: Bram Kragten <[email protected]>
- Loading branch information
1 parent
cb97918
commit ee6f97b
Showing
152 changed files
with
537 additions
and
220,235 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
build | ||
hass_frontend/* | ||
dist | ||
translations | ||
|
||
# yarn | ||
.yarn/* | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,12 @@ | ||
{ | ||
"extends": "../.eslintrc.json", | ||
"rules": { | ||
"import/no-extraneous-dependencies": 0, | ||
"global-require": 0 | ||
"no-console": "off", | ||
"import/no-extraneous-dependencies": "off", | ||
"import/extensions": "off", | ||
"import/no-dynamic-require": "off", | ||
"global-require": "off", | ||
"@typescript-eslint/no-var-requires": "off", | ||
"prefer-arrow-callback": "off" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// Task to download the latest Lokalise translations from the nightly workflow artifacts | ||
|
||
const fs = require("fs/promises"); | ||
const path = require("path"); | ||
const process = require("process"); | ||
const del = require("del"); | ||
const gulp = require("gulp"); | ||
const jszip = require("jszip"); | ||
const tar = require("tar"); | ||
const { Octokit } = require("@octokit/rest"); | ||
const { createOAuthDeviceAuth } = require("@octokit/auth-oauth-device"); | ||
|
||
const MAX_AGE = 24; // hours | ||
const OWNER = "home-assistant"; | ||
const REPO = "frontend"; | ||
const WORKFLOW_NAME = "nightly.yaml"; | ||
const ARTIFACT_NAME = "translations"; | ||
const CLIENT_ID = "Iv1.3914e28cb27834d1"; | ||
const EXTRACT_DIR = "translations"; | ||
const TOKEN_FILE = path.join(EXTRACT_DIR, "token.json"); | ||
const ARTIFACT_FILE = path.join(EXTRACT_DIR, "artifact.json"); | ||
|
||
let allowTokenSetup = false; | ||
gulp.task("allow-setup-fetch-nightly-translations", (done) => { | ||
allowTokenSetup = true; | ||
done(); | ||
}); | ||
|
||
gulp.task("fetch-nightly-translations", async function () { | ||
// Skip all when environment flag is set (assumes translations are already in place) | ||
if (process.env?.SKIP_FETCH_NIGHTLY_TRANSLATIONS) { | ||
console.log("Skipping fetch due to environment signal"); | ||
return; | ||
} | ||
|
||
// Read current translations artifact info if it exists, | ||
// and stop if they are not old enough | ||
let currentArtifact; | ||
try { | ||
currentArtifact = JSON.parse(await fs.readFile(ARTIFACT_FILE, "utf-8")); | ||
const currentAge = | ||
(Date.now() - Date.parse(currentArtifact.created_at)) / 3600000; | ||
if (currentAge < MAX_AGE) { | ||
console.log( | ||
"Keeping current translations (only %s hours old)", | ||
currentAge.toFixed(1) | ||
); | ||
return; | ||
} | ||
} catch { | ||
currentArtifact = null; | ||
} | ||
|
||
// To store file writing promises | ||
const createExtractDir = fs.mkdir(EXTRACT_DIR, { recursive: true }); | ||
const writings = []; | ||
|
||
// Authenticate to GitHub using GitHub action token if it exists, | ||
// otherwise look for a saved user token or generate a new one if none | ||
let tokenAuth; | ||
if (process.env.GITHUB_TOKEN) { | ||
tokenAuth = { token: process.env.GITHUB_TOKEN }; | ||
} else { | ||
try { | ||
tokenAuth = JSON.parse(await fs.readFile(TOKEN_FILE, "utf-8")); | ||
} catch { | ||
if (!allowTokenSetup) { | ||
console.log("No token found so build wil continue with English only"); | ||
return; | ||
} | ||
const auth = createOAuthDeviceAuth({ | ||
clientType: "github-app", | ||
clientId: CLIENT_ID, | ||
onVerification: (verification) => { | ||
console.log( | ||
"Task needs to authenticate to GitHub to fetch the translations from nightly workflow\n" + | ||
"Please go to %s to authorize this task\n" + | ||
"\nEnter user code: %s\n\n" + | ||
"This code will expire in %s minutes\n" + | ||
"Task will automatically continue after authorization and token will be saved for future use", | ||
verification.verification_uri, | ||
verification.user_code, | ||
(verification.expires_in / 60).toFixed(0) | ||
); | ||
}, | ||
}); | ||
tokenAuth = await auth({ type: "oauth" }); | ||
writings.push( | ||
createExtractDir.then( | ||
fs.writeFile(TOKEN_FILE, JSON.stringify(tokenAuth, null, 2)) | ||
) | ||
); | ||
} | ||
} | ||
|
||
// Authenticate with token and request workflow runs from GitHub | ||
console.log("Fetching new translations..."); | ||
const octokit = new Octokit({ | ||
userAgent: "Fetch Nightly Translations", | ||
auth: tokenAuth.token, | ||
}); | ||
|
||
const workflowRunsResponse = await octokit.rest.actions.listWorkflowRuns({ | ||
owner: OWNER, | ||
repo: REPO, | ||
workflow_id: WORKFLOW_NAME, | ||
status: "success", | ||
event: "schedule", | ||
per_page: 1, | ||
exclude_pull_requests: true, | ||
}); | ||
if (workflowRunsResponse.data.total_count === 0) { | ||
throw Error("No successful nightly workflow runs found"); | ||
} | ||
const latestNightlyRun = workflowRunsResponse.data.workflow_runs[0]; | ||
|
||
// Stop if current is already the latest, otherwise Find the translations artifact | ||
if (currentArtifact?.workflow_run.id === latestNightlyRun.id) { | ||
console.log("Stopping because current translations are still the latest"); | ||
return; | ||
} | ||
const latestArtifact = ( | ||
await octokit.actions.listWorkflowRunArtifacts({ | ||
owner: OWNER, | ||
repo: REPO, | ||
run_id: latestNightlyRun.id, | ||
}) | ||
).data.artifacts.find((artifact) => artifact.name === ARTIFACT_NAME); | ||
if (!latestArtifact) { | ||
throw Error("Latest nightly workflow run has no translations artifact"); | ||
} | ||
writings.push( | ||
createExtractDir.then( | ||
fs.writeFile(ARTIFACT_FILE, JSON.stringify(latestArtifact, null, 2)) | ||
) | ||
); | ||
|
||
// Remove the current translations | ||
const deleteCurrent = Promise.all(writings).then( | ||
del([`${EXTRACT_DIR}/*`, `!${ARTIFACT_FILE}`, `!${TOKEN_FILE}`]) | ||
); | ||
|
||
// Get the download URL and follow the redirect to download (stored as ArrayBuffer) | ||
const downloadResponse = await octokit.actions.downloadArtifact({ | ||
owner: OWNER, | ||
repo: REPO, | ||
artifact_id: latestArtifact.id, | ||
archive_format: "zip", | ||
}); | ||
if (downloadResponse.status !== 200) { | ||
throw Error("Failure downloading translations artifact"); | ||
} | ||
|
||
// Artifact is a tarball, but GitHub adds it to a zip file | ||
console.log("Unpacking downloaded translations..."); | ||
const zip = await jszip.loadAsync(downloadResponse.data); | ||
await deleteCurrent; | ||
const extractStream = zip.file(/.*/)[0].nodeStream().pipe(tar.extract()); | ||
await new Promise((resolve, reject) => { | ||
extractStream.on("close", resolve).on("error", reject); | ||
}); | ||
}); | ||
|
||
gulp.task( | ||
"setup-and-fetch-nightly-translations", | ||
gulp.series( | ||
"allow-setup-fetch-nightly-translations", | ||
"fetch-nightly-translations" | ||
) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.