%PDF- %PDF-
Direktori : /home/opti/workflow/src/public/app-assets/vendors/formBuilder-master/tools/ |
Current File : /home/opti/workflow/src/public/app-assets/vendors/formBuilder-master/tools/utils.js |
import fs from 'fs' import { execSync } from 'child_process' import semver from 'semver' import open from 'opener' import 'colors' import replace from 'replace-in-file' import pkg from '../package.json' /* eslint-disable no-console */ export const spinner = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'] export const releasePlural = releaseType => (releaseType === 'release' ? `${releaseType}s` : `${releaseType}es`) export const txts = { error: '\n----- Error -----\n'.red, status: { current: '', gathering: 'Gathering information...', }, unStagedChanges: 'Unstaged changes found. Please stash or commit your work before continuing.', questions: { releaseType: verb => `What type of release are you ${verb}?` }, fetchingLogs: branch => `Fetching git logs from origin/${branch}`, releaseCreated: releaseTitle => [ `${releaseTitle.green} was successfully generated.\n`, 'Next steps:', ' - Merge the request in Gitlab', ` - ${'npm run release finish'.bgWhite.green} to complete the release`, ].join('\n'), uCanceled: 'User Canceled', whatVersionRelease: 'What version will you be releasing?', whichUnfinishedRelease: releaseType => `Multiple unfinished ${releasePlural(releaseType)} found. Which one would you like to finish?`, invalidVersion: version => `${version.red} is not a valid version number. Please enter a valid Semantic Version number`, } /** * Synchronously exec shell command * @param {String} command * @return {String} trimmed stdout */ export const execTrim = command => execSync(command) .toString() .trim() /** * Check if there are unstaged changes * @return {String} git diff */ export const checkUnstagedChanges = () => { return execTrim('git diff --color') } /** * Find existing, unfinished release branches * @param {String} releaseType hotfix or release * @return {Array} Array of potential unfinished branches */ export const findUnfinishedReleases = releaseType => { const unfinishedReleases = execTrim('git branch -l') .split('\n') .filter(branchName => new RegExp(`${releaseType}/.+`).test(branchName)) if (!unfinishedReleases.length) { console.log(`There are no unfinished ${releasePlural(releaseType)}`) process.exit(0) } return unfinishedReleases.map(String.trim) } /** * Read a package.json from master branch * extract version * @return {String} version */ export const getCurrentVersion = () => { const pkgJSON = execTrim('git show master:package.json') return JSON.parse(pkgJSON).version } /** * Check next version based on semver * @param {String|Number} version * @return {Number} newVersion */ export const getNewVersion = version => { const currentVersion = getCurrentVersion() const semverTypes = ['major', 'minor', 'patch'] let newVersion if (semverTypes.includes(version)) { newVersion = semver.inc(currentVersion, version) } else { newVersion = version } return newVersion } /** * Capitalizes a string * @param {String} str uncapitalized string * @return {String} str capitalized string */ export const capitalize = str => str.replace(/\b\w/g, match => match.toUpperCase()) /** * Update the projects version number * @param {Object} version * @return {Buffer} updated file */ export function updatePackageJSON(props) { const packageJSON = JSON.parse(fs.readFileSync('./package.json')) const updatedPackageJSON = JSON.stringify(deepMerge(packageJSON, props), null, ' ') return fs.writeFileSync('./package.json', `${updatedPackageJSON}\n`) } export const releaseVersionDate = version => { const today = new Date() const releaseDate = `${today.getDate()}/${today.getUTCMonth() + 1}/${today.getFullYear()}` return `## ${version} - ${releaseDate}` } /** * Updates README AND CHANGELOG * @param {Object} version current and new version * @param {String} releaseLog tickets in this release * @return {void} */ export function updateChangelog(version, releaseLog) { const changelog = fs.readFileSync('./CHANGELOG.md', 'utf8').split('\n') const fromLine = changelog.find(line => line.match(/##(\s|)\[unreleased\]?.+/i)) || changelog[0] return replace({ files: 'CHANGELOG.md', from: fromLine, to: `${fromLine}\n\n${releaseVersionDate(version)}\n\n${releaseLog}`, }) .then(changedFiles => { console.log('Modified files:', changedFiles.join(', ')) }) .catch(error => { console.error('Error occurred:', error) }) } /** * Fetch and compare the difference in * git logs between 2 branches * @param {String} source branch * @param {String} target branch * @return {Array} of commits */ export function getLogDiff(source, target) { const sourceHEAD = execTrim(`git rev-parse ${source}`) const targetHEAD = execTrim(`git rev-parse ${target}`) return execTrim(`git log --pretty=format:%n%b%n----- ${sourceHEAD}...${targetHEAD}`) .split('-----') .filter(String) } export const git = { parseLogs, getLogDiff, get currentBranch() { return execTrim('git symbolic-ref --short -q HEAD') }, get releaseLog() { return parseLogs(getLogDiff('develop', 'master')) }, get tempBranchName() { return Math.random() .toString(36) .slice(2) }, openMR: (source, target = 'develop') => { const { gitlab } = pkg.config const mrUrl = `${gitlab.url}/${gitlab.project}/merge_requests/new` if (!source) { source = git.currentBranch } execSync(`git push origin ${source}`) open(`${mrUrl}?merge_request[source_branch]=${source}&merge_request[target_branch]=${target}`) }, /** * Fetch updates from repo for provided branches * @param {Array} branches */ fetchLatest: branches => { const fetchingLatest = 'Fetching latest from' const currentBranch = git.currentBranch const tempBranch = git.tempBranchName execSync(`git checkout -b ${tempBranch}`) branches.forEach(branch => { console.log(`${fetchingLatest} origin/${branch}`.dim) execSync(`git fetch origin ${branch}:${branch}`) }) console.log('Cleaning up'.dim) execSync(`git checkout ${currentBranch} && git branch -D ${tempBranch}`) }, } /** * Format an array of parsed git logs * @param {Array} parsedGitLog * @return {String} formattedGitLogs */ export const formatGitLog = parsedGitLog => { return Object.entries(parsedGitLog) .reduce((filtered, [type, log]) => { if (log.length) { filtered.push(`### ${capitalize(type)}\n\n${log.join('\n')}`) } return filtered }, []) .join('\n\n') } /** * Remove duplicates from an array of elements * @param {Array} array array with possible duplicates * @return {Array} array with only unique values */ export const uniqueArray = array => array.filter((elem, pos, arr) => arr.indexOf(elem) === pos) /** * Takes an array of commits and sorts them * by the type of changes eg. 'Changed', 'Added', 'Fixed' * @param {Array} gitlogs * @return {Array} parsed commits */ export function parseLogs(gitlogs) { // case insensitive matcher for past, present and future ie. "fixed, fix, fixes" const typeMap = { added: /add(ed\b|es\b|\b):/gi, changed: /(change|update)+(d\b|s\b|\b):/gi, improved: /improve(d\b|s\b|ment):/gi, fixed: /fix(ed\b|es\b|\b):/gi, } const { jira } = pkg.config const inlineAttributionRegExp = /(\((@.+) in ([A-Z]+-\d+)\))/gim const defaultAttributionRegExp = /^\(@.+ in [A-Z]+-\d+\)/gi const parsedLog = Object.keys(typeMap).reduce((acc, curr) => { acc[curr] = [] return acc }, {}) gitlogs.reverse().forEach(commitLog => { if (commitLog) { const msg = commitLog.split('\n').filter(String) const defaultAttribution = msg.find(log => log.match(defaultAttributionRegExp)) if (msg.length) { msg.forEach(log => { const replacer = (match, developer, taskId) => { const task = taskId.toUpperCase() // ensure correct case or link won't work return ` (${developer} in [${task}](${jira}/browse/${task}))` } let attribution = `${log.split(inlineAttributionRegExp)[1] || defaultAttribution || ''}` attribution = attribution.replace(/\((@.+) in ([A-Z]+-\d+)\)/gim, replacer) const types = Object.entries(typeMap) if (types.length) { types.forEach(([type, typeRegExp]) => { if (log.match(typeRegExp)) { log = log .replace(typeRegExp, '') .replace(inlineAttributionRegExp, '') .trim() const typeLog = `${log}${attribution}\n` parsedLog[type].push(typeLog) } }) } }) } } }) // Ensure all entries are unique Reflect.ownKeys(parsedLog).forEach(type => { parsedLog[type] = uniqueArray(parsedLog[type]) }) return formatGitLog(parsedLog) } export const defaultNewVersion = ({ releaseType }) => { let version if (releaseType === 'hotfix') { version = getNewVersion('patch') } return version } export const validateVersion = version => { let response if (semver.valid(version)) { response = true } else { response = 'Invalid version number' } return response } export const deepMerge = (obj1, obj2) => { const mergedObj = Object.assign({}, obj1, obj2) Reflect.ownKeys(obj2).forEach(prop => { if (Array.isArray(obj2[prop])) { mergedObj[prop] = Array.isArray(obj1[prop]) ? uniqueArray(obj1[prop].concat(obj2[prop])) : obj2[prop] } else if (typeof obj2[prop] === 'object') { mergedObj[prop] = deepMerge(obj1[prop], obj2[prop]) } else { mergedObj[prop] = obj2[prop] } }) return mergedObj } /** * Save a changelog * @param {Float} version */ export const saveLog = (version, log) => { const wstream = fs.createWriteStream(`.git/${version}`) wstream.write(log) wstream.end() } /** * Load the saved changelog * @param {Float} version * @return {String} Changelog for the requested version */ export const loadLog = version => fs.readFileSync(`.git/${version}`).toString() /** * Remove the saved changelog * @param {Float} version * @return {String} removedFile */ export const removeLog = version => fs.unlinkSync(`.git/${version}`) /** * Returns the values of an object in a specific order * @param {Object} obj * @param {Array} order * @return {Array} orderedValues */ export const orderedValues = (obj, order) => { const newOrder = order.map(key => obj[key] || null).filter(Boolean) return uniqueArray(newOrder.concat(Object.values(obj))) }