1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
#!/usr/bin/env bash
# Slightly modified version of xyz that publishes from the build directory,
# rather than the root.
set -e
usage="
Usage: xyz [options]
Publish a new version of the npm package in the current working directory.
This involves updating the version number in package.json, committing this
change (along with any staged changes), tagging the commit, pushing to the
remote git repository, and finally publishing to the public npm registry.
Options:
-b --branch <name>
Specify the branch from which new versions must be published.
xyz aborts if run from any other branch to prevent accidental
publication of feature branches. 'master' is assumed if this
option is omitted.
-i --increment <level>
Specify the level of the current version number to increment.
Valid levels: 'major', 'minor', 'patch', 'premajor', 'preminor',
'prepatch', and 'prerelease'. 'patch' is assumed if this option
is omitted.
-m --message <template>
Specify the format of the commit (and tag) message.
'X.Y.Z' acts as a placeholder for the version number.
'Version X.Y.Z' is assumed if this option is omitted.
-r --repo <repository>
Specify the remote repository to which to 'git push'.
The value must be either a URL or the name of a remote.
The latter is not recommended: it relies on local state.
'origin' is assumed if this option is omitted.
-s --script <path>
Specify a script to be run after the confirmation prompt.
It is passed VERSION and PREVIOUS_VERSION as environment
variables. xyz aborts if the script's exit code is not 0.
-t --tag <template>
Specify the format of the tag name. As with --message,
'X.Y.Z' acts as a placeholder for the version number.
'vX.Y.Z' is assumed if this option is omitted.
--dry-run
Print the commands without evaluating them.
-v --version
Print xyz's version number and exit.
"
# http://stackoverflow.com/a/246128/312785
path="${BASH_SOURCE[0]}"
while [ -h "$path" ] ; do
dir="$(cd -P "$(dirname "$path")" && pwd)"
path="$(readlink "$path")"
[[ $path == /* ]] || path="$dir/$path"
done
dir="$(cd -P "$(dirname "$path")" && pwd)"
branch=master
increment=patch
message_template='Version X.Y.Z'
repo=origin
declare -a scripts
tag_template=vX.Y.Z
dry_run=false
while (($# > 0)) ; do
option="$1"
shift
case "$option" in
-h|--help)
echo "$usage"
exit
;;
-v|--version)
node -p "require('$dir/../package.json').version"
exit
;;
-b|--branch) branch="$1" ; shift ;;
-i|--increment) increment="$1" ; shift ;;
-m|--message) message_template="$1" ; shift ;;
-r|--repo) repo="$1" ; shift ;;
-s|--script) scripts+=("$1") ; shift ;;
-t|--tag) tag_template="$1" ; shift ;;
--dry-run) dry_run=true ;;
*)
echo "Unrecognized option $option" >&2
exit 1
esac
done
case "$increment" in
major|minor|patch|premajor|preminor|prepatch|prerelease) ;;
*) echo "Invalid --increment" >&2 ; exit 1 ;;
esac
[[ $(git rev-parse --abbrev-ref HEAD) == $branch ]] ||
(echo "Current branch does not match specified --branch" >&2 ; exit 1)
#git diff-files --quiet ||
# (echo "Working directory contains unstaged changes" >&2 ; exit 1)
name=$(node -p "require('./package.json').name" 2>/dev/null) ||
(echo "Cannot read package name" >&2 ; exit 1)
version=$(node -p "require('./package.json').version" 2>/dev/null) ||
(echo "Cannot read package version" >&2 ; exit 1)
next_version=$("$dir/../node_modules/.bin/semver" -i "$increment" "$version") ||
(echo "Cannot increment version number" >&2 ; exit 1)
message="${message_template//X.Y.Z/$next_version}"
tag="${tag_template//X.Y.Z/$next_version}"
bold=$(tput bold)
reset=$(tput sgr0)
printf "Current version is ${bold}${version}${reset}. "
printf "Press [enter] to publish ${bold}${name}@${next_version}${reset}."
read -s # suppress user input
echo # output \n since [enter] output was suppressed
run() {
echo "$1"
if [[ $dry_run == false ]] ; then
eval "$1"
fi
}
for script in "${scripts[@]}" ; do
[[ $script == /* ]] || script="$(pwd)/$script"
run "VERSION=$next_version PREVIOUS_VERSION=$version '$script'"
done
inc() {
if [[ -f "$1" ]] ; then
run "node -e '$(echo "
var o = require('./$1'); o.version = '$next_version';
require('fs').writeFileSync('./$1', JSON.stringify(o, null, 2) + '\n');
" | tr "'" '"' | tr -d "\n" | tr -s " " | sed -e "s/^ *//" -e "s/ *$//")'"
run "git add '$1'"
fi
}
inc package.json
run "git add --force *.json"
run "git commit --message '$message'"
run "git tag --annotate '$tag' --message '$message'"
run "git push '$repo' 'refs/heads/$branch' 'refs/tags/$tag'"
# npm publish is managed by the Makefile
|