Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(packages/sui-mono): improve performance #1682

Merged
merged 15 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of generating all the changelog let's generate only the part for the last release

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"
Comment on lines +17 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you define fixed versions the these external dependencies?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will leave it as it was in the dependency for now 🙏🏻

},
"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
Loading