Skip to content

Commit

Permalink
Docs: Automate more of the release process
Browse files Browse the repository at this point in the history
  • Loading branch information
Krinkle committed Oct 20, 2023
1 parent 552ad59 commit 44995db
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 202 deletions.
99 changes: 38 additions & 61 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,106 +15,84 @@ QUnit aims for its releases to be reproducible. Recent releases are automaticall
>
> System prerequisites:
>
> * Node.js 12, or later.
> * Node.js 14, or later.
> * Git 2.11, or later.
1. Ensure that all changes for this release have been merged into the main branch. For patch releases, try landing any other bug fixes; for minor releases, ensure new features have been documented and tested. Major releases likely have their own checklist.
Ensure that all changes for this release have been merged into the main branch. For patch releases, try landing any other bug fixes; for minor releases, ensure new features have been documented and tested. Major releases likely have their own checklist.

2. Create a local `release` branch, and ensure it is up-to-date:
* Verify that the canonical repository is cloned (not a fork):
1. Create a local `release` branch, and ensure it is up-to-date:
Verify that the canonical repository is cloned (not a fork):
```
git remote -v
# …
# origin [email protected]:qunitjs/qunit.git
```
* Create or reset the `release` branch:
Create or reset the `release` branch:
```
git remote update && git checkout -B release -t origin/main
```

3. Install dev dependencies and run the tests:
2. Install dev dependencies:
```
npm ci && npm test
npm ci
```
Run the tests in various real browsers, either locally or via [BrowserStack](https://www.browserstack.com/):
```
python3 -m http.server 4000
# or:
# php -S localhost:4000

open http://localhost:4000/test/
3. Create the release preparation commit:
```
node build/prep-release.js @VERSION
```

4. Create and push the release preparation commit:
* Use `git add -p` to review the changes.
* In `AUTHORS.txt`, if you see duplicate entries, then use the `.mailmap` file to normalize them to a canonical name and e-mail address, and then re-run the above command.
* Edit `History.md` to remove changes not relevant to end-users (e.g. changes relating to tests, build, internal refactoring, doc fixes, etc.).

Commit your changes with the following message (replace `@VERSION` with the release version):
```
Build: Prepare @VERSION release
```

1. Update the package.json and AUTHORS.txt files, by running the below command (replace `@VERSION` with the release version):
```
node build/prep-release.js @VERSION
```
* Use `git add -p` to review the changes.
* In `AUTHORS.txt`, if you see duplicate entries, then use the `.mailmap` file to normalize them to a canonical name and e-mail address, and then re-run the above command.
* Edit `History.md` to remove change not relevant to end-users (e.g. changes relating to tests, build, internal refactoring, doc fixes, etc.).
2. Commit the above changes with the following message (replace `@VERSION` with the release version):
```
Build: Prepare @VERSION release
```
3. Push the `release` branch to GitHub.
4. Create a pull request, and merge it once CI is passing.
Push the `release` branch to GitHub.
Once CI is passing, push again, this time to the (protected) `main` branch.

## Performing the release

5. Create a local `release` branch, and ensure it is up-to-date:
* Run `git remote -v` and verify the following:
```
origin [email protected]:qunitjs/qunit.git
```
* Create or reset the `release` branch:
```
git remote update && git checkout -B release -t origin/main
```
* Verify that the latest commit is your release preparation commit:
```
git show
# Build: Prepare x.y.z release
# …
```
Verify that your local repo is at the release preparation commit:

6. Make changes for the release commit:
* Set the release version for npm and Bower metadata (replace `@VERSION` with the release version):
```
node build/set-release.js @VERSION
```
This script will edit `package.json` and `bower.json`. It does not need any credentials or permissions, apart from read-write in the project directory.
```
git show
# Build: Prepare x.y.z release
# …
```

* Generate the release artifacts:
4. Build the release:
```
npm run build
node build/build-release.js @VERSION
```
This script does not need any credentials or permissions, and may be run in a container that can only read-write the current directory. It will edit `package.json` and `bower.json`, and then execute `npm run build` to generate the release artifacts.

* Review the changes to the package and library files, compared to the previous release.
Review the changes to the package, compared to the previous release.
```
node build/review-package.js @LAST_VERSION
# … reviews package.json, qunit.js, and qunit.css
```

7. Commit and publish the release to GitHub.<br>⚠️ Do not push to the main branch!
5. Publish to GitHub.<br>⚠️ Do not push to the main branch!
```
git add -f package.json bower.json qunit/
git commit -m "Release @VERSION"
git tag -s "@VERSION" -m "Release @VERSION"
git push --tags
```

8. Verify that Bower sees the release, by running `npx bower info qunit` and checking that the latest
version is indeed the version we just published.

9. Publish the release to npm:
* Use `git status` to confirm once more that you have a clean working copy, apart from release artifacts in `qunit/`.
* Run `npm publish`, this will bundle the current directory and publish it to npm with the name and version specified in `package.json`.
* Verify that the release is displayed at <https://www.npmjs.com/package/qunit>.
6. Publish to npm:
```
npm publish
````
This will bundle the current directory and publish it to npm with the name and version specified in `package.json`.
Verify that the release is displayed at <https://www.npmjs.com/package/qunit>.

10. Publish the release to the jQuery CDN:
7. Publish to the jQuery CDN:
* Prepare the commit locally:
```
node build/auth-cdn-commit.js real @VERSION
Expand All @@ -124,7 +102,6 @@ QUnit aims for its releases to be reproducible. Recent releases are automaticall
```
cd __codeorigin
git show
# …
git push
```
* Verify that the release is listed at <https://code.jquery.com/qunit/> and accessible via <https://code.jquery.com/qunit/qunit-x.y.z.js>
Expand Down
83 changes: 0 additions & 83 deletions build/auth-cdn-commit.js

This file was deleted.

144 changes: 144 additions & 0 deletions build/build-release.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Helper to set the QUnit release version in various places,
// and prepare a local commit in a codeorigin.git clone.
//
// To test the local commit step, with an alternate remote
// pass "test" as the second argument.
//
// See also RELEASE.md.
//
// Inspired by <https://github.com/jquery/jquery-release>.

const cp = require('child_process');
const fs = require('fs');
const path = require('path');

const cdnRemotes = {
anonymous: 'https://github.com/jquery/codeorigin.jquery.com.git',
auth: '[email protected]:jquery/codeorigin.jquery.com.git'
};
const cdnFiles = {
'qunit/qunit.js': 'cdn/qunit/[email protected]',
'qunit/qunit.css': 'cdn/qunit/[email protected]'
};
const cdnCommitMessage = 'qunit: Added version @VERSION';

const Repo = {
buildFiles (version) {
if (typeof version !== 'string' || !/^\d+\.\d+\.\d+$/.test(version)) {
throw new Error('Invalid or missing version argument');
}
{
const file = 'bower.json';
console.log(`Updating ${file}...`);
const filePath = path.join(__dirname, '..', file);
const json = fs.readFileSync(filePath, 'utf8');
const packageIndentation = json.match(/\n([\t\s]+)/)[1];
const data = JSON.parse(json);

data.version = version;

fs.writeFileSync(
filePath,
JSON.stringify(data, null, packageIndentation) + '\n'
);
}
{
const file = 'package.json';
console.log(`Updating ${file}...`);
const filePath = path.join(__dirname, '..', file);
const json = fs.readFileSync(filePath, 'utf8');
const packageIndentation = json.match(/\n([\t\s]+)/)[1];
const data = JSON.parse(json);

data.version = version;
data.author.url = data.author.url.replace('main', version);

fs.writeFileSync(
filePath,
JSON.stringify(data, null, packageIndentation) + '\n'
);
}
{
console.log('Running `npm run build`...');
cp.execFileSync('npm', [
'run',
'build'
], { encoding: 'utf8' });
}
},
cdnClone (repoPath) {
const remote = cdnRemotes.anonymous;
console.log('... cloning ' + remote);
if (fs.existsSync(repoPath)) {
fs.rmdirSync(repoPath, { recursive: true });
}
cp.execFileSync('git', [
'clone',
'--depth=5',
'-q',
remote,
repoPath
]);
},
cdnCommit (version) {
if (!version) {
throw new Error('Missing parameters');
}
const repoPath = path.join(__dirname, '..', '__codeorigin');
Repo.cdnClone(repoPath);

const toCommit = [];
for (const src in cdnFiles) {
const srcPath = path.join(__dirname, '..', src);
const dest = cdnFiles[src].replace('@VERSION', version);
const destPath = path.join(repoPath, dest);
console.log('... copying ' + src + ' to ' + dest);
fs.copyFileSync(srcPath, destPath, fs.constants.COPYFILE_EXCL);
toCommit.push(dest);
}

console.log('... creating commit');

const author = cp.execSync('git log -1 --format=%aN%n%aE',
{ encoding: 'utf8', cwd: path.join(__dirname, '..') }
)
.trim()
.split('\n');

cp.execFileSync('git', ['add', ...toCommit],
{ cwd: repoPath }
);

cp.execFileSync('git',
['commit', '-m', cdnCommitMessage.replace('@VERSION', version)],
{
cwd: repoPath,
env: {
GIT_AUTHOR_NAME: author[0],
GIT_AUTHOR_EMAIL: author[1],
GIT_COMMITTER_NAME: author[0],
GIT_COMMITTER_EMAIL: author[1]
}
}
);

// prepre for user to push from the host shell after review
cp.execFileSync('git', ['remote', 'set-url', 'origin', cdnRemotes.auth],
{ cwd: repoPath }
);
}
};

const [version, remote] = process.argv.slice(2);

try {
Repo.buildFiles(version);
Repo.cdnCommit(version, remote || 'real');
} catch (e) {
if (e.stderr) {
e.stdout = e.stdout.toString();
e.stderr = e.stderr.toString();
}
console.error(e);
process.exit(1);
}
2 changes: 1 addition & 1 deletion build/prep-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,6 @@ const version = process.argv[2];
(async function main () {
await Repo.prep(version);
}()).catch(e => {
console.error(e.toString());
console.error(e);
process.exit(1);
});
Loading

0 comments on commit 44995db

Please sign in to comment.