Class: DamageControl::Project
- Inherits:
-
Object
- Object
- DamageControl::Project
- Includes:
- Web::Configuration, ObjectTemplate
- Defined in:
- lib/damagecontrol/project.rb,
lib/damagecontrol/project_dependencies.rb,
app/controllers/rscm_ext.rb
Overview
Represents a project with associated SCM, Tracker and SCMWeb
Constant Summary collapse
- DEFAULT_QUIET_PERIOD =
TODO: move to scms? not sure.…
10
Instance Attribute Summary collapse
-
#build_command ⇒ Object
Returns the value of attribute build_command.
-
#home_page ⇒ Object
Returns the value of attribute home_page.
-
#name ⇒ Object
Returns the value of attribute name.
-
#publishers ⇒ Object
Returns the value of attribute publishers.
-
#quiet_period ⇒ Object
How long to sleep between each changesets invocation for non-transactional SCMs.
-
#scm ⇒ Object
Returns the value of attribute scm.
-
#scm_web ⇒ Object
Returns the value of attribute scm_web.
-
#start_time ⇒ Object
Returns the value of attribute start_time.
-
#tracker ⇒ Object
Returns the value of attribute tracker.
Class Method Summary collapse
-
.find_all ⇒ Object
Loads all projects.
-
.load(name) ⇒ Object
Loads the project with the given
name
.
Instance Method Summary collapse
- #==(o) ⇒ Object
- #add_dependency(project) ⇒ Object
-
#build(changeset_identifier, build_time) ⇒ Object
Returns the Build for the given
changeset_identifier
andbuild_time
. -
#builds(changeset_identifier) ⇒ Object
Returns an array of existing Build s for the given
changeset_identifier
. - #changeset(changeset_identifier) ⇒ Object
- #changeset_identifiers ⇒ Object
- #changesets(changeset_identifier, prior) ⇒ Object
- #changesets_dir ⇒ Object
- #changesets_persister ⇒ Object
- #changesets_rss_exists? ⇒ Boolean
-
#changesets_rss_file ⇒ Object
Where RSS is written.
- #checked_out? ⇒ Boolean
-
#checkout(changeset_identifier) ⇒ Object
Checks out files to project’s checkout directory.
- #checkout_dir ⇒ Object
-
#checkout_list_file ⇒ Object
Path to file containing pathnames of latest checked out files.
- #delete ⇒ Object
- #delete_working_copy ⇒ Object
-
#execute_build(changeset_identifier, build_reason) {|build| ... } ⇒ Object
Creates, persists and executes a Build for the changeset with the given
changeset_identifier
. - #exists? ⇒ Boolean
-
#initialize(name = "") ⇒ Project
constructor
A new instance of Project.
-
#latest_build ⇒ Object
Returns the latest build.
- #latest_changeset_identifier ⇒ Object
-
#next_changeset_identifier(d = changesets_dir) ⇒ Object
Returns the identifier (int label or time) that should be used to get the next (unrecorded) changeset.
-
#poll {|changesets| ... } ⇒ Object
Polls SCM for new changesets and yields them to the given block.
-
#publish(build) ⇒ Object
Tells all publishers to publish a build.
-
#save ⇒ Object
Saves the state of this project to persistent store (YAML).
- #scm_exists? ⇒ Boolean
Methods included from Web::Configuration
Methods included from ObjectTemplate
Constructor Details
#initialize(name = "") ⇒ Project
Returns a new instance of Project.
79 80 81 82 83 84 85 86 87 88 |
# File 'lib/damagecontrol/project.rb', line 79 def initialize(name="") @name = name @publishers = Publisher::Base.classes.collect{|cls| cls.new} @scm = nil @tracker = Tracker::None.new # @scm_web = SCMWeb::None.new # Default start time is 2 weeks ago @start_time = Time.now.utc - (3600*24*14) @quiet_period = DEFAULT_QUIET_PERIOD end |
Instance Attribute Details
#build_command ⇒ Object
Returns the value of attribute build_command.
44 45 46 |
# File 'lib/damagecontrol/project.rb', line 44 def build_command @build_command end |
#home_page ⇒ Object
Returns the value of attribute home_page.
34 35 36 |
# File 'lib/damagecontrol/project.rb', line 34 def home_page @home_page end |
#name ⇒ Object
Returns the value of attribute name.
33 34 35 |
# File 'lib/damagecontrol/project.rb', line 33 def name @name end |
#publishers ⇒ Object
Returns the value of attribute publishers.
45 46 47 |
# File 'lib/damagecontrol/project.rb', line 45 def publishers @publishers end |
#quiet_period ⇒ Object
How long to sleep between each changesets invocation for non-transactional SCMs
42 43 44 |
# File 'lib/damagecontrol/project.rb', line 42 def quiet_period @quiet_period end |
#scm ⇒ Object
Returns the value of attribute scm.
37 38 39 |
# File 'lib/damagecontrol/project.rb', line 37 def scm @scm end |
#scm_web ⇒ Object
Returns the value of attribute scm_web.
39 40 41 |
# File 'lib/damagecontrol/project.rb', line 39 def scm_web @scm_web end |
#start_time ⇒ Object
Returns the value of attribute start_time.
35 36 37 |
# File 'lib/damagecontrol/project.rb', line 35 def start_time @start_time end |
#tracker ⇒ Object
Returns the value of attribute tracker.
38 39 40 |
# File 'lib/damagecontrol/project.rb', line 38 def tracker @tracker end |
Class Method Details
.find_all ⇒ Object
Loads all projects
68 69 70 71 72 |
# File 'lib/damagecontrol/project.rb', line 68 def Project.find_all Directories.project_names.collect do |name| Project.load(name) end end |
.load(name) ⇒ Object
Loads the project with the given name
.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/damagecontrol/project.rb', line 48 def Project.load(name) config_file = Directories.project_config_file(name) Log.info "Loading project from #{config_file}" project = File.open(config_file) do |io| YAML::load(io) end # Add new publishers that may have be defined after the project was YAMLed. project.publishers = [] if project.publishers.nil? Publisher::Base.classes.collect{|cls| cls.new}.each do |publisher| publisher_of_same_type = project.publishers.find do |p| p.class == publisher.class end project.publishers << publisher unless publisher_of_same_type end project end |
Instance Method Details
#==(o) ⇒ Object
230 231 232 233 |
# File 'lib/damagecontrol/project.rb', line 230 def == (o) return false unless o.is_a?(Project) name == o.name end |
#add_dependency(project) ⇒ Object
5 6 |
# File 'lib/damagecontrol/project_dependencies.rb', line 5 def add_dependency(project) end |
#build(changeset_identifier, build_time) ⇒ Object
Returns the Build for the given changeset_identifier
and build_time
257 258 259 |
# File 'lib/damagecontrol/project.rb', line 257 def build(changeset_identifier, build_time) Build.new(name, changeset_identifier, build_time, "FIXME") end |
#builds(changeset_identifier) ⇒ Object
Returns an array of existing Build s for the given changeset_identifier
.
249 250 251 252 253 254 |
# File 'lib/damagecontrol/project.rb', line 249 def builds(changeset_identifier) Directories.build_dirs(name, changeset_identifier).collect do |dir| # The dir's basename will always be a Time Build.new(name, changeset_identifier, File.basename(dir).to_identifier, "TODO: get from file") end end |
#changeset(changeset_identifier) ⇒ Object
212 213 214 215 216 |
# File 'lib/damagecontrol/project.rb', line 212 def changeset(changeset_identifier) result = changesets(changeset_identifier, 1)[0] raise "No changeset with id '#{changeset_identifier}' for project '#{name}'" unless result result end |
#changeset_identifiers ⇒ Object
218 219 220 |
# File 'lib/damagecontrol/project.rb', line 218 def changeset_identifiers changesets_persister.identifiers end |
#changesets(changeset_identifier, prior) ⇒ Object
208 209 210 |
# File 'lib/damagecontrol/project.rb', line 208 def changesets(changeset_identifier, prior) changesets_persister.load_upto(changeset_identifier, prior) end |
#changesets_dir ⇒ Object
204 205 206 |
# File 'lib/damagecontrol/project.rb', line 204 def changesets_dir Directories.changesets_dir(name) end |
#changesets_persister ⇒ Object
235 236 237 |
# File 'lib/damagecontrol/project.rb', line 235 def changesets_persister DamageControl::Visitor::YamlPersister.new(changesets_dir) end |
#changesets_rss_exists? ⇒ Boolean
200 201 202 |
# File 'lib/damagecontrol/project.rb', line 200 def changesets_rss_exists? File.exist?(changesets_rss_file) end |
#changesets_rss_file ⇒ Object
Where RSS is written.
176 177 178 |
# File 'lib/damagecontrol/project.rb', line 176 def changesets_rss_file Directories.changesets_rss_file(name) end |
#checked_out? ⇒ Boolean
180 181 182 |
# File 'lib/damagecontrol/project.rb', line 180 def checked_out? @scm.checked_out?(checkout_dir) end |
#checkout(changeset_identifier) ⇒ Object
Checks out files to project’s checkout directory. Writes the checked out files to checkout_list_file
. The changeset_identifier
parameter is a String or a Time representing a changeset.
126 127 128 129 130 131 132 133 |
# File 'lib/damagecontrol/project.rb', line 126 def checkout(changeset_identifier) File.open(checkout_list_file, "w") do |f| scm.checkout(checkout_dir, changeset_identifier) do |file_name| f << file_name << "\n" f.flush end end end |
#checkout_dir ⇒ Object
192 193 194 |
# File 'lib/damagecontrol/project.rb', line 192 def checkout_dir Directories.checkout_dir(name) end |
#checkout_list_file ⇒ Object
Path to file containing pathnames of latest checked out files.
118 119 120 |
# File 'lib/damagecontrol/project.rb', line 118 def checkout_list_file Directories.checkout_list_file(name) end |
#delete ⇒ Object
226 227 228 |
# File 'lib/damagecontrol/project.rb', line 226 def delete File.delete(Directories.project_dir(name)) end |
#delete_working_copy ⇒ Object
196 197 198 |
# File 'lib/damagecontrol/project.rb', line 196 def delete_working_copy File.delete(checkout_dir) end |
#execute_build(changeset_identifier, build_reason) {|build| ... } ⇒ Object
Creates, persists and executes a Build for the changeset with the given changeset_identifier
. Should be called with a block of arity 1 that will receive the build.
242 243 244 245 246 |
# File 'lib/damagecontrol/project.rb', line 242 def execute_build(changeset_identifier, build_reason) scm.checkout(checkout_dir, changeset_identifier) build = Build.new(name, changeset_identifier, Time.now.utc, build_reason) yield build end |
#exists? ⇒ Boolean
184 185 186 |
# File 'lib/damagecontrol/project.rb', line 184 def exists? File.exists?(project_config_file) end |
#latest_build ⇒ Object
Returns the latest build.
262 263 264 265 266 267 268 |
# File 'lib/damagecontrol/project.rb', line 262 def latest_build changeset_identifiers.reverse.each do |changeset_identifier| builds = builds(changeset_identifier) return builds[-1] unless builds.empty? end nil end |
#latest_changeset_identifier ⇒ Object
222 223 224 |
# File 'lib/damagecontrol/project.rb', line 222 def latest_changeset_identifier changesets_persister.latest_identifier end |
#next_changeset_identifier(d = changesets_dir) ⇒ Object
Returns the identifier (int label or time) that should be used to get the next (unrecorded) changeset. This is the identifier following the latest recorded changeset. This identifier is determined by looking at the directory names under changesets_dir
. If there are none, this method returns nil.
169 170 171 172 173 |
# File 'lib/damagecontrol/project.rb', line 169 def next_changeset_identifier(d=changesets_dir) # See String extension at top of this file. latest_identifier = DamageControl::Visitor::YamlPersister.new(d).latest_identifier latest_identifier ? latest_identifier + 1 : nil end |
#poll {|changesets| ... } ⇒ Object
Polls SCM for new changesets and yields them to the given block.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/damagecontrol/project.rb', line 136 def poll start = Time.now from = next_changeset_identifier || @start_time Log.info "Getting changesets for #{name} from #{from} (retrieved from #{checkout_dir})" changesets = @scm.changesets(checkout_dir, from) if(!changesets.empty? && !@scm.transactional?) # We're dealing with a non-transactional SCM (like CVS/StarTeam/ClearCase, # unlike Subversion/Monotone). Sleep a little, get the changesets again. # When the changesets are not changing, we can consider the last commit done # and the quiet period elapsed. This is not 100% failsafe, but will work # under most circumstances. In the worst case, we'll miss some files in # the changesets for really slow commits, but they will be part of the next # changeset (on next poll). commit_in_progress = true while(commit_in_progress) @quiet_period ||= DEFAULT_QUIET_PERIOD Log.info "Sleeping for #{@quiet_period} seconds since #{name}'s SCM (#{@scm.name}) is not transactional." sleep @quiet_period next_changesets = @scm.changesets(checkout_dir, from) commit_in_progress = changesets != next_changesets changesets = next_changesets end Log.info "Quiet period elapsed for #{name}" end Log.info "Got changesets for #{@name} in #{Time.now.difference_as_text(start)}" yield changesets end |
#publish(build) ⇒ Object
Tells all publishers to publish a build
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/damagecontrol/project.rb', line 91 def publish(build) @publishers.each do |publisher| begin if(publisher.enabled) Log.info("Publishing #{publisher.name} for #{@name}") publisher.publish(build) else Log.info("Skipping disabled publisher #{publisher.name} for #{@name}") end rescue => e Log.error "Error running publisher #{publisher.name} for project #{name}" Log.error e. Log.error " " + e.backtrace.join(" \n") end end end |
#save ⇒ Object
Saves the state of this project to persistent store (YAML)
109 110 111 112 113 114 115 |
# File 'lib/damagecontrol/project.rb', line 109 def save f = project_config_file FileUtils.mkdir_p(File.dirname(f)) File.open(f, "w") do |io| YAML::dump(self, io) end end |
#scm_exists? ⇒ Boolean
188 189 190 |
# File 'lib/damagecontrol/project.rb', line 188 def scm_exists? scm.exists? end |