Skip to content

Commit 861326d

Browse files
committed
Better support for varying PHP support in Plugins
Plugins may now define their minimum and maximum PHP requirements in their plugin.info.txt file using the `minphp` and `maxphp` keywords. The workflows and actions have been extended to take this into account. Tests will only run for the specified range, rector will only refactor PHP constructs up to the minimum supported PHP version.
1 parent 9aa9ecb commit 861326d

File tree

12 files changed

+284
-58
lines changed

12 files changed

+284
-58
lines changed

action.yml renamed to .github/actions/dokuenv/action.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
name: 'DokuWiki Plugin Test Action'
2-
description: 'Run tests for DokuWiki plugins'
1+
name: 'DokuWiki Environment creator'
2+
description: 'Install DokuWiki environment for plugin testing'
33
inputs:
44
branch:
55
description: 'The DokuWiki branch to test against'
@@ -12,6 +12,10 @@ outputs:
1212
description: 'The base name of the extension'
1313
dir:
1414
description: 'The full directory name of the extension (lib/plugins/<base> or lib/tpl/<base>)'
15+
minphp:
16+
description: 'The minimum PHP version required by the extension, if set. Otherwise empty.'
17+
maxphp:
18+
description: 'The maximum PHP version compatible with the extension, if set. Otherwise empty.'
1519
runs:
1620
using: 'node16'
1721
main: 'index.js'

index.js renamed to .github/actions/dokuenv/index.js

Lines changed: 13 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,7 @@ const core = require('@actions/core');
22
const process = require('child_process');
33
const fs = require('fs');
44
const path = require('path');
5-
6-
/**
7-
* Detects if we are in a plugin or template repo and returns the target directory
8-
*
9-
* @returns {string}
10-
*/
11-
function getTargetDir() {
12-
let type = '';
13-
let dir = '';
14-
let info = '';
15-
if (fs.existsSync('plugin.info.txt')) {
16-
type = 'plugin';
17-
dir = 'plugins';
18-
info = 'plugin.info.txt';
19-
} else if (fs.existsSync('template.info.txt')) {
20-
type = 'template';
21-
dir = 'tpl';
22-
info = 'template.info.txt';
23-
} else {
24-
throw new Error('No plugin.info.txt or template.info.txt found!');
25-
}
26-
27-
const data = fs.readFileSync(info, 'utf8');
28-
const lines = data.split('\n');
29-
const baseLine = lines.find(line => line.trim().startsWith('base'));
30-
if (!baseLine) {
31-
throw new Error('No base found in info file!');
32-
}
33-
const [, base] = baseLine.split(/\s+/);
34-
const targetDir = `lib/${dir}/${base}`;
35-
36-
core.setOutput('type', type);
37-
core.setOutput('dir', targetDir);
38-
core.setOutput('base', base);
39-
40-
return targetDir;
41-
}
5+
const dwUtils = require('../dokuwikiUtils');
426

437
/**
448
* Moves all contents of a directory to another directory
@@ -71,7 +35,7 @@ function moveContents(sourceDir, destinationDir) {
7135
}
7236

7337
/**
74-
* Installs additional plugin from requirements.txt if it exists
38+
* Installs additional plugins from requirements.txt if it exists
7539
*/
7640
function installRequirements(dir) {
7741
if (!fs.existsSync(`${dir}/requirements.txt`)) {
@@ -95,17 +59,24 @@ function installRequirements(dir) {
9559

9660
async function main() {
9761
const branch = core.getInput('branch', {required: true});
98-
const targetDir = getTargetDir();
62+
const config = dwUtils.loadExtensionInfo();
9963

100-
console.log(`Moving plugin to ${targetDir}...`);
101-
moveContents('.', targetDir);
64+
console.log(`Moving plugin to ${config.dir}...`);
65+
moveContents('.', config.dir);
10266

10367
// checkout DokuWiki into current directory (no clone because dir isn't empty)
10468
console.log(`Cloning DokuWiki ${branch}...`);
10569
process.execFileSync('git', ['init']);
10670
process.execFileSync('git', ['pull', 'https://github.com/dokuwiki/dokuwiki.git', branch]);
10771

108-
installRequirements(targetDir);
72+
installRequirements(config.dir);
73+
74+
// set outputs
75+
core.setOutput('type', config.type);
76+
core.setOutput('dir', config.dir);
77+
core.setOutput('base', config.base);
78+
core.setOutput('minphp', config.minphp);
79+
core.setOutput('maxphp', config.maxphp);
10980
}
11081

11182

.github/actions/dokuwikiUtils.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
const fs = require('fs');
2+
3+
/**
4+
* Get the extension info from the info file and set the type and dir
5+
*
6+
* @returns {{}}
7+
*/
8+
function loadExtensionInfo() {
9+
let type = '';
10+
let dir = '';
11+
let info = '';
12+
if (fs.existsSync('plugin.info.txt')) {
13+
type = 'plugin';
14+
dir = 'plugins';
15+
info = 'plugin.info.txt';
16+
} else if (fs.existsSync('template.info.txt')) {
17+
type = 'template';
18+
dir = 'tpl';
19+
info = 'template.info.txt';
20+
} else {
21+
throw new Error('No plugin.info.txt or template.info.txt found!');
22+
}
23+
24+
const config = parsePluginInfo(info);
25+
if (!config.base) {
26+
throw new Error('No base found in info file!');
27+
}
28+
const targetDir = `lib/${dir}/${config.base}`;
29+
config.type = type;
30+
config.dir = targetDir;
31+
32+
console.log('Extension info:', config);
33+
return config;
34+
}
35+
36+
/**
37+
* Parses a plugin.info.txt file into an object
38+
*
39+
* @param {string} filePath
40+
* @returns {{}}
41+
*/
42+
function parsePluginInfo(filePath) {
43+
const configData = fs.readFileSync(filePath, 'utf8');
44+
const lines = configData.split('\n');
45+
const configObject = {
46+
base: '',
47+
minphp: '',
48+
maxphp: '',
49+
};
50+
51+
for (const line of lines) {
52+
const [key, value] = line.trim().split(/\s+/);
53+
if (key && value) {
54+
configObject[key] = value;
55+
}
56+
}
57+
58+
return configObject;
59+
}
60+
61+
62+
module.exports = {
63+
loadExtensionInfo,
64+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: 'Create PHP Test Matrix'
2+
description: 'Creates the list of PHP versions and DokuWiki branches to test against'
3+
outputs:
4+
stable_matrix:
5+
description: 'The matrix for the stable branch'
6+
master_matrix:
7+
description: 'The matrix for the master branch'
8+
minphp:
9+
description: 'The minimum PHP version supported'
10+
runs:
11+
using: 'node16'
12+
main: 'index.js'

.github/actions/phpmatrix/index.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
const core = require('@actions/core');
2+
const dwUtils = require('../dokuwikiUtils');
3+
4+
/**
5+
* Convert to string, keeping one decimal place
6+
*
7+
* @param {Number} num
8+
* @returns {string}
9+
*/
10+
function toNumberString(num) {
11+
if (Number.isInteger(num)) {
12+
return num + ".0"
13+
} else {
14+
return num.toString();
15+
}
16+
}
17+
18+
async function main() {
19+
/**
20+
* these are the default versions for each branch
21+
* @fixme ideally we would load this from the dokuwiki repo
22+
*/
23+
const defaults = {
24+
stable: [7.2, 7.3, 7.4, 8.0, 8.1, 8.2],
25+
master: [7.4, 8.0, 8.1, 8.2],
26+
}
27+
28+
const matrix = {
29+
stable: {
30+
'dokuwiki-branch': ['stable'],
31+
'php-version': []
32+
},
33+
master: {
34+
'dokuwiki-branch': ['master'],
35+
'php-version': []
36+
}
37+
};
38+
39+
let minphp = 1000;
40+
41+
const config = dwUtils.loadExtensionInfo();
42+
43+
// iterate over versions, only adding those that are in range for the plugin
44+
for (const [branch, versions] of Object.entries(defaults)) {
45+
for (const php of versions) {
46+
if (config.minphp !== '' && parseFloat(config.minphp) > php) {
47+
continue;
48+
}
49+
if (config.maxphp !== '' && parseFloat(config.maxphp) < php) {
50+
continue;
51+
}
52+
matrix[branch]['php-version'].push(toNumberString(php));
53+
if (php < minphp) {
54+
minphp = php; // remember the lowest version
55+
}
56+
}
57+
}
58+
59+
// output the matrix
60+
core.setOutput('stable_matrix', JSON.stringify(matrix.stable));
61+
core.setOutput('master_matrix', JSON.stringify(matrix.master));
62+
core.setOutput('minphp', toNumberString(minphp));
63+
}
64+
65+
66+
try {
67+
main();
68+
} catch (error) {
69+
core.setFailed(error.message);
70+
}

.github/workflows/all.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,26 @@ on:
44
workflow_call:
55

66
jobs:
7-
code-style:
8-
uses: ./.github/workflows/cs.yml
7+
create-matrix:
8+
uses: ./.github/workflows/matrix.yml
9+
910
test-master:
11+
needs: create-matrix
1012
uses: ./.github/workflows/test.yml
1113
with:
12-
matrix-json: '{"php-version": ["7.4", "8.0", "8.1", "8.2"], "dokuwiki-branch": ["master"]}'
14+
matrix-json: ${{ needs.create-matrix.outputs.master_matrix }}
15+
1316
test-stable:
17+
needs: create-matrix
1418
uses: ./.github/workflows/test.yml
1519
with:
16-
matrix-json: '{"php-version": ["7.2", "7.3", "7.4", "8.0", "8.1", "8.2"], "dokuwiki-branch": ["stable"]}'
20+
matrix-json: ${{ needs.create-matrix.outputs.stable_matrix }}
21+
22+
code-style:
23+
uses: ./.github/workflows/cs.yml
24+
1725
auto-fix:
26+
needs: create-matrix
1827
uses: ./.github/workflows/autofix.yml
28+
with:
29+
rector-php: ${{ needs.create-matrix.outputs.minphp }}

.github/workflows/autofix.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ name: Automatic Code Style Fixing
22

33
on:
44
workflow_call:
5+
inputs:
6+
rector-php:
7+
description: 'The PHP version Rector should assume when updating code.'
8+
required: true
9+
type: string
10+
default: '7.2'
511

612
permissions:
713
contents: write
@@ -27,13 +33,13 @@ jobs:
2733

2834
- name: Create DokuWiki Environment
2935
id: dokuwiki-env
30-
uses: splitbrain/dokuwiki-gh-action@main
36+
uses: dokuwiki/github-action/.github/actions/dokuenv@main
3137
with:
3238
branch: master
3339

34-
- name: Run Rector
40+
- name: Run Rector (PHP ${{ inputs.rector-php }})
3541
env:
36-
RECTOR_MIN_PHP: 7.2
42+
RECTOR_MIN_PHP: ${{ inputs.rector-php }}
3743
run: rector process --config _test/rector.php --no-diffs ${{ steps.dokuwiki-env.outputs.dir }}
3844

3945
- name: Run PHP CodeSniffer AutoFixing

.github/workflows/cs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222

2323
- name: Create DokuWiki Environment
2424
id: dokuwiki-env
25-
uses: splitbrain/dokuwiki-gh-action@main
25+
uses: dokuwiki/github-action/.github/actions/dokuenv@main
2626
with:
2727
branch: master
2828

.github/workflows/matrix.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Create PHP Test Matrix
2+
3+
on:
4+
workflow_call:
5+
outputs:
6+
stable_matrix:
7+
description: 'The matrix for the stable branch'
8+
value: ${{ jobs.create-matrix.outputs.stable_matrix }}
9+
master_matrix:
10+
description: 'The matrix for the master branch'
11+
value: ${{ jobs.create-matrix.outputs.master_matrix }}
12+
minphp:
13+
description: 'The minimum PHP version supported'
14+
value: ${{ jobs.create-matrix.outputs.minphp }}
15+
16+
permissions: { }
17+
18+
jobs:
19+
create-matrix:
20+
runs-on: ubuntu-latest
21+
outputs:
22+
stable_matrix: ${{ steps.matrix.outputs.stable_matrix }}
23+
master_matrix: ${{ steps.matrix.outputs.master_matrix }}
24+
minphp: ${{ steps.matrix.outputs.minphp }}
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v3
28+
- id: matrix
29+
uses: dokuwiki/github-action/.github/actions/phpmatrix@main

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
3939
- name: Create DokuWiki Environment
4040
id: dokuwiki-env
41-
uses: splitbrain/dokuwiki-gh-action@main
41+
uses: dokuwiki/github-action/.github/actions/dokuenv@main
4242
with:
4343
branch: ${{ matrix.dokuwiki-branch }}
4444

0 commit comments

Comments
 (0)