Skip to content

Instantly share code, notes, and snippets.

@shuckster
Last active January 23, 2022 17:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shuckster/246e3d5f98d51d20cdf00ade25029d04 to your computer and use it in GitHub Desktop.
Save shuckster/246e3d5f98d51d20cdf00ade25029d04 to your computer and use it in GitHub Desktop.
Publish a new version of an npm package
#!/bin/sh
#
# Publish a new version of an npm package.
#
# - Runs linter, tests
# - Asks if next version is major, minor or patch
# - Calculates the next version from this
# - Checks that the CHANGELOG references the new version
# - Tags/publishes the new version via git/npm
#
# Download:
#
# curl -s https://gist.githubusercontent.com/shuckster/246e3d5f98d51d20cdf00ade25029d04/raw/publish.sh -o publish.sh
# chmod +x ./publish.sh
# echo "publish.sh" >> .gitignore
#
# Written by Conan: https://gist.github.com/shuckster/246e3d5f98d51d20cdf00ade25029d04
#
_TEST_="pnpm run test"
_LINT_="pnpm run lint"
_VERSION_="pnpm version"
_BUILD_="pnpm run build:all"
_DRY_RUN_="pnpm publish --dry-run"
_PUBLISH_="pnpm publish"
_GIT_='git'
main()
{
lint_and_test
prompt_for_next_semversion
calculate_next_semversion
confirm_changelog_has_semversion
set_package_semversion_and_validate
rebuild_and_dry_run_publish
publish_and_push
}
lint_and_test()
{
$_LINT_ || bail "Linting failed"
$_TEST_ || bail "Tests failed"
}
prompt_for_next_semversion()
{
current_version=$(grep version package.json|awk 'BEGIN { FS="\"" } { print $4 }')
major_v=$(echo "${current_version}"|awk 'BEGIN { FS="." } { print $1 }')
minor_v=$(echo "${current_version}"|awk 'BEGIN { FS="." } { print $2 }')
patch_v=$(echo "${current_version}"|awk 'BEGIN { FS="." } { print $3 }')
minor_space=$(echo "${minor_v}"|sed 's/[0-9\.]/ /g')
minor_dash=$(echo "${minor_v}"|sed 's/[0-9\.]/─/g')
patch_space=$(echo "${patch_v}"|sed 's/[0-9\.]/ /g')
patch_dash=$(echo "${patch_v}"|sed 's/[0-9\.]/─/g')
echo ""
echo "Current version: ${current_version}"
echo " ^${minor_space}^${patch_space}^"
echo " ┌──────────────┘${minor_space}│${patch_space}│"
echo " │ ┌────────${minor_dash}┘${patch_space}│"
echo " │ │ ┌─${minor_dash}─${patch_dash}┘"
echo " ─┴─ ─┴─ ─┴─"
printf "major, minor, patch?: "
read -r semver
case ${semver} in
major|minor|patch) : ;;
*)
bail "Please specify either major, minor or patch"
;;
esac
}
calculate_next_semversion()
{
if [ "${semver}" = "major" ]; then : $((major_v+=1)); minor_v=0; patch_v=0; fi
if [ "${semver}" = "minor" ]; then : $((minor_v+=1)); patch_v=0; fi
if [ "${semver}" = "patch" ]; then : $((patch_v+=1)); fi
next_version="${major_v}.${minor_v}.${patch_v}"
}
confirm_changelog_has_semversion()
{
line_padding=$(echo "${next_version}"|sed 's/[0-9\.]/─/g')
echo ""
echo "┌─────────────────────────────────${line_padding}──┐"
echo "│ Prep CHANGELOG.md for version: ${next_version} │"
echo "└─────────────────────────────────${line_padding}──┘"
echo ""
if ! grep "## \\[${next_version}\\]" CHANGELOG.md
then
bail "It doesn't look like you've done that yet..."
fi
prompter "Did you do that?" "Yes, I did already!"
}
set_package_semversion_and_validate()
{
$_VERSION_ "${semver}" || bail "Could not update package version"
new_version=$(grep version package.json|awk 'BEGIN { FS="\"" } { print $4 }')
if [ "${new_version}" != "${next_version}" ]
then
bail "Version in package.json (${new_version}) doesn't match calculated version (${next_version})"
fi
}
rebuild_and_dry_run_publish()
{
# Rebuild after `npm version` to put version-info into bundle
$_BUILD_ || bail "Build failed"
# Skip pre-commit hooks as we've done that in the first step
$_GIT_ add .
$_GIT_ commit -m "Published ${new_version}" -n
$_DRY_RUN_ || bail "Dry run failed"
prompter "Does the dry-run look good?" "Yes, not too bad!"
}
publish_and_push()
{
$_PUBLISH_ || bail "Publish failed"
$_GIT_ push
$_GIT_ push origin --tags
}
prompter()
{
confirm_text="${2}"
printf "${1} [%s]: " "${confirm_text}"
read -r confirm
echo ""
if [ "${confirm}" != "${confirm_text}" ]
then
bail "That wasn't it..."
fi
}
bail()
{
echo ""
echo "[BAIL] :: $1"
echo ""
exit 1
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment