From 42e9e9c3fd69ca339d0a216849bb11a46230914f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= Date: Fri, 10 Apr 2020 14:30:32 +0200 Subject: [PATCH] Refactor ProjectInfo defaults --- .../crystal/tools/doc/project_info_spec.cr | 118 ++++++++++++++++++ spec/compiler/crystal/tools/doc_spec.cr | 62 --------- src/compiler/crystal/command/docs.cr | 28 ++--- .../crystal/tools/doc/project_info.cr | 43 +++++-- 4 files changed, 162 insertions(+), 89 deletions(-) create mode 100644 spec/compiler/crystal/tools/doc/project_info_spec.cr diff --git a/spec/compiler/crystal/tools/doc/project_info_spec.cr b/spec/compiler/crystal/tools/doc/project_info_spec.cr new file mode 100644 index 000000000000..bc3d7ac90209 --- /dev/null +++ b/spec/compiler/crystal/tools/doc/project_info_spec.cr @@ -0,0 +1,118 @@ +require "../../../../spec_helper" +require "../../../../support/tempfile" + +private alias ProjectInfo = Crystal::Doc::ProjectInfo + +describe Crystal::Doc::ProjectInfo do + it ".new_with_defaults" do + with_tempfile("docs-defaults") do |tempdir| + Dir.mkdir tempdir + Dir.cd(tempdir) do + # Empty dir + ProjectInfo.new_with_defaults(nil, nil) { |name, version| "missing:#{name}:#{version}" }.should eq "missing::" + ProjectInfo.new_with_defaults("foo", "1.0") { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("foo", "1.0") + + # shard.yml + File.write("shard.yml", "name: foo\nversion: 1.0") + ProjectInfo.new_with_defaults(nil, nil) { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("foo", "1.0") + ProjectInfo.new_with_defaults("bar", "2.0") { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("bar", "2.0") + ProjectInfo.new_with_defaults(nil, "2.0") { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("foo", "2.0") + + # git tagged version + `git init` + `git add shard.yml` + `git commit -m 'Initial commit' --no-gpg-sign` + `git tag v3.0` + ProjectInfo.new_with_defaults(nil, nil) { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("foo", "3.0") + ProjectInfo.new_with_defaults("bar", "2.0") { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("bar", "2.0") + + # git dirty dir + File.write("foo.txt", "bar") + ProjectInfo.new_with_defaults(nil, nil) { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("foo", "1.0") + ProjectInfo.new_with_defaults(nil, "1.1") { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("foo", "1.1") + ProjectInfo.new_with_defaults("bar", "2.0") { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("bar", "2.0") + File.delete("foo.txt") + + # No shard.yml, but git version + `git rm shard.yml` + `git commit -m 'Remove shard.yml' --no-gpg-sign` + `git tag v4.0` + ProjectInfo.new_with_defaults(nil, nil) { |name, version| "missing:#{name}:#{version}" }.should eq "missing::4.0" + ProjectInfo.new_with_defaults("foo", nil) { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("foo", "4.0") + ProjectInfo.new_with_defaults("bar", "2.0") { |name, version| "missing:#{name}:#{version}" }.should eq ProjectInfo.new("bar", "2.0") + end + end + end + + it ".find_git_version" do + with_tempfile("docs-git-version") do |tempdir| + Dir.mkdir tempdir + Dir.cd(tempdir) do + # Non-git directory + ProjectInfo.find_git_version.should be_nil + + `git init` + ProjectInfo.find_git_version.should be_nil + + File.write("file.txt", "foo") + `git add file.txt` + `git commit -m 'Initial commit' --no-gpg-sign` + ProjectInfo.find_git_version.should be_nil + + `git tag v0.1.0` + ProjectInfo.find_git_version.should eq "0.1.0" + + File.write("file.txt", "bar") + ProjectInfo.find_git_version.should be_nil + + `git add file.txt` + ProjectInfo.find_git_version.should be_nil + + `git reset --hard v0.1.0` + ProjectInfo.find_git_version.should eq "0.1.0" + + `git tag v0.2.0` + ProjectInfo.find_git_version.should be_nil + end + end + end + + it ".read_shard_properties" do + with_tempfile("docs-shard.yml") do |tempdir| + Dir.mkdir tempdir + Dir.cd(tempdir) do + ProjectInfo.read_shard_properties.should eq({nil, nil}) + + File.write("shard.yml", "foo: bar\n") + ProjectInfo.read_shard_properties.should eq({nil, nil}) + + File.write("shard.yml", "name: \nversion: ") + ProjectInfo.read_shard_properties.should eq({nil, nil}) + + File.write("shard.yml", " name: bar\n version: 1.0") + ProjectInfo.read_shard_properties.should eq({nil, nil}) + + File.write("shard.yml", "name: bar\n") + ProjectInfo.read_shard_properties.should eq({"bar", nil}) + + File.write("shard.yml", "name: bar\nversion: 1.0") + ProjectInfo.read_shard_properties.should eq({"bar", "1.0"}) + + File.write("shard.yml", "name: bar\nversion: 1.0\nname: foo\nversion: foo") + ProjectInfo.read_shard_properties.should eq({"bar", "1.0"}) + + File.write("shard.yml", "name: bar \nversion: 1.0 ") + ProjectInfo.read_shard_properties.should eq({"bar", "1.0"}) + + File.write("shard.yml", "name: 'bar'\nversion: '1.0'") + ProjectInfo.read_shard_properties.should eq({"bar", "1.0"}) + + File.write("shard.yml", "name: bar # comment\nversion: 1.0 # comment") + ProjectInfo.read_shard_properties.should eq({"bar", "1.0"}) + + File.write("shard.yml", "name: # comment\nversion: # comment") + ProjectInfo.read_shard_properties.should eq({nil, nil}) + end + end + end +end diff --git a/spec/compiler/crystal/tools/doc_spec.cr b/spec/compiler/crystal/tools/doc_spec.cr index 96ea75f772d6..e11fadc95f98 100644 --- a/spec/compiler/crystal/tools/doc_spec.cr +++ b/spec/compiler/crystal/tools/doc_spec.cr @@ -1,5 +1,4 @@ require "../../../spec_helper" -require "../../../support/tempfile" private def assert_matches_pattern(url, **options) match = Crystal::Doc::Generator::GIT_REMOTE_PATTERNS.each_key.compact_map(&.match(url)).first? @@ -61,64 +60,3 @@ describe Crystal::Doc::Generator do end end end - -describe Crystal::Doc::ProjectInfo do - it "find_default_version" do - with_tempfile("docs-git-version") do |tempdir| - Dir.mkdir tempdir - Dir.cd(tempdir) do - # Non-git directory - Crystal::Doc::ProjectInfo.find_default_version.should be_nil - - `git init` - Crystal::Doc::ProjectInfo.find_default_version.should be_nil - - File.write("file.txt", "foo") - `git add file.txt` - `git commit -m 'Initial commit' --no-gpg-sign` - Crystal::Doc::ProjectInfo.find_default_version.should be_nil - - `git tag v0.1.0` - `git tag --list` - `git log` - Crystal::Doc::ProjectInfo.find_default_version.should eq "v0.1.0" - - File.write("file.txt", "bar") - Crystal::Doc::ProjectInfo.find_default_version.should be_nil - - `git add file.txt` - Crystal::Doc::ProjectInfo.find_default_version.should be_nil - - `git reset --hard v0.1.0` - Crystal::Doc::ProjectInfo.find_default_version.should eq "v0.1.0" - - `git tag v0.2.0` - Crystal::Doc::ProjectInfo.find_default_version.should be_nil - end - end - end - - it "find_default_name" do - with_tempfile("docs-shard-name") do |tempdir| - Dir.mkdir tempdir - Dir.cd(tempdir) do - Crystal::Doc::ProjectInfo.find_default_name.should be_nil - - File.write("shard.yml", "foo: bar\n") - Crystal::Doc::ProjectInfo.find_default_name.should be_nil - - File.write("shard.yml", "name: \n") - Crystal::Doc::ProjectInfo.find_default_name.should be_nil - - File.write("shard.yml", " name: bar\n") - Crystal::Doc::ProjectInfo.find_default_name.should be_nil - - File.write("shard.yml", "name: bar\n") - Crystal::Doc::ProjectInfo.find_default_name.should eq "bar" - - File.write("shard.yml", "name: bar # comment\n") - Crystal::Doc::ProjectInfo.find_default_name.should eq "bar" - end - end - end -end diff --git a/src/compiler/crystal/command/docs.cr b/src/compiler/crystal/command/docs.cr index 9292d8c63a18..c8f044bc81cd 100644 --- a/src/compiler/crystal/command/docs.cr +++ b/src/compiler/crystal/command/docs.cr @@ -98,7 +98,15 @@ class Crystal::Command setup_compiler_warning_options(opts, compiler) end - project_info = create_project_info(project_name, project_version) + project_info = Doc::ProjectInfo.new_with_defaults(project_name, project_version) do |name, version| + unless name + STDERR.puts "Couldn't determine name from shard.yml, please provide --project-name option" + end + unless version + STDERR.puts "Couldn't determine version from git or shard.yml, please provide --project-version option" + end + abort + end if options.empty? sources = [Compiler::Source.new("require", %(require "./src/**"))] @@ -120,22 +128,4 @@ class Crystal::Command report_warnings result exit 1 if warnings_fail_on_exit?(result) end - - private def create_project_info(name, version) - name ||= Doc::ProjectInfo.find_default_name - unless name - STDERR.puts "Couldn't determine name from shard.yml, please provide --project-name option" - end - - version ||= Doc::ProjectInfo.find_default_version - unless version - STDERR.puts "Couldn't determine version from git, please provide --project-version option" - end - - unless name && version - abort - end - - Doc::ProjectInfo.new(name, version) - end end diff --git a/src/compiler/crystal/tools/doc/project_info.cr b/src/compiler/crystal/tools/doc/project_info.cr index f1db22d4795b..4f95ecd01060 100644 --- a/src/compiler/crystal/tools/doc/project_info.cr +++ b/src/compiler/crystal/tools/doc/project_info.cr @@ -1,6 +1,22 @@ module Crystal::Doc record ProjectInfo, name : String, version : String do - def self.find_default_version + def self.new_with_defaults(name, version) + version ||= find_git_version + + unless name && version + shard_name, shard_version = read_shard_properties + name ||= shard_name + version ||= shard_version + + unless name && version + return yield name, version + end + end + + new(name, version) + end + + def self.find_git_version # Use git to determine if index and working directory are clean io = IO::Memory.new status = Process.run("git", ["status", "--porcelain"], output: io) @@ -14,22 +30,33 @@ module Crystal::Doc return unless status.success? io.rewind tags = io.to_s.lines - # Only accept when there's exactly one tag pointing at HEAD. - if tags.size == 1 - tags.first + versions = tags.select(&.starts_with?("v")) + # Only accept when there's exactly one version tag pointing at HEAD. + if versions.size == 1 + return versions.first.byte_slice(1) end end - def self.find_default_name - return unless File.readable?("shard.yml") + def self.read_shard_properties + return {nil, nil} unless File.readable?("shard.yml") + + name = nil + version = nil # Poor man's YAML reader File.each_line("shard.yml") do |line| - if line.starts_with?("name:") + if name.nil? && line.starts_with?("name:") end_pos = line.byte_index("#") || line.bytesize - return line.byte_slice(5, end_pos - 5).strip.presence + name = line.byte_slice(5, end_pos - 5).strip.strip(%("')) + elsif version.nil? && line.starts_with?("version:") + end_pos = line.byte_index("#") || line.bytesize + version = line.byte_slice(8, end_pos - 8).strip.strip(%("')) + elsif version && name + break end end + + return name.presence, version.presence end end end