Skip to content

Commit 05242f2

Browse files
authored
Create daily test matrix (#522)
1 parent dab5ced commit 05242f2

File tree

8 files changed

+2717
-0
lines changed

8 files changed

+2717
-0
lines changed

.github/scripts/build-wp-env.js

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
'use strict';
2+
3+
const fs = require( 'fs' );
4+
5+
const wpEnv = require( '../../.wp-env.json' );
6+
const {
7+
PHP_VERSION,
8+
WP_CORE_VERSION,
9+
HELLO_THEME_VERSION,
10+
HELLO_PLUS_VERSION,
11+
ELEMENTOR_VERSION,
12+
} = process.env;
13+
14+
if ( ! PHP_VERSION ) {
15+
// eslint-disable-next-line no-console
16+
console.error( 'missing env var PHP_VERSION' );
17+
process.exit( 1 );
18+
}
19+
20+
if ( ! WP_CORE_VERSION ) {
21+
// eslint-disable-next-line no-console
22+
console.error( 'missing env var WP_CORE_VERSION' );
23+
process.exit( 1 );
24+
}
25+
26+
// Set WordPress core version
27+
let wpCore = null;
28+
if ( WP_CORE_VERSION !== 'latest' ) {
29+
wpCore = `WordPress/WordPress#${ WP_CORE_VERSION }`;
30+
}
31+
32+
// Set PHP version
33+
wpEnv.phpVersion = PHP_VERSION;
34+
wpEnv.core = wpCore;
35+
36+
// Configure themes - Require built Hello Theme to avoid false positives
37+
if ( fs.existsSync( './tmp/hello-theme' ) ) {
38+
wpEnv.themes = [ './tmp/hello-theme' ];
39+
// eslint-disable-next-line no-console
40+
console.log( '✅ Using built Hello Theme from ./tmp/hello-theme' );
41+
} else {
42+
// eslint-disable-next-line no-console
43+
console.error( 'Built Hello Theme not found at ./tmp/hello-theme' );
44+
// eslint-disable-next-line no-console
45+
console.error( 'This prevents false positives from using unbuild source theme' );
46+
// eslint-disable-next-line no-console
47+
console.error( 'Current directory contents:' );
48+
// eslint-disable-next-line no-console
49+
console.error( fs.readdirSync( '.' ) );
50+
if ( fs.existsSync( './tmp' ) ) {
51+
// eslint-disable-next-line no-console
52+
console.error( './tmp contents:' );
53+
// eslint-disable-next-line no-console
54+
console.error( fs.readdirSync( './tmp' ) );
55+
}
56+
process.exit( 1 );
57+
}
58+
59+
// Add Hello Plus if available (for Plus matrix tests)
60+
if ( HELLO_PLUS_VERSION && fs.existsSync( './tmp/hello-plus' ) ) {
61+
wpEnv.themes.push( './tmp/hello-plus' );
62+
}
63+
64+
// Configure plugins
65+
wpEnv.plugins = [];
66+
67+
// Add Elementor plugin
68+
if ( ELEMENTOR_VERSION ) {
69+
// eslint-disable-next-line no-console
70+
console.log( '🔍 =============================================' );
71+
// eslint-disable-next-line no-console
72+
console.log( '🔍 BUILD-WP-ENV.JS ELEMENTOR DEBUG' );
73+
// eslint-disable-next-line no-console
74+
console.log( '🔍 =============================================' );
75+
// eslint-disable-next-line no-console
76+
console.log( `🎯 ELEMENTOR_VERSION: "${ ELEMENTOR_VERSION }"` );
77+
78+
if ( 'latest-stable' === ELEMENTOR_VERSION ) {
79+
// Use WordPress.org directly for latest-stable (most reliable)
80+
wpEnv.plugins.push( 'https://downloads.wordpress.org/plugin/elementor.latest-stable.zip' );
81+
// eslint-disable-next-line no-console
82+
console.log( '✅ Using WordPress.org Elementor latest-stable (direct)' );
83+
} else if ( ELEMENTOR_VERSION.match( /^v?[0-9]+\.[0-9]+\.[0-9]+$/ ) ) {
84+
// Use WordPress.org directly for semantic versions (e.g., 3.30.4, v3.30.4)
85+
const cleanVersion = ELEMENTOR_VERSION.replace( /^v/, '' );
86+
wpEnv.plugins.push( `https://downloads.wordpress.org/plugin/elementor.${ cleanVersion }.zip` );
87+
// eslint-disable-next-line no-console
88+
console.log( `✅ Using WordPress.org Elementor ${ cleanVersion } (direct)` );
89+
} else if ( fs.existsSync( './tmp/elementor' ) ) {
90+
// GitHub branches (main, feature-branch) - expect built artifacts from workflow
91+
// eslint-disable-next-line no-console
92+
console.log( `🔍 Using GitHub built artifacts for Elementor ${ ELEMENTOR_VERSION }` );
93+
// Debug: Verify Elementor directory structure
94+
// eslint-disable-next-line no-console
95+
console.log( '🔍 DEBUG: Elementor directory found, verifying structure...' );
96+
try {
97+
const elementorContents = fs.readdirSync( './tmp/elementor' );
98+
// eslint-disable-next-line no-console
99+
console.log( `📁 Elementor directory contents (${ elementorContents.length } items):`, elementorContents.slice( 0, 10 ) );
100+
101+
// Check for main plugin file
102+
if ( fs.existsSync( './tmp/elementor/elementor.php' ) ) {
103+
// eslint-disable-next-line no-console
104+
console.log( '✅ Main plugin file found: elementor.php' );
105+
106+
// Read plugin header for verification
107+
try {
108+
const pluginContent = fs.readFileSync( './tmp/elementor/elementor.php', 'utf8' );
109+
const headerMatch = pluginContent.match( /Plugin Name:\s*(.+)/i );
110+
const versionMatch = pluginContent.match( /Version:\s*(.+)/i );
111+
if ( headerMatch ) {
112+
// eslint-disable-next-line no-console
113+
console.log( `📄 Plugin Name: ${ headerMatch[ 1 ].trim() }` );
114+
}
115+
if ( versionMatch ) {
116+
// eslint-disable-next-line no-console
117+
console.log( `🏷️ Plugin Version: ${ versionMatch[ 1 ].trim() }` );
118+
}
119+
} catch ( error ) {
120+
// eslint-disable-next-line no-console
121+
console.log( '⚠️ Could not read plugin header:', error.message );
122+
}
123+
} else {
124+
// eslint-disable-next-line no-console
125+
console.log( '❌ Main plugin file missing: elementor.php' );
126+
const phpFiles = elementorContents.filter( ( file ) => file.endsWith( '.php' ) );
127+
// eslint-disable-next-line no-console
128+
console.log( `🔍 Available PHP files (${ phpFiles.length }):`, phpFiles.slice( 0, 5 ) );
129+
}
130+
131+
// Check for essential directories
132+
const essentialDirs = [ 'includes', 'assets' ];
133+
essentialDirs.forEach( ( dir ) => {
134+
if ( fs.existsSync( `./tmp/elementor/${ dir }` ) ) {
135+
// eslint-disable-next-line no-console
136+
console.log( `✅ Essential directory found: ${ dir }` );
137+
} else {
138+
// eslint-disable-next-line no-console
139+
console.log( `⚠️ Essential directory missing: ${ dir }` );
140+
}
141+
} );
142+
} catch ( error ) {
143+
// eslint-disable-next-line no-console
144+
console.error( '❌ Error reading Elementor directory:', error.message );
145+
}
146+
147+
// Check if local Elementor installation is valid
148+
const isValidElementor = fs.existsSync( './tmp/elementor/elementor.php' ) &&
149+
fs.existsSync( './tmp/elementor/includes' ) &&
150+
fs.existsSync( './tmp/elementor/assets' );
151+
152+
if ( isValidElementor ) {
153+
// Use the GitHub built artifacts for branches
154+
wpEnv.plugins.push( './tmp/elementor' );
155+
// eslint-disable-next-line no-console
156+
console.log( `✅ Using GitHub built artifacts for Elementor ${ ELEMENTOR_VERSION }` );
157+
} else {
158+
// GitHub artifacts should be valid - if not, something went wrong in workflow
159+
// eslint-disable-next-line no-console
160+
console.error( `❌ Invalid GitHub artifacts for Elementor ${ ELEMENTOR_VERSION }` );
161+
// eslint-disable-next-line no-console
162+
console.error( 'Expected workflow to provide valid built artifacts in ./tmp/elementor' );
163+
process.exit( 1 );
164+
}
165+
} else {
166+
// eslint-disable-next-line no-console
167+
console.error( `❌ Elementor directory not found at ./tmp/elementor for branch/commit: ${ ELEMENTOR_VERSION }` );
168+
// eslint-disable-next-line no-console
169+
console.error( 'Note: Semantic versions (e.g., 3.30.4) and latest-stable are downloaded directly from WordPress.org' );
170+
process.exit( 1 );
171+
}
172+
173+
// eslint-disable-next-line no-console
174+
console.log( '🔍 =============================================' );
175+
// eslint-disable-next-line no-console
176+
console.log( '🔍 END BUILD-WP-ENV.JS ELEMENTOR DEBUG' );
177+
// eslint-disable-next-line no-console
178+
console.log( '🔍 =============================================' );
179+
}
180+
181+
// Test configuration
182+
wpEnv.config = {
183+
...wpEnv.config,
184+
ELEMENTOR_SHOW_HIDDEN_EXPERIMENTS: true,
185+
SCRIPT_DEBUG: false,
186+
WP_DEBUG: true,
187+
WP_DEBUG_LOG: true,
188+
WP_DEBUG_DISPLAY: false,
189+
};
190+
191+
// Add version info for debugging
192+
if ( HELLO_THEME_VERSION ) {
193+
wpEnv.config.HELLO_THEME_VERSION = HELLO_THEME_VERSION;
194+
}
195+
if ( HELLO_PLUS_VERSION ) {
196+
wpEnv.config.HELLO_PLUS_VERSION = HELLO_PLUS_VERSION;
197+
}
198+
199+
// eslint-disable-next-line no-console
200+
console.log( 'Building wp-env configuration:' );
201+
// eslint-disable-next-line no-console
202+
console.log( `- PHP Version: ${ PHP_VERSION }` );
203+
// eslint-disable-next-line no-console
204+
console.log( `- WP Core: ${ wpCore || 'latest' }` );
205+
// eslint-disable-next-line no-console
206+
console.log( `- Hello Theme: ${ HELLO_THEME_VERSION || 'current' }` );
207+
// eslint-disable-next-line no-console
208+
console.log( `- Hello Plus: ${ HELLO_PLUS_VERSION || 'not included' }` );
209+
// eslint-disable-next-line no-console
210+
console.log( `- Elementor: ${ ELEMENTOR_VERSION || 'latest-stable' }` );
211+
// eslint-disable-next-line no-console
212+
console.log( `- Themes: ${ wpEnv.themes.join( ', ' ) }` );
213+
// eslint-disable-next-line no-console
214+
console.log( `- Plugins: ${ wpEnv.plugins.join( ', ' ) }` );
215+
216+
fs.writeFileSync( '.wp-env.json', JSON.stringify( wpEnv, null, 4 ) );
217+
// eslint-disable-next-line no-console
218+
console.log( '✅ wp-env.json updated successfully' );

.github/scripts/daily-report.js

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/**
2+
* Utility functions for the daily Hello Theme test matrix workflow
3+
*/
4+
5+
const {
6+
getStatusEmoji,
7+
getStatusText,
8+
validateWorkflowData,
9+
pollWorkflows,
10+
generateStatusSummary,
11+
setJobStatus,
12+
generateResultLink,
13+
} = require( './workflow-reporting.js' );
14+
15+
/**
16+
* Generates a daily trigger workflow report
17+
* @param {Object} github - GitHub API client
18+
* @param {Object} context - GitHub Actions context
19+
* @param {Object} core - GitHub Actions core utilities
20+
* @param {Array} workflowData - Array of workflow run data
21+
* @param {Object} timing - Timing configuration object
22+
*/
23+
async function generateDailyTriggerReport( github, context, core, workflowData, timing ) {
24+
// eslint-disable-next-line no-console
25+
console.log( `Generating report for ${ workflowData.length } daily compatibility tests` );
26+
27+
const validation = validateWorkflowData( workflowData );
28+
29+
if ( ! validation.hasValidRuns ) {
30+
// eslint-disable-next-line no-console
31+
console.warn( 'No valid workflow run IDs found, generating preliminary report' );
32+
return;
33+
}
34+
35+
// Poll workflows until completion
36+
const results = await pollWorkflows( github, context, validation.validRuns, timing, {
37+
logPrefix: 'daily workflows',
38+
} );
39+
40+
// Generate and write report
41+
const summary = generateDailyMarkdownReport( results );
42+
await core.summary.addRaw( summary ).write();
43+
// eslint-disable-next-line no-console
44+
console.log( 'Generated daily trigger workflow report' );
45+
46+
setJobStatus( core, results, 'Some daily workflows failed or encountered errors' );
47+
}
48+
49+
/**
50+
* Generates a markdown report for daily trigger testing
51+
* @param {Array} results - Array of workflow results
52+
* @return {string} - Markdown formatted report
53+
*/
54+
function generateDailyMarkdownReport( results ) {
55+
const summary = generateStatusSummary( results );
56+
57+
// Sort results by type and name for consistent display
58+
const sortedResults = sortDailyResults( results );
59+
60+
let report = `# 🧪 Hello Theme Daily Test Matrix Results\n\n`;
61+
62+
// Overall summary
63+
report += `## 📊 Summary\n\n`;
64+
report += `| Status | Count |\n`;
65+
report += `|--------|-------|\n`;
66+
report += `| ✅ Success | ${ summary.success } |\n`;
67+
report += `| ❌ Failed | ${ summary.failed } |\n`;
68+
report += `| ❌ Error | ${ summary.error } |\n`;
69+
if ( summary.running > 0 ) {
70+
report += `| 🔄 Running | ${ summary.running } |\n`;
71+
}
72+
if ( summary.cancelled > 0 ) {
73+
report += `| 🚫 Cancelled | ${ summary.cancelled } |\n`;
74+
}
75+
if ( summary.skipped > 0 ) {
76+
report += `| ⏭️ Skipped | ${ summary.skipped } |\n`;
77+
}
78+
report += `| **Total** | **${ summary.total }** |\n\n`;
79+
80+
// Detailed results
81+
report += `## 📋 Detailed Results\n\n`;
82+
83+
// Group by matrix type
84+
const coreTests = sortedResults.filter( ( r ) => r.combination && r.combination.includes( 'el' ) );
85+
const plusTests = sortedResults.filter( ( r ) => r.combination && r.combination.includes( 'hp' ) );
86+
87+
if ( coreTests.length > 0 ) {
88+
report += `### ⚡ Hello Theme × Elementor Tests\n\n`;
89+
report += generateTestTable( coreTests );
90+
report += `\n`;
91+
}
92+
93+
if ( plusTests.length > 0 ) {
94+
report += `### 🔌 Hello Theme × Hello Plus Tests\n\n`;
95+
report += generateTestTable( plusTests );
96+
report += `\n`;
97+
}
98+
99+
// Footer
100+
report += `## 🎯 Matrix Strategy\n\n`;
101+
report += `- **Core Matrix**: Hello Theme × Elementor (main, latest, previous minors)\n`;
102+
report += `- **Plus Matrix**: Hello Theme × Hello Plus (latest, previous patch - WordPress.org only)\n`;
103+
report += `- **Versions**: Tests both main development and GA release combinations\n\n`;
104+
105+
report += `*Generated at ${ new Date().toISOString() }*`;
106+
107+
return report;
108+
}
109+
110+
/**
111+
* Generates a test results table
112+
* @param {Array} tests - Array of test results
113+
* @return {string} - Markdown table
114+
*/
115+
function generateTestTable( tests ) {
116+
let table = `| Status | Test Name | Duration | Link |\n`;
117+
table += `|--------|-----------|----------|------|\n`;
118+
119+
tests.forEach( ( test ) => {
120+
const emoji = getStatusEmoji( test.status, test.conclusion );
121+
const statusText = getStatusText( test.status, test.conclusion );
122+
const duration = test.duration ? `${ test.duration }m` : '-';
123+
const link = generateResultLink( test );
124+
125+
table += `| ${ emoji } ${ statusText } | ${ test.name || test.combination } | ${ duration } | ${ link } |\n`;
126+
} );
127+
128+
return table;
129+
}
130+
131+
/**
132+
* Sorts daily test results for consistent display order
133+
* @param {Array} results - Array of workflow results
134+
* @return {Array} - Sorted array of results
135+
*/
136+
function sortDailyResults( results ) {
137+
return results.sort( ( a, b ) => {
138+
// First sort by matrix type (core vs plus)
139+
const aIsCore = a.combination && a.combination.includes( 'el' );
140+
const bIsCore = b.combination && b.combination.includes( 'el' );
141+
142+
if ( aIsCore && ! bIsCore ) {
143+
return -1;
144+
}
145+
if ( ! aIsCore && bIsCore ) {
146+
return 1;
147+
}
148+
149+
// Then sort by Hello Theme version (main first, then GA)
150+
const aIsMain = 'main' === a.hello_theme_version;
151+
const bIsMain = 'main' === b.hello_theme_version;
152+
153+
if ( aIsMain && ! bIsMain ) {
154+
return -1;
155+
}
156+
if ( ! aIsMain && bIsMain ) {
157+
return 1;
158+
}
159+
160+
// Finally sort by dependency version (main first, then latest, then previous)
161+
const aVersion = a.elementor_version || a.hello_plus_version || '';
162+
const bVersion = b.elementor_version || b.hello_plus_version || '';
163+
164+
if ( 'main' === aVersion && bVersion !== 'main' ) {
165+
return -1;
166+
}
167+
if ( aVersion !== 'main' && 'main' === bVersion ) {
168+
return 1;
169+
}
170+
171+
// Alphabetical fallback
172+
return ( a.name || a.combination || '' ).localeCompare( b.name || b.combination || '' );
173+
} );
174+
}
175+
176+
module.exports = {
177+
generateDailyTriggerReport,
178+
generateDailyMarkdownReport,
179+
sortDailyResults,
180+
};

0 commit comments

Comments
 (0)