From 3cf4a615cfb7a206846133e9702b782b11f405a4 Mon Sep 17 00:00:00 2001 From: Nathan Kleyn Date: Mon, 28 Sep 2015 15:21:52 +0100 Subject: [PATCH 1/2] (#15) Add initial interfaces for changed functionality. This allows work that will depend on this functionality to get started in parallel by agreeing an API upfront that we can all work to. --- lib/shanty/graph.rb | 14 +++++++--- lib/shanty/project.rb | 17 ++++++++++++ lib/shanty/project_tree.rb | 44 +++++++++++++++++++++++++++++- spec/lib/shanty/graph_spec.rb | 10 +++++++ spec/lib/shanty/project_spec.rb | 47 ++++++++++++++++++++++++++++----- spec/spec_helper.rb | 11 +------- 6 files changed, 123 insertions(+), 20 deletions(-) diff --git a/lib/shanty/graph.rb b/lib/shanty/graph.rb index 56e131e..73100d5 100644 --- a/lib/shanty/graph.rb +++ b/lib/shanty/graph.rb @@ -34,12 +34,12 @@ def by_name(name) find { |project| project.name == name } end - # Public: Returns all projects that have the given tags. + # Public: Returns all projects that have one or more of the given tags. # - # *plugins - One or more plugins to filter by. + # *tags - One or more tags to filter by. # # Returns an Array of Project subclasses, one for each project in the - # repository. + # repository that has one or more of the given tags. def all_with_tags(*tags) return [] if tags.empty? select do |project| @@ -47,6 +47,14 @@ def all_with_tags(*tags) end end + # Public: Returns all projects that have been marked as changed. + # + # Returns an Array of Project subclasses, one for each project in the + # repository. + def changed + select(&:changed?) + end + # Public: Given a path to a file or directory (normally a path obtained # while looking at a Git diff), find the project that owns this file. This # works by finding the project with the longest path in common with the diff --git a/lib/shanty/project.rb b/lib/shanty/project.rb index dd8aeda..a4f5a28 100644 --- a/lib/shanty/project.rb +++ b/lib/shanty/project.rb @@ -40,6 +40,9 @@ def initialize(path) @path = path @name = File.basename(path) + # FIXME: When changed is implemented properly, redefine this to default + # to false. + @changed = true @artifacts = [] @plugins = [] @tags = [] @@ -70,6 +73,20 @@ def all_artifacts (@artifacts + @plugins.flat_map { |plugin| plugin.artifacts(project) }).uniq end + # Public: Whether this project is changed. Note that a project is considered + # changed if any of its ancestors are marked as changed. + # + # Returns a boolean, true if the project is considered changed. + def changed? + @changed || parents.any?(&:changed?) + end + + # Public: Mark this project as changed. Note that any decendants of this + # project will also be marked as changed by setting this. + def changed! + @changed = true + end + def publish(name, *args) @plugins.each do |plugin| next unless plugin.subscribed?(name) diff --git a/lib/shanty/project_tree.rb b/lib/shanty/project_tree.rb index 155ed07..167e787 100644 --- a/lib/shanty/project_tree.rb +++ b/lib/shanty/project_tree.rb @@ -30,16 +30,58 @@ def files end end + # Public: Get the changed list of files in the project tree, with any files + # ignored by Git, SVN or some other VCS removed from the list. + # + # Returns an Array of Strings where the strings are paths within the + # project that are changed. + def changed_files + # FIXME: Implement properly once changed detection is available. + files + end + # Public: Get a list of the files in the project tree that match any of the # given globs, with any files ignored by Git, SVN or some other VCS # removed from the list. # # Returns an Array of Strings where the strings are paths within the - # project. + # project that matched. def glob(*globs) files.find_all do |path| globs.any? { |pattern| File.fnmatch(pattern, path, File::FNM_EXTGLOB) } end end + + # Public: Get a list of the changed files in the project tree that match any + # of the given globs, with any files ignored by Git, SVN or some other VCS + # removed from the list. + # + # Returns an Array of Strings where the strings are paths within the + # project that are changed and matched. + def glob_changed(*globs) + # FIXME: Implement properly once changed detection is available. + glob(*globs) + end + + # Public: Whether the given path is in the project tree. + # + # path - An absolute path to check for the presence of in the project tree. + # + # Returns a boolean, true if the project does exist in the project tree. + def exists?(path) + files.include?(path) + end + + # Public: Whether the given path is present and changed in the project tree. + # + # path - An absolute path to check for the presence and changed status of in + # the project tree. + # + # Returns a boolean, true if the project does exist in the project tree and + # is changed. + def changed?(path) + # FIXME: Implement properly once changed detection is available. + exists?(path) + end end end diff --git a/spec/lib/shanty/graph_spec.rb b/spec/lib/shanty/graph_spec.rb index 89724f6..5210e01 100644 --- a/spec/lib/shanty/graph_spec.rb +++ b/spec/lib/shanty/graph_spec.rb @@ -43,6 +43,16 @@ module Shanty end end + describe('#changed') do + it('returns all the changed projects') do + allow(projects[:one]).to receive(:changed?).and_return(true) + allow(projects[:two]).to receive(:changed?).and_return(false) + allow(projects[:three]).to receive(:changed?).and_return(true) + + expect(subject.changed).to match_array([projects[:one], projects[:three]]) + end + end + describe('#owner_of_file') do it('returns nil if the given folder is outside of any project') do expect(subject.owner_of_file('/tmp')).to be_nil diff --git a/spec/lib/shanty/project_spec.rb b/spec/lib/shanty/project_spec.rb index 503889f..42025fc 100644 --- a/spec/lib/shanty/project_spec.rb +++ b/spec/lib/shanty/project_spec.rb @@ -53,6 +53,47 @@ module Shanty end end + describe('#all_artifacts') do + it('defaults the artifacts to an empty array') do + expect(subject.all_artifacts).to eql([]) + end + end + + describe('#changed?') do + before do + # FIXME: Remove this when the default of changed is properly set to + # false once changed detection is actually working. + subject.instance_variable_set(:@changed, false) + end + + it('returns true if the changed flag is true on the current project') do + subject.instance_variable_set(:@changed, true) + + expect(subject.changed?).to be(true) + end + + it('returns true if any of the parents are changed') do + parent = double('parent') + allow(parent).to receive(:add_child) + allow(parent).to receive(:changed?).and_return(true) + subject.add_parent(parent) + + expect(subject.changed?).to be(true) + end + + it('returns false if the changed flag is false and the parents are unchanged') do + expect(subject.changed?).to be(false) + end + end + + describe('#changed!') do + it('adds the changed flag to true on the current project') do + subject.changed! + + expect(subject.changed?).to be(true) + end + end + describe('#publish') do before { subject.add_plugin(plugin) } let(:plugin) { double('plugin') } @@ -84,12 +125,6 @@ module Shanty end end - describe('#all_artifacts') do - it('defaults the artifacts to an empty array') do - expect(subject.all_artifacts).to eql([]) - end - end - describe('#to_s') do it('returns a simple string representation of the project') do expect(subject.to_s).to eql('one') diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7c6bf7c..d4eba82 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -42,20 +42,11 @@ def require_matchers(path) mocks.verify_partial_doubles = true end - # Supress any writing to stdout or stderr during the tests. We don't want - # any of the logging to be written in between our test output. - config.around(:all) do |example| - $stderr = File.open(File::NULL, 'w') - $stdout = File.open(File::NULL, 'w') - example.run - $stderr = STDERR - $stdout = STDOUT - end - config.before(:example) do Shanty::Env.clear! Shanty::TaskEnv.clear! Shanty::Project.clear! + Shanty::Env.logger.level = Logger::ERROR end end From 1d4dc4f58bf95ac34663f4740ecc31a779dc7173 Mon Sep 17 00:00:00 2001 From: Nathan Kleyn Date: Mon, 28 Sep 2015 15:28:06 +0100 Subject: [PATCH 2/2] (#15) Add pending spec for default value of changed. --- spec/lib/shanty/project_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/lib/shanty/project_spec.rb b/spec/lib/shanty/project_spec.rb index 42025fc..801cacb 100644 --- a/spec/lib/shanty/project_spec.rb +++ b/spec/lib/shanty/project_spec.rb @@ -66,6 +66,17 @@ module Shanty subject.instance_variable_set(:@changed, false) end + it('defaults changed to false') do + pending(<<-eof) + This will only pass once the default value is set to true when we + have proper change detection working. + eof + # FIXME: Delete the following setup eventually. + subject.instance_variable_set(:@changed, true) + + expect(subject.changed?).to be(false) + end + it('returns true if the changed flag is true on the current project') do subject.instance_variable_set(:@changed, true)