Skip to content

Commit 52f8a5d

Browse files
authored
Merge pull request rails#197 from rails/flavorjones-better-command-execution
rake task execution: test coverage and refactoring
2 parents 17f61d2 + 653d214 commit 52f8a5d

File tree

7 files changed

+205
-48
lines changed

7 files changed

+205
-48
lines changed

.github/workflows/ci.yml

+16
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,19 @@ jobs:
3333

3434
- name: Run tests
3535
run: bin/test
36+
37+
user-journey:
38+
strategy:
39+
fail-fast: false
40+
matrix:
41+
plat: ["ubuntu", "windows", "macos"]
42+
runs-on: ${{matrix.plat}}-latest
43+
steps:
44+
- uses: actions/checkout@v2
45+
- uses: ruby/setup-ruby@v1
46+
with:
47+
ruby-version: "3.1"
48+
bundler-cache: true
49+
bundler: latest
50+
- run: test/integration/user_journey_test.sh
51+
shell: bash

exe/tailwindcss

+14-41
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,19 @@
11
#! /usr/bin/env ruby
22
# because rubygems shims assume a gem's executables are Ruby
33

4-
require "shellwords"
5-
require "tailwindcss/upstream"
6-
7-
supported_platforms = Tailwindcss::Upstream::NATIVE_PLATFORMS.keys
8-
platform = [:cpu, :os].map { |m| Gem::Platform.local.send(m) }.join("-")
9-
10-
if supported_platforms.none? { |supported_platform| Gem::Platform.match(supported_platform) }
11-
STDERR.puts(<<~ERRMSG)
12-
ERROR: tailwindcss-rails does not support the #{platform} platform
13-
Please install tailwindcss following instructions at https://tailwindcss.com/docs/installation
14-
ERRMSG
4+
require "tailwindcss/commands"
5+
6+
begin
7+
command = [Tailwindcss::Commands.executable, *ARGV]
8+
puts command.inspect
9+
if Gem.win_platform?
10+
# use system rather than exec as exec inexplicably fails to find the executable on Windows
11+
# see related https://github.com/rubys/sprockets-esbuild/pull/4
12+
system(*command, exception: true)
13+
else
14+
exec(*command)
15+
end
16+
rescue Tailwindcss::Commands::UnsupportedPlatformException, Tailwindcss::Commands::ExecutableNotFoundException => e
17+
STDERR.puts("ERROR: " + e.message)
1518
exit 1
1619
end
17-
18-
exe_path = Dir.glob(File.join(__dir__, "*", "tailwindcss")).find do |f|
19-
Gem::Platform.match(File.basename(File.dirname(f)))
20-
end
21-
if exe_path.nil?
22-
STDERR.puts(<<~ERRMSG)
23-
ERROR: Cannot find the tailwindcss executable for #{platform} in #{__dir__}
24-
If you're using bundler, please make sure you're on the latest bundler version:
25-
26-
gem install bundler
27-
bundle update --bundler
28-
29-
Then make sure your lock file includes this platform by running:
30-
31-
bundle lock --add-platform #{platform}
32-
bundle install
33-
34-
See `bundle lock --help` output for details.
35-
36-
If you're still seeing this message after taking those steps, try running
37-
`bundle config` and ensure `force_ruby_platform` isn't set to `true`. See
38-
https://github.com/rails/tailwindcss-rails#check-bundle_force_ruby_platform
39-
for more details.
40-
ERRMSG
41-
exit 1
42-
end
43-
44-
command = Shellwords.join([exe_path, ARGV].flatten)
45-
puts "+ #{command}"
46-
exec(command)

lib/tailwindcss-rails.rb

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Tailwindcss
22
end
33

4-
require "tailwindcss/upstream"
5-
require "tailwindcss/version"
6-
require "tailwindcss/engine"
4+
require_relative "tailwindcss/upstream"
5+
require_relative "tailwindcss/version"
6+
require_relative "tailwindcss/engine"
7+
require_relative "tailwindcss/commands"

lib/tailwindcss/commands.rb

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
require_relative "upstream"
2+
3+
module Tailwindcss
4+
module Commands
5+
# raised when the host platform is not supported by upstream tailwindcss's binary releases
6+
class UnsupportedPlatformException < StandardError
7+
end
8+
9+
# raised when the tailwindcss executable could not be found where we expected it to be
10+
class ExecutableNotFoundException < StandardError
11+
end
12+
13+
class << self
14+
def platform
15+
[:cpu, :os].map { |m| Gem::Platform.local.send(m) }.join("-")
16+
end
17+
18+
def executable(
19+
exe_path: File.expand_path(File.join(__dir__, "..", "..", "exe"))
20+
)
21+
if Tailwindcss::Upstream::NATIVE_PLATFORMS.keys.none? { |p| Gem::Platform.match(p) }
22+
raise UnsupportedPlatformException, <<~MESSAGE
23+
tailwindcss-rails does not support the #{platform} platform
24+
Please install tailwindcss following instructions at https://tailwindcss.com/docs/installation
25+
MESSAGE
26+
end
27+
28+
exe_path = Dir.glob(File.expand_path(File.join(exe_path, "*", "tailwindcss"))).find do |f|
29+
Gem::Platform.match(File.basename(File.dirname(f)))
30+
end
31+
32+
if exe_path.nil?
33+
raise ExecutableNotFoundException, <<~MESSAGE
34+
Cannot find the tailwindcss executable for #{platform} in #{exe_path}
35+
36+
If you're using bundler, please make sure you're on the latest bundler version:
37+
38+
gem install bundler
39+
bundle update --bundler
40+
41+
Then make sure your lock file includes this platform by running:
42+
43+
bundle lock --add-platform #{platform}
44+
bundle install
45+
46+
See `bundle lock --help` output for details.
47+
48+
If you're still seeing this message after taking those steps, try running
49+
`bundle config` and ensure `force_ruby_platform` isn't set to `true`. See
50+
https://github.com/rails/tailwindcss-rails#check-bundle_force_ruby_platform
51+
for more details.
52+
MESSAGE
53+
end
54+
55+
exe_path
56+
end
57+
58+
def compile_command(**kwargs)
59+
[
60+
executable(**kwargs),
61+
"-i", Rails.root.join("app/assets/stylesheets/application.tailwind.css").to_s,
62+
"-o", Rails.root.join("app/assets/builds/tailwind.css").to_s,
63+
"-c", Rails.root.join("config/tailwind.config.js").to_s,
64+
"--minify",
65+
]
66+
end
67+
68+
def watch_command(**kwargs)
69+
compile_command(**kwargs) << "-w"
70+
end
71+
end
72+
end
73+
end

lib/tasks/build.rake

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
TAILWIND_COMPILE_COMMAND = "#{RbConfig.ruby} #{Pathname.new(__dir__).to_s}/../../exe/tailwindcss -i '#{Rails.root.join("app/assets/stylesheets/application.tailwind.css")}' -o '#{Rails.root.join("app/assets/builds/tailwind.css")}' -c '#{Rails.root.join("config/tailwind.config.js")}' --minify"
2-
31
namespace :tailwindcss do
42
desc "Build your Tailwind CSS"
53
task :build do
6-
system(TAILWIND_COMPILE_COMMAND, exception: true)
4+
command = Tailwindcss::Commands.compile_command
5+
puts command.inspect
6+
system(*command, exception: true)
77
end
88

99
desc "Watch and build your Tailwind CSS on file changes"
1010
task :watch do
11-
system "#{TAILWIND_COMPILE_COMMAND} -w"
11+
command = Tailwindcss::Commands.watch_command
12+
puts command.inspect
13+
system(*command)
1214
end
1315
end
1416

test/integration/user_journey_test.sh

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#! /usr/bin/env bash
2+
# reproduce the documented user journey for installing and running tailwindcss-rails
3+
# this is run in the CI pipeline, non-zero exit code indicates a failure
4+
5+
set -o pipefail
6+
set -eux
7+
8+
# fetch the upstream executables
9+
bundle exec rake download
10+
11+
# create a rails app in a directory with spaces in the name (#176, #184)
12+
rm -rf "Has A Space"
13+
mkdir "Has A Space"
14+
pushd "Has A Space"
15+
16+
gem install rails
17+
rails new test-app --skip-bundle
18+
pushd test-app
19+
20+
# install tailwindcss-rails
21+
echo 'gem "tailwindcss-rails", path: "../.."' >> Gemfile
22+
bundle install
23+
24+
bin/rails tailwindcss:install
25+
26+
# ensure rake tasks don't exec (#188)
27+
bin/rails tailwindcss:build about | grep "About your application"

test/lib/tailwindcss/commands_test.rb

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require "test_helper"
2+
require "minitest/mock"
3+
4+
class Tailwindcss::CommandsTest < ActiveSupport::TestCase
5+
test ".platform is a string containing just the cpu and os (not the version)" do
6+
expected = "#{Gem::Platform.local.cpu}-#{Gem::Platform.local.os}"
7+
assert_equal(expected, Tailwindcss::Commands.platform)
8+
end
9+
10+
def mock_exe_directory(platform)
11+
Dir.mktmpdir do |dir|
12+
FileUtils.mkdir(File.join(dir, platform))
13+
path = File.join(dir, platform, "tailwindcss")
14+
FileUtils.touch(path)
15+
Gem::Platform.stub(:match, true) do
16+
yield(dir, path)
17+
end
18+
end
19+
end
20+
21+
test ".executable returns the absolute path to the binary" do
22+
mock_exe_directory("sparc-solaris2.8") do |dir, executable|
23+
expected = File.expand_path(File.join(dir, "sparc-solaris2.8", "tailwindcss"))
24+
assert_equal(expected, executable, "assert on setup")
25+
assert_equal(expected, Tailwindcss::Commands.executable(exe_path: dir))
26+
end
27+
end
28+
29+
test ".executable raises UnsupportedPlatformException when we're not on a supported platform" do
30+
Gem::Platform.stub(:match, false) do # nothing is supported
31+
assert_raises(Tailwindcss::Commands::UnsupportedPlatformException) do
32+
Tailwindcss::Commands.executable
33+
end
34+
end
35+
end
36+
37+
test ".executable raises ExecutableNotFoundException when we can't find the executable we expect" do
38+
Dir.mktmpdir do |dir| # empty directory
39+
assert_raises(Tailwindcss::Commands::ExecutableNotFoundException) do
40+
Tailwindcss::Commands.executable(exe_path: dir)
41+
end
42+
end
43+
end
44+
45+
test ".compile_command" do
46+
mock_exe_directory("sparc-solaris2.8") do |dir, executable|
47+
Rails.stub(:root, File) do # Rails.root won't work in this test suite
48+
actual = Tailwindcss::Commands.compile_command(exe_path: dir)
49+
assert_kind_of(Array, actual)
50+
assert_equal(executable, actual.first)
51+
end
52+
end
53+
end
54+
55+
test ".watch_command" do
56+
mock_exe_directory("sparc-solaris2.8") do |dir, executable|
57+
Rails.stub(:root, File) do # Rails.root won't work in this test suite
58+
actual = Tailwindcss::Commands.watch_command(exe_path: dir)
59+
assert_kind_of(Array, actual)
60+
assert_equal(executable, actual.first)
61+
assert_includes(actual, "-w")
62+
end
63+
end
64+
end
65+
end

0 commit comments

Comments
 (0)