UNPKG

@yuki-no/plugin-batch-pr

Version:

Batch PR plugin for yuki-no - Collects opened Yuki-no translation issues and creates a single pull request

98 lines (97 loc) 5.16 kB
import { applyFileChanges } from './utils/applyFileChanges'; import { createCommit } from './utils/createCommit'; import { createPrBody } from './utils/createPrBody'; import { extractFileChanges } from './utils/extractFileChanges'; import { filterPendedTranslationIssues } from './utils/filterPendedTranslationIssues'; import { getTrackedIssues } from './utils/getTrackedIssues'; import { setupBatchPr } from './utils/setupBatchPr'; import { Git } from '@yuki-no/plugin-sdk/infra/git'; import { GitHub } from '@yuki-no/plugin-sdk/infra/github'; import { getOpenedIssues } from '@yuki-no/plugin-sdk/utils-infra/getOpenedIssues'; import { uniqueWith } from '@yuki-no/plugin-sdk/utils/common'; import { createFileNameFilter } from '@yuki-no/plugin-sdk/utils/createFileNameFilter'; import { getInput, getMultilineInput } from '@yuki-no/plugin-sdk/utils/input'; import { log } from '@yuki-no/plugin-sdk/utils/log'; const BRANCH_NAME = '__yuki-no-batch-pr'; const batchPrPlugin = { name: 'batch-pr', async onFinally({ config }) { log('I', '=== Batch PR plugin started ==='); const upstreamGitHub = new GitHub({ ...config, repoSpec: config.upstreamRepoSpec, }); const upstreamGit = new Git({ ...config, repoSpec: config.upstreamRepoSpec, withClone: true, }); const translationIssues = await getOpenedIssues(upstreamGitHub); // NOTE: Filter out issues that are pending @yuki-no/plugin-release-tracking status const notPendedTranslationIssues = await filterPendedTranslationIssues(upstreamGitHub, translationIssues); if (!notPendedTranslationIssues.length) { log('I', 'batchPr :: No pending translation issues found, skipping batch PR process'); return; } log('I', 'batchPr :: Setting up batch PR branch and pull request'); const { prNumber } = await setupBatchPr(upstreamGitHub, upstreamGit, BRANCH_NAME); log('I', `batchPr :: Getting tracked issues for PR #${prNumber}`); const { trackedIssues, shouldTrackIssues } = await getTrackedIssues(upstreamGitHub, prNumber, notPendedTranslationIssues); log('I', `batchPr :: ${trackedIssues.length} already processed`); const issuesToProcess = uniqueWith(await filterPendedTranslationIssues(upstreamGitHub, shouldTrackIssues), ({ number }) => number); log('I', `batchPr :: Processing ${issuesToProcess.length} issues (${trackedIssues.length} tracked + ${shouldTrackIssues.length} new - ${shouldTrackIssues.length - issuesToProcess.length} filtered)`); const rootDir = getInput('YUKI_NO_BATCH_PR_ROOT_DIR'); if (rootDir) { log('I', `batchPr :: Using root directory filter: ${rootDir}`); } const batchPrExcludePatterns = getMultilineInput('YUKI_NO_BATCH_PR_EXCLUDE'); const extendedConfig = { ...config, exclude: [...config.exclude, ...batchPrExcludePatterns], }; const fileNameFilter = createFileNameFilter(extendedConfig, rootDir); if (batchPrExcludePatterns.length > 0) { log('I', `batchPr :: Using batch PR exclude patterns: ${batchPrExcludePatterns.join(', ')}`); } const headGit = new Git({ ...config, repoSpec: config.headRepoSpec, withClone: true, }); const fileChanges = []; const excludedFiles = new Set(); log('I', 'batchPr :: Extracting file changes from commits'); for (const { hash } of issuesToProcess) { const changes = extractFileChanges(headGit, hash, fileNameFilter, { onExcluded: p => excludedFiles.add(p), rootDir, }); fileChanges.push(...changes); log('I', `batchPr :: Extracted ${changes.length} file changes from commit ${hash.substring(0, 8)}`); } if (!fileChanges.length) { log('W', 'batchPr :: No file changes found, skipping batch PR update'); return; } log('I', `batchPr :: Applying ${fileChanges.length} file changes to upstream repository`); await applyFileChanges(upstreamGit, fileChanges); log('I', 'batchPr :: Creating commit with applied changes'); createCommit(upstreamGit, { message: 'Apply origin changes', }); log('I', `batchPr :: Pushing changes to branch ${BRANCH_NAME}`); upstreamGit.exec(`push -f origin ${BRANCH_NAME}`); log('I', `batchPr :: Updating PR body with ${issuesToProcess.length} linked issues`); const nextPrBody = createPrBody([...issuesToProcess, ...trackedIssues].map(({ number }) => ({ number, type: 'Resolved', })), { excludedFiles: Array.from(excludedFiles) }); await upstreamGitHub.api.pulls.update({ ...upstreamGitHub.ownerAndRepo, pull_number: prNumber, body: nextPrBody, }); log('S', `batchPr :: Batch PR #${prNumber} updated successfully with ${fileChanges.length} file changes`); }, }; export default batchPrPlugin;