binup 1.10.0

Automated app installation from GitHub releases
#!/usr/bin/env bash
#
# Runs tests
#

set -eu

cleanup() {
    [ -z "$temp_dir" ] || rm -rf "$temp_dir"
}

cargo test

temp_dir=""
trap cleanup EXIT
trap "exit 1" INT TERM QUIT
temp_dir="$(mktemp -d "/var/tmp/binup-test.XXXXXX")"

tool=binup
project="KonishchevDmitry/$tool"
binary_matcher="$tool"
changelog="https://github.com/$project/releases"
install_path="$temp_dir/bin"
custom_install_path="$temp_dir/custom-bin"
post_install_marker_path="$temp_dir/post-install-marker"
post_command="touch '$post_install_marker_path' && echo 'Post-install script stdout' && echo 'Post-install script stderr' >&2"

if [ "$(uname)" = Darwin ]; then
    release_matcher="$tool-*-macos-arm64.*"
else
    release_matcher="$tool-*-linux-*"
fi

github_config=""
if [ -n "${GITHUB_TOKEN-}" ]; then
    github_config="github: {token: $GITHUB_TOKEN}"
fi

(
    cd "$temp_dir"
    mkdir bin custom-bin

    cat > old-release-mock <<EOF
#!/bin/bash
echo "$tool 0.1.0"
EOF

    cat > new-release-mock <<EOF
#!/bin/bash
echo "$tool 100.0.0"
EOF

    chmod a+x old-release-mock new-release-mock
    touch -c -d 2024-08-01T00:00:00 old-release-mock

    cat > "config.yaml" <<EOF
path: $install_path

tools:
  $tool:
    project: $project

  up-to-date:
    project: $project

  upgradable:
    project: $project
    prerelease: true
    changelog: $changelog
    release_matcher: $release_matcher
    binary_matcher: $binary_matcher
    force_executable: true
    version_source: flag
    path: $custom_install_path
    post: $post_command

$github_config
EOF
)

config_path="$temp_dir/config.yaml"
shasum "$config_path" > "$config_path.checksum"

run() {
    cargo run --quiet -- --config "$config_path" "$@"
}

ensure_exists_rm() {
    rm "$@"
}

ensure_missing() {
    local path

    for path in "$@"; do
        if [ -e "$path" ]; then
            echo "$path exists when not expected to be." >&2
            return 1
        fi
    done
}

# Test work with missing default config
cargo run --quiet -- list

# List with no installed tools
run list

# Should install the tool, but not change the config (fully matches)
for pass in ensure_exists_rm ensure_missing; do
    run install upgradable --project "$project" --prerelease \
        --release-matcher "$release_matcher" --binary-matcher "$binary_matcher" --force-executable \
        --version-source flag --changelog "$changelog" --path "$custom_install_path" --post "$post_command" < /dev/null

    "$custom_install_path/upgradable" --help > /dev/null
    "$pass" "$post_install_marker_path"
    shasum -c "$config_path.checksum" > /dev/null
done

for command in install "install --force" upgrade; do
    cp -a "$temp_dir/new-release-mock" "$install_path/up-to-date"
    cp -a "$temp_dir/old-release-mock" "$custom_install_path/upgradable"

    run $command

    (
        cd "$temp_dir"

        "bin/$tool" --help > /dev/null

        if [ "$command" = "install --force" ]; then
            cmp bin/up-to-date "bin/$tool"
        else
            cmp bin/up-to-date new-release-mock
        fi

        if [ "$command" = install ]; then
            shasum "bin/$tool" > checksum
            cmp custom-bin/upgradable old-release-mock
            ensure_missing "$post_install_marker_path"
        else
            shasum -c checksum > /dev/null
            cmp custom-bin/upgradable "bin/$tool"
            ensure_exists_rm "$post_install_marker_path"
        fi
    )
done

# Should update existing entry, but not reinstall
updated_post_install_marker="$temp_dir/updated-post-install-marker"
yes | run install --project "$project" --post "touch '$updated_post_install_marker'"
ensure_missing "$updated_post_install_marker"

# Should add a new entry and install
new_post_install_marker="$temp_dir/new-post-install-marker"
run install new --project "$project" --force-executable --version-source command --post "touch '$new_post_install_marker'"
ensure_exists_rm "$new_post_install_marker"

# Ensure persistence of the changes
run install --force "$tool" && ensure_exists_rm "$updated_post_install_marker"
run install --force new && ensure_exists_rm "$new_post_install_marker"

# Uninstall simple and complex configurations
cmp "$install_path/new" "$custom_install_path/upgradable"
yes | run uninstall new upgradable
ensure_missing "$install_path/new" "$custom_install_path/upgradable"

run list
run list --local --full
run list --prerelease --full