Skip to content
Merged
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 1.5.5

Fix the PATH built by `asdf:map_bins`. SSHKit exports the environment inside
double quotes (`PATH="..."`), where a shell never expands a tilde, so the
default `asdf_path` of `~/.asdf` produced two dead entries and left the asdf
shims unreachable. The PATH now carries `$HOME`; an absolute `asdf_path` is
still used as is.

## 1.5.3

Fix ASDF update when git data is not up-to-date.
Expand Down
2 changes: 1 addition & 1 deletion lib/capistrano/asdf/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module Capistrano
module Asdf
VERSION = "1.5.4"
VERSION = "1.5.5"
end
end
5 changes: 4 additions & 1 deletion lib/capistrano/tasks/asdf.rake
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ namespace :asdf do
end

task :map_bins do
path = "#{fetch(:asdf_path)}/shims:#{fetch(:asdf_path)}/bin:" + (SSHKit.config.default_env[:path] || "$PATH")
# SSHKit exports the environment inside double quotes (PATH="..."), where a
# shell leaves a tilde alone, so the PATH has to carry $HOME instead.
asdf_home = fetch(:asdf_path).sub(%r{\A~(?=/|\z)}, "$HOME")
path = "#{asdf_home}/shims:#{asdf_home}/bin:" + (SSHKit.config.default_env[:path] || "$PATH")
SSHKit.config.default_env[:path] = path

asdf_prefix = fetch(:asdf_prefix, -> { "#{fetch(:asdf_path)}/bin/asdf exec" })
Expand Down
67 changes: 67 additions & 0 deletions test/capistrano/test_map_bins.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# frozen_string_literal: true

require "test_helper"

require "capistrano/all"
require "sshkit"

# A Capfile mixes the DSL into the top-level object; the rake file under test
# reaches for `Capistrano::DSL.stages` as it loads, which relies on it.
include Capistrano::DSL # standard:disable Style/MixinUsage

module Capistrano
# `asdf:map_bins` prepends the asdf shims to the PATH that SSHKit exports in
# front of every remote command. SSHKit writes that environment inside double
# quotes (`PATH="..."`), and a shell does not expand a tilde there, so the
# PATH must be built from `$HOME` rather than from `~`.
class TestMapBins < Minitest::Test
include Capistrano::DSL

def setup
# `capistrano/all` turns Rake's trace on; keep it out of the test output.
Rake.application.options.trace = false
Rake::Task.clear
Capistrano::Configuration.reset!
SSHKit.config.default_env = {}
# The rake file hooks itself onto this task as it loads.
Rake::Task.define_task("deploy:updating")
load File.expand_path("../../lib/capistrano/tasks/asdf.rake", __dir__)
Rake::Task["load:defaults"].invoke
# Keep the task away from its jemalloc branch, which opens an SSH connection.
set :asdf_tools, %w[nodejs]
end

def teardown
SSHKit.config.default_env = {}
end

def test_the_exported_path_holds_no_tilde
Rake::Task["asdf:map_bins"].invoke

assert_equal "$HOME/.asdf/shims:$HOME/.asdf/bin:$PATH", exported_path
end

def test_it_keeps_a_path_already_set_by_the_application
SSHKit.config.default_env = {path: "/opt/custom/bin:$PATH"}

Rake::Task["asdf:map_bins"].invoke

assert_equal "$HOME/.asdf/shims:$HOME/.asdf/bin:/opt/custom/bin:$PATH", exported_path
end

def test_an_absolute_asdf_path_is_left_alone
set :asdf_path, "/opt/asdf"

Rake::Task["asdf:map_bins"].invoke

assert_equal "/opt/asdf/shims:/opt/asdf/bin:$PATH", exported_path
end

# What the shell actually receives, tilde expansion included.
def exported_path
command = SSHKit::Command.new(:node, "--version").to_command

command[/PATH="([^"]*)"/, 1]
end
end
end
Loading