Skip to content

Commit

Permalink
Merge pull request #1682 from SUI-Components/feat/improve-mono-releas…
Browse files Browse the repository at this point in the history
…e-performance

feat(packages/sui-mono): improve performance
  • Loading branch information
andresz1 authored Feb 5, 2024
2 parents 4e2f9cc + b6e14d7 commit e036c5c
Show file tree
Hide file tree
Showing 11 changed files with 695 additions and 24 deletions.
40 changes: 26 additions & 14 deletions packages/sui-mono/bin/sui-mono-changelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
const program = require('commander')
const fs = require('fs')
const path = require('path')
const conventionalChangelog = require('conventional-changelog')

const conventionalChangelog = require('../src/conventional-changelog.js')
const {checkIsMonoPackage, getWorkspaces, getChangelogFilename} = require('../src/config.js')
const {fetchTags} = require('../src/tags.js')

program
.usage('<folder1> <folder2> <etc>')
Expand All @@ -28,7 +30,7 @@ const folders = program.args.length ? program.args : getWorkspaces()
const changelogOptions = {
preset: 'angular',
append: false,
releaseCount: 0,
releaseCount: 1,
outputUnreleased: false,
transform: (commit, cb) => {
if (commit.type === 'release') {
Expand Down Expand Up @@ -56,20 +58,30 @@ function generateChangelog(folder) {
return new Promise((resolve, reject) => {
const gitRawCommitsOpts = {path: folder}
const outputFile = path.join(folder, CHANGELOG_NAME)
const output = fs.createWriteStream(path.join(outputFile))
const title = '# CHANGELOG'
const content = fs.existsSync(outputFile) ? fs.readFileSync(outputFile, 'utf8') : ''
const output = fs.createWriteStream(outputFile)

const name = getWorkspaces().find(path => folder.endsWith(path))
const promise = name ? fetchTags(name) : Promise.resolve()

let chunkCount = 0

return conventionalChangelog(changelogOptions, {}, gitRawCommitsOpts)
.on('data', chunk => {
// First chunk is always an empty release
if (!chunkCount++) output.write('# CHANGELOG\n\n')
output.write(chunk)
})
.on('end', () => output.end(() => resolve(outputFile)))
.on('error', error => {
output.destroy(error)
reject(error)
})
return promise.then(tags => {
return conventionalChangelog({...changelogOptions, gitSemverTags: tags}, {}, gitRawCommitsOpts)
.on('data', chunk => {
if (!chunkCount++) output.write(`${title}\n\n`)
output.write(chunk)
})
.on('end', () => {
output.write(chunkCount > 0 && content ? content.replace(title, '').trim() : content)
output.end(() => resolve(outputFile))
})
.on('error', error => {
output.destroy(error)
reject(error)
})
})
})
}

Expand Down
25 changes: 18 additions & 7 deletions packages/sui-mono/bin/sui-mono-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,18 @@ const releasesByPackages = ({status}) => {
.map(scope => scopeMapper({scope, status}))
}

const releasePackage = async ({pkg, code, skipCi} = {}) => {
const getCwd = ({pkg}) => {
const isMonoPackage = checkIsMonoPackage()
return isMonoPackage ? BASE_DIR : path.join(process.cwd(), pkg)
}

const commit = async ({pkg, code, skipCi}) => {
const isMonoPackage = checkIsMonoPackage()
const cwd = getCwd({pkg})

const tagPrefix = isMonoPackage ? '' : `${pkg}-`
const packageScope = isMonoPackage ? 'Root' : pkg.replace(path.sep, '/')

const cwd = isMonoPackage ? BASE_DIR : path.join(process.cwd(), pkg)
const {private: isPrivatePackage, config: localPackageConfig} = getPackageJson(cwd, true)

await exec(`npm --no-git-tag-version version ${RELEASE_CODES[code]}`, {cwd})
await exec(`git add ${path.join(cwd, 'package.json')}`, {cwd})

Expand All @@ -83,11 +87,16 @@ const releasePackage = async ({pkg, code, skipCi} = {}) => {
const commitMsg = `release(${packageScope}): v${version}${skipCiSuffix}`
await exec(`git commit -m "${commitMsg}"`, {cwd})

await exec(`${suiMonoBinPath} changelog ${cwd}`, {cwd})
await exec(`${suiMonoBinPath} changelog ${cwd}`)
await exec(`git add ${path.join(cwd, changelogFilename)}`, {cwd})
await exec(`git commit --amend --no-verify --no-edit`, {cwd})

await exec(`git tag -a ${tagPrefix}${version} -m "v${version}"`, {cwd})
}

const publish = async ({pkg}) => {
const cwd = getCwd({pkg})
const {private: isPrivatePackage, config: localPackageConfig} = getPackageJson(cwd, true)

if (!isPrivatePackage) {
const publishAccess = getPublishAccess({localPackageConfig})
Expand Down Expand Up @@ -154,7 +163,7 @@ checkShouldRelease()
const packagesToRelease = releasesByPackages({status}).filter(({code}) => code !== 0)

for (const pkg of packagesToRelease) {
await releasePackage({...pkg, skipCi})
await commit({...pkg, skipCi})
}

if (packagesToRelease.length > 0) {
Expand All @@ -166,9 +175,11 @@ checkShouldRelease()
await exec('git commit -m "chore(Root): update package-lock.json [skip ci]" --no-verify')
}

await exec('git push -f --tags origin HEAD')
await exec('git push --atomic --tags origin HEAD --no-verify')
}

await Promise.all(packagesToRelease.map(pkg => publish(pkg)))

console.log(`[sui-mono release] ${packagesToRelease.length} packages released`)
})
})
Expand Down
19 changes: 19 additions & 0 deletions packages/sui-mono/hosts/bitbucket.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"issue": "issue",
"commit": "commits",
"referenceActions": [
"close",
"closes",
"closed",
"closing",
"fix",
"fixes",
"fixed",
"fixing",
"resolve",
"resolves",
"resolved",
"resolving"
],
"issuePrefixes": ["#"]
}
6 changes: 6 additions & 0 deletions packages/sui-mono/hosts/github.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"issue": "issues",
"commit": "commit",
"referenceActions": ["close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"],
"issuePrefixes": ["#", "gh-"]
}
6 changes: 6 additions & 0 deletions packages/sui-mono/hosts/gitlab.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"issue": "issues",
"commit": "commit",
"referenceActions": ["close", "closes", "closed", "closing", "fix", "fixes", "fixed", "fixing"],
"issuePrefixes": ["#"]
}
19 changes: 17 additions & 2 deletions packages/sui-mono/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,26 @@
"dependencies": {
"@s-ui/helpers": "1",
"commander": "8.3.0",
"conventional-changelog": "3.1.25",
"enquirer": "2.3.6",
"git-url-parse": "13.1.0",
"glob": "8.0.3",
"word-wrap": "1.2.4"
"word-wrap": "1.2.4",
"add-stream": "^1.0.0",
"conventional-changelog-writer": "^5.0.0",
"conventional-commits-parser": "^3.2.0",
"conventional-changelog-preset-loader": "^2.3.4",
"conventional-changelog-angular": "^5.0.12",
"dateformat": "^3.0.0",
"get-pkg-repo": "^4.0.0",
"git-raw-commits": "^2.0.8",
"git-remote-origin-url": "^2.0.0",
"git-semver-tags": "^4.1.1",
"lodash": "^4.17.15",
"normalize-package-data": "^3.0.0",
"q": "^1.5.1",
"read-pkg": "^3.0.0",
"read-pkg-up": "^3.0.0",
"through2": "^4.0.0"
},
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/sui-mono/src/check.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint no-console:0 */

const conventionalChangelog = require('conventional-changelog')
const conventionalChangelog = require('./conventional-changelog.js')
const {readJsonSync} = require('fs-extra')

const {promisify} = require('util')
Expand Down
152 changes: 152 additions & 0 deletions packages/sui-mono/src/conventional-changelog-core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
'use strict'

const addStream = require('add-stream')
const gitRawCommits = require('git-raw-commits')
const conventionalCommitsParser = require('conventional-commits-parser')
const conventionalChangelogWriter = require('conventional-changelog-writer')
const _ = require('lodash')
const stream = require('stream')
const through = require('through2')
const execFileSync = require('child_process').execFileSync

const mergeConfig = require('./merge-config.js')
function conventionalChangelog(options, context, gitRawCommitsOpts, parserOpts, writerOpts, gitRawExecOpts) {
writerOpts = writerOpts || {}

const readable = new stream.Readable({
objectMode: writerOpts.includeDetails
})
readable._read = function () {}

let commitsErrorThrown = false

let commitsStream = new stream.Readable({
objectMode: true
})
commitsStream._read = function () {}

function commitsRange(from, to) {
return gitRawCommits(
_.merge({}, gitRawCommitsOpts, {
from,
to
})
).on('error', function (err) {
if (!commitsErrorThrown) {
setImmediate(commitsStream.emit.bind(commitsStream), 'error', err)
commitsErrorThrown = true
}
})
}

mergeConfig(options, context, gitRawCommitsOpts, parserOpts, writerOpts, gitRawExecOpts)
.then(function (data) {
options = data.options
context = data.context
gitRawCommitsOpts = data.gitRawCommitsOpts
parserOpts = data.parserOpts
writerOpts = data.writerOpts
gitRawExecOpts = data.gitRawExecOpts

try {
execFileSync('git', ['rev-parse', '--verify', 'HEAD'], {
stdio: 'ignore'
})
let reverseTags = context.gitSemverTags.slice(0).reverse()
reverseTags.push('HEAD')

if (gitRawCommitsOpts.from) {
if (reverseTags.indexOf(gitRawCommitsOpts.from) !== -1) {
reverseTags = reverseTags.slice(reverseTags.indexOf(gitRawCommitsOpts.from))
} else {
reverseTags = [gitRawCommitsOpts.from, 'HEAD']
}
}

let streams = reverseTags.map((to, i) => {
const from = i > 0 ? reverseTags[i - 1] : ''
return commitsRange(from, to)
})

if (gitRawCommitsOpts.from) {
streams = streams.splice(1)
}

if (gitRawCommitsOpts.reverse) {
streams.reverse()
}

streams
.reduce((prev, next) => next.pipe(addStream(prev)))
.on('data', function (data) {
setImmediate(commitsStream.emit.bind(commitsStream), 'data', data)
})
.on('end', function () {
setImmediate(commitsStream.emit.bind(commitsStream), 'end')
})
} catch (_e) {
commitsStream = gitRawCommits(gitRawCommitsOpts, gitRawExecOpts)
}

commitsStream
.on('error', function (err) {
err.message = 'Error in git-raw-commits: ' + err.message
setImmediate(readable.emit.bind(readable), 'error', err)
})
.pipe(conventionalCommitsParser(parserOpts))
.on('error', function (err) {
err.message = 'Error in conventional-commits-parser: ' + err.message
setImmediate(readable.emit.bind(readable), 'error', err)
})
// it would be better if `gitRawCommits` could spit out better formatted data
// so we don't need to transform here
.pipe(
through.obj(function (chunk, enc, cb) {
try {
options.transform.call(this, chunk, cb)
} catch (err) {
cb(err)
}
})
)
.on('error', function (err) {
err.message = 'Error in options.transform: ' + err.message
setImmediate(readable.emit.bind(readable), 'error', err)
})
.pipe(conventionalChangelogWriter(context, writerOpts))
.on('error', function (err) {
err.message = 'Error in conventional-changelog-writer: ' + err.message
setImmediate(readable.emit.bind(readable), 'error', err)
})
.pipe(
through(
{
objectMode: writerOpts.includeDetails
},
function (chunk, enc, cb) {
try {
readable.push(chunk)
} catch (err) {
setImmediate(function () {
throw err
})
}

cb()
},
function (cb) {
readable.push(null)

cb()
}
)
)
})
.catch(function (err) {
setImmediate(readable.emit.bind(readable), 'error', err)
})

return readable
}

module.exports = conventionalChangelog
27 changes: 27 additions & 0 deletions packages/sui-mono/src/conventional-changelog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict'

const conventionalChangelogPresetLoader = require('conventional-changelog-preset-loader')

const conventionalChangelogCore = require('./conventional-changelog-core.js')

function conventionalChangelog(options, context, gitRawCommitsOpts, parserOpts, writerOpts) {
options.warn = options.warn || function () {}

if (options.preset) {
try {
options.config = conventionalChangelogPresetLoader(options.preset)
} catch (err) {
if (typeof options.preset === 'object') {
options.warn(`Preset: "${options.preset.name}" ${err.message}`)
} else if (typeof options.preset === 'string') {
options.warn(`Preset: "${options.preset}" ${err.message}`)
} else {
options.warn(`Preset: ${err.message}`)
}
}
}

return conventionalChangelogCore(options, context, gitRawCommitsOpts, parserOpts, writerOpts)
}

module.exports = conventionalChangelog
Loading

0 comments on commit e036c5c

Please sign in to comment.