diff --git a/app/assets/stylesheets/screen.scss b/app/assets/stylesheets/screen.scss
index 5dadd3f6..a1893ead 100644
--- a/app/assets/stylesheets/screen.scss
+++ b/app/assets/stylesheets/screen.scss
@@ -330,7 +330,7 @@ TABLES GENERALS
font-size: 1.1em;
}
-#table-wrap table td.contributor-since {
+#table-wrap table td.contributor-timestamp {
white-space: nowrap;
text-align: left;
}
diff --git a/app/models/contributor.rb b/app/models/contributor.rb
index 5a5931c7..3beea3ec 100644
--- a/app/models/contributor.rb
+++ b/app/models/contributor.rb
@@ -39,8 +39,8 @@ def self._all_with_ncommits(joins, where=nil)
order('ncommits DESC, contributors.url_id ASC')
end
- def self.set_first_contribution_timestamps(only_new)
- scope = only_new ? 'first_contribution_at IS NULL' : '1 = 1'
+ def self.set_first_contribution_timestamps(only_missing)
+ scope = only_missing ? 'first_contribution_at IS NULL' : '1 = 1'
connection.execute(<<-SQL)
UPDATE contributors
@@ -56,6 +56,23 @@ def self.set_first_contribution_timestamps(only_new)
SQL
end
+ def self.set_last_contribution_timestamps(only_missing)
+ scope = only_missing ? 'last_contribution_at IS NULL' : '1 = 1'
+
+ connection.execute(<<-SQL)
+ UPDATE contributors
+ SET last_contribution_at = last_contributions.committer_date
+ FROM (
+ SELECT contributor_id, MAX(commits.committer_date) AS committer_date
+ FROM contributions
+ INNER JOIN commits ON commits.id = commit_id
+ GROUP BY contributor_id
+ ) AS last_contributions
+ WHERE id = last_contributions.contributor_id
+ AND #{scope}
+ SQL
+ end
+
# The contributors table may change if new name equivalences are added and IDs
# in particular are expected to move. So, we just put the parameterized name
# in URLs, which is unique anyway.
diff --git a/app/models/repo.rb b/app/models/repo.rb
index 3183339c..efada0ea 100644
--- a/app/models/repo.rb
+++ b/app/models/repo.rb
@@ -85,7 +85,7 @@ def sync
if ncommits > 0 || nreleases > 0 || rebuild_all
sync_names
sync_ranks
- sync_first_contribution_timestamps
+ sync_contribution_timestamps
end
RepoUpdate.create!(
@@ -188,8 +188,9 @@ def sync_ranks
end
end
- def sync_first_contribution_timestamps
+ def sync_contribution_timestamps
Contributor.set_first_contribution_timestamps(!rebuild_all)
+ Contributor.set_last_contribution_timestamps(!rebuild_all)
end
# Determines whether the names mapping has been updated. This is useful because
diff --git a/app/views/contributors/_contributor.html.erb b/app/views/contributors/_contributor.html.erb
index 717cebb0..1994a09f 100644
--- a/app/views/contributors/_contributor.html.erb
+++ b/app/views/contributors/_contributor.html.erb
@@ -1,7 +1,8 @@
-
+
#<%= contributor.rank %> |
<%= link_to_contributor contributor %> |
- <%= date contributor.first_contribution_at %> |
+ <%= date contributor.first_contribution_at %> |
+ <%= date contributor.last_contribution_at %> |
<% path = if @time_window
contributor_commits_in_time_window_path(contributor, @time_window)
diff --git a/app/views/contributors/index.html.erb b/app/views/contributors/index.html.erb
index a702b24c..240456f9 100644
--- a/app/views/contributors/index.html.erb
+++ b/app/views/contributors/index.html.erb
@@ -14,6 +14,7 @@
| |
Name |
Since |
+ Until |
Commits |
<%= render @contributors %>
diff --git a/db/migrate/20150326181907_add_first_contribution_at_to_contributors.rb b/db/migrate/20150326181907_add_first_contribution_at_to_contributors.rb
index a53264c0..540d162d 100644
--- a/db/migrate/20150326181907_add_first_contribution_at_to_contributors.rb
+++ b/db/migrate/20150326181907_add_first_contribution_at_to_contributors.rb
@@ -1,7 +1,7 @@
class AddFirstContributionAtToContributors < ActiveRecord::Migration[4.2]
def up
add_column :contributors, :first_contribution_at, :datetime
- Contributor.try(:fill_missing_first_contribution_timestamps)
+ Contributor.set_first_contribution_timestamps
end
def down
diff --git a/db/migrate/20240824030051_add_last_contribution_at_to_contributors.rb b/db/migrate/20240824030051_add_last_contribution_at_to_contributors.rb
new file mode 100644
index 00000000..a8bb2c00
--- /dev/null
+++ b/db/migrate/20240824030051_add_last_contribution_at_to_contributors.rb
@@ -0,0 +1,10 @@
+class AddLastContributionAtToContributors < ActiveRecord::Migration[7.1]
+ def up
+ add_column :contributors, :last_contribution_at, :datetime
+ Contributor.set_last_contribution_timestamps
+ end
+
+ def down
+ remove_column :contributors, :last_contribution_at
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 58f95d82..15ebb140 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2016_05_12_095609) do
+ActiveRecord::Schema[7.1].define(version: 2024_08_24_030051) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -42,6 +42,7 @@
t.string "url_id", null: false
t.integer "rank"
t.datetime "first_contribution_at", precision: nil
+ t.datetime "last_contribution_at"
t.index ["name"], name: "index_contributors_on_name", unique: true
t.index ["url_id"], name: "index_contributors_on_url_id", unique: true
end
diff --git a/test/controllers/commits_controller_test.rb b/test/controllers/commits_controller_test.rb
index 9de49358..3853ea41 100644
--- a/test/controllers/commits_controller_test.rb
+++ b/test/controllers/commits_controller_test.rb
@@ -24,7 +24,7 @@ def test_index_for_contributors
cases = [
[:david, [:commit_339e4e8, :commit_e0ef631]],
[:jeremy, [:commit_b821094, :commit_7cdfd91, :commit_5b90635]],
- [:jose, [:commit_5b90635]],
+ [:jose, [:commit_e243a8a, :commit_5b90635]],
].map {|a, b| [contributors(a), Array(commits(*b))]}
cases.each do |contributor, commits|
diff --git a/test/controllers/contributors_controller_test.rb b/test/controllers/contributors_controller_test.rb
index a84f7fc1..a2cacd72 100644
--- a/test/controllers/contributors_controller_test.rb
+++ b/test/controllers/contributors_controller_test.rb
@@ -3,7 +3,7 @@
class ContributorsControllerTest < ActionController::TestCase
def test_index_main_listing
# Order by ncommits DESC, url_id ASC.
- expected = [[:jeremy, 3], [:david, 2], [:jose, 1], [:vijay, 1], [:xavier, 1]]
+ expected = [[:jeremy, 3], [:david, 2], [:jose, 2], [:vijay, 1], [:xavier, 1]]
get :index
@@ -13,13 +13,27 @@ def test_index_main_listing
assert_equal expected.size, actual.size
expected.zip(actual).each do |e, a|
- assert_equal contributors(e.first).name, a.name
+ contributor = contributors(e.first)
+
+ assert_equal contributor.name, a.name
assert_equal e.second, a.ncommits
+
+ assert_select "tr##{contributor.name.downcase.tr(' ', '-') }" do |elements|
+ assert_select 'td.contributor-rank', "##{contributor.rank.to_s}"
+ assert_select 'td.contributor-name', /#{contributor.name}/
+ assert_select 'td.contributor-timestamp' do |elements|
+ assert_equal 2, elements.size
+ assert_equal contributor.first_contribution_at.strftime("%d %b %Y"), elements[0].text.strip
+ assert_equal contributor.last_contribution_at.strftime("%d %b %Y"), elements[1].text.strip
+ end
+ assert_select "td.no-commits", e.second.to_s
+ end
end
end
def test_index_by_release
releases = {
+ 'v4.0.0' => [[:jose, 1]],
'v3.2.0' => [[:jeremy, 1], [:jose, 1], [:vijay, 1]],
'v0.14.4' => [[:david, 1]]
}
@@ -48,11 +62,11 @@ def test_in_time_window
date_range = '20121201-20121231'
time_windows = {
- 'all-time' => [[:jeremy, 3], [:david, 2], [:jose, 1], [:vijay, 1], [:xavier, 1]],
+ 'all-time' => [[:jeremy, 3], [:david, 2], [:jose, 2], [:vijay, 1], [:xavier, 1]],
'today' => [[:jeremy, 1]],
'this-week' => [[:jeremy, 1], [:xavier, 1]],
'this-month' => [[:david, 1], [:jeremy, 1], [:xavier, 1]],
- 'this-year' => [[:jeremy, 3], [:david, 1], [:jose, 1], [:vijay, 1], [:xavier, 1]],
+ 'this-year' => [[:jeremy, 3], [:jose, 2], [:david, 1], [:vijay, 1], [:xavier, 1]],
since => [[:jeremy, 1], [:xavier, 1]],
date_range => [[:david, 1], [:jeremy, 1], [:xavier, 1]],
}
diff --git a/test/controllers/releases_controller_test.rb b/test/controllers/releases_controller_test.rb
index 6c3d4397..813968b8 100644
--- a/test/controllers/releases_controller_test.rb
+++ b/test/controllers/releases_controller_test.rb
@@ -5,9 +5,8 @@ def test_index
get :index
assert_response :success
- assert_select 'span.listing-total', 'Showing 5 releases'
-
expected = %w(
+ v4_0_0
v3_2_0
v2_3_2_1
v2_3_2
@@ -24,7 +23,7 @@ def test_index
assert_equal e.contributors.count, a.ncontributors
end
- assert_select 'span.listing-total', 'Showing 5 releases'
+ assert_select 'span.listing-total', "Showing #{expected.size} releases"
assert_select 'li.current', 'Releases'
end
end
diff --git a/test/fixtures/commits.yml b/test/fixtures/commits.yml
index f9c44cdf..c75bc808 100644
--- a/test/fixtures/commits.yml
+++ b/test/fixtures/commits.yml
@@ -1,4 +1,4 @@
-# WARNING: contributors.yml has first contribution timestamps that depend on
+# WARNING: contributors.yml has contribution timestamps that depend on
# these fixtures. Keep them in sync as needed.
#
# In the following comments we assumed today is 26 December 2012.
@@ -40,7 +40,7 @@ commit_26c024e:
one, because it is issued at parse-time. It seemed to in
some places because the constant was the only expression in
the block and therefore it was its return value, that could
- potentially be used by silence_warnings are return value of
+ potentially be used by silence_warnings as a return value of
the yield call.
To bypass the warning we assign to a variable. The chosen
@@ -90,6 +90,20 @@ commit_5b90635:
release: 'v3_2_0'
merge: false
+# This commit belongs to this year, release 4.0.0
+commit_e243a8a:
+ sha1: 'e243a8a32eb4c8777f07ca4b974bd7e38d9477d3'
+ author_email: 'jose.valim@gmail.com'
+ author_name: 'José Valim'
+ author_date: '2012-07-18 07:21:57'
+ committer_email: 'jose.valim@gmail.com'
+ committer_name: 'José Valim'
+ committer_date: '2012-07-18 07:47:52'
+ message: |
+ Update changelog for migration generator change
+ release: v4_0_0
+ merge: false
+
# This commit is seven years old, release v0.14.4.
commit_e0ef631:
sha1: 'e0ef63105538f8d97faa095234f069913dd5229c'
@@ -106,7 +120,7 @@ commit_e0ef631:
release: 'v0_14_4'
merge: false
-# This commit has a committer_date that is more recent the author_date and
+# This commit has a committer_date that is more recent than the author_date and
# should appear in the contributions list before 5b90635.
commit_7cdfd91:
sha1: '7cdfd910b7cdd398f8b54542c5a6a17966a5c8f3'
diff --git a/test/fixtures/contributions.yml b/test/fixtures/contributions.yml
index 933f847a..fd6684d9 100644
--- a/test/fixtures/contributions.yml
+++ b/test/fixtures/contributions.yml
@@ -20,6 +20,10 @@ contribution_<%= n += 1 %>:
commit: commit_5b90635
contributor: jose
+contribution_<%= n += 1 %>:
+ commit: commit_e243a8a
+ contributor: jose
+
contribution_<%= n += 1 %>:
commit: commit_5b90635
contributor: jeremy
diff --git a/test/fixtures/contributors.yml b/test/fixtures/contributors.yml
index e1c702df..732af268 100644
--- a/test/fixtures/contributors.yml
+++ b/test/fixtures/contributors.yml
@@ -2,23 +2,28 @@ david:
name: 'David Heinemeier Hansson'
url_id: 'david-heinemeier-hansson'
first_contribution_at: '2005-11-11 10:07:24'
+ last_contribution_at: '2012-12-07 20:38:53'
jeremy:
name: 'Jeremy Daer'
url_id: 'jeremy-kemper'
first_contribution_at: '2012-01-19 19:49:13'
+ last_contribution_at: '2012-12-26 21:16:05'
jose:
name: 'José Valim'
url_id: 'jose-valim'
first_contribution_at: '2012-01-19 19:49:13'
+ last_contribution_at: '2012-07-18 07:47:52'
xavier:
name: 'Xavier Noria'
url_id: 'xavier-noria'
first_contribution_at: '2012-12-24 21:16:16'
+ last_contribution_at: '2012-12-24 21:16:16'
vijay:
name: 'Vijay Dev'
url_id: 'vijay-dev'
first_contribution_at: '2012-01-20 00:47:14'
+ last_contribution_at: '2012-01-20 00:47:14'
diff --git a/test/fixtures/releases.yml b/test/fixtures/releases.yml
index 94777062..c79fb3b9 100644
--- a/test/fixtures/releases.yml
+++ b/test/fixtures/releases.yml
@@ -1,3 +1,11 @@
+v4_0_0:
+ tag: 'v4.0.0'
+ major: 4
+ minor: 0
+ tiny: 0
+ patch: 0
+ date: '2013-06-25 14:27:04'
+
v3_2_0:
tag: 'v3.2.0'
major: 3
diff --git a/test/models/repo_test.rb b/test/models/repo_test.rb
index d00aba0a..b0feb3b4 100644
--- a/test/models/repo_test.rb
+++ b/test/models/repo_test.rb
@@ -4,34 +4,53 @@ class RepoTest < ActiveSupport::TestCase
test '#sync_ranks' do
Repo.new.send(:sync_ranks)
- {jeremy: 1, david: 2, jose: 3, xavier: 3, vijay: 3}.each do |c, r|
+ {jeremy: 1, david: 2, jose: 2, xavier: 4, vijay: 4}.each do |c, r|
assert_equal r, contributors(c).rank
end
end
- test '#sync_first_contributed_timestamps' do
- Contributor.update_all(first_contribution_at: nil)
- Repo.new.send(:sync_first_contribution_timestamps)
+ test '#sync_contribution_timestamps' do
+ Contributor.update_all(first_contribution_at: nil, last_contribution_at: nil)
+ Repo.new.send(:sync_contribution_timestamps)
assert_first_contribution :commit_e0ef631, :david
+ assert_last_contribution :commit_339e4e8, :david
+
assert_first_contribution :commit_5b90635, :jeremy
+ assert_last_contribution :commit_b821094, :jeremy
+
assert_first_contribution :commit_5b90635, :jose
+ assert_last_contribution :commit_e243a8a, :jose
+
assert_first_contribution :commit_26c024e, :xavier
+ assert_last_contribution :commit_26c024e, :xavier
+
assert_first_contribution :commit_6c65676, :vijay
+ assert_last_contribution :commit_6c65676, :vijay
end
- test '#sync_first_contributed_timestamps rebuilding all' do
+ test '#sync_contribution_timestamps rebuilding all' do
Contributor.update_all(
- first_contribution_at: Commit.minimum(:committer_date) - 1.year
+ first_contribution_at: Commit.minimum(:committer_date) - 1.year,
+ last_contribution_at: Commit.maximum(:committer_date) + 1.year
)
- Repo.new(rebuild_all: true).send(:sync_first_contribution_timestamps)
+ Repo.new(rebuild_all: true).send(:sync_contribution_timestamps)
assert_first_contribution :commit_e0ef631, :david
+ assert_last_contribution :commit_339e4e8, :david
+
assert_first_contribution :commit_5b90635, :jeremy
+ assert_last_contribution :commit_b821094, :jeremy
+
assert_first_contribution :commit_5b90635, :jose
+ assert_last_contribution :commit_e243a8a, :jose
+
assert_first_contribution :commit_26c024e, :xavier
+ assert_last_contribution :commit_26c024e, :xavier
+
assert_first_contribution :commit_6c65676, :vijay
+ assert_last_contribution :commit_6c65676, :vijay
end
def assert_first_contribution(commit, contributor)
@@ -40,4 +59,11 @@ def assert_first_contribution(commit, contributor)
assert_equal expected, actual
end
+
+ def assert_last_contribution(commit, contributor)
+ expected = commits(commit).committer_date
+ actual = contributors(contributor).last_contribution_at
+
+ assert_equal expected, actual
+ end
end