Skip to content

Commit 3fb51c3

Browse files
committed
feat: add scripts/generate-prerelease-matrix.js
1 parent 4ab8e95 commit 3fb51c3

File tree

2 files changed

+229
-35
lines changed

2 files changed

+229
-35
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Script to generate locale deployment matrix for prerelease workflow
5+
* Usage: node generate-prerelease-matrix.js <labels-json>
6+
*
7+
* labels-json: JSON string containing array of PR labels
8+
*/
9+
10+
const fs = require('node:fs');
11+
const path = require('node:path');
12+
13+
// Default values
14+
const SCRIPT_DIR = __dirname;
15+
const ROOT_DIR = path.resolve(SCRIPT_DIR, '../..');
16+
const LOCALE_CONFIG_FILE = path.join(ROOT_DIR, '.github/locales-config.json');
17+
18+
/**
19+
* Print usage information
20+
*/
21+
function usage() {
22+
console.log(`Usage: ${process.argv[1]} <labels-json>`);
23+
console.log('');
24+
console.log('Arguments:');
25+
console.log(' labels-json JSON string containing array of PR labels');
26+
console.log('');
27+
console.log('Examples:');
28+
console.log(` ${process.argv[1]} '["prerelease"]'`);
29+
console.log(` ${process.argv[1]} '["prerelease:en", "prerelease:zh-hans"]'`);
30+
process.exit(1);
31+
}
32+
33+
/**
34+
* Log messages with timestamp and emoji
35+
*/
36+
function log(message) {
37+
const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
38+
console.error(`🔧 [${timestamp}] ${message}`);
39+
}
40+
41+
/**
42+
* Check if locale is enabled in config
43+
*/
44+
function isLocaleEnabled(localeConfig, locale) {
45+
return localeConfig[locale]?.enabled === true;
46+
}
47+
48+
/**
49+
* Get locale configuration value
50+
*/
51+
function getLocaleConfig(localeConfig, locale, field) {
52+
return localeConfig[locale]?.[field] || '';
53+
}
54+
55+
/**
56+
* Add locale to matrix
57+
*/
58+
function addLocaleToMatrix(matrix, locale, secretProjectId) {
59+
return [
60+
...matrix,
61+
{
62+
locale,
63+
secret_project_id: secretProjectId,
64+
},
65+
];
66+
}
67+
68+
/**
69+
* Process prerelease labels and generate matrix
70+
*/
71+
function processPrerelease(localeConfig, labels) {
72+
let matrixInclude = [];
73+
74+
log(`Processing labels: ${JSON.stringify(labels)}`);
75+
76+
// Check if we should deploy all locales (general prerelease)
77+
const shouldDeployAll = labels.includes('prerelease');
78+
79+
if (shouldDeployAll) {
80+
log('📦 General prerelease label found - deploying all enabled locales');
81+
82+
// Deploy all enabled locales
83+
for (const locale of Object.keys(localeConfig)) {
84+
if (isLocaleEnabled(localeConfig, locale)) {
85+
const secretProjectId = getLocaleConfig(
86+
localeConfig,
87+
locale,
88+
'secret_project_id',
89+
);
90+
91+
if (secretProjectId) {
92+
matrixInclude = addLocaleToMatrix(
93+
matrixInclude,
94+
locale,
95+
secretProjectId,
96+
);
97+
log(`✅ Added ${locale} to deployment matrix`);
98+
} else {
99+
log(`⚠️ Skipping ${locale} (missing secret_project_id)`);
100+
}
101+
} else {
102+
log(`⏭️ Skipping ${locale} (not enabled)`);
103+
}
104+
}
105+
} else {
106+
// Check for specific locale labels (prerelease:locale)
107+
const localeLabels = labels.filter((label) =>
108+
label.startsWith('prerelease:'),
109+
);
110+
111+
if (localeLabels.length > 0) {
112+
log(`🎯 Specific locale labels found: ${localeLabels.join(', ')}`);
113+
114+
for (const label of localeLabels) {
115+
const locale = label.replace('prerelease:', '');
116+
117+
if (isLocaleEnabled(localeConfig, locale)) {
118+
const secretProjectId = getLocaleConfig(
119+
localeConfig,
120+
locale,
121+
'secret_project_id',
122+
);
123+
124+
if (secretProjectId) {
125+
matrixInclude = addLocaleToMatrix(
126+
matrixInclude,
127+
locale,
128+
secretProjectId,
129+
);
130+
log(`✅ Added ${locale} to deployment matrix`);
131+
} else {
132+
log(`⚠️ Skipping ${locale} (missing secret_project_id)`);
133+
}
134+
} else {
135+
log(`❌ Skipping ${locale} (not enabled or not found)`);
136+
}
137+
}
138+
} else {
139+
log('🚫 No prerelease labels found');
140+
}
141+
}
142+
143+
const hasChanges = matrixInclude.length > 0;
144+
145+
log(`📊 Generated matrix with ${matrixInclude.length} locales`);
146+
147+
return {
148+
matrixInclude,
149+
hasChanges,
150+
};
151+
}
152+
153+
/**
154+
* Main function
155+
*/
156+
function main() {
157+
try {
158+
// Parse command line arguments
159+
const args = process.argv.slice(2);
160+
161+
if (args.length !== 1) {
162+
console.error('Error: Invalid number of arguments');
163+
usage();
164+
}
165+
166+
const labelsJson = args[0];
167+
168+
// Validate and parse labels JSON
169+
let labels;
170+
try {
171+
labels = JSON.parse(labelsJson);
172+
if (!Array.isArray(labels)) {
173+
throw new Error('Labels must be an array');
174+
}
175+
} catch (error) {
176+
console.error(`Error: Invalid labels JSON: ${error.message}`);
177+
process.exit(1);
178+
}
179+
180+
// Read locale configuration
181+
let localeConfig;
182+
try {
183+
if (!fs.existsSync(LOCALE_CONFIG_FILE)) {
184+
throw new Error(`Locale config file not found: ${LOCALE_CONFIG_FILE}`);
185+
}
186+
187+
const configContent = fs.readFileSync(LOCALE_CONFIG_FILE, 'utf8');
188+
localeConfig = JSON.parse(configContent);
189+
} catch (error) {
190+
console.error(`Error reading locale config: ${error.message}`);
191+
process.exit(1);
192+
}
193+
194+
// Process prerelease labels
195+
const result = processPrerelease(localeConfig, labels);
196+
197+
// Output results in GitHub Actions format
198+
console.log(`matrix={"include":${JSON.stringify(result.matrixInclude)}}`);
199+
200+
// Validate that we have at least one locale to deploy
201+
if (result.matrixInclude.length === 0) {
202+
log('❌ No enabled locales found to deploy');
203+
process.exit(1);
204+
}
205+
} catch (error) {
206+
console.error(`💥 Error: ${error.message}`);
207+
process.exit(1);
208+
}
209+
}
210+
211+
// Run main function if script is executed directly
212+
if (require.main === module) {
213+
main();
214+
}
215+
216+
module.exports = {
217+
main,
218+
processPrerelease,
219+
isLocaleEnabled,
220+
getLocaleConfig,
221+
};

.github/workflows/prerelease.yml

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,47 +23,20 @@ jobs:
2323
steps:
2424
- name: Checkout code
2525
uses: actions/checkout@v3
26+
- name: Setup Node
27+
uses: actions/[email protected]
28+
with:
29+
node-version-file: .nvmrc
2630
- name: Generate matrix from locales config
2731
id: set-matrix
2832
run: |
2933
LABELS_JSON='${{ toJson(github.event.pull_request.labels.*.name) }}'
3034
echo "LABELS_JSON: $LABELS_JSON"
3135
32-
# Check if we should deploy all locales (general prerelease)
33-
SHOULD_DEPLOY_GENERAL=false
34-
if [[ "${{ github.event_name }}" != "pull_request" ]]; then
35-
SHOULD_DEPLOY_GENERAL=true
36-
elif echo "$LABELS_JSON" | grep -E '"prerelease"' > /dev/null; then
37-
SHOULD_DEPLOY_GENERAL=true
38-
fi
39-
40-
echo "Should deploy all locales: $SHOULD_DEPLOY_GENERAL"
41-
42-
# Read the locales config and generate matrix for enabled locales that should deploy
43-
MATRIX=$(jq -c --argjson should_deploy_general "$SHOULD_DEPLOY_GENERAL" --argjson labels "$LABELS_JSON" '
44-
to_entries |
45-
map(select(.value.enabled == true)) |
46-
map(. as $item | {
47-
locale: $item.key,
48-
secret_project_id: $item.value.secret_project_id,
49-
should_deploy: (
50-
$should_deploy_general or
51-
($labels | any(. == ("prerelease:" + $item.key)))
52-
)
53-
}) |
54-
map(select(.should_deploy == true)) |
55-
map({locale: .locale, secret_project_id: .secret_project_id})
56-
' .github/locales-config.json)
57-
58-
echo "matrix={\"include\":$MATRIX}" >> $GITHUB_OUTPUT
59-
echo "Generated matrix: {\"include\":$MATRIX}"
60-
61-
# Check if there are any enabled locales
62-
ENABLED_COUNT=$(echo "$MATRIX" | jq length)
63-
if [ "$ENABLED_COUNT" -eq 0 ]; then
64-
echo "No enabled locales found in locales-config.json"
65-
exit 1
66-
fi
36+
# Use Node.js script to generate matrix
37+
OUTPUT=$(node .github/scripts/generate-prerelease-matrix.js "$LABELS_JSON")
38+
echo "$OUTPUT" >> $GITHUB_OUTPUT
39+
echo "Generated matrix output: $OUTPUT"
6740
test:
6841
needs: generate-matrix
6942
if: needs.generate-matrix.outputs.matrix != '[]'

0 commit comments

Comments
 (0)