diff --git a/release.sh b/release.sh index 97ae424e..c9652170 100755 --- a/release.sh +++ b/release.sh @@ -8,6 +8,7 @@ NEXT_VERSION= BRANCH=$(git rev-parse --abbrev-ref HEAD) NARGS=0 DRY_RUN= +PUBLISH= INSANE=0 # usage [ERROR-MESSAGES...] EXIT-CODE @@ -20,21 +21,24 @@ usage() { echo "./release.sh [OPTIONS] [NEXT_VERSION]" echo "" echo "Options:" + echo " --publish|-p: publish a release." echo " --dry-run|-n: only print commands, do not execute them." echo "" - echo "Examples:" - echo " When releasing a new point release:" - echo " ./release.sh 0.6.3 0.6.4" - echo " When releasing a new major version:" - echo " ./release.sh 0.7.0 0.8.0" - echo "" echo "You may omit NEXT_VERSION in order to avoid updating the version field" echo "of the package.json." echo "" - echo "Run this on the master branch, if you have permission to directly push" - echo "to the master branch. Otherwise, create a branch with the version number" - echo "as its name and a suffix to distinguish from its tag, e.g.," - echo "'v1.0.0-release', and run this on it." + echo "Run this on the master branch. This will create a release branch." + echo "Open a pull request and after it gets merged, run with --publish" + echo "option on the master branch." + echo "" + echo "To update SRI hashes, run this again on the generated release branch" + echo "" + echo "Examples:" + echo " When releasing a v0.6.3:" + echo " ./release.sh 0.6.3 0.6.4" + echo " Open a pull request from v0.6.3-release to master." + echo " After it's merged:" + echo " ./release.sh -p 0.6.3" exit $1 } @@ -45,6 +49,9 @@ while [ $# -gt 0 ]; do git() { echo "git $*"; } yarn() { echo "yarn $*"; } ;; + --publish|-p) + PUBLISH=true + ;; -h|-\?|--help) usage 0 ;; @@ -79,12 +86,16 @@ if ! command git diff --stat --exit-code HEAD; then echo "Please make sure you have no uncommitted changes" >&2 : $((++INSANE)) fi -if [[ $BRANCH != @(v*|master) ]]; then +if [[ $BRANCH != @(v*-release|master) ]]; then echo "'$BRANCH' does not look like a release branch to me" >&2 : $((++INSANE)) fi -if [[ -z "$NEXT_VERSION" ]]; then +if [[ $PUBLISH ]]; then + echo "About to publish $VERSION from $BRANCH. " +elif [[ $BRANCH != "master" ]]; then + echo "About to update SRI hashes for $BRANCH. " +elif [[ -z "$NEXT_VERSION" ]]; then echo "About to release $VERSION from $BRANCH. " else echo "About to release $VERSION from $BRANCH and bump to $NEXT_VERSION-pre." @@ -98,94 +109,119 @@ if [[ "$CONFIRM" != "y" ]]; then exit 1 fi -# Make a new detached HEAD git checkout "$BRANCH" git pull -git checkout --detach - -# Edit package.json to the right version (see -# http://stackoverflow.com/a/22084103 for why we need the .bak file to make -# this mac & linux compatible) -sed -i.bak -E 's|"version": "[^"]+",|"version": "'$VERSION'",|' package.json -rm -f package.json.bak - -# Build generated files and add them to the repository -git clean -fdx dist -yarn dist -sed -i.bak -E '/^\/dist\/$/d' .gitignore -rm -f .gitignore.bak -git add .gitignore dist/ - -# Edit docs to use CSS from CDN -grep -l '{@stylesheet: katex.min.css}' docs/*.md | xargs sed -i.bak \ - 's|{@stylesheet: katex.min.css}||' - -# Update the version number in CDN URLs included in the README and the documentation, -# and regenerate the Subresource Integrity hash for these files. -node update-sri.js "${VERSION}" README.md contrib/*/README.md dist/README.md \ - docs/*.md docs/*.md.bak website/pages/index.html - -# Generate a new version of the docs and publish the website -pushd website -yarn run version "${VERSION}" - -# Restore docs to use local built CSS -for file in ../docs/*.md.bak; do - mv -f "$file" "${file%.bak}" -done - -USE_SSH=true yarn publish-gh-pages -popd - -# Make the commit and tag, and push them. -git add package.json README.md contrib/*/README.md dist/README.md \ - docs/*.md website/pages/index.html website/versioned_docs/ \ - website/versioned_sidebars/ website/versions.json -git commit -n -m "v$VERSION" -git diff --stat --exit-code # check for uncommitted changes -git tag -a "v$VERSION" -m "v$VERSION" -git push origin "v$VERSION" - -# Update npm (cdnjs update automatically) -yarn publish --new-version "${VERSION}" - -# Go back to original branch to bump -git checkout "$BRANCH" - -if [ ! -z "$NEXT_VERSION" ]; then - # Edit package.json to the next version - sed -i.bak -E 's|"version": "[^"]+",|"version": "'$NEXT_VERSION'-pre",|' package.json - rm -f package.json.bak - git add package.json -fi - -# Refer to the just-released version in the documentation of the -# development branch, too. Most people will read docs on master. -git checkout "v${VERSION}" -- README.md contrib/*/README.md docs/*.md website/ - -if [[ -z "$NEXT_VERSION" ]]; then - git commit -n -m "Release v$VERSION" -else - git commit -n -m "Bump $BRANCH to v$NEXT_VERSION-pre" -fi - -git push origin "$BRANCH" - -# Go back to the tag which has katex.tar.gz and katex.zip -git checkout "v$VERSION" - -echo "" -echo "The automatic parts are done!" if [[ $BRANCH != "master" ]]; then - echo "Now all that's left is to create a pull request against master from '$BRANCH'" - echo "and to create the release on github." + # Build generated files + yarn build + + # Regenerate the Subresource Integrity hash in the README and the documentation + node update-sri.js "${VERSION}" README.md contrib/*/README.md \ + docs/*.md website/pages/index.html website/versioned_docs/version-$VERSION/*.md + + # Make the commit and push + git add README.md contrib/*/README.md \ + docs website/pages/index.html website/versioned_docs/ + git commit -n -m "Update SRI hashes" + git push +elif [[ ! $PUBLISH ]]; then + # Make a release branch + git checkout -b "v$VERSION-release" + + # Edit package.json to the right version, as it's inlined (see + # http://stackoverflow.com/a/22084103 for why we need the .bak file to make + # this mac & linux compatible) + sed -i.bak -E 's|"version": "[^"]+",|"version": "'$VERSION'",|' package.json + rm -f package.json.bak + + # Build generated files + yarn build + + if [ ! -z "$NEXT_VERSION" ]; then + # Edit package.json to the next version + sed -i.bak -E 's|"version": "[^"]+",|"version": "'$NEXT_VERSION'-pre",|' package.json + rm -f package.json.bak + git add package.json + fi + + # Edit docs to use CSS from CDN + grep -l '{@stylesheet: katex.min.css}' docs/*.md | xargs sed -i.bak \ + 's|{@stylesheet: katex.min.css}||' + + # Update the version number in CDN URLs included in the README and the documentation, + # and regenerate the Subresource Integrity hash for these files. + node update-sri.js "${VERSION}" README.md contrib/*/README.md \ + docs/*.md docs/*.md.bak website/pages/index.html + + # Generate a new version of the docs + pushd website + yarn run version "${VERSION}" + popd + + # Restore docs to use local built CSS + for file in docs/*.md.bak; do + mv -f "$file" "${file%.bak}" + done + + # Make the commit and push + git add package.json README.md contrib/*/README.md \ + docs website/pages/index.html website/versioned_docs/ \ + website/versioned_sidebars/ website/versions.json + if [[ -z "$NEXT_VERSION" ]]; then + git commit -n -m "Release v$VERSION" + else + git commit -n -m "Release v$VERSION" -m "Bump $BRANCH to v$NEXT_VERSION-pre" + fi + git push -u origin "v$VERSION-release" + + echo "" + echo "The automatic parts are done!" + echo "Now create a pull request against master from 'v$VERSION-release'" + echo "Visit https://github.com/Khan/KaTeX/pulls to open a pull request." + echo "After it gets merged, run './release.sh -p $VERSION'!" + echo "Note that if KaTeX source code is changed after running this script," + echo "you have to run the release script again." else - echo "Now all that's left is to create the release on github." + # Make a new detached HEAD + git checkout --detach + + # Edit package.json to the right version + sed -i.bak -E 's|"version": "[^"]+",|"version": "'$VERSION'",|' package.json + rm -f package.json.bak + + # Build generated files and add them to the repository + git clean -fdx dist + yarn dist + sed -i.bak -E '/^\/dist\/$/d' .gitignore + rm -f .gitignore.bak + + # Check Subresource Integrity hashes + node update-sri.js check README.md contrib/*/README.md + + # Make the commit and tag, and push them. + git add package.json .gitignore dist/ + git commit -n -m "v$VERSION" + git diff --stat --exit-code # check for uncommitted changes + git tag -a "v$VERSION" -m "v$VERSION" + git push origin "v$VERSION" + + # Update npm (cdnjs update automatically) + yarn publish --new-version "${VERSION}" + + # Publish the website + pushd website + USE_SSH=true yarn publish-gh-pages + popd + + echo "" + echo "The automatic parts are done!" + echo "Now all that's left is to create the release on GitHub." + echo "Visit https://github.com/Khan/KaTeX/releases/new?tag=v$VERSION to edit the release notes." + echo "Don't forget to upload katex.tar.gz and katex.zip to the release!" fi -echo "Visit https://github.com/Khan/KaTeX/releases/new?tag=v$VERSION to edit the release notes" -echo "Don't forget to upload katex.tar.gz and katex.zip to the release!" +git diff --stat --exit-code # check for uncommitted changes if [[ ${DRY_RUN} ]]; then echo "" diff --git a/update-sri.js b/update-sri.js index ed875bf6..0d74b359 100644 --- a/update-sri.js +++ b/update-sri.js @@ -1,3 +1,6 @@ +// Update badge and CDN urls and subresource integrity hashes +// Usage: node update-sri.js FILES... +// To check SRI hashes, pass `check` as VERSION const fs = require("fs-extra"); const sriToolbox = require("sri-toolbox"); @@ -27,14 +30,22 @@ Promise.all(process.argv.slice(3).map(file => } return pre + version + post; }); - return Promise.all(Object.keys(hashes).map(hash => + const promise = Promise.all(Object.keys(hashes).map(hash => fs.readFile(hashes[hash].file, null) .then(data => { - body = body.replace(hash, sriToolbox.generate({ + const newHash = sriToolbox.generate({ algorithms: [hashes[hash].algo], - }, data)); + }, data); + body = body.replace(hash, newHash); + + if (version === "check" && hash !== newHash) { + throw new Error("SRI mismatch! " + + "Please run the release script again."); + } }) - )).then(() => fs.writeFile(file, body)); + )); + return version === "check" ? promise + : promise.then(() => fs.writeFile(file, body)); }) )).then(() => process.exit(0), err => { // eslint-disable-next-line no-console