Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 55 additions & 11 deletions go-template
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
# description. You may remove any other comments from this template as well.
#
# This template automatically checks for the presence of the go-script-bash
# sources and makes a shallow clone of the the go-script-bash repository if
# necessary before dispatching commands. (If you prefer, you can change the
# logic to create a regular clone instead.) This allows users to set up the
# sources and downloads the go-script-bash repository contents if necessary
# before dispatching commands. (If you prefer, you can change the logic to
# create a shallow or regular clone instead.) This allows users to set up the
# framework without taking any extra steps when running the command for the
# first time, without the need to commit the framework to your repository.
#
Expand All @@ -35,23 +35,67 @@ export _GO_STANDALONE=
declare GO_SCRIPTS_DIR="${GO_SCRIPTS_DIR:-scripts}"

# The `GO_SCRIPT_BASH_REPO_URL` tag or branch you wish to use
declare GO_SCRIPT_BASH_VERSION="${GO_SCRIPT_BASH_VERSION:-v1.4.0}"
declare GO_SCRIPT_BASH_VERSION="${GO_SCRIPT_BASH_VERSION:-v1.5.0}"

# The target version string, removing the leading 'v'
declare _GO_SCRIPT_BASH_VERSION_NUMBER="${GO_SCRIPT_BASH_VERSION:1}"

# The go-script-bash installation directory within your project
declare GO_SCRIPT_BASH_CORE_DIR="${GO_SCRIPT_BASH_CORE_DIR:-${0%/*}/$GO_SCRIPTS_DIR/go-script-bash}"

# The URL of the go-script-bash framework sources
declare GO_SCRIPT_BASH_REPO_URL="${GO_SCRIPT_BASH_REPO_URL:-https://github.com/mbland/go-script-bash.git}"

# URL with the release files
declare GO_SCRIPT_BASH_DOWNLOAD_URL="${GO_SCRIPT_BASH_DOWNLOAD_URL:-${GO_SCRIPT_BASH_REPO_URL%.git}/archive}/$GO_SCRIPT_BASH_VERSION.tar.gz"

if [[ ! -e "$GO_SCRIPT_BASH_CORE_DIR/go-core.bash" ]]; then
printf "Cloning framework from '%s'...\n" "$GO_SCRIPT_BASH_REPO_URL"
if ! git clone --depth 1 -c advice.detachedHead=false \
-b "$GO_SCRIPT_BASH_VERSION" "$GO_SCRIPT_BASH_REPO_URL" \
"$GO_SCRIPT_BASH_CORE_DIR"; then
printf "Failed to clone '%s'; aborting.\n" "$GO_SCRIPT_BASH_REPO_URL" >&2
exit 1
declare PIPEFAIL_BACKUP
PIPEFAIL_BACKUP=$(shopt -op | grep pipefail)
set -o pipefail

# Using a function to allow for multiple return points
curl_download(){
if ! command curl -V >/dev/null; then
printf "Failed to find cURL or tar\n"
return 1
fi
if ! command tar --help >/dev/null; then
printf "Failed to find cURL or tar\n"
return 1
fi
printf "Downloading framework from '%s'...\n" "$GO_SCRIPT_BASH_DOWNLOAD_URL"
if ! curl -LfsS "$GO_SCRIPT_BASH_DOWNLOAD_URL" | tar -xz 2>/dev/null ; then
printf "Failed to download from '%s'.\n" "$GO_SCRIPT_BASH_DOWNLOAD_URL" >&2
return 1
fi
if ! mkdir -p $GO_SCRIPTS_DIR ; then
printf "Failed to create scripts dir '%s'\n" $GO_SCRIPTS_DIR >&2
rm -rf go-script-bash-$_GO_SCRIPT_BASH_VERSION_NUMBER
return 1
fi
if ! mv go-script-bash-$_GO_SCRIPT_BASH_VERSION_NUMBER $GO_SCRIPT_BASH_CORE_DIR; then
printf "Failed to install downloaded directory in '%s'\n" $GO_SCRIPT_BASH_CORE_DIR >&2
rm -rf go-script-bash-$_GO_SCRIPT_BASH_VERSION_NUMBER
return 1
fi
printf "Download of '%s' successful.\n\n" "$GO_SCRIPT_BASH_DOWNLOAD_URL"
return 0
}

if ! curl_download; then
printf "Using git clone as fallback\n"
printf "Cloning framework from '%s'...\n" "$GO_SCRIPT_BASH_REPO_URL"
if ! git clone --depth 1 -c advice.detachedHead=false \
-b "$GO_SCRIPT_BASH_VERSION" "$GO_SCRIPT_BASH_REPO_URL" \
"$GO_SCRIPT_BASH_CORE_DIR"; then
printf "Failed to clone '%s'; aborting.\n" "$GO_SCRIPT_BASH_REPO_URL" >&2
$PIPEFAIL_BACKUP
exit 1
fi
printf "Clone of '%s' successful.\n\n" "$GO_SCRIPT_BASH_REPO_URL"
fi
printf "Clone of '%s' successful.\n\n" "$GO_SCRIPT_BASH_REPO_URL"
$PIPEFAIL_BACKUP
fi

. "$GO_SCRIPT_BASH_CORE_DIR/go-core.bash" "$GO_SCRIPTS_DIR"
Expand Down
155 changes: 127 additions & 28 deletions tests/template.bats
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,17 @@

load environment

# By default, the test will try to clone its own repo to avoid flakiness due to
# an external dependency. However, doing so causes a failure on Travis, since it
# uses shallow clones to produce test runs, resulting in the error:
#
# fatal: attempt to fetch/clone from a shallow repository
#
# However, since Travis already depends on having a good connection to GitHub,
# we'll use the real URL. Alternatively, `git` could be stubbed out via
# `stub_program_in_path` from `_GO_CORE_DIR/lib/bats/helpers`, but the potential
# for neither flakiness nor complexity seems that great, and this approach
# provides extra confidence that the mechanism works as advertised.
#
# A developer can also run the test locally against the real URL by setting
# `TEST_USE_REAL_URL` on the command line. The value of `GO_CORE_URL` is
# subsequently displayed in the name of the test case to validate which repo is
# being used during the test run.
TEST_USE_REAL_URL="${TEST_USE_REAL_URL:-$TRAVIS}"
GO_CORE_URL="${TEST_USE_REAL_URL:+$_GO_CORE_URL}"
GO_CORE_URL="${GO_CORE_URL:-$_GO_CORE_DIR}"

setup() {
test_filter
export GO_SCRIPT_BASH_VERSION="$_GO_CORE_VERSION"
export GO_SCRIPTS_DIR="$_GO_TEST_DIR/tmp/go-template-test-scripts"
export GO_SCRIPT_BASH_REPO_URL="$GO_CORE_URL"
export GO_SCRIPT_BASH_REPO_URL="https://github.com/mbland/go-script-bash.git"
export GO_SCRIPT_BASH_DOWNLOAD_URL="${GO_SCRIPT_BASH_REPO_URL%.git}/archive"
}

teardown() {
Expand All @@ -40,21 +26,65 @@ teardown() {
assert_output_matches "Usage: $_GO_CORE_DIR/go-template <command>"
}

@test "$SUITE: clone the go-script-bash repository from $GO_CORE_URL" {
if [[ -e "$GO_CORE_URL/.git/shallow" ]]; then
skip "Can't clone shallow repositories"
fi
@test "$SUITE: download the go-script-bash release from $GO_SCRIPT_BASH_REPO_URL" {
run "$_GO_CORE_DIR/go-template"

# Without a command argument, the script will print the top-level help and
# return an error, but the core repo should exist as expected.
assert_failure
assert_output_matches "Cloning framework from '$GO_CORE_URL'\.\.\."
assert_output_matches "Downloading framework from '${GO_SCRIPT_BASH_REPO_URL%.git}.*.tar.gz'\.\.\."

# Use `.*/scripts/go-script-bash` to account for the fact that `git clone` on
# MSYS2 will output `C:/Users/<user>/AppData/Local/Temp/` in place of `/tmp`.
assert_output_matches "Download of '${GO_SCRIPT_BASH_REPO_URL%.git}.*.tar.gz' successful."
assert_output_matches "Usage: $_GO_CORE_DIR/go-template <command>"
[[ -f "$_GO_ROOTDIR/$GO_SCRIPTS_DIR/go-script-bash/go-core.bash" ]]

}

@test "$SUITE: fail to download a nonexistent repo" {
GO_SCRIPT_BASH_REPO_URL='bogus-repo-that-does-not-exist' \
GO_SCRIPT_BASH_DOWNLOAD_URL='bogus-url-that-does-not-exist' \
run "$_GO_CORE_DIR/go-template"
assert_failure "Downloading framework from 'bogus-url-that-does-not-exist/$GO_SCRIPT_BASH_VERSION.tar.gz'..." \
"curl: (6) Could not resolve host: bogus-url-that-does-not-exist" \
"Failed to download from 'bogus-url-that-does-not-exist/$GO_SCRIPT_BASH_VERSION.tar.gz'." \
"Using git clone as fallback" \
"Cloning framework from 'bogus-repo-that-does-not-exist'..." \
"fatal: repository 'bogus-repo-that-does-not-exist' does not exist" \
"Failed to clone 'bogus-repo-that-does-not-exist'; aborting."
}

@test "$SUITE: fail to download a nonexistent version" {
GO_SCRIPT_BASH_VERSION='vnonexistent' \
run "$_GO_CORE_DIR/go-template"
assert_failure "Downloading framework from 'https://github.com/mbland/go-script-bash/archive/vnonexistent.tar.gz'..." \
"curl: (22) The requested URL returned error: 404 Not Found" \
"Failed to download from 'https://github.com/mbland/go-script-bash/archive/vnonexistent.tar.gz'." \
"Using git clone as fallback" \
"Cloning framework from 'https://github.com/mbland/go-script-bash.git'..." \
"Cloning into '$PWD/$GO_SCRIPTS_DIR/go-script-bash'..." \
"warning: Could not find remote branch vnonexistent to clone." \
"fatal: Remote branch vnonexistent not found in upstream origin" \
"Failed to clone 'https://github.com/mbland/go-script-bash.git'; aborting."
}

@test "$SUITE: fail to find curl uses git clone" {
PATH="$BATS_TEST_BINDIR:$PATH"
stub_program_in_path curl "exit 1"
run "$_GO_CORE_DIR/go-template"
restore_program_in_path curl

# Without a command argument, the script will print the top-level help and
# return an error, but the core repo should exist as expected.
assert_output_matches "Failed to find cURL or tar"
assert_output_matches "Using git clone as fallback"
assert_output_matches "Cloning framework from '$GO_SCRIPT_BASH_REPO_URL'\.\.\."

# Use `.*/scripts/go-script-bash` to account for the fact that `git clone` on
# MSYS2 will output `C:/Users/<user>/AppData/Local/Temp/` in place of `/tmp`.
assert_output_matches "Cloning into '.*/$GO_SCRIPTS_DIR/go-script-bash'\.\.\."
assert_output_matches "Clone of '$GO_CORE_URL' successful\."$'\n\n'
assert_output_matches "Clone of '$GO_SCRIPT_BASH_REPO_URL' successful\."$'\n\n'
assert_output_matches "Usage: $_GO_CORE_DIR/go-template <command>"
[[ -f "$_GO_ROOTDIR/$GO_SCRIPTS_DIR/go-script-bash/go-core.bash" ]]

Expand All @@ -64,10 +94,79 @@ teardown() {
assert_output_matches "go-script-bash $_GO_CORE_VERSION"
}

@test "$SUITE: fail to clone a nonexistent repo" {
GO_SCRIPT_BASH_REPO_URL='bogus-repo-that-does-not-exist' \
run "$_GO_CORE_DIR/go-template"
assert_failure "Cloning framework from 'bogus-repo-that-does-not-exist'..." \
"fatal: repository 'bogus-repo-that-does-not-exist' does not exist" \
"Failed to clone 'bogus-repo-that-does-not-exist'; aborting."
@test "$SUITE: fail to find tar uses git clone" {
PATH="$BATS_TEST_BINDIR:$PATH"
stub_program_in_path tar "exit 1"
run "$_GO_CORE_DIR/go-template"
restore_program_in_path tar

# Without a command argument, the script will print the top-level help and
# return an error, but the core repo should exist as expected.
assert_output_matches "Failed to find cURL or tar"
assert_output_matches "Using git clone as fallback"
assert_output_matches "Cloning framework from '$GO_SCRIPT_BASH_REPO_URL'\.\.\."

# Use `.*/scripts/go-script-bash` to account for the fact that `git clone` on
# MSYS2 will output `C:/Users/<user>/AppData/Local/Temp/` in place of `/tmp`.
assert_output_matches "Cloning into '.*/$GO_SCRIPTS_DIR/go-script-bash'\.\.\."
assert_output_matches "Clone of '$GO_SCRIPT_BASH_REPO_URL' successful\."$'\n\n'
assert_output_matches "Usage: $_GO_CORE_DIR/go-template <command>"
[[ -f "$_GO_ROOTDIR/$GO_SCRIPTS_DIR/go-script-bash/go-core.bash" ]]

cd "$_GO_ROOTDIR/$GO_SCRIPTS_DIR/go-script-bash"
run git log --oneline -n 1
assert_success
assert_output_matches "go-script-bash $_GO_CORE_VERSION"
}

@test "$SUITE: fail to create directory uses git clone" {
PATH="$BATS_TEST_BINDIR:$PATH"
stub_program_in_path mkdir "exit 1"
run "$_GO_CORE_DIR/go-template"
restore_program_in_path mkdir

# Without a command argument, the script will print the top-level help and
# return an error, but the core repo should exist as expected.
assert_output_matches "Downloading framework from '${GO_SCRIPT_BASH_REPO_URL%.git}.*.tar.gz'\.\.\."
assert_output_matches "Failed to create scripts dir '$GO_SCRIPTS_DIR'"
assert_output_matches "Using git clone as fallback"
assert_output_matches "Cloning framework from '$GO_SCRIPT_BASH_REPO_URL'\.\.\."

# Use `.*/scripts/go-script-bash` to account for the fact that `git clone` on
# MSYS2 will output `C:/Users/<user>/AppData/Local/Temp/` in place of `/tmp`.
assert_output_matches "Cloning into '.*/$GO_SCRIPTS_DIR/go-script-bash'\.\.\."
assert_output_matches "Clone of '$GO_SCRIPT_BASH_REPO_URL' successful\."$'\n\n'
assert_output_matches "Usage: $_GO_CORE_DIR/go-template <command>"
[[ -f "$_GO_ROOTDIR/$GO_SCRIPTS_DIR/go-script-bash/go-core.bash" ]]

cd "$_GO_ROOTDIR/$GO_SCRIPTS_DIR/go-script-bash"
run git log --oneline -n 1
assert_success
assert_output_matches "go-script-bash $_GO_CORE_VERSION"
}

@test "$SUITE: fail to move extracted directory uses git clone" {
PATH="$BATS_TEST_BINDIR:$PATH"
stub_program_in_path mv "exit 1"
run "$_GO_CORE_DIR/go-template"
restore_program_in_path mv

# Without a command argument, the script will print the top-level help and
# return an error, but the core repo should exist as expected.
assert_output_matches "Downloading framework from '${GO_SCRIPT_BASH_REPO_URL%.git}.*.tar.gz'\.\.\."
assert_output_matches "Failed to install downloaded directory in '.*/$GO_SCRIPTS_DIR/go-script-bash'"
assert_output_matches "Using git clone as fallback"
assert_output_matches "Cloning framework from '$GO_SCRIPT_BASH_REPO_URL'\.\.\."

# Use `.*/scripts/go-script-bash` to account for the fact that `git clone` on
# MSYS2 will output `C:/Users/<user>/AppData/Local/Temp/` in place of `/tmp`.
assert_output_matches "Cloning into '.*/$GO_SCRIPTS_DIR/go-script-bash'\.\.\."
assert_output_matches "Clone of '$GO_SCRIPT_BASH_REPO_URL' successful\."$'\n\n'
assert_output_matches "Usage: $_GO_CORE_DIR/go-template <command>"
[[ -f "$_GO_ROOTDIR/$GO_SCRIPTS_DIR/go-script-bash/go-core.bash" ]]

cd "$_GO_ROOTDIR/$GO_SCRIPTS_DIR/go-script-bash"
run git log --oneline -n 1
assert_success
assert_output_matches "go-script-bash $_GO_CORE_VERSION"
}