mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
Merge branch 'MDL-81125-main-alt' of https://github.com/andrewnicols/moodle
This commit is contained in:
commit
bd9631bda5
1
.gitignore
vendored
1
.gitignore
vendored
@ -56,3 +56,4 @@ moodle-plugin-ci.phar
|
||||
.hugo_build.lock
|
||||
phpcs.xml
|
||||
jsconfig.json
|
||||
UPGRADING-CURRENT.md
|
||||
|
@ -40,9 +40,20 @@ const fetchComponentData = () => {
|
||||
if (!Object.entries(componentData).length) {
|
||||
componentData.subsystems = {};
|
||||
componentData.pathList = [];
|
||||
componentData.components = {};
|
||||
componentData.standardComponents = {};
|
||||
|
||||
// Fetch the component definiitions from the distributed JSON file.
|
||||
const components = JSON.parse(fs.readFileSync(`${gruntFilePath}/lib/components.json`));
|
||||
const pluginData = JSON.parse(fs.readFileSync(`${gruntFilePath}/lib/plugins.json`));
|
||||
|
||||
componentData.pluginTypes = components.plugintypes;
|
||||
|
||||
const standardPlugins = Object.entries(pluginData.standard).map(
|
||||
([pluginType, pluginNames]) => {
|
||||
return pluginNames.map(pluginName => `${pluginType}_${pluginName}`);
|
||||
}
|
||||
).reduce((acc, val) => acc.concat(val), []);
|
||||
|
||||
// Build the list of moodle subsystems.
|
||||
componentData.subsystems.lib = 'core';
|
||||
@ -55,8 +66,8 @@ const fetchComponentData = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// The list of components incldues the list of subsystems.
|
||||
componentData.components = componentData.subsystems;
|
||||
// The list of components includes the list of subsystems.
|
||||
componentData.components = {...componentData.subsystems};
|
||||
|
||||
// Go through each of the plugintypes.
|
||||
Object.entries(components.plugintypes).forEach(([pluginType, pluginTypePath]) => {
|
||||
@ -87,6 +98,20 @@ const fetchComponentData = () => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Create a list of the standard subsystem and plugins.
|
||||
componentData.standardComponents = Object.fromEntries(
|
||||
Object.entries(componentData.components).filter(([, name]) => {
|
||||
if (name === 'core' || name.startsWith('core_')) {
|
||||
return true;
|
||||
}
|
||||
return standardPlugins.indexOf(name) !== -1;
|
||||
})
|
||||
);
|
||||
|
||||
componentData.componentMapping = Object.fromEntries(
|
||||
Object.entries(componentData.components).map(([path, name]) => [name, path])
|
||||
);
|
||||
}
|
||||
|
||||
return componentData;
|
||||
|
110
.grunt/notes/src/components.mjs
Normal file
110
.grunt/notes/src/components.mjs
Normal file
@ -0,0 +1,110 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import * as Components from '../../components.js';
|
||||
|
||||
const componentData = Components.fetchComponentData();
|
||||
|
||||
/**
|
||||
* The standard components shipped with core Moodle.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
export const standardComponents = componentData.standardComponents;
|
||||
|
||||
/**
|
||||
* All components of the current Moodle instance.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
export const allComponents = componentData.components;
|
||||
|
||||
/**
|
||||
* Get all components of the current Moodle instance.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getAllComponents = () => {
|
||||
let components = new Map(Object.entries(componentData.pluginTypes).map(([value, path]) => ([path,{
|
||||
path,
|
||||
value,
|
||||
name: `${value} (plugin type)`,
|
||||
}])));
|
||||
|
||||
Object
|
||||
.entries(componentData.components)
|
||||
.filter(([path, value]) => Object.values(componentData.standardComponents).includes(value))
|
||||
.forEach(([path, value]) => {
|
||||
const entry = {
|
||||
path,
|
||||
value,
|
||||
name: value,
|
||||
};
|
||||
if (Object.values(componentData.subsystems).includes(value)) {
|
||||
if (components.has(path)) {
|
||||
entry.name = `${value} (subsystem / plugintype)`;
|
||||
} else {
|
||||
entry.name = `${value} (subsystem)`;
|
||||
}
|
||||
}
|
||||
|
||||
components.set(path, entry);
|
||||
});
|
||||
|
||||
return Array.from(components.values());
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the specified component is a standard component shipped with core Moodle.
|
||||
*
|
||||
* @param {string} componentName
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isStandardComponent = (componentName) => {
|
||||
if (Object.values(componentData.standardComponents).includes(componentName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Object.keys(componentData.pluginTypes).includes(componentName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export const rewritePlugintypeAsSubsystem = (componentName) => {
|
||||
if (Object.keys(componentData.pluginTypes).includes(componentName)) {
|
||||
const pluginTypePath = componentData.pluginTypes[componentName];
|
||||
if (Object.keys(componentData.subsystems).includes(pluginTypePath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the specified component is a community component.
|
||||
*
|
||||
* @param {string} componentName
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isCommunityComponent = (componentName) => {
|
||||
if (isStandardComponent(componentName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Object.values(componentData.components).indexOf(componentName) !== -1;
|
||||
}
|
85
.grunt/notes/src/create.mjs
Normal file
85
.grunt/notes/src/create.mjs
Normal file
@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env node
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import inquirer from 'inquirer';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { createNote } from './note.mjs';
|
||||
import { getInitialValues } from './helpers.mjs';
|
||||
import * as Prompts from './prompts.mjs';
|
||||
import logger from './logger.mjs';
|
||||
|
||||
export default async (options) => {
|
||||
// Processs the initial values.
|
||||
const initialValues = getInitialValues(options);
|
||||
|
||||
// Fetch information.
|
||||
const messages = [];
|
||||
const { issueNumber } = await inquirer.prompt([
|
||||
Prompts.getIssuePrompt(),
|
||||
], initialValues);
|
||||
|
||||
let selection = {};
|
||||
let notePath;
|
||||
do {
|
||||
selection = {};
|
||||
selection = await inquirer.prompt([
|
||||
Prompts.getComponentsPrompt(),
|
||||
Prompts.getTypePrompt(),
|
||||
Prompts.getMessagePromptInput(),
|
||||
], initialValues);
|
||||
if (selection.message === '') {
|
||||
selection = Object.assign(
|
||||
selection,
|
||||
await inquirer.prompt([
|
||||
Prompts.getMessagePromptEditor(),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
logger.info(`
|
||||
Creating upgrade note with the following options:
|
||||
|
||||
- Issue: ${chalk.bold(issueNumber)}
|
||||
- Component: ${chalk.bold(selection.components)}
|
||||
- Type: ${chalk.bold(selection.type)}
|
||||
- Message:
|
||||
${chalk.bold(selection.message)}
|
||||
`);
|
||||
|
||||
messages.push({
|
||||
components: [selection.components],
|
||||
type: selection.type,
|
||||
message: selection.message,
|
||||
});
|
||||
|
||||
// Save the note so far.
|
||||
if (notePath) {
|
||||
await createNote(issueNumber, messages, notePath);
|
||||
logger.info(`Updated note at: ${chalk.underline(chalk.bold(notePath))}`);
|
||||
} else {
|
||||
notePath = await createNote(issueNumber, messages);
|
||||
logger.info(`Note created at: ${chalk.underline(chalk.bold(notePath))}`);
|
||||
}
|
||||
|
||||
selection = Object.assign(
|
||||
selection,
|
||||
await inquirer.prompt([
|
||||
Prompts.getAddAnotherPrompt(),
|
||||
], initialValues),
|
||||
);
|
||||
} while (selection.addAnother);
|
||||
};
|
318
.grunt/notes/src/generate.mjs
Normal file
318
.grunt/notes/src/generate.mjs
Normal file
@ -0,0 +1,318 @@
|
||||
#!/usr/bin/env node
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { getAllComponents } from './components.mjs';
|
||||
import { getCombinedNotesByComponent, deleteAllNotes } from './note.mjs';
|
||||
import { getNoteName } from './noteTypes.mjs';
|
||||
import { writeFile, readFile, unlink } from 'fs/promises';
|
||||
import { join as joinPath } from 'path';
|
||||
import logger from './logger.mjs';
|
||||
import { getCurrentVersion } from './helpers.mjs';
|
||||
|
||||
/**
|
||||
* Helper to fetch the current notes from a file.
|
||||
*
|
||||
* @param {string} file
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
const getCurrentNotes = async (file) => {
|
||||
try {
|
||||
return await readFile(file, 'utf8');
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the UPGRADING.md file.
|
||||
*
|
||||
* @param {string} upgradeNotes
|
||||
* @param {Object} options
|
||||
* @param {boolean} options.deleteNotes
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const updateUpgradeNotes = async (upgradeNotes, options) => {
|
||||
const fileName = 'UPGRADING.md';
|
||||
// Write the notes to a file.
|
||||
logger.info(`Writing notes to ${chalk.underline(chalk.bold(fileName))}`);
|
||||
// Prepend to the existing file.
|
||||
const existingContent = await getCurrentNotes(fileName);
|
||||
if (existingContent) {
|
||||
await writeFile(fileName, getUpdatedNotes(existingContent, upgradeNotes));
|
||||
} else {
|
||||
// This should not normally happen.
|
||||
await writeFile(fileName, upgradeNotes);
|
||||
}
|
||||
|
||||
if (options.deleteNotes) {
|
||||
logger.warn(`>>> Deleting all notes <<<`)
|
||||
// Delete the notes.
|
||||
deleteAllNotes();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the current summary notes.
|
||||
*
|
||||
* @param {string} upgradeNotes
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const createCurrentSummary = async (upgradeNotes) => {
|
||||
const fileName = 'UPGRADING-CURRENT.md';
|
||||
const notes = `# Moodle upgrade notes\n\n${upgradeNotes}`;
|
||||
await writeFile(fileName, notes);
|
||||
|
||||
logger.info(`Running upgrade notes written to ${chalk.underline(chalk.bold(fileName))}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the indexes of the lines that contain the version headings.
|
||||
*
|
||||
* @param {array<string>} lines
|
||||
* @returns {array<object>}
|
||||
*/
|
||||
const getVersionLineIndexes = (lines) => {
|
||||
const h2Indexes = [];
|
||||
lines.forEach((line, index) => {
|
||||
const matches = line.match(/^##\s(?<version>.*)$/);
|
||||
if (matches) {
|
||||
h2Indexes.push({
|
||||
index,
|
||||
line,
|
||||
version: matches.groups.version,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return h2Indexes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the index of the Unreleased heading.
|
||||
*
|
||||
* @param {array<object>} versionHeadings
|
||||
* @returns {number}
|
||||
*/
|
||||
const findUnreleasedHeadingIndex = (versionHeadings) => versionHeadings.findIndex((heading) => {
|
||||
if (heading.version === 'Unreleased') {
|
||||
// Used if version cannot be guessed.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (heading.version.endsWith('+')) {
|
||||
// Weekly release for a stable branch.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (heading.version.match(/beta|rc\d/)) {
|
||||
// Beta and RC rolls are treated as weeklies.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (heading.version.endsWith('dev')) {
|
||||
// Development version.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the before and after content, to facilitate replacing any existing Unreleased notes.
|
||||
*
|
||||
* @param {array<string>} lines
|
||||
* @returns {Object} {beforeContent: string, afterContent: string}
|
||||
*/
|
||||
const getBeforeAndAfterContent = (lines) => {
|
||||
const existingLines = lines.split('\n');
|
||||
const versionHeadings = getVersionLineIndexes(existingLines);
|
||||
|
||||
if (versionHeadings.length > 0) {
|
||||
const unreleasedHeadingIndex = findUnreleasedHeadingIndex(versionHeadings);
|
||||
if (unreleasedHeadingIndex !== -1) {
|
||||
const beforeContent = existingLines.slice(0, versionHeadings[unreleasedHeadingIndex].index).join('\n');
|
||||
if (versionHeadings.length > unreleasedHeadingIndex + 1) {
|
||||
const afterContent = existingLines.slice(versionHeadings[unreleasedHeadingIndex + 1].index).join('\n');
|
||||
return {
|
||||
beforeContent,
|
||||
afterContent,
|
||||
};
|
||||
}
|
||||
return {
|
||||
beforeContent,
|
||||
afterContent: '',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
beforeContent: existingLines.slice(0, versionHeadings[0].index).join('\n'),
|
||||
afterContent: existingLines.slice(versionHeadings[0].index).join('\n'),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
beforeContent: existingLines.join('\n'),
|
||||
afterContent: '',
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the notes for the component.
|
||||
*
|
||||
* @param {string} type
|
||||
* @param {Number} headingLevel
|
||||
* @returns {string}
|
||||
*/
|
||||
const getNotesForComponent = (types, headingLevel) => {
|
||||
let upgradeNotes = '';
|
||||
Object.entries(types).forEach(([type, notes]) => {
|
||||
upgradeNotes += '#'.repeat(headingLevel);
|
||||
upgradeNotes += ` ${getNoteName(type)}\n\n`;
|
||||
notes.forEach(({ message, issueNumber }) => {
|
||||
// Split the message into lines, removing empty lines.
|
||||
const messageLines = message
|
||||
.split('\n')
|
||||
.filter((line) => line.trim().length > 0);
|
||||
|
||||
const firstLine = messageLines.shift().trim();
|
||||
upgradeNotes += `- ${firstLine}\n`;
|
||||
|
||||
messageLines
|
||||
.forEach((line) => {
|
||||
upgradeNotes += ` ${line.trimEnd()}\n`;
|
||||
});
|
||||
upgradeNotes += `\n For more information see [${issueNumber}](https://tracker.moodle.org/browse/${issueNumber})\n`;
|
||||
});
|
||||
upgradeNotes += '\n';
|
||||
});
|
||||
|
||||
return upgradeNotes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the updated notes mixed with existing content.
|
||||
*
|
||||
* @param {string} existingContent
|
||||
* @param {string} upgradeNotes
|
||||
*/
|
||||
const getUpdatedNotes = (existingContent, upgradeNotes) => {
|
||||
const { beforeContent, afterContent } = getBeforeAndAfterContent(existingContent);
|
||||
const newContent = `${beforeContent}\n${upgradeNotes}\n${afterContent}`
|
||||
.split('\n')
|
||||
.filter((line, index, lines) => {
|
||||
if (line === '' && lines[index - 1] === '') {
|
||||
// Remove multiple consecutive empty lines.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
return newContent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the notes for each component.
|
||||
*/
|
||||
const updateComponentNotes = (
|
||||
notes,
|
||||
version,
|
||||
notesFileName = 'UPGRADING.md',
|
||||
removeEmpty = false,
|
||||
) => {
|
||||
return getAllComponents().map(async (component) => {
|
||||
logger.verbose(`Updating notes for ${component.name} into ${component.path}`);
|
||||
const fileName = joinPath(component.path, notesFileName);
|
||||
|
||||
const existingContent = await getCurrentNotes(fileName);
|
||||
|
||||
if (!existingContent) {
|
||||
if (!notes[component.value]) {
|
||||
// No existing notes, and no new notes to add.
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!notes[component.value]) {
|
||||
// There is existing content, but nothing to add.
|
||||
if (removeEmpty) {
|
||||
logger.verbose(`Removing empty notes file ${fileName}`);
|
||||
await unlink(fileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const componentNotes = notes[component.value];
|
||||
let upgradeNotes = `## ${version}\n\n`;
|
||||
upgradeNotes += getNotesForComponent(componentNotes, 3);
|
||||
|
||||
if (existingContent) {
|
||||
await writeFile(fileName, getUpdatedNotes(existingContent, upgradeNotes));
|
||||
} else {
|
||||
await writeFile(
|
||||
fileName,
|
||||
`# ${component.name} Upgrade notes\n\n${upgradeNotes}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the upgrade notes for a new release.
|
||||
*
|
||||
* @param {string|undefined} version
|
||||
* @param {Object} options
|
||||
* @param {boolean} options.generateUpgradeNotes
|
||||
* @param {boolean} options.deleteNotes
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export default async (version, options = {}) => {
|
||||
const notes = await getCombinedNotesByComponent();
|
||||
|
||||
if (Object.keys(notes).length === 0) {
|
||||
logger.warn('No notes to generate');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!version) {
|
||||
version = await getCurrentVersion();
|
||||
}
|
||||
|
||||
// Generate the upgrade notes for this release.
|
||||
// We have
|
||||
// - a title with the release name
|
||||
// - the change types
|
||||
// - which contain the components
|
||||
// - which document each changev
|
||||
let upgradeNotes = `## ${version}\n\n`;
|
||||
|
||||
Object.entries(notes).forEach(([component, types]) => {
|
||||
upgradeNotes += `### ${component}\n\n`;
|
||||
upgradeNotes += getNotesForComponent(types, 4);
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
createCurrentSummary(upgradeNotes),
|
||||
...updateComponentNotes(notes, version, 'UPGRADING-CURRENT.md', true),
|
||||
]);
|
||||
if (options.generateUpgradeNotes) {
|
||||
await Promise.all(updateComponentNotes(notes, version));
|
||||
await updateUpgradeNotes(upgradeNotes, options);
|
||||
}
|
||||
};
|
230
.grunt/notes/src/helpers.mjs
Normal file
230
.grunt/notes/src/helpers.mjs
Normal file
@ -0,0 +1,230 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { isStandardComponent, isCommunityComponent, rewritePlugintypeAsSubsystem } from './components.mjs';
|
||||
import { isValidNoteName } from './noteTypes.mjs';
|
||||
import logger from './logger.mjs';
|
||||
import { readFile } from 'fs/promises';
|
||||
|
||||
/**
|
||||
* Validate an issue number input
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {string|boolean}
|
||||
*/
|
||||
export const validateIssueNumber = (input) => {
|
||||
if (!input) {
|
||||
return 'You must provide a tracker issue number';
|
||||
}
|
||||
|
||||
if (input.match(/^[a-zA-Z]*-\d+$/)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (input.match(/^\d+$/)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return 'The issue number was not recognised as a valid issue number';
|
||||
};
|
||||
|
||||
/**
|
||||
* Format an issue number input.
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {string}
|
||||
*/
|
||||
export const formatIssueNumber = (input) => {
|
||||
if (input.match(/^[a-zA-Z]*-\d+$/)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
if (input.match(/^\d+$/)) {
|
||||
return `MDL-${input}`;
|
||||
}
|
||||
|
||||
return input;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate a component.
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {string|boolean}
|
||||
*/
|
||||
export const validateComponent = (input) => {
|
||||
if (isStandardComponent(input)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isCommunityComponent(input)) {
|
||||
return 'Currently only core plugins are supported.';
|
||||
}
|
||||
|
||||
return 'The component was not recognised as a standard component';
|
||||
};
|
||||
|
||||
export const formatComponent = (input) => {
|
||||
if (rewritePlugintypeAsSubsystem(input)) {
|
||||
return `core_${input}`;
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initial values from the options.
|
||||
*
|
||||
* @param {object} options
|
||||
* @returns {object}
|
||||
*/
|
||||
export const getInitialValues = (options) => {
|
||||
const initialValues = {};
|
||||
|
||||
const type = getInitialTypeValue(options);
|
||||
if (type) {
|
||||
initialValues.type = type;
|
||||
}
|
||||
|
||||
const issueNumber = getInitialIssueValue(options);
|
||||
if (issueNumber) {
|
||||
initialValues.issueNumber = issueNumber;
|
||||
}
|
||||
|
||||
const component = getInitialComponentValue(options);
|
||||
if (component) {
|
||||
initialValues.components = component;
|
||||
}
|
||||
|
||||
const message = getInitialMessageValue(options);
|
||||
if (message) {
|
||||
initialValues.message = message
|
||||
initialValues.addAnother = false;
|
||||
}
|
||||
|
||||
return initialValues;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the initial type value.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
const getInitialTypeValue = (options) => {
|
||||
if (!options.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.type = options.type.trim().toLowerCase();
|
||||
|
||||
if (isValidNoteName(options.type)) {
|
||||
return options.type;
|
||||
}
|
||||
|
||||
logger.warn(`Note type "${chalk.underline(chalk.red(options.type))}" is not valid.`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the initial issue number value.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
|
||||
const getInitialIssueValue = (options) => {
|
||||
if (!options.issue) {
|
||||
return;
|
||||
}
|
||||
options.issue = options.issue.trim().toUpperCase();
|
||||
|
||||
const issueNumberValidated = validateIssueNumber(options.issue);
|
||||
if (issueNumberValidated === true) {
|
||||
const issueNumber = formatIssueNumber(options.issue);
|
||||
if (issueNumber !== options.issue) {
|
||||
logger.warn(
|
||||
`Issue number "${chalk.underline(chalk.red(options.issue))}" was updated to ` +
|
||||
`"${chalk.underline(chalk.green(issueNumber))}"`
|
||||
);
|
||||
}
|
||||
|
||||
return issueNumber;
|
||||
} else {
|
||||
logger.warn(`Issue number "${chalk.underline(chalk.red(options.issue))}" is not valid: ${issueNumberValidated}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the initial component value.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
const getInitialComponentValue = (options) => {
|
||||
if (!options.component) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.component = options.component.trim().toLowerCase();
|
||||
const componentValidated = validateComponent(options.component);
|
||||
if (componentValidated === true) {
|
||||
const component = formatComponent(options.component);
|
||||
if (component !== options.component) {
|
||||
logger.warn(
|
||||
`Component "${chalk.underline(chalk.red(options.component))}" was updated to ` +
|
||||
`"${chalk.underline(chalk.green(component))}"`
|
||||
);
|
||||
}
|
||||
|
||||
return component;
|
||||
} else {
|
||||
logger.warn(`Component "${chalk.underline(chalk.red(options.component))}" is not valid: ${componentValidated}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the initial message value.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
|
||||
const getInitialMessageValue = (options) => {
|
||||
if (!options.message) {
|
||||
return;
|
||||
}
|
||||
|
||||
return options.message.trim();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current version from the project /version.php file.
|
||||
*
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export const getCurrentVersion = async () => {
|
||||
const versionRegex = new RegExp(/^ *\$release *= *['\"](?<release>[^ \+]+\+?) *\(Build:.*/m);
|
||||
try {
|
||||
const versionFile = await readFile('version.php', 'utf8');
|
||||
const match = versionFile.match(versionRegex);
|
||||
if (match) {
|
||||
return match.groups.release;
|
||||
}
|
||||
} catch(error) {
|
||||
logger.error('Unable to read the version file');
|
||||
}
|
||||
|
||||
return "Unreleased";
|
||||
}
|
30
.grunt/notes/src/logger.mjs
Normal file
30
.grunt/notes/src/logger.mjs
Normal file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env node
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import winston from 'winston';
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.simple()
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.Console(),
|
||||
],
|
||||
});
|
||||
|
||||
export default logger;
|
183
.grunt/notes/src/note.mjs
Normal file
183
.grunt/notes/src/note.mjs
Normal file
@ -0,0 +1,183 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import yaml from 'js-yaml';
|
||||
import path from 'path';
|
||||
import { writeFile, mkdir, readdir, readFile, unlink } from 'fs/promises';
|
||||
import { isValidNoteName } from './noteTypes.mjs';
|
||||
|
||||
const unreleasedPath = path.resolve('.upgradenotes');
|
||||
|
||||
/**
|
||||
* Get the filename for the note.
|
||||
*
|
||||
* @param {string} issueNumnber The issue number
|
||||
* @returns {string}
|
||||
*/
|
||||
const getFilename = (issueNumber) => {
|
||||
const dateTimeFormat = new Intl.DateTimeFormat(undefined, {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
fractionalSecondDigits: 2,
|
||||
timeZone: 'UTC',
|
||||
});
|
||||
|
||||
const date = Object.fromEntries(
|
||||
dateTimeFormat.formatToParts(new Date())
|
||||
.filter((p) => p.type !== 'literal')
|
||||
.map((p) => ([p.type, p.value]))
|
||||
);
|
||||
|
||||
const dateString = [
|
||||
date.year,
|
||||
date.month,
|
||||
date.day,
|
||||
date.hour,
|
||||
date.minute,
|
||||
date.second,
|
||||
date.fractionalSecond,
|
||||
].join('');
|
||||
|
||||
return `${issueNumber}-${dateString}.yml`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new note.
|
||||
*
|
||||
* @param {string} issueNumber
|
||||
* @param {[type: string]: {message: string}} messages
|
||||
* @returns {string} The path to the note on disk
|
||||
*/
|
||||
export const createNote = async (
|
||||
issueNumber,
|
||||
messages,
|
||||
notePath,
|
||||
) => {
|
||||
const note = {
|
||||
issueNumber,
|
||||
notes: {},
|
||||
};
|
||||
|
||||
messages.forEach(({components, type, message}) => {
|
||||
note.notes[components] = note.notes[components] || [];
|
||||
note.notes[components].push({message, type});
|
||||
});
|
||||
|
||||
if (!notePath) {
|
||||
notePath = path.resolve(unreleasedPath, getFilename(issueNumber));
|
||||
}
|
||||
const noteContent = yaml.dump(note);
|
||||
|
||||
await mkdir(unreleasedPath, {recursive: true});
|
||||
await writeFile(notePath, noteContent);
|
||||
|
||||
return notePath;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all unreleased notes.
|
||||
*
|
||||
* @returns {Promise<{issueNumber: string, components: string[], types: {[type: string]: {message: string}[]}}[]>
|
||||
*/
|
||||
export const getAllNotes = async () => {
|
||||
const files = await readdir(unreleasedPath);
|
||||
const notes = files
|
||||
.filter((file) => file.endsWith('.yml'))
|
||||
.map(async (file) => {
|
||||
const filePath = path.resolve(unreleasedPath, file);
|
||||
const fileContent = await readFile(filePath, 'utf8');
|
||||
|
||||
return {
|
||||
...yaml.load(fileContent),
|
||||
filePath,
|
||||
};
|
||||
});
|
||||
|
||||
return Promise.all(notes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the list of notes, grouped by note type, then component.
|
||||
*
|
||||
* @returns {Promise<{[type: string]: {[components: string]: {message: string, issueNumber: string}[]}}>}
|
||||
*/
|
||||
export const getCombinedNotes = async () => {
|
||||
const notes = await getAllNotes();
|
||||
const combinedNotes = {};
|
||||
|
||||
notes.forEach((note) => {
|
||||
Object.entries(note.notes).forEach(([components, data]) => {
|
||||
data.forEach((entry) => {
|
||||
if (!isValidNoteName(entry.type)) {
|
||||
throw new Error(`Invalid note type: "${entry.type}" in file ${note.filePath}`);
|
||||
}
|
||||
combinedNotes[entry.type] = combinedNotes[entry.type] || {};
|
||||
combinedNotes[entry.type][components] = combinedNotes[entry.type][components] || [];
|
||||
combinedNotes[entry.type][components].push({message: entry.message, issueNumber: note.issueNumber});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return combinedNotes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the list of notes, grouped by component, then by note type.
|
||||
*
|
||||
* @returns {Promise<{[component: string]: {[type: string]: {message: string, issueNumber: string}[]}}>}
|
||||
*/
|
||||
export const getCombinedNotesByComponent = async () => {
|
||||
const notes = await getAllNotes();
|
||||
const combinedNotes = {};
|
||||
|
||||
notes.forEach((note) => {
|
||||
Object.entries(note.notes).forEach(([component, data]) => {
|
||||
combinedNotes[component] = combinedNotes[component] || {};
|
||||
data.forEach((entry) => {
|
||||
if (!isValidNoteName(entry.type)) {
|
||||
throw new Error(`Invalid note type: "${entry.type}" in file ${note.filePath}`);
|
||||
}
|
||||
combinedNotes[component][entry.type] = combinedNotes[component][entry.type] || [];
|
||||
combinedNotes[component][entry.type].push({
|
||||
component,
|
||||
message: entry.message,
|
||||
issueNumber: note.issueNumber,
|
||||
type: entry.type,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return combinedNotes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete all unreleased notes.
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const deleteAllNotes = async () => {
|
||||
const files = await readdir(unreleasedPath);
|
||||
return Promise.all(
|
||||
files
|
||||
.filter((item, index) => files.indexOf(item) === index)
|
||||
.filter((file) => file.endsWith('.yml'))
|
||||
.map((file) => unlink(`${unreleasedPath}/${file}`))
|
||||
);
|
||||
};
|
45
.grunt/notes/src/noteTypes.mjs
Normal file
45
.grunt/notes/src/noteTypes.mjs
Normal file
@ -0,0 +1,45 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
const noteTypes = {
|
||||
'improved': 'Added',
|
||||
'removed': 'Removed',
|
||||
'changed': 'Changed',
|
||||
'deprecated': 'Deprecated',
|
||||
'fixed': 'Fixed',
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the note names.
|
||||
*
|
||||
* @returns {string[]}
|
||||
*/
|
||||
export const getNoteNames = () => Object.keys(noteTypes);
|
||||
|
||||
/**
|
||||
* Get the human-readable note name.
|
||||
*
|
||||
* @param {string} type
|
||||
* @returns {string}
|
||||
*/
|
||||
export const getNoteName = (type) => noteTypes[type];
|
||||
|
||||
/**
|
||||
* Whether the note name is valid.
|
||||
*
|
||||
* @param {string} type
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isValidNoteName = (type) => noteTypes[type] !== undefined;
|
153
.grunt/notes/src/prompts.mjs
Normal file
153
.grunt/notes/src/prompts.mjs
Normal file
@ -0,0 +1,153 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import inquirer from 'inquirer';
|
||||
import SearchList from 'inquirer-search-list';
|
||||
|
||||
import { getNoteNames } from './noteTypes.mjs';
|
||||
import { getAllComponents } from './components.mjs';
|
||||
import {
|
||||
formatComponent,
|
||||
formatIssueNumber,
|
||||
validateComponent,
|
||||
validateIssueNumber,
|
||||
} from './helpers.mjs';
|
||||
|
||||
/**
|
||||
* A Search List which accepts an initial value.
|
||||
*/
|
||||
class SearchListWithInitialValue extends SearchList {
|
||||
constructor(options, ...args) {
|
||||
super(options, ...args);
|
||||
|
||||
if (options.default) {
|
||||
const pointer = this.filterList.findIndex((item) => {
|
||||
return item.value === options.default;
|
||||
});
|
||||
if (pointer > -1) {
|
||||
this.pointer = pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inquirer.registerPrompt('search-list', SearchListWithInitialValue);
|
||||
|
||||
/**
|
||||
* Get the issue type prompt.
|
||||
*
|
||||
* @param {string} defaultData The initially selected value
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const getTypePrompt = (defaultData) => ({
|
||||
default: defaultData,
|
||||
type: 'search-list',
|
||||
message: 'Type of change',
|
||||
name: 'type',
|
||||
choices: getNoteNames(),
|
||||
validate: (selection) => {
|
||||
if (selection.length < 1) {
|
||||
return 'You must select at least one type of change';
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the component prompt.
|
||||
*
|
||||
* @param {string} [defaultValue='core'] The initally selected value.
|
||||
* @returns
|
||||
*/
|
||||
export const getComponentsPrompt = (defaultValue) => {
|
||||
if (!defaultValue ) {
|
||||
defaultValue = 'core';
|
||||
}
|
||||
|
||||
return {
|
||||
choices: getAllComponents(),
|
||||
default: defaultValue,
|
||||
type: 'search-list',
|
||||
message: 'Component',
|
||||
name: 'components',
|
||||
validate: validateComponent,
|
||||
filter: formatComponent,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the issue number prompt as an inline input.
|
||||
*
|
||||
* @param {string} defaultData
|
||||
* @returns {object}
|
||||
*/
|
||||
export const getIssuePrompt = (defaultData) => ({
|
||||
default: defaultData,
|
||||
type: 'input',
|
||||
message: 'Tracker issue number',
|
||||
name: 'issueNumber',
|
||||
validate: validateIssueNumber,
|
||||
filter: formatIssueNumber,
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a message prompt.
|
||||
*
|
||||
* @param {string} defaultData
|
||||
* @returns
|
||||
*/
|
||||
export const getMessagePromptEditor = (defaultData) => ({
|
||||
default: defaultData,
|
||||
type: process.stdin.isTTY ? 'editor' : 'input',
|
||||
postfix: '.md',
|
||||
message: 'Message',
|
||||
name: 'message',
|
||||
waitUserInput: false,
|
||||
validate: (input) => {
|
||||
if (!input) {
|
||||
return 'You must provide a message';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// Remove any trailing whitespace.
|
||||
filter: (input) => input.split('\n').map((line) => line.trimEnd()).join('\n'),
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a message prompt.
|
||||
*
|
||||
* @param {string} defaultData
|
||||
* @returns
|
||||
*/
|
||||
export const getMessagePromptInput = (defaultData) => ({
|
||||
default: defaultData,
|
||||
type: 'input',
|
||||
message: 'Message (leave empty to use editor)',
|
||||
name: 'message',
|
||||
filter: (input) => input.trim(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a prompt to ask the user if they wish to add another entry.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const getAddAnotherPrompt = () => ({
|
||||
type: 'confirm',
|
||||
message: 'Do you want to add another note?',
|
||||
default: false,
|
||||
name: 'addAnother',
|
||||
});
|
103
.grunt/upgradenotes.mjs
Executable file
103
.grunt/upgradenotes.mjs
Executable file
@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env node
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Argument, Option, program } from 'commander';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { getNoteNames } from './notes/src/noteTypes.mjs';
|
||||
import createAction from './notes/src/create.mjs';
|
||||
import generateAction from './notes/src/generate.mjs';
|
||||
import logger from './notes/src/logger.mjs';
|
||||
|
||||
console.log(`
|
||||
${chalk.bold(chalk.underline(chalk.green('Moodle Upgrade Notes Generator')))}
|
||||
|
||||
This tool is used to generate the upgrade notes for changes you make in Moodle.
|
||||
|
||||
Please remember that the intended audience of these changes is
|
||||
${chalk.italic('plugin developers')} who need to know how to update their plugins
|
||||
for a new Moodle version.
|
||||
|
||||
Upgrade notes should not be used to document changes for site administrators, or
|
||||
for internal API changes which are not expected to be used outside of the
|
||||
relevant component.
|
||||
`)
|
||||
|
||||
program.configureHelp({
|
||||
helpWidth: 100,
|
||||
});
|
||||
|
||||
program.on('option:verbose', () => {
|
||||
logger.level = 'verbose';
|
||||
});
|
||||
|
||||
program.addOption(
|
||||
new Option(
|
||||
'-v, --verbose',
|
||||
'Output more information during the generation process',
|
||||
)
|
||||
.default(false)
|
||||
);
|
||||
|
||||
// Define the command line options.
|
||||
program
|
||||
.command('create')
|
||||
.summary('Generate a new upgrade note')
|
||||
.addOption(
|
||||
new Option('-t, --type <type>', `The type of change to document. Valid types are: ${getNoteNames().join(', ')}`)
|
||||
)
|
||||
.addOption(new Option('-i, --issue <issue>', 'The tracker issue number'))
|
||||
.addOption(new Option('-c, --component <component>', 'The component to write a note for'))
|
||||
.addOption(new Option(
|
||||
'-m, --message <message>',
|
||||
'The message to use for the upgrade note',
|
||||
))
|
||||
.action((options) => createAction(options));
|
||||
|
||||
program
|
||||
.command('summary')
|
||||
.summary('Generate a local copy of the upgrade notes summary')
|
||||
.addArgument(
|
||||
new Argument('[version]', 'The Moodle version to create the summary notes for')
|
||||
)
|
||||
.action((version) => generateAction(version));
|
||||
|
||||
program
|
||||
.command('release')
|
||||
.summary('Generate the markdown copies of the upgrade notes for a Moodle release')
|
||||
.addArgument(
|
||||
new Argument('[version]', 'The Moodle version to create the release notes for')
|
||||
)
|
||||
.addOption(
|
||||
new Option(
|
||||
'--generate-upgrade-notes',
|
||||
'Generate the UPGRADING.md notes for the release. ' +
|
||||
'Note: This option is intended for use by the release manager when generating the upgrade notes.',
|
||||
)
|
||||
.default(true)
|
||||
)
|
||||
.addOption(
|
||||
new Option(
|
||||
'-d, --delete-notes',
|
||||
'Delete the notes after generating the UPGRADING.md notes for the release. ' +
|
||||
'Note: This option is intended for use by the release manager when generating the upgrade notes.' +
|
||||
'This option has no effect unless --generate-upgrade-notes is also set.'
|
||||
)
|
||||
.default(false)
|
||||
)
|
||||
.action((version, options) => generateAction(version, options));
|
||||
|
||||
program.parse();
|
0
.upgradenotes/.gitkeep
Normal file
0
.upgradenotes/.gitkeep
Normal file
6
.upgradenotes/MDL-48940-2024052002223792.yml
Normal file
6
.upgradenotes/MDL-48940-2024052002223792.yml
Normal file
@ -0,0 +1,6 @@
|
||||
issueNumber: MDL-48940
|
||||
notes:
|
||||
core:
|
||||
- message: >
|
||||
The previously deprecated function `search_generate_text_SQL` has been removed and can no longer be used.
|
||||
type: removed
|
6
.upgradenotes/MDL-71748-2024052002223792.yml
Normal file
6
.upgradenotes/MDL-71748-2024052002223792.yml
Normal file
@ -0,0 +1,6 @@
|
||||
issueNumber: MDL-71748
|
||||
notes:
|
||||
core:
|
||||
- message: >
|
||||
The previously deprecated function `core_text::reset_caches()` has been removed and can no longer be used.
|
||||
type: removed
|
6
.upgradenotes/MDL-72353-2024052002223792.yml
Normal file
6
.upgradenotes/MDL-72353-2024052002223792.yml
Normal file
@ -0,0 +1,6 @@
|
||||
issueNumber: MDL-72353
|
||||
notes:
|
||||
report:
|
||||
- message: >-
|
||||
The previously deprecated `report_helper::save_selected_report` method has been removed and can no longer be used
|
||||
type: removed
|
7
.upgradenotes/MDL-73165-2024052002223792.yml
Normal file
7
.upgradenotes/MDL-73165-2024052002223792.yml
Normal file
@ -0,0 +1,7 @@
|
||||
issueNumber: MDL-73165
|
||||
notes:
|
||||
core:
|
||||
- message: >
|
||||
The following previously deprecated methods have been removed and can no longer be used:
|
||||
- `renderer_base::should_display_main_logo`
|
||||
type: removed
|
5
.upgradenotes/MDL-74484-2024052002223792.yml
Normal file
5
.upgradenotes/MDL-74484-2024052002223792.yml
Normal file
@ -0,0 +1,5 @@
|
||||
issueNumber: MDL-74484
|
||||
notes:
|
||||
core:
|
||||
- message: Final deprecation of print_error(). Use moodle_exception instead.
|
||||
type: removed
|
8
.upgradenotes/MDL-76690-2024052002223792.yml
Normal file
8
.upgradenotes/MDL-76690-2024052002223792.yml
Normal file
@ -0,0 +1,8 @@
|
||||
issueNumber: MDL-76690
|
||||
notes:
|
||||
core_reportbuilder:
|
||||
- message: >
|
||||
The following previously deprecated local helper methods have been removed and can no longer be used:
|
||||
- `audience::get_all_audiences_menu_types`
|
||||
- `report::get_available_columns`
|
||||
type: removed
|
11
.upgradenotes/MDL-81168-2024052002223792.yml
Normal file
11
.upgradenotes/MDL-81168-2024052002223792.yml
Normal file
@ -0,0 +1,11 @@
|
||||
issueNumber: MDL-81168
|
||||
notes:
|
||||
core_reportbuilder:
|
||||
- message: >
|
||||
In order to better support float values in filter forms, the following
|
||||
filter types now cast given SQL prior to comparison:
|
||||
|
||||
- `duration`
|
||||
- `filesize`
|
||||
- `number`
|
||||
type: changed
|
6
.upgradenotes/MDL-81274-2024052002223792.yml
Normal file
6
.upgradenotes/MDL-81274-2024052002223792.yml
Normal file
@ -0,0 +1,6 @@
|
||||
issueNumber: MDL-81274
|
||||
notes:
|
||||
mod_data:
|
||||
- message: >-
|
||||
The `data_add_record` method accepts a new `$approved` parameter to set the corresponding state of the new record
|
||||
type: improved
|
6
.upgradenotes/MDL-81330-2024052002223792.yml
Normal file
6
.upgradenotes/MDL-81330-2024052002223792.yml
Normal file
@ -0,0 +1,6 @@
|
||||
issueNumber: MDL-81330
|
||||
notes:
|
||||
core_reportbuilder:
|
||||
- message: >
|
||||
The base datasource `add_all_from_entities` method accepts a new optional parameter to specify which entities to add elements from
|
||||
type: changed
|
8
.upgradenotes/MDL-81433-2024052002223792.yml
Normal file
8
.upgradenotes/MDL-81433-2024052002223792.yml
Normal file
@ -0,0 +1,8 @@
|
||||
issueNumber: MDL-81433
|
||||
notes:
|
||||
core_reportbuilder:
|
||||
- message: >
|
||||
The following external methods now return tags data relevant to each custom report:
|
||||
- `core_reportbuilder_list_reports`
|
||||
- `core_reportbuilder_retrieve_report`
|
||||
type: improved
|
6
.upgradenotes/MDL-81434-2024052002223792.yml
Normal file
6
.upgradenotes/MDL-81434-2024052002223792.yml
Normal file
@ -0,0 +1,6 @@
|
||||
issueNumber: MDL-81434
|
||||
notes:
|
||||
core_reportbuilder:
|
||||
- message: |2
|
||||
Added a new database helper method `sql_replace_parameters` to help ensure uniqueness of parameters within a SQL expression
|
||||
type: improved
|
8
.upgradenotes/MDL-81610-2024052002223792.yml
Normal file
8
.upgradenotes/MDL-81610-2024052002223792.yml
Normal file
@ -0,0 +1,8 @@
|
||||
issueNumber: MDL-81610
|
||||
notes:
|
||||
core_courseformat:
|
||||
- message: >
|
||||
The constructor of `core_courseformat\output\local\state\cm` has been updated to accept a new optional parameter, `$istrackeduser`.
|
||||
|
||||
If `istrackeduser` is pre-computed for the course module's course, it can be provided here to avoid an additional function call.
|
||||
type: improved
|
7
UPGRADING.md
Normal file
7
UPGRADING.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Moodle Upgrade notes
|
||||
|
||||
This file contains important information for developers on changes to the Moodle codebase.
|
||||
|
||||
More detailed information on key changes can be found in the [Developer update notes](https://moodledev.io/docs/devupdate) for your version of Moodle.
|
||||
|
||||
The format of this change log follows the advice given at [Keep a CHANGELOG](https://keepachangelog.com).
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the tool_behat code.
|
||||
|
||||
=== 4.3 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /admin/tool/brickfield/*.
|
||||
|
||||
=== 4.0 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in /admin/tool/dataprivacy/*
|
||||
Information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the logstore_database code.
|
||||
|
||||
=== 3.4 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /admin/tool/log - plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes changes in /admin/tool/lp/* - plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes for code that uses MFA.
|
||||
|
||||
=== 4.4 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes changes in tool_mobile code.
|
||||
Information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the tool_phpunit code.
|
||||
|
||||
=== 3.9 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /admin/tool/* - plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the tool_usertours code.
|
||||
|
||||
=== 4.4 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /admin/*.
|
||||
|
||||
=== 4.4 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in analytics sub system,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /auth/cas/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /auth/db/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /auth/email/*,
|
||||
information provided here is intended especially for developers.
|
||||
=== 4.4 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the auth_ldap code.
|
||||
|
||||
=== 3.4 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /auth/manual/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in auth_mnet code.
|
||||
|
||||
=== 3.3 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /auth/none/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /auth/shibboleth/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /auth/* - plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /availability/*.
|
||||
|
||||
The information here is intended only for developers.
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /backup/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /badges/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
=== 4.4 ===
|
||||
* The following previously deprecated methods have been removed and can no longer be used:
|
||||
- block_calendar_upcoming::get_upcoming_content
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in the lp block code.
|
||||
|
||||
=== 3.7 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in the myoverview block code.
|
||||
|
||||
=== 3.7 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in the recentlyaccessedcourses block code.
|
||||
|
||||
=== 3.8 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in the recentlyaccesseditems block code.
|
||||
|
||||
=== 4.4 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in the section_links block code.
|
||||
|
||||
=== 3.11 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in the starredcourses block code.
|
||||
|
||||
=== 3.8 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the block tag_youtube code.
|
||||
|
||||
=== 3.10.1 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in the timeline block code.
|
||||
|
||||
=== 4.0 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /blocks/* - activity modules,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /blog/* ,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
5
cache/upgrade.txt
vendored
5
cache/upgrade.txt
vendored
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /cache/stores/* - cache store plugins.
|
||||
Information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /calendar/* ,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /cohort/ information provided here is intended
|
||||
especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /comment/* ,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,2 +1,7 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in /communication/provider/*
|
||||
Information provided here is intended especially for developers.
|
||||
|
@ -1,2 +1,7 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in /communication/*
|
||||
Information provided here is intended especially for developers.
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /competency/*. The information provided
|
||||
here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in /completion/* - completion,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes for course formats
|
||||
|
||||
Overview of this plugin type at https://moodledev.io/docs/apis/plugintypes/format
|
||||
|
||||
=== 4.5 ===
|
||||
* The constructor of core_courseformat\output\local\state\cm has been updated to accept a new optional parameter called is_tracked_user.
|
||||
If is_tracked_user is pre-computed for this CM's course, it can be provided here to avoid an additional function call.
|
||||
|
||||
=== 4.4 ===
|
||||
* The core_courseformat\output\local\content\section::export_for_template() is not returning hiddenfromstudents and notavailable
|
||||
directly in the data array anymore. Instead, it returns the visibility data in the 'visibility' key. It means that templates
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /course/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /customfield/field/* - customfield field types,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /customfield/*,
|
||||
Information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /dataformat/ download system,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the enrol_database code.
|
||||
|
||||
=== 3.11 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the enrol_ldap code.
|
||||
|
||||
=== 3.8 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /enrol/* - plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /files/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in core filter API and plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /grade/export/* - plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /grade/grading/form/* - Advanced grading methods
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /grade/report/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes in /grade/* ;
|
||||
Information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /group/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the editor_atto code.
|
||||
|
||||
=== 4.1 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in tiny_accessibilitychecker - TinyMCE Accessibility checker plugin,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /lib/editor/tiny/* - TinyMCE editor,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in core_form libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the mlbackend_php code, the
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the mlbackend_python code, the
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 4.5 ===
|
||||
|
||||
* Final deprecation and removal of the function core_text::reset_caches().
|
||||
* The previously deprecated function `search_generate_text_SQL` has been removed and can no longer be used.
|
||||
* The following previously deprecated methods have been removed and can no longer be used:
|
||||
- `renderer_base::should_display_main_logo`
|
||||
* Final deprecation of print_error(). Use moodle_exception instead.
|
||||
|
||||
=== 4.4 ===
|
||||
|
||||
* New modinfo methods related to delegated sections (sections controlled by a component):
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in core_xapi libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This file describes API changes for the plugins of the type 'local'.
|
||||
|
||||
=== 3.1 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /media/ plugins,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in /message/ messaging system,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the assign code.
|
||||
|
||||
=== 4.3 ===
|
||||
|
@ -1,3 +1,8 @@
|
||||
=== 4.5 Onwards ===
|
||||
|
||||
This file has been replaced by UPGRADING.md. See MDL-81125 for further information.
|
||||
|
||||
===
|
||||
This files describes API changes in the bigbluebuttonbn code.
|
||||
=== 4.3 ===
|
||||
* Make instance class constructor private and use the factory method to create instances.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user