From 17b50a8ba3578a2d957bc43b47c2e6352c9b6ade Mon Sep 17 00:00:00 2001 From: gautamkrishnar Date: Mon, 8 Jan 2024 19:46:21 +0530 Subject: [PATCH] refactor to make workflow more testable, code fixes --- src/blog-post-workflow.js | 313 ++++++++++++++++++++------------------ 1 file changed, 164 insertions(+), 149 deletions(-) diff --git a/src/blog-post-workflow.js b/src/blog-post-workflow.js index 9e902e0..002ce60 100644 --- a/src/blog-post-workflow.js +++ b/src/blog-post-workflow.js @@ -195,8 +195,12 @@ feedList.forEach((siteUrl) => { ) { post = null; } else { - post.title && appendedPostTitles.push(post.title.trim()); - post.description && appendedPostDesc.push(post.description.trim()); + if (post.title) { + appendedPostTitles.push(post.title.trim()); + } + if (post.description) { + appendedPostDesc.push(post.description.trim()); + } } } @@ -219,165 +223,176 @@ feedList.forEach((siteUrl) => { })); }); -// Processing the generated promises -Promise.allSettled(promiseArray).then((results) => { - results.forEach((result, index) => { - if (result.status === 'fulfilled') { - // Succeeded - core.info(runnerNameArray[index] + ' runner succeeded. Post count: ' + result.value.length); - // Adds feed name to the items - if (typeof feedNamesList[index] !== undefined && feedNamesList[index]) { - result.value = result.value.map((item) => { - item.feedName = feedNamesList[index]; - return item; - }); - } - postsArray.push(...result.value); - } else { - jobFailFlag = true; - // Rejected - core.error(runnerNameArray[index] + ' runner failed, please verify the configuration. Error:'); - if (result.reason && result.reason.message && result.reason.message.startsWith('Status code')) { - const code = result.reason.message.replace('Status code ', ''); - core.error(`Looks like your website returned ${code}, There is nothing blog post workflow` + - ` can do to fix it. Please check your website's RSS feed generation source code. Also double check the URL.`); - if (code === `503`) { - core.error(`If you are using Cloudflare or Akamai, make sure that you have the user agent ` + - ` ${userAgent} or GitHub actions IP ranges whitelisted in your firewall.`); +const runWorkflow = async () => { + // Processing the generated promises + await Promise.allSettled(promiseArray).then((results) => { + results.forEach((result, index) => { + if (result.status === 'fulfilled') { + // Succeeded + core.info(runnerNameArray[index] + ' runner succeeded. Post count: ' + result.value.length); + // Adds feed name to the items + if (typeof feedNamesList[index] !== undefined && feedNamesList[index]) { + result.value = result.value.map((item) => { + item.feedName = feedNamesList[index]; + return item; + }); } + postsArray.push(...result.value); } else { - core.error(result.reason || result.reason.message); + jobFailFlag = true; + // Rejected + core.error(runnerNameArray[index] + ' runner failed, please verify the configuration. Error:'); + if (result.reason && result.reason.message && result.reason.message.startsWith('Status code')) { + const code = result.reason.message.replace('Status code ', ''); + core.error(`Looks like your website returned ${code}, There is nothing blog post workflow` + + ` can do to fix it. Please check your website's RSS feed generation source code. Also double check + the URL.`); + if (code === `503`) { + core.error(`If you are using Cloudflare or Akamai, make sure that you have the user agent ` + + ` ${userAgent} or GitHub actions IP ranges whitelisted in your firewall.`); + } + } else { + core.error(result.reason || result.reason.message); + } } - } - }); -}).finally(async () => { - // Ignore null items, allows you to ignore items by setting null in post via `item_exec` - postsArray = postsArray.filter(item => item !== null); - - // Sorting posts based on date - if (ENABLE_SORT) { - postsArray.sort(function (a, b) { - return b.date - a.date; }); - } - // Slicing with the max count - postsArray = postsArray.slice(0, TOTAL_POST_COUNT); - if (postsArray.length > 0) { - try { - if (!process.env.TEST_MODE) { - await exec('git', ['config', 'pull.rebase', 'true'], {stdio: ['pipe', 'pipe', 'pipe']}); - // Pulling the latest changes from upstream - await exec('git', ['pull'], {stdio: ['pipe', 'pipe', 'pipe']}); - } - const template = core.getInput('template'); - const randEmojiArr = getParameterisedTemplate(template, 'randomEmoji'); - const constEmojiArr = getParameterisedTemplate(template, 'emojiKey'); - const postListMarkdown = postsArray.reduce((acc, cur, index) => { - if (template === 'default') { - // Default template: - [$title]($url) - return acc + `\n- [${cur.title}](${cur.url})` + (((index + 1) === postsArray.length) ? '\n' : ''); - } else { - // Building categories listing - const categoryTemplate = core.getInput('categories_template'); - const categoryList = categoryTemplate === 'default' ? - cur.categories.join(', ') : cur.categories.reduce((prev, current) => - prev + categoryTemplate.replace(/\$category\b/g, current.toString()), ''); - // Building with custom template - const date = dateFormat(cur.date, core.getInput('date_format')); // Formatting date - let content = template - .replace(/\$title\b/g, cur.title) - .replace(/\$url\b/g, cur.url) - .replace(/\$description\b/g, cur.description) - .replace(/\$date\b/g, date) - .replace(/\$counter\b/g, (index + 1).toString()) - .replace(/\$feedName\b/g, cur.feedName ? cur.feedName : '') - .replace(/\$categories\b/g, categoryList.toString()) - .replace(/\$newline/g, '\n'); - - // Setting Custom tags to the template - Object.keys(CUSTOM_TAGS).forEach((tag) => { - const replaceValue = cur[tag] ? cur[tag] : ''; - content = content.replace(new RegExp('\\$' + tag + '\\b', 'g'), replaceValue); - }); + }).finally(async () => { + // Ignore null items, allows you to ignore items by setting null in post via `item_exec` + postsArray = postsArray.filter(item => item !== null); + + // Sorting posts based on date + if (ENABLE_SORT) { + postsArray.sort(function (a, b) { + return b.date - a.date; + }); + } + // Slicing with the max count + postsArray = postsArray.slice(0, TOTAL_POST_COUNT); + if (postsArray.length > 0) { + try { + if (!process.env.TEST_MODE) { + await exec('git', ['config', 'pull.rebase', 'true'], {stdio: ['pipe', 'pipe', 'pipe']}); + // Pulling the latest changes from upstream + await exec('git', ['pull'], {stdio: ['pipe', 'pipe', 'pipe']}); + } + const template = core.getInput('template'); + const randEmojiArr = getParameterisedTemplate(template, 'randomEmoji'); + const constEmojiArr = getParameterisedTemplate(template, 'emojiKey'); + const postListMarkdown = postsArray.reduce((acc, cur, index) => { + if (template === 'default') { + // Default template: - [$title]($url) + return acc + `\n- [${cur.title}](${cur.url})` + (((index + 1) === postsArray.length) ? '\n' : ''); + } else { + // Building categories listing + const categoryTemplate = core.getInput('categories_template'); + const categoryList = categoryTemplate === 'default' ? + cur.categories.join(', ') : cur.categories.reduce((prev, current) => + prev + categoryTemplate.replace(/\$category\b/g, current.toString()), ''); + // Building with custom template + const date = dateFormat(cur.date, core.getInput('date_format')); // Formatting date + let content = template + .replace(/\$title\b/g, cur.title) + .replace(/\$url\b/g, cur.url) + .replace(/\$description\b/g, cur.description) + .replace(/\$date\b/g, date) + .replace(/\$counter\b/g, (index + 1).toString()) + .replace(/\$feedName\b/g, cur.feedName ? cur.feedName : '') + .replace(/\$categories\b/g, categoryList.toString()) + .replace(/\$newline/g, '\n'); + + // Setting Custom tags to the template + Object.keys(CUSTOM_TAGS).forEach((tag) => { + const replaceValue = cur[tag] ? cur[tag] : ''; + content = content.replace(new RegExp('\\$' + tag + '\\b', 'g'), replaceValue); + }); - // Emoji implementation: Random - if (randEmojiArr) { - // For making randomness unique for each repos - let seed = (process.env.GITHUB_REPOSITORY && !process.env.TEST_MODE ? - process.env.GITHUB_REPOSITORY : 'example') + index; - if (core.getInput('rand_seed')) { - // If manual seed is provided, use it - seed = core.getInput('rand_seed') + index; + // Emoji implementation: Random + if (randEmojiArr) { + // For making randomness unique for each repos + let seed = (process.env.GITHUB_REPOSITORY && !process.env.TEST_MODE ? + process.env.GITHUB_REPOSITORY : 'example') + index; + if (core.getInput('rand_seed')) { + // If manual seed is provided, use it + seed = core.getInput('rand_seed') + index; + } + const emoji = randEmojiArr[rand.create(seed).range(randEmojiArr.length)]; + content = content.replace(/\$randomEmoji\((\S)*\)/g, emoji); } - const emoji = randEmojiArr[rand.create(seed).range(randEmojiArr.length)]; - content = content.replace(/\$randomEmoji\((\S)*\)/g, emoji); - } - // Emoji implementation: Static - if (constEmojiArr) { - // using modulus - content = content.replace(/\$emojiKey\((\S)*\)/g, constEmojiArr[index % constEmojiArr.length]); - } + // Emoji implementation: Static + if (constEmojiArr) { + // using modulus + content = content.replace(/\$emojiKey\((\S)*\)/g, constEmojiArr[index % constEmojiArr.length]); + } - return acc + content; - } - }, ''); - - // Output only mode - const outputOnly = core.getInput('output_only') !== 'false'; - if (outputOnly) { - // Sets output as output as `results` variable in github action - core.info('outputOnly mode: set `results` variable. Readme not committed.'); - core.setOutput('results', postsArray); - const outputFilePath = path.join('/','tmp', 'blog_post_workflow_output.json'); - if(fs.existsSync(outputFilePath)) { - fs.rmSync(outputFilePath); + return acc + content; + } + }, ''); + + // Output only mode + const outputOnly = core.getInput('output_only') !== 'false'; + if (outputOnly) { + // Sets output as output as `results` variable in github action + core.info('outputOnly mode: set `results` variable. Readme not committed.'); + core.setOutput('results', postsArray); + const outputFilePath = path.join('/','tmp', 'blog_post_workflow_output.json'); + if(fs.existsSync(outputFilePath)) { + fs.rmSync(outputFilePath); + } + fs.writeFileSync(outputFilePath, JSON.stringify(postsArray), { encoding: 'utf-8'}); + process.exit(jobFailFlag ? 1 : 0); } - fs.writeFileSync(outputFilePath, JSON.stringify(postsArray), { encoding: 'utf-8'}); - process.exit(jobFailFlag ? 1 : 0); - } - // Writing to each readme file - let changedReadmeCount = 0; - README_FILE_PATH_LIST.forEach((README_FILE_PATH) => { - const readmeData = fs.readFileSync(README_FILE_PATH, 'utf8'); - const newReadme = buildReadme(readmeData, postListMarkdown); - // if there's change in readme file update it - if (newReadme !== readmeData) { - core.info('Writing to ' + README_FILE_PATH); - fs.writeFileSync(README_FILE_PATH, newReadme); - changedReadmeCount = changedReadmeCount + 1; - } - }); + // Writing to each readme file + let changedReadmeCount = 0; + README_FILE_PATH_LIST.forEach((README_FILE_PATH) => { + const readmeData = fs.readFileSync(README_FILE_PATH, 'utf8'); + const newReadme = buildReadme(readmeData, postListMarkdown); + // if there's change in readme file update it + if (newReadme !== readmeData) { + core.info('Writing to ' + README_FILE_PATH); + fs.writeFileSync(README_FILE_PATH, newReadme); + changedReadmeCount = changedReadmeCount + 1; + } + }); - if (changedReadmeCount > 0 && !SKIP_COMMITS) { - if (!process.env.TEST_MODE) { - // Commit to readme - await commitReadme(GITHUB_TOKEN, README_FILE_PATH_LIST).then(() => { - // Making job fail if one of the source fails - process.exit(jobFailFlag ? 1 : 0); - }); - } - } else { - // Calculating last commit date, please see https://git.io/Jtm4V - if (!process.env.TEST_MODE && ENABLE_KEEPALIVE) { - // Do dummy commit if elapsed time is greater than 50 days - const committerUsername = core.getInput('committer_username'); - const committerEmail = core.getInput('committer_email'); - const message = await keepaliveWorkflow.KeepAliveWorkflow(GITHUB_TOKEN, committerUsername, committerEmail, - 'dummy commit to keep the repository active, see https://git.io/Jtm4V', 50, true); - core.info(message); + if (changedReadmeCount > 0 && !SKIP_COMMITS) { + if (!process.env.TEST_MODE) { + // Commit to readme + await commitReadme(GITHUB_TOKEN, README_FILE_PATH_LIST).then(() => { + // Making job fail if one of the source fails + process.exit(jobFailFlag ? 1 : 0); + }); + } } else { - core.info('No change detected, skipping'); + // Calculating last commit date, please see https://git.io/Jtm4V + if (!process.env.TEST_MODE && ENABLE_KEEPALIVE) { + // Do dummy commit if elapsed time is greater than 50 days + const committerUsername = core.getInput('committer_username'); + const committerEmail = core.getInput('committer_email'); + const message = await keepaliveWorkflow.KeepAliveWorkflow(GITHUB_TOKEN, committerUsername, committerEmail, + 'dummy commit to keep the repository active, see https://git.io/Jtm4V', 50, true); + core.info(message); + } else { + core.info('No change detected, skipping'); + } + process.exit(jobFailFlag ? 1 : 0); } - process.exit(jobFailFlag ? 1 : 0); + } catch (e) { + core.error(e); + process.exit(1); } - } catch (e) { - core.error(e); - process.exit(1); + } else { + core.info('0 blog posts fetched'); + process.exit(jobFailFlag ? 1 : 0); } - } else { - core.info('0 blog posts fetched'); - process.exit(jobFailFlag ? 1 : 0); - } -}); + }); +}; + +module.exports = { + runWorkflow +}; + +if (!module.parent) { + runWorkflow().then(); +}