|
| 1 | +'use strict'; |
| 2 | +require('dotenv').config(); |
| 3 | +const moment = require('moment'); |
| 4 | +const fs = require('fs'); |
| 5 | +const simpleGit = require('simple-git')(); |
| 6 | +const semver = require('semver'); |
| 7 | +const exec = require('child_process').execSync; |
| 8 | +const { ReleaseNoteManager } = require('@forestadmin/devops'); |
| 9 | + |
| 10 | +const { DEVOPS_SLACK_TOKEN, DEVOPS_SLACK_CHANNEL } = process.env; |
| 11 | +const OPTIONS = { releaseIcon: '🌱', withVersion: true }; |
| 12 | + |
| 13 | +const BRANCH_MASTER = 'master'; |
| 14 | +const BRANCH_DEVEL = 'devel'; |
| 15 | +const PRERELEASE_OPTIONS = ['premajor', 'preminor', 'prepatch', 'prerelease']; |
| 16 | +const RELEASE_OPTIONS = ['major', 'minor', 'patch', ...PRERELEASE_OPTIONS]; |
| 17 | + |
| 18 | +function build() { |
| 19 | + const parseCommandLineArguments = () => { |
| 20 | + let releaseType = 'patch'; |
| 21 | + let prereleaseTag; |
| 22 | + |
| 23 | + if (process.argv) { |
| 24 | + if (process.argv[2]) { |
| 25 | + const option = process.argv[2].replace('--', ''); |
| 26 | + if (RELEASE_OPTIONS.includes(option)) { |
| 27 | + releaseType = option; |
| 28 | + } |
| 29 | + } |
| 30 | + if (process.argv[3]) { |
| 31 | + const option = process.argv[3].replace('--', ''); |
| 32 | + prereleaseTag = option; |
| 33 | + } else if (PRERELEASE_OPTIONS.includes(releaseType)) { |
| 34 | + prereleaseTag = 'beta'; |
| 35 | + } |
| 36 | + } |
| 37 | + |
| 38 | + return { releaseType, prereleaseTag }; |
| 39 | + }; |
| 40 | + |
| 41 | + const gitPullErrorCatcher = (error) => { |
| 42 | + if (error) { |
| 43 | + throw new Error('Git Pull Error'); |
| 44 | + } |
| 45 | + }; |
| 46 | + |
| 47 | + const getBranchLabel = (branchName) => branchName || 'current branch'; |
| 48 | + |
| 49 | + const pullAndCommitChanges = async (newPackageFile, newVersionFile, newChanges, commitMessage, branchName) => { |
| 50 | + if (branchName) { |
| 51 | + await simpleGit.checkout(branchName); |
| 52 | + } |
| 53 | + |
| 54 | + return simpleGit |
| 55 | + .pull(gitPullErrorCatcher) |
| 56 | + .exec(() => { console.log(`Pull ${getBranchLabel(branchName)} done.`); }) |
| 57 | + .exec(() => { |
| 58 | + fs.writeFileSync('lib/forest_liana/version.rb', newVersionFile); |
| 59 | + fs.writeFileSync('package.json', newPackageFile); |
| 60 | + fs.writeFileSync('CHANGELOG.md', newChanges); |
| 61 | + }) |
| 62 | + .add(['CHANGELOG.md', 'package.json']) |
| 63 | + .commit(commitMessage) |
| 64 | + .push() |
| 65 | + .exec(() => { console.log(`Commit Release on ${getBranchLabel(branchName)} done.`); }); |
| 66 | + }; |
| 67 | + |
| 68 | + const addTagToGit = (tag, branchName) => simpleGit |
| 69 | + .addTag(tag) |
| 70 | + .push('origin', tag) |
| 71 | + .exec(() => { console.log(`Tag ${tag} on ${getBranchLabel(branchName)} done.`); }); |
| 72 | + |
| 73 | + const mergeDevelOntoMaster = () => simpleGit |
| 74 | + .checkout(BRANCH_MASTER) |
| 75 | + .pull(gitPullErrorCatcher) |
| 76 | + .exec(() => { console.log(`Pull ${BRANCH_MASTER} done.`); }) |
| 77 | + .mergeFromTo(BRANCH_DEVEL, BRANCH_MASTER) |
| 78 | + .exec(() => { console.log(`Merge ${BRANCH_DEVEL} on ${BRANCH_MASTER} done.`); }) |
| 79 | + .push(); |
| 80 | + |
| 81 | + let releaseType = 'patch'; |
| 82 | + let prereleaseTag; |
| 83 | + |
| 84 | + ({ releaseType, prereleaseTag } = parseCommandLineArguments()); |
| 85 | + |
| 86 | + // VERSION (version.rb) |
| 87 | + let versionFile = fs.readFileSync('lib/forest_liana/version.rb').toString().split('\n'); |
| 88 | + let version = versionFile[1].match(/\w*VERSION = "(.*)"/)[1]; |
| 89 | + version = semver.inc(version, releaseType, prereleaseTag); |
| 90 | + versionFile[1] = ` VERSION = "${version}"`; |
| 91 | + const newVersionFile = versionFile.join('\n'); |
| 92 | + |
| 93 | + // VERSION (package.json) |
| 94 | + const packageContents = fs.readFileSync('./package.json', 'utf8'); |
| 95 | + const packageJson = JSON.parse(packageContents); |
| 96 | + packageJson.version = version; |
| 97 | + const newPackageFile = JSON.stringify(packageJson, null, 2); |
| 98 | + |
| 99 | + // CHANGELOG |
| 100 | + const changes = fs.readFileSync('CHANGELOG.md').toString().split('\n'); |
| 101 | + const today = moment().format('YYYY-MM-DD'); |
| 102 | + |
| 103 | + const index = changes.indexOf('## [Unreleased]') + 1; |
| 104 | + changes.splice(index, 0, `\n## RELEASE ${version} - ${today}`); |
| 105 | + const newChanges = changes.join('\n'); |
| 106 | + |
| 107 | + const commitMessage = `Release ${version}`; |
| 108 | + const tag = `v${version}`; |
| 109 | + |
| 110 | + return new Promise((resolve) => { |
| 111 | + simpleGit.status((_, statusSummary) => { |
| 112 | + const currentBranch = statusSummary.current; |
| 113 | + |
| 114 | + let promise; |
| 115 | + if (prereleaseTag || /v\d+(\.\d+)?/i.test(currentBranch)) { |
| 116 | + promise = pullAndCommitChanges(newPackageFile, newVersionFile, newChanges, commitMessage, currentBranch) |
| 117 | + .then(() => addTagToGit(tag, currentBranch)); |
| 118 | + } else { |
| 119 | + promise = pullAndCommitChanges(newPackageFile, newVersionFile, newChanges, commitMessage, BRANCH_DEVEL) |
| 120 | + .then(() => mergeDevelOntoMaster()) |
| 121 | + .then(() => addTagToGit(tag, BRANCH_MASTER)) |
| 122 | + .then(() => simpleGit.checkout(BRANCH_DEVEL)); |
| 123 | + } |
| 124 | + |
| 125 | + promise.catch(() => {}); |
| 126 | + |
| 127 | + resolve(promise); |
| 128 | + }); |
| 129 | + }); |
| 130 | +} |
| 131 | + |
| 132 | +return build() |
| 133 | + .then(() => new ReleaseNoteManager(DEVOPS_SLACK_TOKEN, DEVOPS_SLACK_CHANNEL, OPTIONS).create()) |
0 commit comments