Skip to content

Commit

Permalink
chore: add script to make versioning and publishing prereleases easier (
Browse files Browse the repository at this point in the history
#2206)

* chore: add prerelease script to make creating prereleases easier

* chore: improve prerelease script and add ignore field on changeset config

* docs: improve documentation around prereleases

* docs: add note about prereleases being only for new packages
  • Loading branch information
massao authored Sep 13, 2022
1 parent bc7fc77 commit c75ecd0
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 2 deletions.
7 changes: 6 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
"$schema": "https://unpkg.com/@changesets/config@1.6.4/schema.json",
"changelog": [
"@changesets/changelog-github",
{ "repo": "contentful/forma-36" }
{
"repo": "contentful/forma-36"
}
],
"ignore": [
"@contentful/f36-website"
],
"commit": false,
"fixed": [
Expand Down
19 changes: 19 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,22 @@ This file reads and parse the `.changelogrc` file, and adds the news changesets
After updating the `.changelogrc` file it uses the changeset version to update the packages `CHANGELOG` files, and then calls [generate-releases.js](https://github.com/contentful/forma-36/blob/fe934ff657852993ef321348651cbce0a68dc349/scripts/changesets/generate-releases.js) script file, that handles publishing to NPM and generating the releases on Github.

Every day there is a task running on the CI that calls the [changelog-write.js](https://github.com/contentful/forma-36/blob/fe934ff657852993ef321348651cbce0a68dc349/scripts/changesets/changelog-write.js). This file checks for contents on the `.changelogrc` file and generates the [What's new](https://f36.contentful.com/whats-new) page based on those. Then it empty the files to not have duplicated contents when it needs to generate the page again.

## Prereleases

> Prereleases are only used for new components, once a package is stable we avoid adding prerelease code into it.
>
> For changes in stable components we follow the semver versioning
We work with the concept of the prereleases being `alpha` and `beta`.

Since we want to show the documentation of the components that are still on prereleases on our website, we need to have them merged on `main` branch, but we don't want to have them published or handled by changeset.

For that we need to take some precautions:

- The package that is in prerelease (alpha, beta) needs to be added to the ignore field on the [.changeset/config.json](https://github.com/contentful/forma-36/blob/main/.changeset/config.json), so if a changeset is created for that package it will be ignored and not change the version or publish that specific package.
- And we don't have prerelease packages being part of the umbrela package (`f36-components`), which means that when it becomes stable we add it there and replace where it was being used before, e.g. on the website and/or playground.

Trying to make prereleases easier to handle we created a script that you can use on your branch before merging into master, that will bump the package you select, and you can choose if you it's an alpha or beta release, before publishing it to NPM.

You can check the script [here](https://github.com/contentful/forma-36/blob/c6b10071959a085b21e49f5411a5ebff2f8a70d6/scripts/prerelease.mjs)
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"changelog:gen": "node scripts/changesets/changelog-generate.js",
"changelog:write": "node scripts/changesets/changelog-write.js",
"changeset:publish": "node scripts/changesets/generate-releases.js",
"prerelease": "node scripts/prerelease.mjs",
"pretty:quick": "yarn pretty-quick --staged --pattern '**/*.*(js|jsx|ts|tsx|md|mdx)'"
},
"husky": {
Expand Down Expand Up @@ -121,6 +122,7 @@
"globby": "^11.0.2",
"husky": "^4.3.0",
"identity-obj-proxy": "^3.0.0",
"inquirer": "^9.1.1",
"jest": "^27.3.1",
"jest-axe": "6.0.0",
"jest-emotion": "^10.0.27",
Expand Down
86 changes: 86 additions & 0 deletions scripts/prerelease.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import fs from 'fs/promises'
import path from 'path'
import inquirer from 'inquirer'
import semver from 'semver'
import { getPackages } from '@manypkg/get-packages'
import { exec } from 'child_process'

const cwd = process.cwd()

async function updatePackageJson(pkgJsonPath, version) {
const pkgRaw = await fs.readFile(pkgJsonPath, { encoding: 'utf-8' })
const stringified = pkgRaw.replace(/("version".*?) (".*?")/i, `$1 "${version}"`)
await fs.writeFile(pkgJsonPath, stringified)
}

async function ignorePackage(pkgName) {
const changesetConfigPath = path.resolve(cwd, '.changeset/config.json')
const rawConfig = await fs.readFile(changesetConfigPath, { encoding: 'utf-8' })
const jsonConfig = JSON.parse(rawConfig)
const ignorePkgs = jsonConfig.ignore || []
if(!ignorePkgs.includes(pkgName)) {
jsonConfig.ignore = [pkgName, ...ignorePkgs]
const stringified = JSON.stringify(jsonConfig, null, 2)
await fs.writeFile(changesetConfigPath, stringified, { encoding: 'utf-8' })
}
}

async function main() {
const { packages } = await getPackages(cwd)
const choices = packages.map(({ packageJson }) => ({
name: `${packageJson.name} (${packageJson.version})`,
value: packageJson.name
})).concat(new inquirer.Separator())

const { pkgName } = await inquirer.prompt([{
pageSize: 12,
name: 'pkgName',
message: 'Which package to make a pre-release?',
type: 'list',
choices
}])

const { packageJson, dir } = packages.find(({ packageJson }) => packageJson.name === pkgName)
const { version, name } = packageJson
const prereleaseTag = semver.prerelease(version)?.[0]

const { tag, publish } = await inquirer.prompt([{
name: 'tag',
message: 'Which tag should be used for the pre-release?',
type: 'list',
choices: [{
name: 'alpha',
}, {
name: 'beta'
}],
default: prereleaseTag
}, {
name: 'publish',
message: 'Should the package be published?',
type: 'confirm'
}])

const increase = prereleaseTag === tag ? 'prerelease' : 'preminor'
const newVersion = semver.inc(version, increase, tag)
await updatePackageJson(path.resolve(dir, 'package.json'), newVersion)

// Avoid chageset publishing it, by adding the package to the ignore list
await ignorePackage(name)

if(publish) {
// TODO: remove dry-run, kept here for testing before merging
await exec(`npm publish ${dir} --tag ${tag} --dry-run`, (error, stdout, stderr) => {
if(!error) {
console.log(stdout)
console.log(`${name}@${newVersion} published: \nhttps://www.npmjs.com/package/${name}\n`)
} else {
console.error(error)
console.error(stderr)
}
})
} else {
console.log(`Version for ${name} updated on package.json.`)
}
}

main()
Loading

1 comment on commit c75ecd0

@vercel
Copy link

@vercel vercel bot commented on c75ecd0 Sep 13, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.