#!/usr/bin/env zsh # Publish a new release. set -euo pipefail # For docs see docs/RELEASE.md autoload -U colors && colors if [[ -n ${DEBUG:-} ]]; then set -x fi project_dir=${0:a:h:h} cd $project_dir # Deny all warnings in CI. export RUSTFLAGS="-D warnings" # Set trace logs for tests using test_log::test export RUST_LOG=up=trace # Don't send SIGTTOU to background jobs that write to the tty. Theoretically fixes this in busy commands: # [1] + 82656 suspended (tty output) cargo run # Note that this doesn't fix tty input issues, for those you need to make things not read from the # tty. stty -tostop # Don't go to sleep while we're running the release script. caffeinate -ds -w $$ & binary_name=up macos_binary=build/$binary_name-Darwin linux_amd64_binary=build/$binary_name-Linux linux_arm64_binary=build/$binary_name-Linux_arm64 task_schema_json=build/$binary_name-task-schema.json main() { echo -e "${fg[magenta]}Publishing new version of the ${binary_name} CLI...${reset_color}" # Install nextest runner if missing: https://nexte.st (( $+commands[cargo-nextest] )) || brew install cargo-nextest (( $+commands[git-cliff] )) || brew install git-cliff (( $+commands[gh] )) || brew install gh # Delete stale files. log_section "Cleaning up files from last release..." rm -rfv build/ rm -fv target/universal-apple-darwin/release/$binary_name mkdir -p build/ if [[ $(git branch --show-current) != main ]]; then error "Not currently on the main branch." fi if [[ -n ${SKIP_GIT_DIFF_CHECK:-} ]]; then log_section "Skipping it changed file check as SKIP_GIT_DIFF_CHECK env var was set." else # Bail on uncommitted diffs. diff=$(git diff --color=always) if [[ -n $diff ]]; then error "${fg[cyan]}-> Repo has uncommitted diffs:${reset_color} $diff" fi fi if [[ -n ${SKIP_GIT_UNTRACKED_CHECK:-} ]]; then log_section "Skipping git untracked file check as SKIP_GIT_UNTRACKED_CHECK env var was set." else # Bail on untracked files. untracked=$(git ls-files . --exclude-standard --others | head) if [[ -n $untracked ]]; then error "Repo has untracked files:\n$untracked" fi fi # Takes a line like: # `## [0.13.4](https://github.com/gibfahn/up/releases/tag/0.13.4) (2023-02-07)` # and extracts the `0.13.4`. changelog_version=$(awk docs/CommandLineHelp-macOS.md meta/cargo-docker --pull -- cargo run --color=always -- doc markdown >docs/CommandLineHelp-Linux.md log_section "Committing version updates..." git add Cargo.toml Cargo.lock CHANGELOG.md docs/CommandLineHelp-macOS.md docs/CommandLineHelp-Linux.md git commit -m "chore: bump version to ${new_version?}" git show --stat | cat # Check version is correct. echo >&2 "Does this look correct?" fi # Run unit and integration tests for macOS. if [[ -n ${SKIP_CARGO_TEST_CHECK:-} ]]; then log_section "Skipping tests as SKIP_CARGO_TEST_CHECK env var was set." else log_and_run cargo nextest run --release --run-ignored=all --no-fail-fast fi # Generate the JSON schema for a task. cargo run -- doc schema $task_schema_json log_section "Running end-to-end tests..." # Run End-to-End tests and build Linux binaries: log_and_run meta/bootstrap-test # Build Darwin release binaries (without the CI feature). log_and_run meta/build_macos # This was built as part of running e2e tests. cp target/universal-apple-darwin/release/up $macos_binary # This allows them to be downloaded as `up-$(uname)`. cp target/x86_64-unknown-linux-musl/release/up $linux_amd64_binary cp target/aarch64-unknown-linux-musl/release/up $linux_arm64_binary latest_crate_version=$(curl https://crates.io/api/v1/crates/up | jq -r .crate.newest_version) if [[ $latest_crate_version == $new_version ]]; then prompt_to_skip "Skipping cargo publish as latest release is already $latest_crate_version." else # Publish to crates.io: log_and_run cargo publish fi log_and_run git push up main log_and_run gh release create "${new_version?}" --target=main \ --notes="$(git cliff --tag="${new_version?}" --strip=all "${last_release}"..)" \ $macos_binary \ $linux_amd64_binary \ $linux_arm64_binary \ $task_schema_json new_release=$(gh release list -L 1 | awk '{print $1}') gh release view $new_release if [[ $new_release != $new_version ]]; then error "Something went wrong, latest GitHub version is not what the script just released." fi # Pull in the tag we just created remotely. log_section "Fetching just-created tag..." git fetch --all } # Bump the major, minor, or patch (set by $1) version of the given version. # $1: major|minor|patch , which number to bump. # $2: the input version string, e.g. `1.2.3`. bump_version() { case $1 in major) awk -F '.' '{print $1+1 ".0.0"}' <<<$2 ;; minor) awk -F '.' '{print $1 "." $2+1 ".0"}' <<<$2 ;; patch) awk -F '.' '{print $1 "." $2 "." $3+1}' <<<$2 ;; *) error "bump_version: unknown input ${2}" ;; esac } log_section() { echo " ${fg[cyan]}=> $*${reset_color}" >&2 } log_and_run() { log_section "Running $*" time "$@" } # $1: Error message # $2: Error code (default: 1). error() { echo -e "${fg[red]}ERROR${reset_color}: $1" >&2 exit "${2:-1}" } prompt_to_skip() { read "user_input?$1 Press Enter to continue, type anything or press Ctrl-C to cancel: " if [[ -n ${user_input:-} ]]; then error "User entered text." fi } main "$@"