houston-core 0.5.6 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +94 -69
- data/app/adapters/houston/adapters/deployment/engineyard.rb +4 -3
- data/app/adapters/houston/adapters/version_control/git_adapter.rb +36 -42
- data/app/adapters/houston/adapters/version_control/git_adapter/github_repo.rb +2 -2
- data/app/adapters/houston/adapters/version_control/git_adapter/remote_repo.rb +23 -11
- data/app/adapters/houston/adapters/version_control/git_adapter/repo.rb +18 -8
- data/app/adapters/houston/adapters/version_control/null_repo.rb +8 -0
- data/app/assets/javascripts/core/handlebars_helpers.coffee +3 -3
- data/app/assets/stylesheets/application/github_repos.scss +77 -0
- data/app/assets/stylesheets/application/navigation.scss +2 -0
- data/app/assets/stylesheets/application/pull_requests.scss +44 -58
- data/app/assets/stylesheets/core/avatars.scss +5 -0
- data/app/assets/stylesheets/core/colors.scss.erb +10 -7
- data/app/concerns/commit_synchronizer.rb +3 -0
- data/app/controllers/github/pulls_controller.rb +12 -0
- data/app/controllers/project_tests_controller.rb +3 -3
- data/app/controllers/projects_controller.rb +45 -1
- data/app/controllers/releases_controller.rb +42 -26
- data/app/helpers/application_helper.rb +8 -0
- data/app/helpers/avatar_helper.rb +2 -2
- data/app/helpers/commit_helper.rb +2 -2
- data/app/helpers/oembed_helper.rb +8 -0
- data/app/helpers/project_helper.rb +4 -5
- data/app/helpers/release_helper.rb +11 -0
- data/app/helpers/timeline_helper.rb +1 -1
- data/app/helpers/url_helper.rb +0 -18
- data/app/interactors/cache_key_dependencies.rb +28 -0
- data/app/jobs/sync_all_tickets_job.rb +1 -0
- data/app/mailers/view_mailer.rb +0 -1
- data/app/models/commit.rb +1 -1
- data/app/models/github/pull_request.rb +82 -26
- data/app/models/github/pull_request_event.rb +2 -2
- data/app/models/milestone.rb +1 -0
- data/app/models/project.rb +14 -0
- data/app/models/project_dependencies.rb +5 -3
- data/app/models/task.rb +1 -1
- data/app/models/user.rb +41 -0
- data/app/views/commits/show.html.erb +9 -1
- data/app/views/github/pulls/index.html.erb +102 -0
- data/app/views/project_notification/new_release.html.erb +6 -0
- data/app/views/project_tickets/index.xls.erb +0 -7
- data/app/views/projects/_form.html.erb +29 -17
- data/app/views/projects/index.html.erb +3 -3
- data/app/views/projects/new_from_github.html.erb +67 -0
- data/app/views/releases/_commits.html.erb +1 -1
- data/app/views/releases/show.html.erb +9 -0
- data/app/views/users/_form.html.erb +35 -19
- data/config/application.rb +12 -0
- data/config/initializers/mime_types.rb +1 -0
- data/config/routes.rb +17 -3
- data/db/migrate/20151201042126_require_projects_to_have_name_and_slug.rb +6 -0
- data/db/migrate/20151202005557_add_head_sha_to_projects.rb +24 -0
- data/db/migrate/20151202011812_require_projects_to_have_color.rb +13 -0
- data/db/migrate/20151205204922_require_project_slugs_to_be_unique.rb +5 -0
- data/db/migrate/20151205214647_add_avatar_url_to_pull_requests.rb +5 -0
- data/db/migrate/20151209004458_add_json_labels_to_pull_requests.rb +5 -0
- data/db/migrate/20151209030113_add_timestamps_to_pull_requests.rb +6 -0
- data/db/structure.sql +31 -5
- data/houston.gemspec +7 -7
- data/lib/configuration.rb +3 -2
- data/lib/houston/version.rb +1 -1
- data/lib/rack/oembed.rb +23 -0
- data/templates/new-instance/config/jobs/cache_key_dependencies.rb +3 -0
- data/templates/new-instance/config/triggers/tests/slack_when_analyzed.rb +1 -4
- data/templates/new-instance/config/triggers/tests/slack_when_completed.rb +1 -1
- data/templates/new-instance/lib/slack_helpers.rb +1 -1
- data/test/integration/ticket_tasks_api_test.rb +1 -1
- data/test/unit/adapters/git_adapter_test.rb +29 -8
- data/test/unit/adapters/version_control_adapters_api_test.rb +2 -0
- data/test/unit/controllers/hooks_controller_test.rb +4 -4
- data/test/unit/models/commit_test.rb +2 -2
- data/test/unit/models/project_test.rb +2 -2
- data/test/unit/models/pull_request_test.rb +9 -4
- data/test/unit/models/task_test.rb +1 -1
- data/test/unit/models/ticket_test.rb +1 -1
- metadata +31 -16
@@ -14,6 +14,8 @@ module CommitSynchronizer
|
|
14
14
|
|
15
15
|
unreachable_commits = project.commits.unreachable.pluck(:sha)
|
16
16
|
flag_reachable_commits! unreachable_commits & expected_commits
|
17
|
+
|
18
|
+
project.update_column :head_sha, project.repo.branch("master")
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
@@ -82,6 +84,7 @@ private
|
|
82
84
|
commit = find_by_sha(native_commit.sha)
|
83
85
|
return commit if commit
|
84
86
|
|
87
|
+
$!.additional_information["project"] = project.slug
|
85
88
|
$!.additional_information["native_commit.sha"] = native_commit.sha
|
86
89
|
raise
|
87
90
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Github::PullsController < ApplicationController
|
2
|
+
|
3
|
+
def index
|
4
|
+
@pulls = Github::PullRequest.order(created_at: :desc).preload(:project, :user)
|
5
|
+
@labels = @pulls.flat_map(&:labels).uniq { |label| label["name"] }.sort_by { |label| label["name"] }
|
6
|
+
@selected_labels = params.fetch(:only, "").split(/,\s*/)
|
7
|
+
@selected_labels = @labels.map { |label| label["name"] } if @selected_labels.none?
|
8
|
+
@selected_labels -= params.fetch(:except, "").split(/,\s*/)
|
9
|
+
@title = "Pull Requests (#{@pulls.count})"
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -3,7 +3,7 @@ class ProjectTestsController < ApplicationController
|
|
3
3
|
def index
|
4
4
|
@project = Project.find_by_slug! params[:slug]
|
5
5
|
|
6
|
-
head = params.fetch :at, @project.
|
6
|
+
head = params.fetch :at, @project.head_sha
|
7
7
|
commits = params.fetch(:limit, 500).to_i
|
8
8
|
|
9
9
|
@commits = Houston.benchmark("[project_tests#index] fetch commits") {
|
@@ -35,7 +35,7 @@ class ProjectTestsController < ApplicationController
|
|
35
35
|
@totals = Hash[@test.test_results.group(:status).pluck(:status, "COUNT(*)")]
|
36
36
|
|
37
37
|
begin
|
38
|
-
head = params.fetch :at, @project.
|
38
|
+
head = params.fetch :at, @project.head_sha
|
39
39
|
stop_shas = @test.introduced_in_shas
|
40
40
|
@commits = Houston.benchmark("[project_tests#show] fetch commits") {
|
41
41
|
@project.repo.ancestors(head, including_self: true, limit: 100, hide: stop_shas) }
|
@@ -54,7 +54,7 @@ class ProjectTestsController < ApplicationController
|
|
54
54
|
|
55
55
|
@results = @test.test_results.where(test_run_id: @runs.map(&:id))
|
56
56
|
.joins(:test_run)
|
57
|
-
.select("test_runs.sha",
|
57
|
+
.select("test_runs.sha", "test_results.*")
|
58
58
|
.index_by { |result| result[:sha] }
|
59
59
|
@runs = @runs.index_by(&:sha)
|
60
60
|
end
|
@@ -9,8 +9,8 @@ class ProjectsController < ApplicationController
|
|
9
9
|
@projects = Project \
|
10
10
|
.includes(:owners)
|
11
11
|
.includes(:maintainers)
|
12
|
+
.includes(:head)
|
12
13
|
.unretired
|
13
|
-
.map { |project| ProjectDependencies.new(project) }
|
14
14
|
@test_runs = TestRun.most_recent.index_by(&:project_id)
|
15
15
|
@releases = Release.where(environment_name: "production").most_recent.index_by(&:project_id)
|
16
16
|
end
|
@@ -28,6 +28,50 @@ class ProjectsController < ApplicationController
|
|
28
28
|
@project.roles.build(user: current_user) if @project.roles.none?
|
29
29
|
end
|
30
30
|
|
31
|
+
def new_from_github
|
32
|
+
authorize! :create, Project
|
33
|
+
|
34
|
+
existing_projects = Project.unscoped.where("extended_attributes->'git_location' LIKE '%github.com%'")
|
35
|
+
github_repos = Houston.benchmark "Fetching repos" do
|
36
|
+
Houston.github.repos
|
37
|
+
end
|
38
|
+
@repos = github_repos.map do |repo|
|
39
|
+
project = existing_projects.detect { |project|
|
40
|
+
[repo.git_url, repo.ssh_url, repo.clone_url].member?(project.extended_attributes["git_location"]) }
|
41
|
+
{ name: repo.name,
|
42
|
+
owner: repo.owner.login,
|
43
|
+
full_name: repo.full_name,
|
44
|
+
private: repo[:private],
|
45
|
+
git_location: repo.ssh_url,
|
46
|
+
project: project }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def create_from_github
|
52
|
+
authorize! :create, Project
|
53
|
+
|
54
|
+
repos = params.fetch(:repos, [])
|
55
|
+
projects = Project.transaction do
|
56
|
+
repos.map do |repo|
|
57
|
+
owner, name = repo.split("/")
|
58
|
+
title = name.humanize.gsub(/\b(?<!['’.`])[a-z]/) { $&.capitalize }.gsub("-", "::")
|
59
|
+
Project.create!(
|
60
|
+
name: title,
|
61
|
+
slug: name,
|
62
|
+
version_control_name: "Git",
|
63
|
+
extended_attributes: {"git_location" => "git@github.com:#{repo}.git"})
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
flash[:notice] = "#{projects.count} projects added"
|
68
|
+
redirect_to projects_path
|
69
|
+
|
70
|
+
rescue ActiveRecord::RecordInvalid
|
71
|
+
flash[:error] = $!.message
|
72
|
+
redirect_to :back
|
73
|
+
end
|
74
|
+
|
31
75
|
|
32
76
|
def edit
|
33
77
|
@project = Project.find_by_slug!(params[:id])
|
@@ -1,20 +1,17 @@
|
|
1
1
|
class ReleasesController < ApplicationController
|
2
2
|
include UrlHelper
|
3
|
-
|
3
|
+
include ReleaseHelper
|
4
|
+
before_filter :get_release_and_project, only: [:show, :edit, :update, :destroy]
|
5
|
+
before_filter :get_project_and_environment, only: [:index, :new, :create]
|
4
6
|
before_filter :load_tickets, only: [:new, :edit, :create, :update]
|
5
7
|
|
8
|
+
|
9
|
+
|
6
10
|
def index
|
7
11
|
@title = "Releases • #{@project.name}"
|
8
12
|
@title << " (#{@environment})" if @environment
|
9
13
|
end
|
10
14
|
|
11
|
-
def show
|
12
|
-
@release = @releases.find(params[:id])
|
13
|
-
authorize! :show, @release
|
14
|
-
|
15
|
-
@title = "Release #{@release.release_date.strftime("%b %-d")} • #{@project.name}"
|
16
|
-
end
|
17
|
-
|
18
15
|
def new
|
19
16
|
@title = "New Release (#{@environment}) • #{@project.name}"
|
20
17
|
|
@@ -42,22 +39,6 @@ class ReleasesController < ApplicationController
|
|
42
39
|
end
|
43
40
|
end
|
44
41
|
|
45
|
-
def edit
|
46
|
-
@release = @releases.find(params[:id])
|
47
|
-
authorize! :update, @release
|
48
|
-
|
49
|
-
if params[:recreate]
|
50
|
-
if @release.can_read_commits?
|
51
|
-
@release.load_commits!
|
52
|
-
@release.load_tickets!
|
53
|
-
@release.build_changes_from_commits
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
@release.release_changes = [ReleaseChange.new(@release, "", "")] if @release.release_changes.none?
|
58
|
-
@release.valid?
|
59
|
-
end
|
60
|
-
|
61
42
|
def create
|
62
43
|
@release = @releases.new(params[:release])
|
63
44
|
@release.user = current_user
|
@@ -81,8 +62,39 @@ class ReleasesController < ApplicationController
|
|
81
62
|
end
|
82
63
|
end
|
83
64
|
|
65
|
+
|
66
|
+
|
67
|
+
def show
|
68
|
+
authorize! :show, @release
|
69
|
+
|
70
|
+
@title = "Release #{@release.release_date.strftime("%b %-d")} • #{@project.name}"
|
71
|
+
|
72
|
+
if request.format.oembed?
|
73
|
+
render json: {
|
74
|
+
version: "1.0",
|
75
|
+
type: "link",
|
76
|
+
author_name: "#{@project.slug} / #{@release.environment_name}",
|
77
|
+
title: format_release_subject(@release),
|
78
|
+
html: format_release_description(@release) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def edit
|
83
|
+
authorize! :update, @release
|
84
|
+
|
85
|
+
if params[:recreate]
|
86
|
+
if @release.can_read_commits?
|
87
|
+
@release.load_commits!
|
88
|
+
@release.load_tickets!
|
89
|
+
@release.build_changes_from_commits
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
@release.release_changes = [ReleaseChange.new(@release, "", "")] if @release.release_changes.none?
|
94
|
+
@release.valid?
|
95
|
+
end
|
96
|
+
|
84
97
|
def update
|
85
|
-
@release = @releases.find(params[:id])
|
86
98
|
authorize! :update, @release
|
87
99
|
|
88
100
|
if @release.update_attributes(params[:release])
|
@@ -93,7 +105,6 @@ class ReleasesController < ApplicationController
|
|
93
105
|
end
|
94
106
|
|
95
107
|
def destroy
|
96
|
-
@release = @releases.find(params[:id])
|
97
108
|
authorize! :destroy, @release
|
98
109
|
|
99
110
|
@release.destroy
|
@@ -103,6 +114,11 @@ class ReleasesController < ApplicationController
|
|
103
114
|
|
104
115
|
private
|
105
116
|
|
117
|
+
def get_release_and_project
|
118
|
+
@release = Release.find(params[:id])
|
119
|
+
@project = @release.project
|
120
|
+
end
|
121
|
+
|
106
122
|
def get_project_and_environment
|
107
123
|
@project = Project.find_by_slug!(params[:project_id])
|
108
124
|
@environment = params[:environment] || @project.environments_with_release_notes.first
|
@@ -75,6 +75,14 @@ module ApplicationHelper
|
|
75
75
|
|
76
76
|
|
77
77
|
|
78
|
+
def pull_request_label(label)
|
79
|
+
background = "##{label["color"]}"
|
80
|
+
foreground = "#fff"
|
81
|
+
foreground = "#333" if %w{#f7c6c7 #d4c5f9 #fbca04 #fad8c7 #bfe5bf}.member? background
|
82
|
+
"<span class=\"label\" style=\"background: #{background}; color: #{foreground};\">#{label["name"]}</span>".html_safe
|
83
|
+
end
|
84
|
+
|
85
|
+
|
78
86
|
end
|
79
87
|
|
80
88
|
|
@@ -22,11 +22,11 @@ module AvatarHelper
|
|
22
22
|
# http://en.gravatar.com/site/implement/ruby
|
23
23
|
# http://en.gravatar.com/site/implement/url
|
24
24
|
def gravatar_url(email, options={})
|
25
|
-
url = "
|
25
|
+
url = "https://www.gravatar.com/avatar/#{Digest::MD5::hexdigest(email)}?r=g&d=retro"
|
26
26
|
url << "&s=#{options[:size]}" if options.key?(:size)
|
27
27
|
url
|
28
28
|
end
|
29
29
|
|
30
30
|
|
31
31
|
|
32
|
-
end
|
32
|
+
end
|
@@ -13,8 +13,8 @@ module CommitHelper
|
|
13
13
|
project = commit.project
|
14
14
|
content = block_given? ? yield : "<span class=\"commit-sha\">#{commit.sha[0...7]}</span>".html_safe
|
15
15
|
|
16
|
-
return content unless
|
17
|
-
link_to content,
|
16
|
+
return content unless url = github_commit_url(project, commit.sha)
|
17
|
+
link_to content, url, options.reverse_merge(target: "_blank")
|
18
18
|
end
|
19
19
|
|
20
20
|
def link_to_release_commit_range(release)
|
@@ -1,10 +1,9 @@
|
|
1
1
|
module ProjectHelper
|
2
2
|
|
3
3
|
def with_most_recent_commit(project)
|
4
|
-
|
5
|
-
commit = project.find_commit_by_sha project.repo.branch("master")
|
4
|
+
commit = project.head
|
6
5
|
if commit
|
7
|
-
commit.project = project
|
6
|
+
commit.project = project # so that _Commit_ doesn't load project again
|
8
7
|
yield commit
|
9
8
|
end
|
10
9
|
end
|
@@ -12,7 +11,7 @@ module ProjectHelper
|
|
12
11
|
def with_most_recent_release(project)
|
13
12
|
release = @releases[project.id]
|
14
13
|
if release
|
15
|
-
release.project = project
|
14
|
+
release.project = project # so that _Release_ doesn't load project again
|
16
15
|
yield release
|
17
16
|
end
|
18
17
|
end
|
@@ -20,7 +19,7 @@ module ProjectHelper
|
|
20
19
|
def with_most_recent_test_run(project)
|
21
20
|
test_run = @test_runs[project.id]
|
22
21
|
if test_run
|
23
|
-
test_run.project = project
|
22
|
+
test_run.project = project # so that _TestRun_ doesn't load project again
|
24
23
|
yield test_run
|
25
24
|
end
|
26
25
|
end
|
@@ -4,6 +4,17 @@ module ReleaseHelper
|
|
4
4
|
"<span class=\"weekday\">#{date.strftime("%A")}</span> #{date.strftime("%b %e, %Y")}".html_safe
|
5
5
|
end
|
6
6
|
|
7
|
+
def format_release_subject(release)
|
8
|
+
release.date.strftime("%b %e, %Y • ") + release.released_at.strftime("%-I:%M%p").downcase
|
9
|
+
end
|
10
|
+
|
11
|
+
def format_release_description(release)
|
12
|
+
ordered_by_tag(release.release_changes)
|
13
|
+
.map { |change| "#{change.tag.name.upcase} #{change.description}" }
|
14
|
+
.join("\r\n")
|
15
|
+
.html_safe
|
16
|
+
end
|
17
|
+
|
7
18
|
def ordered_by_tag(changes)
|
8
19
|
changes.sort_by { |change| change.tag ? change.tag.position : 99 }
|
9
20
|
end
|
@@ -3,7 +3,7 @@ module TimelineHelper
|
|
3
3
|
def render_timeline_gap_for(date_range)
|
4
4
|
days = date_range.end - date_range.begin
|
5
5
|
if days < 3
|
6
|
-
date_range.inject("") { |html, date| html << render_timeline_date(date) }.html_safe
|
6
|
+
date_range.to_a.reverse.inject("") { |html, date| html << render_timeline_date(date) }.html_safe
|
7
7
|
else
|
8
8
|
<<-HTML.html_safe
|
9
9
|
<div class="timeline-date-gap"></div>
|
data/app/helpers/url_helper.rb
CHANGED
@@ -48,24 +48,6 @@ module UrlHelper
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
def release_path(release, options={})
|
52
|
-
super(release.project.to_param, release.environment_name, release, options)
|
53
|
-
end
|
54
|
-
|
55
|
-
def edit_release_path(release, options={})
|
56
|
-
super(release.project.to_param, release.environment_name, release, options)
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
def release_url(release, options={})
|
62
|
-
super(release.project.to_param, release.environment_name, release, options)
|
63
|
-
end
|
64
|
-
|
65
|
-
def edit_release_url(release, options={})
|
66
|
-
super(release.project.to_param, release.environment_name, release, options)
|
67
|
-
end
|
68
|
-
|
69
51
|
def new_release_url(release, options={})
|
70
52
|
super(release.project.to_param, release.environment_name, options.merge(deploy_id: release.deploy_id))
|
71
53
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class CacheKeyDependencies
|
2
|
+
attr_reader :project
|
3
|
+
|
4
|
+
def self.for(*projects)
|
5
|
+
projects = projects[0] if projects.length == 1 && projects[0].respond_to?(:each)
|
6
|
+
projects.each do |project|
|
7
|
+
begin
|
8
|
+
self.new(project).perform!
|
9
|
+
rescue StandardError => e
|
10
|
+
Houston.report_exception(e)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(project)
|
16
|
+
@project = ProjectDependencies.new(project)
|
17
|
+
end
|
18
|
+
|
19
|
+
def perform!
|
20
|
+
KeyDependency.all.each do |dependency|
|
21
|
+
version = ProjectDependency.new(project, dependency).version
|
22
|
+
project.extended_attributes = project.extended_attributes.merge(
|
23
|
+
"key_dependency.#{dependency.slug}" => version)
|
24
|
+
end
|
25
|
+
project.update_column :extended_attributes, project.extended_attributes
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/app/mailers/view_mailer.rb
CHANGED
data/app/models/commit.rb
CHANGED
@@ -21,21 +21,63 @@ module Github
|
|
21
21
|
validates :number, uniqueness: { scope: :project_id }
|
22
22
|
|
23
23
|
class << self
|
24
|
-
|
24
|
+
# Makes X + Y requests to GitHub
|
25
|
+
# where X is the number of projects in Houston on GitHub
|
26
|
+
# and Y is the number of pull requests for those projects
|
27
|
+
#
|
28
|
+
# We _could_ group repos by their owner and fetch `org_issues`
|
29
|
+
# but that will only work for organizations, not personal
|
30
|
+
# accounts.
|
31
|
+
#
|
32
|
+
# This method can chomp through your rate limit rather quickly.
|
33
|
+
# Also, on my computer it took 19 seconds to fetch 39 pull
|
34
|
+
# requests from 52 repos.
|
35
|
+
def fetch!(projects = Project.unretired)
|
36
|
+
repos = projects
|
37
|
+
.where("extended_attributes->'git_location' LIKE '%github.com%'")
|
38
|
+
.pluck("extended_attributes->'git_location'")
|
39
|
+
.map { |url| _repo_name_from_url(url) }
|
40
|
+
.compact
|
41
|
+
|
25
42
|
Houston.benchmark "Fetching pull requests" do
|
26
|
-
|
43
|
+
requests = 0
|
44
|
+
issues = repos.flat_map do |repo|
|
45
|
+
_fetch_issues_for!(repo).tap do |results|
|
46
|
+
requests += 1 + (results.length / 30)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
pulls = issues
|
27
51
|
.select { |issue| !issue.pull_request.nil? }
|
28
|
-
.map { |issue|
|
29
|
-
|
30
|
-
|
31
|
-
.
|
52
|
+
.map { |issue|
|
53
|
+
requests += 1
|
54
|
+
repo = issue.pull_request.url[/https:\/\/api.github.com\/repos\/(.*)\/pulls\/\d+/, 1]
|
55
|
+
Houston.github.pull_request(repo, issue.number)
|
56
|
+
.to_h
|
57
|
+
.merge(labels: issue.labels)
|
58
|
+
.with_indifferent_access }
|
59
|
+
|
60
|
+
Rails.logger.info "[pulls] #{requests} requests; #{Houston.github.last_response.headers["x-ratelimit-remaining"]} remaining"
|
61
|
+
pulls
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def _repo_name_from_url(url)
|
66
|
+
url[/\Agit@github\.com:(.*)\.git\Z/, 1] || url[/\Agit:\/\/github.com\/(.*)\.git\Z/, 1]
|
67
|
+
end
|
68
|
+
|
69
|
+
def _fetch_issues_for!(repo)
|
70
|
+
if repo.end_with? "/*"
|
71
|
+
Houston.github.org_issues(repo[0...-2], filter: "all", state: "open")
|
72
|
+
else
|
73
|
+
Houston.github.issues(repo, filter: "all", state: "open")
|
32
74
|
end
|
75
|
+
rescue Octokit::NotFound
|
76
|
+
[]
|
33
77
|
end
|
34
78
|
|
35
|
-
def sync!
|
36
|
-
expected_pulls = fetch!
|
37
|
-
expected_pulls.select! { |pr| pr["base"]["repo"]["name"] == pr["head"]["repo"]["name"] }
|
38
|
-
# select only ones where head and base are the same repo
|
79
|
+
def sync!(projects = Project.unretired)
|
80
|
+
expected_pulls = fetch!(projects)
|
39
81
|
Houston.benchmark "Syncing pull requests" do
|
40
82
|
existing_pulls = all.to_a
|
41
83
|
|
@@ -56,7 +98,9 @@ module Github
|
|
56
98
|
|
57
99
|
existing_pr ||= Github::PullRequest.new
|
58
100
|
existing_pr.merge_attributes(expected_pr)
|
59
|
-
existing_pr.save
|
101
|
+
unless existing_pr.save
|
102
|
+
Rails.logger.warn "\e[31m[pulls] Invalid PR: #{existing_pr.errors.full_messages.join("; ")}\e[0m"
|
103
|
+
end
|
60
104
|
existing_pr
|
61
105
|
end
|
62
106
|
end
|
@@ -93,42 +137,52 @@ module Github
|
|
93
137
|
end
|
94
138
|
|
95
139
|
def labeled(*labels)
|
96
|
-
where(["
|
140
|
+
where(["exists (select 1 from jsonb_array_elements(pull_requests.json_labels) as \"label\" where \"label\"->>'name' IN (?))", labels])
|
97
141
|
end
|
98
142
|
end
|
99
143
|
|
100
144
|
|
101
145
|
|
102
146
|
def labels=(value)
|
103
|
-
|
147
|
+
self.json_labels = value.map { |label| label.to_h.stringify_keys.pick("name", "color") }
|
148
|
+
end
|
149
|
+
|
150
|
+
def labels
|
151
|
+
json_labels
|
104
152
|
end
|
105
153
|
|
106
154
|
def add_label!(label, options={})
|
155
|
+
label = label.to_h.stringify_keys.pick("name", "color")
|
156
|
+
|
107
157
|
transaction do
|
108
158
|
pr = self.class.lock.find id
|
109
|
-
|
159
|
+
new_labels = pr.json_labels.reject { |l| l["name"] == label["name"] } + [label]
|
160
|
+
pr.update_attributes! json_labels: new_labels, actor: options[:as]
|
110
161
|
end
|
111
162
|
end
|
112
163
|
|
113
164
|
def remove_label!(label, options={})
|
165
|
+
label = label.to_h.stringify_keys.pick("name", "color")
|
166
|
+
|
114
167
|
transaction do
|
115
168
|
pr = self.class.lock.find id
|
116
|
-
|
169
|
+
new_labels = pr.json_labels.reject { |l| l["name"] == label["name"] }
|
170
|
+
pr.update_attributes! json_labels: new_labels, actor: options[:as]
|
117
171
|
end
|
118
172
|
end
|
119
173
|
|
120
174
|
|
121
175
|
|
122
176
|
def merge_attributes(pr)
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
177
|
+
self.repo = pr["base"]["repo"]["name"] unless repo
|
178
|
+
self.number = pr["number"] unless number
|
179
|
+
self.username = pr["user"]["login"] unless username
|
180
|
+
self.avatar_url = pr["user"]["avatar_url"] unless avatar_url
|
181
|
+
self.url = pr["html_url"] unless url
|
182
|
+
self.base_sha = pr["base"]["sha"] unless base_sha
|
183
|
+
self.base_ref = pr["base"]["ref"] unless base_ref
|
184
|
+
|
185
|
+
self.created_at = pr["created_at"]
|
132
186
|
self.title = pr["title"]
|
133
187
|
self.body = pr["body"]
|
134
188
|
self.head_sha = pr["head"]["sha"]
|
@@ -145,11 +199,13 @@ module Github
|
|
145
199
|
end
|
146
200
|
|
147
201
|
def associate_user_with_self
|
148
|
-
self.user = User.
|
202
|
+
self.user = User.find_by_github_username(username)
|
149
203
|
end
|
150
204
|
|
151
205
|
def associate_commits_with_self
|
152
|
-
|
206
|
+
Houston.try({max_tries: 2, base: 0}, ActiveRecord::RecordNotUnique) do
|
207
|
+
self.commits = project.commits.between(base_sha, head_sha)
|
208
|
+
end
|
153
209
|
end
|
154
210
|
|
155
211
|
end
|