From e03e6d2a1ba67dbf3a94761213f954cf3ed0863a Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 30 Jun 2021 16:03:03 +0200 Subject: [PATCH] MOBILE-3320 DX: Implement behat gulp command --- gulp/task-build-behat-plugin.js | 47 ++++++++ gulpfile.js | 21 +++- scripts/build-behat-plugin.js | 104 ++++++++++++++++++ .../lang/en/local_moodleappbehat.php | 3 + scripts/templates/behat-plugin/version.php | 13 +++ tests/behat/.gitkeep | 0 6 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 gulp/task-build-behat-plugin.js create mode 100755 scripts/build-behat-plugin.js create mode 100644 scripts/templates/behat-plugin/lang/en/local_moodleappbehat.php create mode 100644 scripts/templates/behat-plugin/version.php create mode 100644 tests/behat/.gitkeep diff --git a/gulp/task-build-behat-plugin.js b/gulp/task-build-behat-plugin.js new file mode 100644 index 000000000..964e61d5a --- /dev/null +++ b/gulp/task-build-behat-plugin.js @@ -0,0 +1,47 @@ +// (C) Copyright 2021 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const { exec } = require('child_process'); +const { resolve } = require('path'); + +/** + * Task to build a Moodle plugin to run Behat tests. + */ +class BuildBehatPluginTask { + + /** + * Check whether Behat is configured to run app tests. + * + * @returns Whether Behat is configured. + */ + static isBehatConfigured() { + if (process.env.MOODLE_APP_BEHAT_PLUGIN_PATH) { + return !['0', 'false'].includes(process.env.MOODLE_APP_BEHAT_PLUGIN_PATH); + } + + return !!process.env.MOODLE_DOCKER_WWWROOT; + } + + /** + * Run the task. + * + * @param done Function to call when done. + */ + run(done) { + exec(resolve(__dirname, '../scripts/build-behat-plugin.js'), done); + } + +} + +module.exports = BuildBehatPluginTask; diff --git a/gulpfile.js b/gulpfile.js index 605ac7e40..9f3f5f93f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -13,6 +13,7 @@ // limitations under the License. const BuildLangTask = require('./gulp/task-build-lang'); +const BuildBehatPluginTask = require('./gulp/task-build-behat-plugin'); const BuildEnvTask = require('./gulp/task-build-env'); const PushTask = require('./gulp/task-push'); const Utils = require('./gulp/utils'); @@ -40,13 +41,31 @@ gulp.task('env', (done) => { new BuildEnvTask().run(done); }); +// Build a Moodle plugin to run Behat tests. +if (BuildBehatPluginTask.isBehatConfigured()) { + gulp.task('behat', (done) => { + new BuildBehatPluginTask().run(done); + }); +} + gulp.task('push', (done) => { new PushTask().run(args, done); }); -gulp.task('default', gulp.parallel(['lang', 'env'])); +gulp.task( + 'default', + gulp.parallel([ + 'lang', + 'env', + ...(BuildBehatPluginTask.isBehatConfigured() ? ['behat'] : []) + ]), +); gulp.task('watch', () => { gulp.watch(paths.lang, { interval: 500 }, gulp.parallel('lang')); gulp.watch(['./moodle.config.json', './moodle.config.*.json'], { interval: 500 }, gulp.parallel('env')); + + if (BuildBehatPluginTask.isBehatConfigured()) { + gulp.watch(['./tests/behat'], { interval: 500 }, gulp.parallel('behat')); + } }); diff --git a/scripts/build-behat-plugin.js b/scripts/build-behat-plugin.js new file mode 100755 index 000000000..e5d62c6bc --- /dev/null +++ b/scripts/build-behat-plugin.js @@ -0,0 +1,104 @@ +#!/usr/bin/env node + +// (C) Copyright 2021 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const { existsSync, readFileSync, writeFileSync } = require('fs'); +const { readdir } = require('fs').promises; +const { mkdirSync, copySync } = require('fs-extra'); +const { resolve } = require('path'); + +async function main() { + const pluginPath = process.argv[2] || guessPluginPath() || fail('Folder argument missing!'); + + if (!existsSync(pluginPath)) { + mkdirSync(pluginPath); + } + + // Copy plugin template. + const { version: appVersion } = require(projectPath('package.json')); + const templatePath = projectPath('scripts/templates/behat-plugin'); + const replacements = { + appVersion, + pluginVersion: getMoodlePluginVersion(), + }; + + copySync(templatePath, pluginPath); + + for await (const templateFilePath of getDirectoryFiles(templatePath)) { + const pluginFilePath = pluginPath + templateFilePath.substr(templatePath.length); + const fileContents = readFileSync(pluginFilePath).toString(); + + writeFileSync(pluginFilePath, replaceArguments(fileContents, replacements)); + } + + // Copy features. + copySync(projectPath('tests/behat'), `${pluginPath}/tests/behat`); +} + +function fail(message) { + console.error(message); + process.exit(1); +} + +function guessPluginPath() { + if (process.env.MOODLE_APP_BEHAT_PLUGIN_PATH) { + return process.env.MOODLE_APP_BEHAT_PLUGIN_PATH; + } + + if (process.env.MOODLE_DOCKER_WWWROOT) { + return `${process.env.MOODLE_DOCKER_WWWROOT}/local/moodleappbehat`; + } + + return null; +} + +function projectPath(path) { + return resolve(__dirname, '../', path); +} + +async function* getDirectoryFiles(dir) { + const files = await readdir(dir, { withFileTypes: true }); + + for (const file of files) { + const path = resolve(dir, file.name); + if (file.isDirectory()) { + yield* getDirectoryFiles(path); + } else { + yield path; + } + } +} + +function replaceArguments(text, args) { + for (const [arg, value] of Object.entries(args)) { + const regexp = new RegExp(`\\{\\{\\s+${arg}\\s+\\}\\}`, 'gm'); + + text = text.replace(regexp, value); + } + + return text; +} + +function getMoodlePluginVersion() { + const now = new Date(); + const padded = (number, length = 2) => number.toString().padStart(length, '0'); + const year = padded(now.getFullYear(), 4); + const month = padded(now.getMonth() + 1); + const day = padded(now.getDate()); + + return `${year}${month}${day}00`; +} + +main(); diff --git a/scripts/templates/behat-plugin/lang/en/local_moodleappbehat.php b/scripts/templates/behat-plugin/lang/en/local_moodleappbehat.php new file mode 100644 index 000000000..ba8d678e0 --- /dev/null +++ b/scripts/templates/behat-plugin/lang/en/local_moodleappbehat.php @@ -0,0 +1,3 @@ +version = {{ pluginVersion }}; +$plugin->requires = 2016052300; +$plugin->maturity = MATURITY_STABLE; +$plugin->release = '{{ appVersion }}'; +$plugin->component = 'local_moodleappbehat'; diff --git a/tests/behat/.gitkeep b/tests/behat/.gitkeep new file mode 100644 index 000000000..e69de29bb