-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add dynamic test matrixes, concurrency checks and more options
- Dynamic matrixes: workflows will check the version.php file which should always exist, and run checks based on the supported versions. It will apply a moodle_branches input check, or check the supported range, or fallback and check the plugin->requires range. This should cover most cases and other edge cases could be fixed by setting the appropriate plugin version settings (e.g. requires or supported) - Concurrency check: This prevents multiple tests for the same combination from running in the workflow. This can happen when performing another push to the same PR, this will effectively cancel the previous run and should reduce the time taken to run the most current workflow. - Added master branch to the list of branches to run workflows against by default (except when a support range is provided). This can be disabled explicitly by providing an input option disable_master - Full matrix options is now managed by a single yaml file currently located at `.github/actions/matrix/matrix_includes.yml` - Automating releases: to test if releases will trigger under the appropriate conditions, I've added an additional job to allow us to monitor if the release job will be triggered as expected. If so it would be safe then, to add the real release job to the workflow, and then we can remove the need for having 2 workflows (ci + release) and have them run inside a single workflow file.
- Loading branch information
Showing
49 changed files
with
5,992 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
include: | ||
# Versions 3.3 - 3.4 are not LTS, so only test a single combo for each. | ||
- {moodle-branch: 'MOODLE_33_STABLE', php: '7.1', node: '14.15', database: 'mariadb'} | ||
- {moodle-branch: 'MOODLE_34_STABLE', php: '7.1', node: '14.15', database: 'pgsql'} | ||
# Test all combinations for version 3.5 (as it is LTS). | ||
- {moodle-branch: 'MOODLE_35_STABLE', php: '7.1', node: '14.15', database: 'mariadb'} | ||
- {moodle-branch: 'MOODLE_35_STABLE', php: '7.1', node: '14.15', database: 'pgsql'} | ||
- {moodle-branch: 'MOODLE_35_STABLE', php: '7.2', node: '14.15', database: 'mariadb'} | ||
- {moodle-branch: 'MOODLE_35_STABLE', php: '7.2', node: '14.15', database: 'pgsql'} | ||
# Versions 3.6 - 3.8 are not LTS, so only test a single combo for each. | ||
- {moodle-branch: 'MOODLE_36_STABLE', php: '7.1', node: '14.15', database: 'mariadb'} | ||
- {moodle-branch: 'MOODLE_37_STABLE', php: '7.2', node: '14.15', database: 'pgsql'} | ||
- {moodle-branch: 'MOODLE_38_STABLE', php: '7.3', node: '14.15', database: 'mariadb'} | ||
# Also test all variants of 3.9 (LTS). | ||
- {moodle-branch: 'MOODLE_39_STABLE', php: '7.2', node: '14.15', database: 'mariadb'} | ||
- {moodle-branch: 'MOODLE_39_STABLE', php: '7.2', node: '14.15', database: 'pgsql'} | ||
- {moodle-branch: 'MOODLE_39_STABLE', php: '7.3', node: '14.15', database: 'mariadb'} | ||
- {moodle-branch: 'MOODLE_39_STABLE', php: '7.3', node: '14.15', database: 'pgsql'} | ||
# 3.10 - 4.00 are not LTS, so only test a single combo for each. | ||
- {moodle-branch: 'MOODLE_310_STABLE', php: '7.2', node: '14.15', database: 'pgsql'} | ||
- {moodle-branch: 'MOODLE_311_STABLE', php: '7.3', node: '14.15', database: 'mariadb'} | ||
- {moodle-branch: 'MOODLE_400_STABLE', php: '7.3', node: '14.15', database: 'pgsql'} | ||
# Always include master (issue #18) - disable-able by config by setting 'disable_master' to true | ||
- {moodle-branch: 'master', php: '7.3', node: '14.15', database: 'pgsql'} |
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,130 @@ | ||
<?php | ||
|
||
require __DIR__ . '../../../../vendor/autoload.php'; | ||
|
||
use Symfony\Component\Yaml\Yaml; | ||
|
||
/** | ||
* Outputs a value and binds it to a name provided. | ||
* | ||
* Note that arrays/objects should be JSON encoded, and read via the fromJson | ||
* method as described here: | ||
* https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson | ||
* | ||
* @param string $name name of the output | ||
* @param string $value value of the output - preferably JSON encoded if its an object/array | ||
* @author Kevin Pham <[email protected]> | ||
* @copyright Catalyst IT, 2022 | ||
*/ | ||
function output(string $name, string $value) { | ||
echo PHP_EOL; | ||
echo "::set-output name=$name::$value"; | ||
echo PHP_EOL; | ||
echo "Setting output.. $name = $value"; | ||
echo PHP_EOL; | ||
} | ||
|
||
// Greet the user. | ||
echo "Hello from PHP!"; | ||
$workspace = $_SERVER['GITHUB_WORKSPACE'] ?? ''; | ||
|
||
// This check is only possible with the version.php file, so end early if it doesn't exist. | ||
$versionFilePath = "$workspace/plugin/version.php"; | ||
if (!file_exists($versionFilePath)) { | ||
echo "version.php does not exist"; | ||
exit(1); | ||
} | ||
|
||
// Some moodle constants to prevent errors when trying to require the version.php file. | ||
define('MOODLE_INTERNAL', 1); | ||
/** Software maturity level - internals can be tested using white box techniques. */ | ||
define('MATURITY_ALPHA', 50); | ||
/** Software maturity level - feature complete, ready for preview and testing. */ | ||
define('MATURITY_BETA', 100); | ||
/** Software maturity level - tested, will be released unless there are fatal bugs. */ | ||
define('MATURITY_RC', 150); | ||
/** Software maturity level - ready for production deployment. */ | ||
define('MATURITY_STABLE', 200); | ||
/** Any version - special value that can be used in $plugin->dependencies in version.php files. */ | ||
define('ANY_VERSION', 'any'); | ||
|
||
$plugin = new \stdClass(); | ||
|
||
require_once($versionFilePath); | ||
|
||
|
||
// All supported matrix includes: | ||
$matrixYaml = file_get_contents("$workspace/ci/.github/actions/matrix/matrix_includes.yml"); | ||
$matrix = Yaml::parse($matrixYaml); | ||
|
||
// Version breakpoints are sourced from: | ||
// https://download.moodle.org/api/1.3/updates.php?format=json&version=0.0&branch=$lowestSupportedBranch | ||
$updates = json_decode(file_get_contents('https://download.moodle.org/api/1.3/updates.php?format=json&version=0.0&branch=3.3'), true); | ||
$updates = $updates['updates']['core'] ?? []; | ||
|
||
$preparedMatrix = array_filter($matrix['include'], function($entry) use($plugin, $updates) { | ||
// Regex and replacement templates - Partially generated from https://regex101.com/ | ||
$re = '/MOODLE_(.*)_STABLE/m'; | ||
$subst = '$1'; | ||
$coreVersion = preg_replace($re, $subst, $entry['moodle-branch']); | ||
$disable_master = !empty($_SERVER['INPUT_DISABLE_MASTER']); | ||
|
||
// If a fixed support range is set, use this. | ||
if (!empty($plugin->supported)) { | ||
[$lower, $upper] = $plugin->supported; | ||
if ($lower <= $coreVersion && $coreVersion <= $upper) { | ||
return true; | ||
} | ||
// For non master branches, immediately return false as they should not be included in the run. | ||
if ($entry['moodle-branch'] !== 'master') { | ||
return false; | ||
} | ||
} | ||
|
||
if (isset($_SERVER['INPUT_FILTER'])) { | ||
$filter = $_SERVER['INPUT_FILTER']; | ||
$filter = preg_split('/\s+/', $filter); | ||
// Otherwise if not defined, it should check if the INPUT_FILTER variable has been provided, and use the matching versions there instead. | ||
if (in_array($entry['moodle-branch'], $filter)) { | ||
return true; | ||
} | ||
} | ||
|
||
// If that hasn't been provided either, it should fallback and do a | ||
// requirement check on the version itself. Noting that this is probably the | ||
// worst option as it may need to go all the way down to version 3.3 to | ||
// support Totara and is probably wrong, as it also assumes the range is | ||
// open e.g. 35+ | ||
if (!empty($plugin->requires)) { | ||
// Notes: | ||
// - $plugin->requires = lowest version supported | ||
// - Use $plugin->requires to ensure the version checked (matching based | ||
// on regex) is higher than the lowest supported, if so, include it in | ||
// the matrix. | ||
foreach ($updates as $apiVersion) { | ||
$branchValue = str_replace('.', '', $apiVersion['branch']); | ||
$branch = "MOODLE_{$branchValue}_STABLE"; | ||
if ($entry['moodle-branch'] === $branch && $plugin->requires <= $apiVersion['version']) { | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
// Determine whether or not to include the master/dev branch | ||
if ($entry['moodle-branch'] === 'master' && !$disable_master) { | ||
return true; | ||
} | ||
|
||
return false; | ||
}); | ||
|
||
$jsonMatrix = json_encode(['include' => array_values($preparedMatrix)], JSON_UNESCAPED_SLASHES); | ||
output('matrix', $jsonMatrix); | ||
|
||
// Output the component / plugin name (which would be useful e.g. for a release) | ||
output('component', $plugin->component); | ||
|
||
// Output the highest available moodle branch in this set, which will be used to | ||
// determine whether or not various tests/tasks will run, such as grunt. | ||
output('highest_moodle_branch', end($preparedMatrix)['moodle-branch'] ?? ''); | ||
|
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,11 @@ | ||
#!/usr/bin/env bash | ||
|
||
# Get the current file/script path | ||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) | ||
|
||
# Output debugging | ||
echo "Hello from bash!" | ||
php -v | ||
|
||
# Run the PHP script | ||
php $SCRIPT_DIR/script.php |
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,174 @@ | ||
# .github/workflows/ci.yml | ||
name: ci | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
extra_php_extensions: | ||
type: string | ||
extra_plugin_runners: | ||
type: string | ||
disable_behat: | ||
type: boolean | ||
disable_phplint: | ||
type: boolean | ||
disable_phpunit: | ||
type: boolean | ||
disable_grunt: | ||
type: boolean | ||
disable_master: | ||
description: 'If true, this will skip testing against moodle/master branch' | ||
type: boolean | ||
disable_release: | ||
description: 'If true, this will skip the release job' | ||
type: boolean | ||
default: false | ||
release_branches: | ||
description: 'Required if the branch that should process releases is in a non-standard format (e.g. main or MOODLE_XX_STABLE)' | ||
type: string | ||
moodle_branches: | ||
description: 'Specify the MOODLE_XX_STABLE branch you want to test against' | ||
type: string | ||
|
||
jobs: | ||
prepare_matrix: | ||
name: prepare test matrix | ||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.ref }} | ||
cancel-in-progress: true | ||
runs-on: 'ubuntu-latest' | ||
outputs: | ||
matrix: ${{ steps.parse-version.outputs.matrix }} | ||
component: ${{ steps.parse-version.outputs.component }} | ||
highest_moodle_branch: ${{ steps.parse-version.outputs.highest_moodle_branch }} | ||
release_required: ${{ ( | ||
contains(github.event_name, 'push') && | ||
steps.check-version.outputs.any_changed == 'true' && | ||
steps.check-branch.outputs.publishable == 'true' | ||
) }} | ||
steps: | ||
- name: Check if currently on a publishable branch | ||
id: check-branch | ||
run: | | ||
publishable=${{ github.event.repository.fork == false && | ||
inputs.disable_release == false && ( | ||
(startsWith(github.ref, 'refs/heads/MOODLE_') && | ||
endsWith(github.ref, '_STABLE')) || | ||
github.ref == 'refs/heads/main' || ( | ||
inputs.release_branches != '' && | ||
endsWith(github.ref, inputs.release_branches) | ||
) | ||
) }} | ||
echo '::set-output name=publishable::$publishable' | ||
- name: Check out CI code | ||
uses: actions/checkout@v2 | ||
with: | ||
path: ci | ||
repository: catalyst/catalyst-moodle-workflows | ||
ref: v2 | ||
token: ${{ github.token }} | ||
- name: Check out plugin code | ||
uses: actions/checkout@v2 | ||
with: | ||
# Needed for 'changed-files' actions (alternatively could be a fixed | ||
# large number but may cause issues if limited). | ||
fetch-depth: ${{ (contains(github.event_name, 'push') && steps.check-branch.outputs.publishable == 'true') && 0 || 1 }} | ||
path: plugin | ||
- name: Check if release is required (version.php changes) | ||
if: contains(github.event_name, 'push') && steps.check-branch.outputs.publishable == 'true' | ||
uses: tj-actions/[email protected] | ||
id: check-version | ||
with: | ||
path: plugin | ||
files: version.php | ||
since_last_remote_commit: "true" | ||
- name: Install PHP | ||
uses: shivammathur/setup-php@v2 | ||
with: | ||
php-version: '8.1' | ||
coverage: none | ||
# extensions: yaml # FYI: makes the workflow very slow | ||
- name: Determine test requirements and plugin info | ||
id: parse-version | ||
run: | | ||
chmod +x "${GITHUB_WORKSPACE}/ci/.github/actions/parse-version/script.sh" | ||
"${GITHUB_WORKSPACE}/ci/.github/actions/parse-version/script.sh" | ||
env: | ||
disable_master: ${{ inputs.disable_master }} | ||
filter: ${{ inputs.moodle_branches }} | ||
|
||
# fake_test: | ||
# needs: prepare_matrix | ||
# runs-on: 'ubuntu-latest' | ||
# steps: | ||
# - run: | | ||
# echo "testing..." | ||
# exit 0 | ||
|
||
setup: | ||
name: ${{ matrix.moodle-branch }} - ${{ matrix.database }} - php ${{ matrix.php }} - ${{ needs.prepare_matrix.outputs.component }} | ||
needs: prepare_matrix | ||
strategy: | ||
fail-fast: false | ||
matrix: ${{ fromJson(needs.prepare_matrix.outputs.matrix) }} | ||
env: | ||
IGNORE_PATHS: tests/fixtures | ||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.moodle-branch }}-${{ matrix.database }}-${{ matrix.php }}-${{ needs.prepare_matrix.outputs.component }} | ||
cancel-in-progress: true | ||
runs-on: 'ubuntu-latest' | ||
services: | ||
postgres: | ||
image: postgres:10 | ||
env: | ||
POSTGRES_USER: 'postgres' | ||
POSTGRES_HOST_AUTH_METHOD: 'trust' | ||
options: >- | ||
--health-cmd pg_isready | ||
--health-interval 10s | ||
--health-timeout 5s | ||
--health-retries 3 | ||
ports: | ||
- 5432:5432 | ||
mariadb: | ||
image: mariadb:10.5 | ||
env: | ||
MYSQL_USER: 'root' | ||
MYSQL_ALLOW_EMPTY_PASSWORD: "true" | ||
ports: | ||
- 3306:3306 | ||
options: >- | ||
--health-cmd="mysqladmin ping" | ||
--health-interval 10s | ||
--health-timeout 5s | ||
--health-retries 3 | ||
steps: | ||
- name: Run plugin setup | ||
uses: catalyst/catalyst-moodle-workflows/.github/plugin/setup@main | ||
with: | ||
extra_php_extensions: ${{ inputs.extra_php_extensions }} | ||
extra_plugin_runners: ${{ inputs.extra_plugin_runners }} | ||
disable_behat: ${{ inputs.disable_behat }} | ||
disable_phplint: ${{ inputs.disable_phplint }} | ||
disable_phpunit: ${{ inputs.disable_phpunit }} | ||
disable_grunt: ${{ inputs.disable_grunt }} | ||
highest_moodle_branch: ${{ needs.prepare_matrix.outputs.highest_moodle_branch }} | ||
|
||
fake_release: | ||
name: release (check test only) | ||
needs: setup | ||
# needs: fake_test | ||
# If it matches a standard branch naming convention, it should permit a | ||
# release to happen, otherwise this step should be skipped. | ||
# Patterns allowed: | ||
# - MOODLE_XX_STABLE | ||
# - MOODLE_XXX_STABLE | ||
# - main | ||
if: needs.prepare_matrix.outputs.release_required == 'true' | ||
runs-on: 'ubuntu-latest' | ||
steps: | ||
- run: | | ||
echo "Only testing if releasing would occur. This step will always succeed." | ||
exit 0 | ||
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,5 @@ | ||
{ | ||
"require": { | ||
"symfony/yaml": "^5.4" | ||
} | ||
} |
Oops, something went wrong.