diff --git a/build/dist/sync.js b/.github/actions/dist/core-synchronization.js similarity index 66% rename from build/dist/sync.js rename to .github/actions/dist/core-synchronization.js index a9ebc88..6f62f59 100644 --- a/build/dist/sync.js +++ b/.github/actions/dist/core-synchronization.js @@ -1,7 +1,27 @@ -module.exports = async ({github, context, core, exec}) => { - // Nested functions, core.startGroup() MUST NOT be used - - function debug(...data) { +/** + * Core synchronization action. + * + * @param {@actions/github/GitHub} github + * @param {@actions/github/Context} context + * @param {@actions/core} core + * @param {@actions/exec} exec + * @param {string} typo3CoreOwner + * @param {string} typo3CoreRepo + * @returns {void} + */ +module.exports = async ({github, context, core, exec}, typo3CoreOwner, typo3CoreRepo) => { + /** + * Log a debug message. + * + * core.debug does not recursively resolve all objects so instead we use the + * console.log which behalfs like expected. + * + * @param {...any} data + * @returns {void} + */ + function debug( + ...data + ) { if (!core.isDebug()) { return } @@ -9,12 +29,18 @@ module.exports = async ({github, context, core, exec}) => { console.log(...data) } + /** + * Download a file from the core. + * + * @param {string} path + * @returns {string} + */ async function getCoreFileContent( path ) { const response = await github.rest.repos.getContent({ - owner: 'TYPO3', - repo: 'typo3', + owner: typo3CoreOwner, + repo: typo3CoreRepo, path: path, }) @@ -29,17 +55,37 @@ module.exports = async ({github, context, core, exec}) => { return Buffer.from(response.data.content, 'base64').toString('utf8') } + /** + * Extract rules from core's php-cs-fixer config. + * + * @param {string} content + * @param {RegExp} regex + * @returns {string} + */ function getRules( content, regex ) { const coreRulesMatches = regex.exec(content) + if (coreRulesMatches === null) { + debug(content) + throw new Error('Error while extracting rules.') + } + debug(`PHP Coding Standards Fixer rules extracted:\n\n${coreRulesMatches[1]}`) return coreRulesMatches[1] } + /** + * Replaces the rules in a local file by the provided ones. + * + * @param {string} path + * @param {RegExp} regex + * @param {string} coreRules + * @returns {boolean} + */ function replaceRules( path, regex, @@ -48,6 +94,11 @@ module.exports = async ({github, context, core, exec}) => { const fs = require('fs') const currentContent = fs.readFileSync(path, 'utf8') + if (regex.exec(currentContent) === null) { + debug(currentContent) + throw new Error('Error while replacing rules.') + } + const newContent = currentContent.replace(regex, '$1' + coreRules + '$2') if (currentContent === newContent) { @@ -61,6 +112,13 @@ module.exports = async ({github, context, core, exec}) => { return true } + /** + * Replaces the content of a file with a new one. + * + * @param {string} path + * @param {string} newContent + * @returns {boolean} + */ function replaceFile( path, newContent @@ -79,6 +137,14 @@ module.exports = async ({github, context, core, exec}) => { return true } + /** + * Executes a command and throws in case of a failure. + * + * @param {string} commandLine + * @param {string[]} args + * @param {ExecOptions} options + * @returns {void} + */ async function safeExec( commandLine, args, @@ -91,18 +157,37 @@ module.exports = async ({github, context, core, exec}) => { } } + /** + * Commits all changes with the given message. + * + * @param {string} message + * @returns {void} + */ async function commitChange( message ) { safeExec(`git commit -a -m "${message}"`) } + /** + * Pushes the active branch to the given remote branch. + * + * @param {string} branch + * @returns {void} + */ async function pushChanges( branch ) { safeExec(`git push -f origin ${branch}`) } + /** + * Lookups a pending pull request and returns its number or 0 if + * not found. + * + * @param {string} branch + * @returns {number} + */ async function getPendingPullRequest( branch ) { @@ -129,6 +214,11 @@ module.exports = async ({github, context, core, exec}) => { return pullRequestNo } + /** + * Returns the default branch of the repository. + * + * @returns {string} + */ async function getDefaultBranch() { if (context.payload.repository.default_branch !== undefined) { return context.payload.repository.default_branch @@ -148,6 +238,12 @@ module.exports = async ({github, context, core, exec}) => { return response.data.default_branch } + /** + * Creates a pull request for the given branch and returns its number. + * + * @param {string} branch + * @returns {number} + */ async function createPullRequest( branch ) { @@ -156,7 +252,7 @@ module.exports = async ({github, context, core, exec}) => { repo: context.repo.repo, title: "[TASK] Sync files with the latest TYPO3 Core version", head: branch, - base: await getDefaultBranch(), + base: getDefaultBranch(), body: `Test body.`, }) @@ -171,9 +267,11 @@ module.exports = async ({github, context, core, exec}) => { return response.data.number } - - // Top level functions, core.startGroup() MUST be used - + /** + * Dumps the context if debug mode is enabled. + * + * @returns {void} + */ function dumpContext() { if (!core.isDebug()) { return @@ -188,6 +286,13 @@ module.exports = async ({github, context, core, exec}) => { } } + /** + * Setups the repository to be able to commit and switches to the + * given branch. + * + * @param {string} branch + * @returns {void} + */ async function setupRepository( branch ) { @@ -203,6 +308,11 @@ module.exports = async ({github, context, core, exec}) => { } } + /** + * Synchronizes the php-cs-fixer rules with the core. + * + * @returns {boolean} + */ async function syncPhpCsFixerRules() { core.startGroup('Sync PHP Coding Standards Fixer rules with the latest TYPO3 Core version') @@ -222,6 +332,11 @@ module.exports = async ({github, context, core, exec}) => { } } + /** + * Synchronizes the editorconfig with the core. + * + * @returns {boolean} + */ async function syncEditorconfig() { core.startGroup('Sync editorconfig with the latest TYPO3 Core version') @@ -240,18 +355,18 @@ module.exports = async ({github, context, core, exec}) => { } } + /** + * Handles changes by pushing and creating a pull request. + * + * @param {string} branch + * @returns {boolean} + */ async function handleChanges( - hasChanges, branch ) { core.startGroup(`Handle changes`) try { - if (!hasChanges) { - core.info('No changes found.') - return 0 - } - pushChanges(branch) const pullRequestNo = await getPendingPullRequest(branch) @@ -278,7 +393,10 @@ module.exports = async ({github, context, core, exec}) => { const editorconfig = await syncEditorconfig() core.setOutput('editorconfig', editorconfig) - const pullRequestNo = await handleChanges(phpCsFixer || editorconfig, branch) + let pullRequestNo = 0 + if (phpCsFixer || editorconfig) { + pullRequestNo = await handleChanges(branch) + } core.setOutput('pull-request', pullRequestNo) } catch (err) { diff --git a/.github/workflows/core-synchronization.yml b/.github/workflows/core-synchronization.yml index 6e6a9cd..7ecc960 100644 --- a/.github/workflows/core-synchronization.yml +++ b/.github/workflows/core-synchronization.yml @@ -17,11 +17,10 @@ jobs: fetch-depth: 0 - name: Sync files with the latest TYPO3 Core version - id: sync-rules + id: core-synchronization uses: actions/github-script@v5 with: github-token: ${{secrets.GITHUB_TOKEN}} - debug: ${{ secrets.ACTIONS_DEBUG == 'true' }} script: | - const script = require('./build/dist/sync.js') - await script({github, context, core, exec}) + const script = require('./.github/actions/dist/core-synchronization.js') + await script({github, context, core, exec}, 'TYPO3', 'typo3')