diff --git a/.rubocop.yml b/.rubocop.yml index 44ce5b39a..386a99230 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,7 @@ --- AllCops: - Excludes: - - compile-extensions/** + Exclude: + - compile-extensions/**/* Documentation: Enabled: false LineLength: @@ -10,3 +10,5 @@ MethodLength: Max: 25 ParameterLists: Max: 12 +Metrics/AbcSize: + Max: 40 diff --git a/CHANGELOG.md b/CHANGELOG.md index 38e41d7ef..c3f32d1a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v0.5.0 Aug 17, 2015 + +- Removed Nowin server, replaced with use of Kestrel which allows the buildpack to run beta4 - beta6 apps. + ## v0.4.0 Aug 05, 2015 - Add support for beta6 apps diff --git a/Gemfile b/Gemfile index 64e479fe6..ff498bf4e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ -source "https://rubygems.org" +source 'https://rubygems.org' gem 'rspec', '~> 3.3.0' gem 'rake', '~> 10.4.2' - +gem 'rubocop', '~> 0.33.0' diff --git a/Gemfile.lock b/Gemfile.lock index f235e46a3..f3e823129 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,14 @@ GEM remote: https://rubygems.org/ specs: + ast (2.1.0) + astrolabe (1.3.1) + parser (~> 2.2) diff-lcs (1.2.5) + parser (2.2.2.6) + ast (>= 1.1, < 3.0) + powerpack (0.1.1) + rainbow (2.0.0) rake (10.4.2) rspec (3.3.0) rspec-core (~> 3.3.0) @@ -16,6 +23,13 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.3.0) rspec-support (3.3.0) + rubocop (0.33.0) + astrolabe (~> 1.3) + parser (>= 2.2.2.5, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.4) + ruby-progressbar (1.7.5) PLATFORMS ruby @@ -23,3 +37,4 @@ PLATFORMS DEPENDENCIES rake (~> 10.4.2) rspec (~> 3.3.0) + rubocop (~> 0.33.0) diff --git a/README.md b/README.md index e330f04c4..8fb1426b4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Cloud Foundry buildpack: ASP.NET 5 -A Cloud Foundry buildpack for ASP.NET 5 ([beta6][]) apps. For more information about ASP.NET 5 see: +A Cloud Foundry buildpack for ASP.NET 5 applications (tested with [beta6][] applications). For more information about ASP.NET 5 see: * https://github.com/aspnet/home * http://docs.asp.net/en/latest/conceptual-overview/aspnet.html @@ -11,21 +11,14 @@ A Cloud Foundry buildpack for ASP.NET 5 ([beta6][]) apps. For more information a cf push my_app -b https://github.com/cloudfoundry-community/asp.net5-buildpack.git ``` -This buildpack will be used if there is a `NuGet.Config` file in the root directory of your project. +This buildpack will be used if there is a `NuGet.Config` file in the root directory of your project and one or more 'project.json' files anywhere. -The application structure would then be: -- NuGet.Config -- src - - project directory - - Startup.cs - - project.json - - wwwroot - - Models/Views/Controllers or other directories +Use a 'global.json' file to specify the desired DNX version if different than the latest stable beta release. Also make sure the application includes a 'kestrel' command and the corresponding dependency as that is what the buildpack will use to run the application. For a basic example see this [Hello World sample][]. ## Disconnected environments -Disconnected environments are not fully supported. The .NET Version Manager, .NET Execution Environment and NuGet packages required by the application are always downloaded during staging. The Mono binaries, however, can be cached or uncached. +Disconnected environments are not fully supported. The .NET Version Manager, .NET Execution Environment and NuGet packages required by the application are always downloaded during staging. The Mono and libuv binaries, however, can be cached or uncached. ## Building @@ -43,7 +36,7 @@ Disconnected environments are not fully supported. The .NET Version Manager, .NE 3. Build the buildpack - `uncached` means a TAR file containing Mono will be downloaded the first time an application is staged, and `cached` means it will be packaged in the buildpack ZIP. + `uncached` means a TAR files containing Mono and libuv will be downloaded the first time an application is staged, and `cached` means they will be packaged in the buildpack ZIP. ```shell BUNDLE_GEMFILE=cf.Gemfile bundle exec buildpack-packager [ uncached | cached ] @@ -68,6 +61,4 @@ Open an issue on this project. [Hello World sample]: https://github.com/IBM-Bluemix/asp.net5-helloworld -[beta4]: https://github.com/aspnet/Home/releases/tag/v1.0.0-beta4 -[beta5]: https://github.com/aspnet/Home/releases/tag/v1.0.0-beta5 [beta6]: https://github.com/aspnet/Home/releases/tag/v1.0.0-beta6 diff --git a/Rakefile b/Rakefile index 866b9734e..b3b525ac7 100644 --- a/Rakefile +++ b/Rakefile @@ -1,10 +1,11 @@ - - require 'rake' require 'rspec/core/rake_task' +require 'rubocop/rake_task' +RuboCop::RakeTask.new + RSpec::Core::RakeTask.new(:spec) do |t| t.pattern = Dir.glob('spec/**/*_spec.rb') end -task :default => :spec +task default: [:spec] diff --git a/VERSION b/VERSION index 1d0ba9ea1..8f0916f76 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.0 +0.5.0 diff --git a/bin/compile b/bin/compile index fd989efb8..701035630 100755 --- a/bin/compile +++ b/bin/compile @@ -29,4 +29,3 @@ if AspNet5Buildpack.compile(build_dir, cache_dir) else exit 1 end - diff --git a/cf.Gemfile b/cf.Gemfile index 29d15b9d2..3b6863478 100644 --- a/cf.Gemfile +++ b/cf.Gemfile @@ -1,4 +1,3 @@ source "https://rubygems.org" -gem 'rspec', '~> 3.1.0' gem 'buildpack-packager', github: 'cf-buildpacks/buildpack-packager', tag: 'v2.2.0' diff --git a/cf.Gemfile.lock b/cf.Gemfile.lock index 60ac99dcd..19293c4c2 100644 --- a/cf.Gemfile.lock +++ b/cf.Gemfile.lock @@ -43,4 +43,3 @@ PLATFORMS DEPENDENCIES buildpack-packager! - rspec (~> 3.1.0) diff --git a/lib/buildpack.rb b/lib/buildpack.rb index 368bbf57c..a608623b9 100644 --- a/lib/buildpack.rb +++ b/lib/buildpack.rb @@ -34,7 +34,7 @@ def self.compiler(build_dir, cache_dir) build_dir, cache_dir, MonoInstaller.new(build_dir, shell), - File.expand_path('../../resources/Nowin.vNext', __FILE__), + LibuvInstaller.new(build_dir, shell), DnvmInstaller.new(shell), Mozroots.new(shell), DnxInstaller.new(shell), @@ -51,5 +51,4 @@ def self.out def self.shell @shell ||= Shell.new end - end diff --git a/lib/buildpack/version.rb b/lib/buildpack/bp_version.rb similarity index 100% rename from lib/buildpack/version.rb rename to lib/buildpack/bp_version.rb diff --git a/lib/buildpack/compile/app_dir.rb b/lib/buildpack/compile/app_dir.rb new file mode 100644 index 000000000..ee4ea8f9f --- /dev/null +++ b/lib/buildpack/compile/app_dir.rb @@ -0,0 +1,69 @@ +# Encoding: utf-8 +# ASP.NET 5 Buildpack +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module AspNet5Buildpack + class AppDir + DEPLOYMENT_FILE_NAME = '.deployment'.freeze + + def initialize(dir, out) + @dir = dir + @out = out + end + + def root + @dir + end + + def release_yml_path + File.join(@dir, 'aspnet5-buildpack-release.yml') + end + + def startup_script_path + File.join(@dir, '.profile.d', 'startup.sh') + end + + def with_command(cmd) + with_project_json.select { |d| !commands(d)[cmd].nil? && commands(d)[cmd] != '' } + end + + def with_project_json + Dir.glob(File.join(@dir, '**', 'project.json')).map do |d| + Pathname.new(File.dirname(d)).relative_path_from(Pathname.new(@dir)) + end + end + + def project_json(dir) + File.join(@dir, dir, 'project.json') + end + + def commands(dir) + JSON.load(IO.read(project_json(dir), encoding: 'bom|utf-8')).fetch('commands', {}) + end + + def deployment_file_project + paths = with_project_json + deployment_file = File.expand_path(File.join(@dir, DEPLOYMENT_FILE_NAME)) + File.foreach(deployment_file) do |line| + m = /project = (.*)/.match(line) + if m + path = Pathname.new(m[1]) + return path if paths.include?(path) + end + end if File.exist?(deployment_file) + nil + end + end +end diff --git a/lib/buildpack/compile/dnu.rb b/lib/buildpack/compile/dnu.rb index efd4f3a19..17f258bd9 100644 --- a/lib/buildpack/compile/dnu.rb +++ b/lib/buildpack/compile/dnu.rb @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +require_relative 'app_dir' + module AspNet5Buildpack class DNU def initialize(shell) @@ -22,8 +24,10 @@ def initialize(shell) def restore(dir, out) @shell.env['HOME'] = dir + @shell.env['MONO_THREADS_PER_CPU'] = '2000' @shell.path << '/app/mono/bin' - cmd = "bash -c 'source #{dir}/.dnx/dnvm/dnvm.sh; dnvm use default -r mono -a x64; cd #{dir}; dnu restore'" + project_list = AppDir.new(dir, out).with_project_json.join(' ') + cmd = "bash -c 'source #{dir}/.dnx/dnvm/dnvm.sh; dnvm use default -r mono -a x64; cd #{dir}; dnu restore #{project_list}'" @shell.exec(cmd, out) end end diff --git a/lib/buildpack/compile/dnx_installer.rb b/lib/buildpack/compile/dnx_installer.rb index f7efda505..2884e18f6 100644 --- a/lib/buildpack/compile/dnx_installer.rb +++ b/lib/buildpack/compile/dnx_installer.rb @@ -14,14 +14,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -require 'json' +require_relative 'dnx_version' module AspNet5Buildpack class DnxInstaller - - DNX_VERSION_FILE_NAME = 'global.json'.freeze - DEFAULT_DNX_VERSION = 'latest'.freeze - def initialize(shell) @shell = shell end @@ -29,27 +25,8 @@ def initialize(shell) def install(dir, out) @shell.env['HOME'] = dir @shell.path << '/app/mono/bin' - version = dnx_version(dir, out) + version = DnxVersion.new.version(dir, out) @shell.exec("bash -c 'source #{dir}/.dnx/dnvm/dnvm.sh; dnvm install #{version} -p -r mono'", out) end - - private - - def dnx_version(dir, out) - dnx_version = DEFAULT_DNX_VERSION - version_file = File.expand_path(File.join(dir, DNX_VERSION_FILE_NAME)) - if File.exists?(version_file) - begin - global_props = JSON.parse(File.read(version_file, encoding: 'bom|utf-8')) - if global_props.has_key?('sdk') - sdk = global_props['sdk'] - dnx_version = sdk['version'] if sdk.has_key?('version') - end - rescue - out.warn("File #{version_file} is not valid JSON") - end - end - dnx_version - end end end diff --git a/lib/buildpack/compile/dnx_version.rb b/lib/buildpack/compile/dnx_version.rb new file mode 100644 index 000000000..588bd844c --- /dev/null +++ b/lib/buildpack/compile/dnx_version.rb @@ -0,0 +1,41 @@ +# Encoding: utf-8 +# ASP.NET 5 Buildpack +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'json' + +module AspNet5Buildpack + class DnxVersion + DNX_VERSION_FILE_NAME = 'global.json'.freeze + DEFAULT_DNX_VERSION = 'latest'.freeze + + def version(dir, out) + dnx_version = DEFAULT_DNX_VERSION + version_file = File.expand_path(File.join(dir, DNX_VERSION_FILE_NAME)) + if File.exist?(version_file) + begin + global_props = JSON.parse(File.read(version_file, encoding: 'bom|utf-8')) + if global_props.key?('sdk') + sdk = global_props['sdk'] + dnx_version = sdk['version'] if sdk.key?('version') + end + rescue + out.warn("File #{version_file} is not valid JSON") + end + end + dnx_version + end + end +end diff --git a/lib/buildpack/compile/libuv_installer.rb b/lib/buildpack/compile/libuv_installer.rb new file mode 100644 index 000000000..a67262127 --- /dev/null +++ b/lib/buildpack/compile/libuv_installer.rb @@ -0,0 +1,61 @@ +# Encoding: utf-8 +# ASP.NET 5 Buildpack +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module AspNet5Buildpack + class LibuvInstaller + VERSION = '1.4.2'.freeze + + def initialize(app_dir, shell) + @app_dir = app_dir + @shell = shell + end + + def extract(dest_dir, out) + out.print("libuv version: #{version}") + cmd = "mkdir -p #{dest_dir}; curl -L `translate_dependency_url #{dependency_name}` -s | tar zxv -C #{dest_dir} &> /dev/null" + run_common_cmd(cmd, out) + end + + def libuv_tar_gz(out) + run_common_cmd("translate_dependency_url #{dependency_name}", out) + end + + def version + VERSION + end + + private + + def run_common_cmd(cmd, out) + commoncmd = "bash -c 'export BUILDPACK_PATH=#{buildpack_root}; source $BUILDPACK_PATH/compile-extensions/lib/common &> /dev/null; #{cmd}'" + shell.exec(commoncmd, out) + end + + def buildpack_root + current_dir = File.expand_path(File.dirname(__FILE__)) + File.dirname(File.dirname(File.dirname(current_dir))) + end + + def dependency_name + "libuv-x-#{version}.tar.gz" + end + + private + + attr_reader :app_dir + attr_reader :shell + end +end diff --git a/lib/buildpack/compile/mono_installer.rb b/lib/buildpack/compile/mono_installer.rb index 5733eaad2..3fcf43fc0 100644 --- a/lib/buildpack/compile/mono_installer.rb +++ b/lib/buildpack/compile/mono_installer.rb @@ -16,7 +16,6 @@ module AspNet5Buildpack class MonoInstaller - # really 4.0.1.44 fix release - needed for mozroots error DEFAULT_VERSION = '4.0.1' @@ -56,7 +55,7 @@ def dependency_name end def desired_version_from_monoversion_file - IO.read(mono_version_file) if File.exists?(mono_version_file) + IO.read(mono_version_file) if File.exist?(mono_version_file) end def mono_version_file diff --git a/lib/buildpack/compile/release_yml_writer.rb b/lib/buildpack/compile/release_yml_writer.rb index 519fdc9eb..9257ce814 100644 --- a/lib/buildpack/compile/release_yml_writer.rb +++ b/lib/buildpack/compile/release_yml_writer.rb @@ -14,110 +14,48 @@ # See the License for the specific language governing permissions and # limitations under the License. -require 'fileutils' -require 'json' +require_relative 'app_dir' module AspNet5Buildpack class ReleaseYmlWriter + CFWEB_CMD = 'kestrel'.freeze + def write_release_yml(build_dir, out) - dirs = Dirs.new(build_dir) - write_startup_script(dirs.startup_script_path) - write_yml(dirs) + dirs = AppDir.new(build_dir, out) + path = main_project_path(dirs) + fail 'No application found' unless path + fail "No #{CFWEB_CMD} command found in #{path}" unless dirs.commands(path)[CFWEB_CMD] + write_startup_script(dirs) + write_yml(dirs.release_yml_path, path) end private - def write_yml(dirs) - unless dirs.with_existing_cfweb.empty? - write_yml_for(dirs.release_yml_path, dirs.with_existing_cfweb.first, 'cf-web') - return - end - - unless dirs.with_project_json.empty? - add_cfweb_command(dirs.project_json(dirs.with_project_json.first)) - write_yml_for(dirs.release_yml_path, dirs.with_project_json.first, 'cf-web') - return - end - - write_yml_for(dirs.release_yml_path, '.', 'cf-web') - end - - def add_cfweb_command(project_json) - json = JSON.parse(IO.read(project_json, encoding: 'bom|utf-8')) - json['dependencies'] ||= {} - json['dependencies']['Nowin.vNext'] = '1.0.0-*' unless json['dependencies']['Nowin.vNext'] - json['commands'] ||= {} - json['commands']['cf-web'] = 'Microsoft.AspNet.Hosting --server Nowin.vNext' - IO.write(project_json, JSON.pretty_generate(json)) - end - - def write_startup_script(path) - FileUtils.mkdir_p(File.dirname(path)) - File.open(path, 'w') do |f| - f.write 'export PATH=/app/mono/bin:$PATH;' + def write_startup_script(dirs) + FileUtils.mkdir_p(File.dirname(dirs.startup_script_path)) + File.open(dirs.startup_script_path, 'w') do |f| f.write 'export HOME=/app;' - f.write 'source /app/.dnx/dnvm/dnvm.sh;' + f.write 'export PATH=$HOME/mono/bin:$PATH;' + f.write 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/libuv/lib;' + f.write 'source $HOME/.dnx/dnvm/dnvm.sh;' f.write 'dnvm use default -r mono -a x64;' - f.write 'dnu restore;' end end - def write_yml_for(ymlPath, web_dir, cmd) + def write_yml(ymlPath, web_dir) File.open(ymlPath, 'w') do |f| f.write < _callback; - - private Task HandleRequest(IDictionary env) - { - return _callback(new OwinFeatureCollection(env)); - } - - public IServerInformation Initialize(IConfiguration configuration) - { - var port = Environment.GetEnvironmentVariable("PORT"); - var builder = ServerBuilder.New() - .SetAddress(IPAddress.Any) - .SetPort(int.Parse(port)) - .SetOwinApp(OwinWebSocketAcceptAdapter.AdaptWebSockets(HandleRequest)); - - return new NowinServerInformation(builder); - } - - public IDisposable Start(IServerInformation serverInformation, Func application) - { - var information = (NowinServerInformation)serverInformation; - _callback = application; - INowinServer server = information.Builder.Build(); - server.Start(); - return server; - } - - private class NowinServerInformation : IServerInformation - { - public NowinServerInformation(ServerBuilder builder) - { - Builder = builder; - } - - public ServerBuilder Builder { get; private set; } - - public string Name - { - get - { - return "Nowin"; - } - } - } - } -} diff --git a/resources/Nowin.vNext/project.json b/resources/Nowin.vNext/project.json deleted file mode 100644 index 4cefa48f1..000000000 --- a/resources/Nowin.vNext/project.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": "1.0.0-*", - "dependencies": { - "Nowin": "0.17.1", - "Microsoft.AspNet.Owin": "1.0.0-beta6", - "Microsoft.AspNet.Hosting": "1.0.0-beta6", - "Microsoft.AspNet.Http": "1.0.0-beta6" - }, - "frameworks": { - "dnx451": { } - } -} diff --git a/spec/buildpack/version_spec.rb b/spec/buildpack/bp_version_spec.rb similarity index 100% rename from spec/buildpack/version_spec.rb rename to spec/buildpack/bp_version_spec.rb diff --git a/spec/buildpack/compile/app_dir_spec.rb b/spec/buildpack/compile/app_dir_spec.rb new file mode 100644 index 000000000..cebf47399 --- /dev/null +++ b/spec/buildpack/compile/app_dir_spec.rb @@ -0,0 +1,105 @@ +# Encoding: utf-8 +# ASP.NET 5 Buildpack +# Copyright 2014-2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'rspec' +require 'tmpdir' +require 'fileutils' +require_relative '../../../lib/buildpack.rb' + +describe AspNet5Buildpack::AppDir do + let(:dir) do + Dir.mktmpdir + end + + let(:out) do + double(:out) + end + + subject(:appdir) do + AspNet5Buildpack::AppDir.new(dir, out) + end + + describe 'app dir' do + context 'with multiple projects' do + let(:proj1) do + File.join(dir, 'src', 'proj1').tap { |f| FileUtils.mkdir_p(f) } + end + + let(:proj2) do + File.join(dir, 'src', 'proj2').tap { |f| FileUtils.mkdir_p(f) } + end + + let(:dnx) do + File.join(dir, '.dnx', 'dep').tap { |f| FileUtils.mkdir_p(f) } + end + + before do + File.open(File.join(proj1, 'project.json'), 'w') do |f| + f.write '{ "commands": { "web1": "whatever", "web2": "whatever" } }' + end + File.open(File.join(proj2, 'project.json'), 'w') do |f| + f.write "\uFEFF" + f.write '{ "commands": { "web": "whatever" } }' + end + File.open(File.join(dnx, 'project.json'), 'w') do |f| + f.write '{ "commands": { "web": "whatever" } }' + end + end + + it 'finds all project.json files from non-hidden directories' do + expect(appdir.with_project_json).to match_array([Pathname.new('src/proj1'), Pathname.new('src/proj2')]) + end + + it 'finds project paths where project.json files have specific commands' do + expect(appdir.with_command('web')).to match_array([Pathname.new('src/proj2')]) + expect(appdir.with_command('fakecmd')).to match_array([]) + end + + it 'reads commands from project.json files' do + expect(appdir.commands('src/proj1')).to eq('web1' => 'whatever', 'web2' => 'whatever') + end + + it 'reads commands from project.json files with byte-order marks' do + expect(appdir.commands('src/proj2')).to eq('web' => 'whatever') + end + + it 'can find project based on a .deployment file' do + File.open(File.join(dir, '.deployment'), 'w') do |f| + f.write("project = src/proj1\n") + end + expect(appdir.deployment_file_project).to eq(Pathname.new('src/proj1')) + end + + it 'does not find a project when no .deployment file exists' do + expect(appdir.deployment_file_project).to be_nil + end + + it 'does not find a project when the .deployment file points to a non-existent project' do + File.open(File.join(dir, '.deployment'), 'w') do |f| + f.write("project = dne\n") + end + expect(appdir.deployment_file_project).to be_nil + end + + it 'does not find a project when the .deployment file does not specify a project' do + File.open(File.join(dir, '.deployment'), 'w') do |f| + f.write("[config]\n") + end + expect(appdir.deployment_file_project).to be_nil + end + end + end +end diff --git a/spec/buildpack/compile/compile_spec.rb b/spec/buildpack/compile/compile_spec.rb index 015a73c5c..406ac78bc 100644 --- a/spec/buildpack/compile/compile_spec.rb +++ b/spec/buildpack/compile/compile_spec.rb @@ -21,7 +21,7 @@ describe AspNet5Buildpack::Compiler do subject(:compiler) do - AspNet5Buildpack::Compiler.new(build_dir, cache_dir, mono_binary, nowin_dir, dnvm_installer, mozroots, dnx_installer, dnu, release_yml_writer, copier, out) + AspNet5Buildpack::Compiler.new(build_dir, cache_dir, mono_binary, libuv_binary, dnvm_installer, mozroots, dnx_installer, dnu, release_yml_writer, copier, out) end before do @@ -32,6 +32,10 @@ double(:mono_binary, extract: nil) end + let(:libuv_binary) do + double(:libuv_binary, extract: nil) + end + let(:copier) do double(:copier, cp: nil) end @@ -45,7 +49,7 @@ end let(:dnu) do - double(:dnu, restore: nil) + double(:dnu, restore: nil) end let(:mozroots) do @@ -70,10 +74,6 @@ Dir.mktmpdir end - let(:nowin_dir) do - Dir.mktmpdir - end - it 'prints a big warning message' do expect(out).to receive(:warn).with(match('experimental')) compiler.compile @@ -140,15 +140,6 @@ end end - describe 'Adding Nowin.vNext' do - it_behaves_like 'A Step', 'Adding Nowin.vNext', :copy_nowin, :install_mozroot_certs - - it 'extracts to build dir' do - expect(copier).to receive(:cp).with(nowin_dir, "#{build_dir}/src", anything) - compiler.compile - end - end - describe 'Importing Certificates' do it_behaves_like 'A Step', 'Importing Mozilla Root Certificates', :install_mozroot_certs, :install_dnvm @@ -191,12 +182,14 @@ Dir.mkdir(File.join(cache_dir, '.dnx')) Dir.mkdir(File.join(cache_dir, 'mono')) FileUtils.mkdir_p(File.join(cache_dir, 'certs')) + Dir.mkdir(File.join(cache_dir, 'libuv')) end it 'restores all files from the cache to build dir' do expect(copier).to receive(:cp).with(File.join(cache_dir, '.dnx'), build_dir, anything) expect(copier).to receive(:cp).with(File.join(cache_dir, 'mono'), '/app', anything) expect(copier).to receive(:cp).with(File.join(cache_dir, 'certs'), File.join(build_dir, '..', '.config', '.mono'), anything) + expect(copier).to receive(:cp).with(File.join(cache_dir, 'libuv'), build_dir, anything) compiler.compile end end @@ -227,6 +220,7 @@ expect(copier).to receive(:cp).with("#{build_dir}/.dnx", cache_dir, anything) expect(copier).to receive(:cp).with('/app/mono', cache_dir, anything) expect(copier).to receive(:cp).with(File.join(Dir.home, '.config', '.mono', 'certs'), cache_dir, anything) + expect(copier).to receive(:cp).with("#{build_dir}/libuv", cache_dir, anything) compiler.compile end @@ -235,6 +229,7 @@ Dir.mkdir(File.join(cache_dir, '.dnx')) Dir.mkdir(File.join(cache_dir, 'mono')) FileUtils.mkdir_p(File.join(cache_dir, '.config', '.mono', 'certs')) + Dir.mkdir(File.join(cache_dir, 'libuv')) end it 'copies only .dnx to cache dir' do expect(copier).to receive(:cp).with("#{build_dir}/.dnx", cache_dir, anything) diff --git a/spec/buildpack/compile/dnu_spec.rb b/spec/buildpack/compile/dnu_spec.rb index 4892028f4..58f56d0d8 100644 --- a/spec/buildpack/compile/dnu_spec.rb +++ b/spec/buildpack/compile/dnu_spec.rb @@ -60,5 +60,4 @@ expect(shell).to receive(:exec).with(match('dnu restore'), out) dnu.restore('app-dir', out) end - end diff --git a/spec/buildpack/compile/dnx_install_spec.rb b/spec/buildpack/compile/dnx_install_spec.rb index 1484f8628..4b8db2820 100644 --- a/spec/buildpack/compile/dnx_install_spec.rb +++ b/spec/buildpack/compile/dnx_install_spec.rb @@ -53,62 +53,9 @@ installer.install(dir, out) end - describe 'dnvm installer' do - context 'global.json does not exist' do - it 'installs the latest version' do - allow(shell).to receive(:exec) - expect(shell).to receive(:exec).with(match('dnvm install latest -p -r mono'), out) - installer.install(dir, out) - end - end - - context 'global.json exists' do - before do - json = '{ "sdk": { "version": "1.0.0-beta1" } }' - IO.write(File.join(dir, 'global.json'), json) - end - it 'installs the specified version' do - allow(shell).to receive(:exec) - expect(shell).to receive(:exec).with(match('dnvm install 1.0.0-beta1 -p -r mono'), out) - installer.install(dir, out) - end - end - - context 'global.json exists with a BOM from Visual Studio in it' do - before do - json = "\uFEFF{ \"sdk\": { \"version\": \"1.0.0-beta1\" } }" - IO.write(File.join(dir, 'global.json'), json) - end - it 'installs the specified version' do - allow(shell).to receive(:exec) - expect(shell).to receive(:exec).with(match('dnvm install 1.0.0-beta1 -p -r mono'), out) - installer.install(dir, out) - end - end - - context 'invalid global.json exists' do - before do - json = '"version": "1.0.0-beta1"' - IO.write(File.join(dir, 'global.json'), json) - end - it 'warns and installs the latest version' do - allow(shell).to receive(:exec) - expect(shell).to receive(:exec).with(match('dnvm install latest -p -r mono'), out) - expect(out).to receive(:warn).with("File #{dir}/global.json is not valid JSON") - installer.install(dir, out) - end - end - - context 'global.json exists but does not include a version' do - before do - json = '{ "projects": [ "src", "test" ] }' - IO.write(File.join(dir, 'global.json'), json) - end - it 'installs the latest version' do - allow(shell).to receive(:exec) - expect(shell).to receive(:exec).with(match('dnvm install latest -p -r mono'), out) - installer.install(dir, out) - end - end + it 'installs DNX' do + allow(shell).to receive(:exec) + expect(shell).to receive(:exec).with(match('dnvm install latest -p -r mono'), out) + installer.install(dir, out) end end diff --git a/spec/buildpack/compile/dnx_version_spec.rb b/spec/buildpack/compile/dnx_version_spec.rb new file mode 100644 index 000000000..accb6f5e7 --- /dev/null +++ b/spec/buildpack/compile/dnx_version_spec.rb @@ -0,0 +1,78 @@ +# Encoding: utf-8 +# ASP.NET 5 Buildpack +# Copyright 2014-2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'rspec' +require 'tmpdir' +require_relative '../../../lib/buildpack.rb' + +describe AspNet5Buildpack::DnxVersion do + let(:out) do + double(:out) + end + + let(:dir) do + Dir.mktmpdir + end + + describe 'DNX version' do + context 'global.json does not exist' do + it 'resolves to the latest version' do + expect(subject.version(dir, out)).to eq('latest') + end + end + + context 'global.json exists' do + before do + json = '{ "sdk": { "version": "1.0.0-beta1" } }' + IO.write(File.join(dir, 'global.json'), json) + end + it 'resolves to the specified version' do + expect(subject.version(dir, out)).to eq('1.0.0-beta1') + end + end + + context 'global.json exists with a BOM from Visual Studio in it' do + before do + json = "\uFEFF{ \"sdk\": { \"version\": \"1.0.0-beta1\" } }" + IO.write(File.join(dir, 'global.json'), json) + end + it 'resolves to the specified version' do + expect(subject.version(dir, out)).to eq('1.0.0-beta1') + end + end + + context 'invalid global.json exists' do + before do + json = '"version": "1.0.0-beta1"' + IO.write(File.join(dir, 'global.json'), json) + end + it 'warns and resolves to the latest version' do + expect(out).to receive(:warn).with("File #{dir}/global.json is not valid JSON") + expect(subject.version(dir, out)).to eq('latest') + end + end + + context 'global.json exists but does not include a version' do + before do + json = '{ "projects": [ "src", "test" ] }' + IO.write(File.join(dir, 'global.json'), json) + end + it 'resolves to the latest version' do + expect(subject.version(dir, out)).to eq('latest') + end + end + end +end diff --git a/spec/buildpack/compile/libuv_installer_spec.rb b/spec/buildpack/compile/libuv_installer_spec.rb new file mode 100644 index 000000000..e602e6311 --- /dev/null +++ b/spec/buildpack/compile/libuv_installer_spec.rb @@ -0,0 +1,81 @@ +# Encoding: utf-8 +# ASP.NET 5 Buildpack +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'rspec' +require 'tmpdir' +require 'tempfile' +require_relative '../../../lib/buildpack.rb' +require_relative '../../../lib/buildpack/shell.rb' + +describe AspNet5Buildpack::LibuvInstaller do + let(:dir) do + Dir.mktmpdir + end + + let(:shell) do + AspNet5Buildpack::Shell.new + end + + let(:out) do + double(:out) + end + + subject(:libuv_installer) do + described_class.new(dir, shell) + end + + describe 'libuv version' do + it 'uses default version' do + expect(subject.version).to eq('1.4.2') + end + end + + describe 'libuv file location' do + context 'when present in dependencies dir' do + it 'extracts the local binary' do + begin + dependencies = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'dependencies')) + FileUtils.mkdir_p dependencies + expect(out).to receive(:print).with(%r{file:///}) + subject.libuv_tar_gz(out) + ensure + FileUtils.rm_rf(dependencies) if File.exist? dependencies + end + end + end + + context 'when not present in dependencies dir' do + it 'downloads and extracts the binary' do + expect(out).to receive(:print).with(%r{https://}) + subject.libuv_tar_gz(out) + end + end + end + + describe 'libuv extraction' do + it 'uses compile-extensions' do + allow(shell).to receive(:exec).and_return(0) + expect(shell).to receive(:exec) do |*args| + cmd = args.first + expect(cmd).to match(/curl/) + expect(cmd).to match(/translate_dependency_url/) + expect(cmd).to match(/tar/) + end + expect(out).to receive(:print).with(/libuv version/) + subject.extract(dir, out) + end + end +end diff --git a/spec/buildpack/compile/mono_installer_spec.rb b/spec/buildpack/compile/mono_installer_spec.rb index 4c1698b86..71d88f383 100644 --- a/spec/buildpack/compile/mono_installer_spec.rb +++ b/spec/buildpack/compile/mono_installer_spec.rb @@ -21,7 +21,6 @@ require_relative '../../../lib/buildpack/shell.rb' describe AspNet5Buildpack::MonoInstaller do - let(:dir) do Dir.mktmpdir end @@ -65,7 +64,7 @@ expect(out).to receive(:print).with(%r{file:///}) subject.mono_tar_gz(out) ensure - FileUtils.rm_rf(dependencies) if File.exists? dependencies + FileUtils.rm_rf(dependencies) if File.exist? dependencies end end end @@ -84,7 +83,7 @@ it 'returns an error' do expect(out).to receive(:print).with(/DEPENDENCY_MISSING_IN_MANIFEST/) - expect { subject.mono_tar_gz(out) }.to raise_error + expect { subject.mono_tar_gz(out) }.to raise_error(/command failed/) end end end @@ -102,5 +101,4 @@ subject.extract(dir, out) end end - end diff --git a/spec/buildpack/compile/release_yml_writer_spec.rb b/spec/buildpack/compile/release_yml_writer_spec.rb index 4e3600c89..00b907d7f 100644 --- a/spec/buildpack/compile/release_yml_writer_spec.rb +++ b/spec/buildpack/compile/release_yml_writer_spec.rb @@ -29,14 +29,19 @@ double(:out) end - describe 'the release yml' do - let(:yml_path) do - File.join(build_dir, 'aspnet5-buildpack-release.yml') + describe 'the .profile.d script' do + let(:web_dir) do + File.join(build_dir, 'foo').tap { |f| Dir.mkdir(f) } end - let(:yml) do - subject.write_release_yml(build_dir, out) - YAML.load_file(yml_path) + let(:project_json) do + '{"commands": {"kestrel": "whatever"}}' + end + + before do + File.open(File.join(web_dir, 'project.json'), 'w') do |f| + f.write project_json + end end let(:profile_d_script) do @@ -44,232 +49,150 @@ IO.read(File.join(build_dir, '.profile.d', 'startup.sh')) end - describe 'the .profile.d script' do - let(:web_dir) do - File.join(build_dir, 'foo').tap { |f| Dir.mkdir(f) } - end + it 'should add /app/mono/bin to the PATH' do + expect(profile_d_script).to include('export PATH=$HOME/mono/bin:$PATH;') + end - it 'should add /app/mono/bin to the PATH' do - expect(profile_d_script).to include('export PATH=/app/mono/bin:$PATH;') - end + it 'should set HOME to /app (so that dependencies are picked up from /app/.dnx)' do + expect(profile_d_script).to include('export HOME=/app') + end - it 'should set HOME to /app (so that dependencies are picked up from /app/.dnx)' do - expect(profile_d_script).to include('export HOME=/app') - end + it 'make sure dlopen can access libuv.so.1' do + expect(profile_d_script).to include('export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/libuv/lib') + end - it 'should source dnvm script' do - expect(profile_d_script).to include('source /app/.dnx/dnvm/dnvm.sh') - end + it 'should source dnvm script' do + expect(profile_d_script).to include('source $HOME/.dnx/dnvm/dnvm.sh') + end - it 'should add the runtime to the PATH' do - expect(profile_d_script).to include('dnvm use default') - end + it 'should add the runtime to the PATH' do + expect(profile_d_script).to include('dnvm use default') + end + end - it 'should re-run package restore' do - expect(profile_d_script).to include('dnu restore') + describe 'the release yml' do + context 'when there are no directories containing a project.json' do + it 'should raise an error because dnu/dnx will not work' do + expect { subject.write_release_yml(build_dir, out) }.to raise_error(/No application found/) end end - describe 'the web process type' do - let(:web_process) do - yml.fetch('default_process_types').fetch('web') + context 'when there is a directory with a project.json file' do + let(:web_dir) do + File.join(build_dir, 'foo').tap { |f| Dir.mkdir(f) } end - context 'when there are no directories containing a project.json' do - it 'should work (the user might be using a custom start command)' do - expect(out).not_to receive(:fail) - subject.write_release_yml(build_dir, out) - expect(File).to exist(yml_path) - end + let(:project_json) do + '{"commands": {"kestrel": "whatever"}}' end - context 'when there is a directory with a project.json file containing a BOM' do - let(:web_dir) do - File.join(build_dir, 'foo').tap { |f| Dir.mkdir(f) } - end - - let(:project_json) do - '{}' + before do + File.open(File.join(web_dir, 'project.json'), 'w') do |f| + f.write project_json end + end - before do - File.open(File.join(web_dir, 'project.json'), 'w') do |f| - f.write "\uFEFF" - f.write project_json - end - end + it 'writes a release yml' do + subject.write_release_yml(build_dir, out) + expect(File).to exist(File.join(build_dir, 'aspnet5-buildpack-release.yml')) + end - it 'writes a release yml' do - subject.write_release_yml(build_dir, out) - expect(File).to exist(File.join(build_dir, 'aspnet5-buildpack-release.yml')) - end + it 'contains a web process type' do + subject.write_release_yml(build_dir, out) + yml = YAML.load_file(File.join(build_dir, 'aspnet5-buildpack-release.yml')) + expect(yml).to have_key('default_process_types') + expect(yml.fetch('default_process_types')).to have_key('web') end - context 'when there is a directory with a project.json file' do - let(:web_dir) do - File.join(build_dir, 'foo').tap { |f| Dir.mkdir(f) } - end + it 'does not contain any exports (these should be done via .profile.d script)' do + subject.write_release_yml(build_dir, out) + yml = YAML.load_file(File.join(build_dir, 'aspnet5-buildpack-release.yml')) + expect(yml['default_process_types']['web']).not_to include('export') + end + context 'and the project.json does not contain a kestrel command' do let(:project_json) do - '{}' + '{"commands": {"web": "whatever"}}' end - before do - File.open(File.join(web_dir, 'project.json'), 'w') do |f| - f.write project_json - end + it 'should raise an error because dnx will not work' do + expect { subject.write_release_yml(build_dir, out) }.to raise_error(/No kestrel command found in foo/) end + end - it 'writes a release yml' do - subject.write_release_yml(build_dir, out) - expect(File).to exist(File.join(build_dir, 'aspnet5-buildpack-release.yml')) + context 'and the project.json contains a kestrel command' do + let(:project_json) do + '{"commands": {"kestrel": "whatever"}}' end - it 'contains a web process type' do - expect(yml).to have_key('default_process_types') - expect(yml.fetch('default_process_types')).to have_key('web') + let(:web_process) do + subject.write_release_yml(build_dir, out) + yml = YAML.load_file(File.join(build_dir, 'aspnet5-buildpack-release.yml')) + yml.fetch('default_process_types').fetch('web') end - it 'does not contain any exports (these should be done via .profile.d script)' do - expect(yml).to have_key('default_process_types') - expect(yml['default_process_types']['web']).not_to include('export') + it 'changes directory to that directory' do + expect(web_process).to match('cd foo;') end - context 'and the project.json contains a cf-web command' do - let(:project_json) do - '{"commands": {"cf-web": "whatever"}}' - end - - it 'changes directory to that directory' do - expect(web_process).to match('cd foo;') - end - - it "runs 'dnx . cf-web'" do - expect(web_process).to match('dnx . cf-web') - end - - context 'and if the cf-web command is empty' do - let(:project_json) do - '{"commands": {"cf-web": ""}}' - end - - it 'sets it to serve NoWin.vNext' do - subject.write_release_yml(build_dir, out) - - json = JSON.parse(IO.read(File.join(web_dir, 'project.json'))) - expect(json['commands']['cf-web']).to match('Microsoft.AspNet.Hosting --server Nowin.vNext') - end - end + it "runs 'dnx . kestrel'" do + expect(web_process).to match('dnx . kestrel') end + end + end - context 'and the project.json does not contain a cf-web command' do - it 'adds cf-web command to project.json' do - subject.write_release_yml(build_dir, out) - - json = JSON.parse(IO.read(File.join(web_dir, 'project.json'))) - expect(json).to have_key('commands') - expect(json['commands']).to have_key('cf-web') - expect(json['commands']['cf-web']).to match('Microsoft.AspNet.Hosting --server Nowin.vNext') - end - - context 'when Nowin.vNext dependency exists' do - let(:project_json) do - '{ "dependencies" : { "Nowin.vNext" : "345" } }' - end - - it 'leaves it alone' do - subject.write_release_yml(build_dir, out) - - json = JSON.parse(IO.read(File.join(web_dir, 'project.json'))) - expect(json['dependencies']['Nowin.vNext']).to match('345') - end - end - - context 'when Nowin.vNext dependency does not exist' do - it 'adds Nowin.vNext dependency to project.json' do - subject.write_release_yml(build_dir, out) - - json = JSON.parse(IO.read(File.join(web_dir, 'project.json'))) - expect(json).to have_key('dependencies') - expect(json['dependencies']).to have_key('Nowin.vNext') - expect(json['dependencies']['Nowin.vNext']).to match('1.0.0-*') - end - end - end + context 'when there are multiple directories containing project.json files' do + let(:proj1) do + File.join(build_dir, 'src', 'proj1').tap { |f| FileUtils.mkdir_p(f) } end - context 'when there are multiple directories with a project.json file' do - let(:web_dir) do - File.join(build_dir, 'foo-cfweb').tap { |f| Dir.mkdir(f) } - end + let(:proj2) do + File.join(build_dir, 'src', 'proj2').tap { |f| FileUtils.mkdir_p(f) } + end - let(:other_dir) do - File.join(build_dir, 'bar').tap { |f| Dir.mkdir(f) } + before do + File.open(File.join(proj1, 'project.json'), 'w') do |f| + f.write '{"commands": {"migrate": "whatever"}}' end - - context 'and one contains a cf-web command' do - before do - File.open(File.join(other_dir, 'project.json'), 'w') do |f| - f.write '{ "commands": { "web": "whatever" } }' - end - - File.open(File.join(web_dir, 'project.json'), 'w') do |f| - f.write '{ "commands": { "cf-web": "whatever" } }' - end - end - - it 'changes directory to that directory' do - expect(web_process).to match('cd foo-cfweb;') - end - - it "runs 'dnx . cf-web'" do - expect(web_process).to match('dnx . cf-web') - end + File.open(File.join(proj2, 'project.json'), 'w') do |f| + f.write '{"commands": {"kestrel": "whatever"}}' end + end - context 'and one contains a web command' do - before do - File.open(File.join(other_dir, 'project.json'), 'w') do |f| - f.write '{ "commands": { "something": "whatever" } }' - end + let(:web_process) do + subject.write_release_yml(build_dir, out) + yml = YAML.load_file(File.join(build_dir, 'aspnet5-buildpack-release.yml')) + yml.fetch('default_process_types').fetch('web') + end - File.open(File.join(web_dir, 'project.json'), 'w') do |f| - f.write '{ "commands": { "web": "whatever" } }' - end - end + it 'changes directory to the correct directory' do + expect(web_process).to match('cd src/proj2;') + end - it 'changes directory to that directory' do - expect(web_process).to match('cd foo-cfweb;') - end + it "runs 'dnx . kestrel'" do + expect(web_process).to match('dnx . kestrel') + end + end - it "runs 'dnx . cf-web'" do - expect(web_process).to match('dnx . cf-web') - end + context 'when project.json is in the base app directory' do + before do + File.open(File.join(build_dir, 'project.json'), 'w') do |f| + f.write '{"commands": {"kestrel": "whatever"}}' end + end - context 'and one is Nowin.vNext' do - let(:nowin_dir) do - File.join(build_dir, 'src', 'Nowin.vNext').tap { |f| FileUtils.mkdir_p(f) } - end - - before do - File.open(File.join(nowin_dir, 'project.json'), 'w') do |f| - f.write '{ "commands": { "web": "whatever" } }' - end - - File.open(File.join(web_dir, 'project.json'), 'w') do |f| - f.write '{ "commands": { "whatever": "whatever" } }' - end - end + let(:web_process) do + subject.write_release_yml(build_dir, out) + yml = YAML.load_file(File.join(build_dir, 'aspnet5-buildpack-release.yml')) + yml.fetch('default_process_types').fetch('web') + end - it 'changes directory to the other directory' do - expect(web_process).to match('cd foo-cfweb;') - end + it 'changes directory to the correct directory' do + expect(web_process).to match('cd .;') + end - it "runs 'dnx . cf-web'" do - expect(web_process).to match('dnx . cf-web') - end - end + it "runs 'dnx . kestrel'" do + expect(web_process).to match('dnx . kestrel') end end end diff --git a/spec/buildpack/detect_spec.rb b/spec/buildpack/detect_spec.rb index 985f516fb..2142b0f85 100644 --- a/spec/buildpack/detect_spec.rb +++ b/spec/buildpack/detect_spec.rb @@ -25,14 +25,41 @@ describe 'detect' do context 'when there is no NuGet.Config in the root directory' do + before do + File.open(File.join(dir, 'project.json'), 'w') { |f| f.write('a') } + end + it 'returns false' do expect(subject.detect(dir)).to be_falsey end end - context 'when there is a NuGet.Config in the root directory' do + context 'when there is no project.json' do + before do + File.open(File.join(dir, 'NuGet.Config'), 'w') { |f| f.write('a') } + end + + it 'returns false' do + expect(subject.detect(dir)).to be_falsey + end + end + + context 'when project.json and NuGet.Config exist in the same directory' do + before do + File.open(File.join(dir, 'NuGet.Config'), 'w') { |f| f.write('a') } + File.open(File.join(dir, 'project.json'), 'w') { |f| f.write('a') } + end + + it 'returns true' do + expect(subject.detect(dir)).to be_truthy + end + end + + context 'when project.json and NuGet.Config exist in different directories' do before do File.open(File.join(dir, 'NuGet.Config'), 'w') { |f| f.write('a') } + FileUtils.mkdir_p(File.join(dir, 'src', 'proj')) + File.open(File.join(dir, 'src', 'proj', 'project.json'), 'w') { |f| f.write('a') } end it 'returns true' do diff --git a/spec/out_spec.rb b/spec/out_spec.rb index 0da3f84a2..a83675c54 100644 --- a/spec/out_spec.rb +++ b/spec/out_spec.rb @@ -27,11 +27,11 @@ describe '#warn' do it 'prints a big warning message surrounded by asterixes' do - expect($stdout).to receive(:puts).with("\n" + - " ************************************************************************\n" + - " * WARNING: xyz abc 123 should wrap blah blah blah foo bar baz bing bo *\n" + - " * o. this is the first message of line 2. *\n" + - " ************************************************************************\n" + + expect($stdout).to receive(:puts).with("\n" \ + " ************************************************************************\n" \ + " * WARNING: xyz abc 123 should wrap blah blah blah foo bar baz bing bo *\n" \ + " * o. this is the first message of line 2. *\n" \ + " ************************************************************************\n" \ ".\n") subject.warn('xyz abc 123 should wrap blah blah blah foo bar baz bing boo. this is the first message of line 2.') end