This is an automated email from the ASF dual-hosted git repository.
young pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-website.git
The following commit(s) were added to refs/heads/master by this push:
new 49bc0a78617 chore: show failed logs in ci (#1968)
49bc0a78617 is described below
commit 49bc0a786177ca1eb86bd9b697e9290c6ae7ac76
Author: YYYoung <[email protected]>
AuthorDate: Wed Oct 29 14:39:37 2025 +0800
chore: show failed logs in ci (#1968)
---
.github/workflows/deploy.yml | 26 ++++++++
scripts/generate-website.js | 137 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 154 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 2cb5edb2f50..ba4e2b39827 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -108,6 +108,32 @@ jobs:
run: |
yarn build
+ - name: Show build logs on failure
+ if: failure()
+ run: |
+ LOG_DIR="/tmp/apisix-website-build-logs"
+ if [ -d "$LOG_DIR" ]; then
+ echo "Build logs:"
+ for logfile in "$LOG_DIR"/*.log; do
+ if [ -f "$logfile" ]; then
+ echo ""
+ echo "========== $(basename $logfile .log) =========="
+ cat "$logfile"
+ fi
+ done
+ else
+ echo "No log directory found at $LOG_DIR"
+ fi
+
+ - name: Upload build logs as artifact
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: build-logs
+ path: /tmp/apisix-website-build-logs/
+ retention-days: 7
+ if-no-files-found: warn
+
- name: Update sitemap.xml
run: |
yarn update-sitemap && git status
diff --git a/scripts/generate-website.js b/scripts/generate-website.js
index 0efa4371ccc..dee5122a0b2 100644
--- a/scripts/generate-website.js
+++ b/scripts/generate-website.js
@@ -1,8 +1,43 @@
const Listr = require('listr');
const util = require('util');
+const fs = require('fs');
+const path = require('path');
const { chdir } = require('node:process');
const exec = util.promisify(require('node:child_process').exec);
+// Detect CI environment
+const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS ===
'true';
+
+// Control whether to show logs locally (default: true for convenience)
+// Set SHOW_BUILD_LOGS=false to disable local log output
+const showLogsLocally = process.env.SHOW_BUILD_LOGS !== 'false';
+
+// Log directory for build outputs
+const logDir = '/tmp/apisix-website-build-logs';
+
+// Ensure log directory exists
+if (!fs.existsSync(logDir)) {
+ fs.mkdirSync(logDir, { recursive: true });
+}
+
+// Helper function to print logs from files
+function printLogFiles(logFiles, showAll = false) {
+ /* eslint-disable no-console */
+ logFiles.forEach((file) => {
+ // Only print failed logs, or all logs if showAll is true
+ if (showAll || file.failed) {
+ console.error(`\n========== ${file.step} ==========`);
+ try {
+ const content = fs.readFileSync(file.path, 'utf8');
+ console.error(content);
+ } catch (err) {
+ console.error(`Error reading log file: ${err.message}`);
+ }
+ }
+ });
+ /* eslint-enable no-console */
+}
+
const tasks = new Listr([
{
title: `Change working dir`,
@@ -17,34 +52,118 @@ const tasks = new Listr([
},
{
title: `Build website's all parts`,
- task: () => Promise.allSettled([
- exec('yarn run build:blog:zh', { stdio: 'ignore' }),
- exec('yarn run build:blog:en', { stdio: 'ignore' }),
- exec('yarn run build:doc', { stdio: 'ignore' }),
- exec('yarn run build:website', { stdio: 'ignore' }),
- ]),
+ task: async (ctx) => {
+ const buildSteps = [
+ { name: 'blog-zh', cmd: 'yarn run build:blog:zh' },
+ { name: 'blog-en', cmd: 'yarn run build:blog:en' },
+ { name: 'doc', cmd: 'yarn run build:doc' },
+ { name: 'website', cmd: 'yarn run build:website' },
+ ];
+
+ // Execute all builds in parallel, capturing output
+ const results = await Promise.allSettled(
+ buildSteps.map((step) => exec(step.cmd)),
+ );
+
+ // Check for failures and save logs to files
+ const failures = [];
+ const logFiles = [];
+
+ results.forEach((result, index) => {
+ const step = buildSteps[index];
+ const logFilePath = path.join(logDir, `${step.name}.log`);
+ let logContent = '';
+
+ if (result.status === 'fulfilled') {
+ // Write raw stdout and stderr without extra formatting
+ if (result.value.stdout) {
+ logContent += result.value.stdout;
+ }
+ if (result.value.stderr) {
+ if (logContent) logContent += '\n';
+ logContent += result.value.stderr;
+ }
+ } else {
+ failures.push(step.name);
+ // Write raw stdout and stderr for failed builds
+ if (result.reason.stdout) {
+ logContent += result.reason.stdout;
+ }
+ if (result.reason.stderr) {
+ if (logContent) logContent += '\n';
+ logContent += result.reason.stderr;
+ }
+ // Add error message at the end if available
+ if (result.reason.message &&
!result.reason.stderr?.includes(result.reason.message)) {
+ if (logContent) logContent += '\n';
+ logContent += `Error: ${result.reason.message}\n`;
+ }
+ }
+
+ // Write to log file
+ fs.writeFileSync(logFilePath, logContent);
+ logFiles.push({ path: logFilePath, step: step.name, failed:
result.status === 'rejected' });
+ });
+
+ // Store in context for later use
+ ctx.buildLogFiles = logFiles;
+ ctx.buildFailures = failures;
+
+ // If any build failed, throw error
+ if (failures.length > 0) {
+ throw new Error(`Build failed for: ${failures.join(', ')}`);
+ }
+ },
},
{
title: `Copy website's all parts to website's root`,
task: () => Promise.allSettled([
exec(
'cp ./.asf.yaml ./.htaccess ./blog/en/build/blog
./blog/en/build/assets ./doc/build/assets ./doc/build/docs ./website/build/ -r',
- { stdio: 'ignore' },
),
exec(
'cp ./blog/zh/build/blog ./blog/zh/build/assets ./doc/build/zh/docs
./doc/build/zh/assets ./website/build/zh/ -r',
- { stdio: 'ignore' },
),
]),
},
-]);
+], {
+ renderer: isCI ? 'verbose' : 'default',
+});
tasks
.run()
.then(() => {
+ /* eslint-disable-next-line no-console */
console.log(`[Finish] Generate website`);
+
+ // In local environment, show log location after successful build
+ if (!isCI && showLogsLocally && fs.existsSync(logDir)) {
+ /* eslint-disable-next-line no-console */
+ console.log(`\nBuild logs: ${logDir}/*.log`);
+ }
})
.catch((err) => {
+ /* eslint-disable-next-line no-console */
console.error(err);
+
+ // Print information about log files and their content
+ if (err.context && err.context.buildLogFiles) {
+ /* eslint-disable no-console */
+ console.error(`\nBuild logs saved to: ${logDir}`);
+ err.context.buildLogFiles.forEach((file) => {
+ const status = file.failed ? '❌' : '✓';
+ console.error(` ${status} ${file.step}.log`);
+ });
+ /* eslint-enable no-console */
+
+ // In local environment, automatically print failed logs
+ if (!isCI && showLogsLocally) {
+ printLogFiles(err.context.buildLogFiles, false);
+ } else if (!isCI) {
+ /* eslint-disable-next-line no-console */
+ console.error(`\nView logs: cat ${logDir}/*.log`);
+ }
+ }
+
process.exit(1);
});