From b372968e936a8b02f8d7ff73a1e1cc25b332406c Mon Sep 17 00:00:00 2001 From: Baldinof Date: Tue, 22 Mar 2016 10:56:44 +0100 Subject: Add number sign on external issue reference text --- app/models/external_issue.rb | 8 ++++++++ spec/models/external_issue_spec.rb | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb index 2ca79df0a29..92f1f174941 100644 --- a/app/models/external_issue.rb +++ b/app/models/external_issue.rb @@ -34,7 +34,15 @@ class ExternalIssue %r{(?\b([A-Z][A-Z0-9_]+-)\d+)} end + def self.reference_prefix + '#' + end + def to_reference(_from_project = nil) id end + + def reference_link_text(from_project = nil) + "#{self.class.reference_prefix}#{id}" + end end diff --git a/spec/models/external_issue_spec.rb b/spec/models/external_issue_spec.rb index 9b144dd1ecc..b3d0c4efe98 100644 --- a/spec/models/external_issue_spec.rb +++ b/spec/models/external_issue_spec.rb @@ -36,4 +36,10 @@ describe ExternalIssue, models: true do expect(issue.title).to eq "External Issue #{issue}" end end + + describe '#reference_link_text' do + it 'returns a String reference to the object' do + expect(issue.reference_link_text).to eq '#EXT-1234' + end + end end -- cgit v1.2.1 From 3cf512362ef6e459c4a10f53818db799b9b1a248 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 4 Apr 2016 15:39:08 +0200 Subject: Add notice about GitLab Runner to requirements docs This is related to !14589, and problems that may stem from running GitLab Runner on same machine user installed GitLab web app on. --- doc/install/requirements.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 03cb08dd1f1..03433a72fa2 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -79,6 +79,16 @@ With less memory GitLab will give strange errors during the reconfigure run and Notice: The 25 workers of Sidekiq will show up as separate processes in your process overview (such as top or htop) but they share the same RAM allocation since Sidekiq is a multithreaded application. Please see the section below about Unicorn workers for information about many you need of those. +## Gitlab Runner + +We strongly advise against installing GitLab Runner on the same machine you plan to install GitLab on. Depending on how you decide to configure GitLab Runner and what tools you use to exercise your application in the CI environment, GitLab Runner can consume significant amount of available memory. + +Memory consumption calculations, that are available above, will not be valid if you decide to run GitLab Runner and GitLab web application on the same machine. + +It is also not safe to install everything on a single machine, because of the security reasons - especially when you plan to use shell executor with GitLab Runner. + +We recommend using a separate machine for each GitLab Runner, if you plan to use CI features. + ## Unicorn Workers It's possible to increase the amount of unicorn workers and this will usually help for to reduce the response time of the applications and increase the ability to handle parallel requests. -- cgit v1.2.1 From 3122e5cc847b224d5531f23a9c2fe9bc2043b01f Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Mon, 11 Apr 2016 12:35:26 +0300 Subject: Add link to Runner security doc [ci skip] --- doc/install/requirements.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 03433a72fa2..eb9fe5e1b1b 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -81,13 +81,23 @@ Notice: The 25 workers of Sidekiq will show up as separate processes in your pro ## Gitlab Runner -We strongly advise against installing GitLab Runner on the same machine you plan to install GitLab on. Depending on how you decide to configure GitLab Runner and what tools you use to exercise your application in the CI environment, GitLab Runner can consume significant amount of available memory. +We strongly advise against installing GitLab Runner on the same machine you plan +to install GitLab on. Depending on how you decide to configure GitLab Runner and +what tools you use to exercise your application in the CI environment, GitLab +Runner can consume significant amount of available memory. -Memory consumption calculations, that are available above, will not be valid if you decide to run GitLab Runner and GitLab web application on the same machine. +Memory consumption calculations, that are available above, will not be valid if +you decide to run GitLab Runner and the GitLab Rails application on the same +machine. -It is also not safe to install everything on a single machine, because of the security reasons - especially when you plan to use shell executor with GitLab Runner. +It is also not safe to install everything on a single machine, because of the +[security reasons] - especially when you plan to use shell executor with GitLab +Runner. -We recommend using a separate machine for each GitLab Runner, if you plan to use CI features. +We recommend using a separate machine for each GitLab Runner, if you plan to +use the CI features. + +[security reasons]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/security/index.md ## Unicorn Workers -- cgit v1.2.1 From d86190eead0075d1b0ba7e73ff2efa8a610b5398 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Mon, 11 Apr 2016 12:41:27 +0300 Subject: Add a note about installing Runners in ci/runners/README.md --- doc/ci/runners/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md index 295d953db11..36e90e21419 100644 --- a/doc/ci/runners/README.md +++ b/doc/ci/runners/README.md @@ -7,6 +7,10 @@ through the coordinator API of GitLab CI. A runner can be specific to a certain project or serve any project in GitLab CI. A runner that serves all projects is called a shared runner. +Ideally, GitLab Runner should not be installed on the same machine as GitLab. +Read the [requirements documentation](../../install/requirements.md#gitlab-runner) +for more information. + ## Shared vs. Specific Runners A runner that is specific only runs for the specified project. A shared runner @@ -140,7 +144,7 @@ to it. This means that if you have shared runners setup for a project and someone forks that project, the shared runners will also serve jobs of this project. -# Attack vectors in runners +## Attack vectors in Runners Mentioned briefly earlier, but the following things of runners can be exploited. We're always looking for contributions that can mitigate these [Security Considerations](https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/security/index.md). -- cgit v1.2.1 From 3cfbd2b1601842feea0a7739098a90e2d1dccec4 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 11 Apr 2016 18:27:34 +0100 Subject: Added loading icon to import buttons See #14488 for more details --- app/assets/javascripts/importer_status.js.coffee | 39 ++++++++++++++++-------- app/assets/stylesheets/pages/import.scss | 21 +++++++++++++ app/views/import/bitbucket/status.html.haml | 20 ++++++++---- app/views/import/fogbugz/status.html.haml | 15 ++++++--- app/views/import/github/status.html.haml | 15 ++++++--- app/views/import/gitlab/status.html.haml | 15 ++++++--- app/views/import/gitorious/status.html.haml | 15 ++++++--- app/views/import/google_code/status.html.haml | 19 +++++++++--- 8 files changed, 120 insertions(+), 39 deletions(-) diff --git a/app/assets/javascripts/importer_status.js.coffee b/app/assets/javascripts/importer_status.js.coffee index be8d225e73b..c51c4a1a182 100644 --- a/app/assets/javascripts/importer_status.js.coffee +++ b/app/assets/javascripts/importer_status.js.coffee @@ -4,18 +4,33 @@ class @ImporterStatus this.setAutoUpdate() initStatusPage: -> - $(".js-add-to-import").click (event) => - new_namespace = null - tr = $(event.currentTarget).closest("tr") - id = tr.attr("id").replace("repo_", "") - if tr.find(".import-target input").length > 0 - new_namespace = tr.find(".import-target input").prop("value") - tr.find(".import-target").empty().append(new_namespace + "/" + tr.find(".import-target").data("project_name")) - $.post @import_url, {repo_id: id, new_namespace: new_namespace}, dataType: 'script' - - $(".js-import-all").click (event) => - $(".js-add-to-import").each -> - $(this).click() + $(".js-add-to-import") + .off 'click' + .on 'click', (event) => + new_namespace = null + $btn = $(event.currentTarget) + $tr = $btn.closest("tr") + id = $tr.attr("id").replace("repo_", "") + if $tr.find(".import-target input").length > 0 + new_namespace = $tr.find(".import-target input").prop("value") + $tr.find(".import-target").empty().append(new_namespace + "/" + $tr.find(".import-target").data("project_name")) + + $btn + .disable() + .addClass 'is-loading' + + $.post @import_url, {repo_id: id, new_namespace: new_namespace}, dataType: 'script' + + $(".js-import-all") + .off 'click' + .on 'click', (event) => + $btn = $(event.currentTarget) + $btn + .disable() + .addClass 'is-loading' + + $(".js-add-to-import").each -> + $(this).click() setAutoUpdate: -> setInterval (=> diff --git a/app/assets/stylesheets/pages/import.scss b/app/assets/stylesheets/pages/import.scss index 6a99cd9cb94..84cc35239f9 100644 --- a/app/assets/stylesheets/pages/import.scss +++ b/app/assets/stylesheets/pages/import.scss @@ -16,3 +16,24 @@ i.icon-gitorious-big { width: 18px; height: 18px; } + +.import-jobs-from-col, +.import-jobs-to-col { + width: 40%; +} + +.import-jobs-status-col { + width: 20%; +} + +.btn-import { + .loading-icon { + display: none; + } + + &.is-loading { + .loading-icon { + display: inline-block; + } + } +} diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml index aec2e836c9f..134d88481db 100644 --- a/app/views/import/bitbucket/status.html.haml +++ b/app/views/import/bitbucket/status.html.haml @@ -10,13 +10,19 @@ %hr %p - if @incompatible_repos.any? - = button_tag 'Import all compatible projects', class: "btn btn-success js-import-all" + = button_tag class: "btn btn-import btn-success js-import-all" do + = icon('spinner spin', class: 'loading-icon') + Import all compatible projects - else - = button_tag 'Import all projects', class: "btn btn-success js-import-all" + = button_tag class: "btn btn-success js-import-all" do + = icon('spinner spin', class: 'loading-icon') + Import all projects - -.table-holder +.table-responsive %table.table.import-jobs + %colgroup.import-jobs-from-col + %colgroup.import-jobs-to-col + %colgroup.import-jobs-status-col %thead %tr %th From Bitbucket @@ -28,7 +34,7 @@ %td = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: "_blank" %td - %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span @@ -47,7 +53,9 @@ %td.import-target = "#{repo["owner"]}/#{repo["slug"]}" %td.import-actions.job-status - = button_tag "Import", class: "btn js-add-to-import" + = button_tag class: "btn btn-import js-add-to-import" do + = icon('spinner spin', class: 'loading-icon') + Import - @incompatible_repos.each do |repo| %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"} %td diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml index 6ee16c8be4b..f5966fac65b 100644 --- a/app/views/import/fogbugz/status.html.haml +++ b/app/views/import/fogbugz/status.html.haml @@ -13,10 +13,15 @@ how FogBugz email addresses and usernames are imported into GitLab. %hr %p - = button_tag 'Import all projects', class: 'btn btn-success js-import-all' + = button_tag class: 'btn btn-import btn-success js-import-all' do + = icon('spinner spin', class: 'loading-icon') + Import all projects -.table-holder +.table-responsive %table.table.import-jobs + %colgroup.import-jobs-from-col + %colgroup.import-jobs-to-col + %colgroup.import-jobs-status-col %thead %tr %th From FogBugz @@ -28,7 +33,7 @@ %td = project.import_source %td - %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span @@ -47,7 +52,9 @@ %td.import-target = "#{current_user.username}/#{repo.name}" %td.import-actions.job-status - = button_tag "Import", class: "btn js-add-to-import" + = button_tag class: "btn btn-import js-add-to-import" do + = icon('spinner spin', class: 'loading-icon') + Import :javascript new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}"); diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml index 1416ee5bd5a..65432951ec8 100644 --- a/app/views/import/github/status.html.haml +++ b/app/views/import/github/status.html.haml @@ -8,10 +8,15 @@ Select projects you want to import. %hr %p - = button_tag 'Import all projects', class: "btn btn-success js-import-all" + = button_tag class: "btn btn-import btn-success js-import-all" do + = icon('spinner spin', class: 'loading-icon') + Import all projects -.table-holder +.table-responsive %table.table.import-jobs + %colgroup.import-jobs-from-col + %colgroup.import-jobs-to-col + %colgroup.import-jobs-status-col %thead %tr %th From GitHub @@ -23,7 +28,7 @@ %td = link_to project.import_source, "https://github.com/#{project.import_source}", target: "_blank" %td - %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span @@ -42,7 +47,9 @@ %td.import-target = repo.full_name %td.import-actions.job-status - = button_tag "Import", class: "btn js-add-to-import" + = button_tag class: "btn btn-import js-add-to-import" do + = icon('spinner spin', class: 'loading-icon') + Import :javascript new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}"); diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml index 911a55eb85d..f20011f5684 100644 --- a/app/views/import/gitlab/status.html.haml +++ b/app/views/import/gitlab/status.html.haml @@ -8,10 +8,15 @@ Select projects you want to import. %hr %p - = button_tag 'Import all projects', class: "btn btn-success js-import-all" + = button_tag class: "btn btn-import btn-success js-import-all" do + = icon('spinner spin', class: 'loading-icon') + Import all projects -.table-holder +.table-responsive %table.table.import-jobs + %colgroup.import-jobs-from-col + %colgroup.import-jobs-to-col + %colgroup.import-jobs-status-col %thead %tr %th From GitLab.com @@ -23,7 +28,7 @@ %td = link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank" %td - %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span @@ -42,7 +47,9 @@ %td.import-target = repo["path_with_namespace"] %td.import-actions.job-status - = button_tag "Import", class: "btn js-add-to-import" + = button_tag class: "btn js-add-to-import" do + = icon('spinner spin', class: 'loading-icon') + Import :javascript new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}"); diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml index 6b0fa1edf8c..725910ed213 100644 --- a/app/views/import/gitorious/status.html.haml +++ b/app/views/import/gitorious/status.html.haml @@ -8,10 +8,15 @@ Select projects you want to import. %hr %p - = button_tag 'Import all projects', class: "btn btn-success js-import-all" + = button_tag class: "btn btn-import btn-success js-import-all" do + = icon('spinner spin', class: 'loading-icon') + Import all projects -.table-holder +.table-responsive %table.table.import-jobs + %colgroup.import-jobs-from-col + %colgroup.import-jobs-to-col + %colgroup.import-jobs-status-col %thead %tr %th From Gitorious.org @@ -23,7 +28,7 @@ %td = link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank" %td - %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span @@ -42,7 +47,9 @@ %td.import-target = repo.full_name %td.import-actions.job-status - = button_tag "Import", class: "btn js-add-to-import" + = button_tag class: "btn btn-import js-add-to-import" do + = icon('spinner spin', class: 'loading-icon') + Import :javascript new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}"); diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml index 175ef6921cd..2cb0931838b 100644 --- a/app/views/import/google_code/status.html.haml +++ b/app/views/import/google_code/status.html.haml @@ -14,12 +14,19 @@ %hr %p - if @incompatible_repos.any? - = button_tag 'Import all compatible projects', class: "btn btn-success js-import-all" + = button_tag class: "btn btn-import btn-success js-import-all" do + = icon('spinner spin', class: 'loading-icon') + Import all compatible projects - else - = button_tag 'Import all projects', class: "btn btn-success js-import-all" + = button_tag class: "btn btn-import btn-success js-import-all" do + = icon('spinner spin', class: 'loading-icon') + Import all projects -.table-holder +.table-responsive %table.table.import-jobs + %colgroup.import-jobs-from-col + %colgroup.import-jobs-to-col + %colgroup.import-jobs-status-col %thead %tr %th From Google Code @@ -31,7 +38,7 @@ %td = link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank" %td - %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span @@ -50,7 +57,9 @@ %td.import-target = "#{current_user.username}/#{repo.name}" %td.import-actions.job-status - = button_tag "Import", class: "btn js-add-to-import" + = button_tag class: "btn btn-import js-add-to-import" do + = icon('spinner spin', class: 'loading-icon') + Import - @incompatible_repos.each do |repo| %tr{id: "repo_#{repo.id}"} %td -- cgit v1.2.1 From 3918fce5bd073e18addb7d1d4aaf3c81ce8150b0 Mon Sep 17 00:00:00 2001 From: Baldinof Date: Tue, 12 Apr 2016 10:01:52 +0200 Subject: Hide number sign for string prefixed external issues --- app/models/external_issue.rb | 8 +++----- spec/models/external_issue_spec.rb | 13 +++++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb index 92f1f174941..d47b479faa8 100644 --- a/app/models/external_issue.rb +++ b/app/models/external_issue.rb @@ -34,15 +34,13 @@ class ExternalIssue %r{(?\b([A-Z][A-Z0-9_]+-)\d+)} end - def self.reference_prefix - '#' - end - def to_reference(_from_project = nil) id end def reference_link_text(from_project = nil) - "#{self.class.reference_prefix}#{id}" + return "##{id}" if /^\d+$/.match(id) + + id end end diff --git a/spec/models/external_issue_spec.rb b/spec/models/external_issue_spec.rb index b3d0c4efe98..4fc3b065592 100644 --- a/spec/models/external_issue_spec.rb +++ b/spec/models/external_issue_spec.rb @@ -38,8 +38,17 @@ describe ExternalIssue, models: true do end describe '#reference_link_text' do - it 'returns a String reference to the object' do - expect(issue.reference_link_text).to eq '#EXT-1234' + context 'if issue id has a prefix' do + it 'returns the issue ID' do + expect(issue.reference_link_text).to eq 'EXT-1234' + end + end + + context 'if issue id is a number' do + let(:issue) { described_class.new('1234', project) } + it 'returns the issue ID prefixed by #' do + expect(issue.reference_link_text).to eq '#1234' + end end end end -- cgit v1.2.1 From a650af12261b850d9565cbfc473ea82db59f2e3d Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 12 Apr 2016 09:48:39 +0100 Subject: Moved loading icon to match todo loading icon --- app/views/import/base/create.js.haml | 4 ++-- app/views/import/bitbucket/status.html.haml | 6 +++--- app/views/import/fogbugz/status.html.haml | 4 ++-- app/views/import/github/status.html.haml | 4 ++-- app/views/import/gitlab/status.html.haml | 4 ++-- app/views/import/gitorious/status.html.haml | 4 ++-- app/views/import/google_code/status.html.haml | 6 +++--- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/views/import/base/create.js.haml b/app/views/import/base/create.js.haml index d8af0295b2d..ec7a2b86566 100644 --- a/app/views/import/base/create.js.haml +++ b/app/views/import/base/create.js.haml @@ -20,10 +20,10 @@ job.attr("id", "project_#{@project.id}") target_field = job.find(".import-target") target_field.empty() - target_field.append('#{link_to @project.path_with_namespace, namespace_project_path(@project.namespace, @project)}') + target_field.append('#{link_to @project.path_with_namespace, namespace_project_path(@project.namespace, @project)}') $("table.import-jobs tbody").prepend(job) job.addClass("active").find(".import-actions").html(" started") - else :plain job = $("tr#repo_#{@repo_id}") - job.find(".import-actions").html(" Error saving project: #{escape_javascript(@project.errors.full_messages.join(','))}") + job.find(".import-actions").html(" Error saving project: #{escape_javascript(@project.errors.full_messages.join(','))}") diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml index 134d88481db..e24c01f3e0f 100644 --- a/app/views/import/bitbucket/status.html.haml +++ b/app/views/import/bitbucket/status.html.haml @@ -11,12 +11,12 @@ %p - if @incompatible_repos.any? = button_tag class: "btn btn-import btn-success js-import-all" do - = icon('spinner spin', class: 'loading-icon') Import all compatible projects + = icon('spinner spin', class: 'loading-icon') - else = button_tag class: "btn btn-success js-import-all" do - = icon('spinner spin', class: 'loading-icon') Import all projects + = icon('spinner spin', class: 'loading-icon') .table-responsive %table.table.import-jobs @@ -54,8 +54,8 @@ = "#{repo["owner"]}/#{repo["slug"]}" %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do - = icon('spinner spin', class: 'loading-icon') Import + = icon('spinner spin', class: 'loading-icon') - @incompatible_repos.each do |repo| %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"} %td diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml index f5966fac65b..d842d1cbd94 100644 --- a/app/views/import/fogbugz/status.html.haml +++ b/app/views/import/fogbugz/status.html.haml @@ -14,8 +14,8 @@ %hr %p = button_tag class: 'btn btn-import btn-success js-import-all' do - = icon('spinner spin', class: 'loading-icon') Import all projects + = icon('spinner spin', class: 'loading-icon') .table-responsive %table.table.import-jobs @@ -53,8 +53,8 @@ = "#{current_user.username}/#{repo.name}" %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do - = icon('spinner spin', class: 'loading-icon') Import + = icon('spinner spin', class: 'loading-icon') :javascript new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}"); diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml index 65432951ec8..d6fa0d8023b 100644 --- a/app/views/import/github/status.html.haml +++ b/app/views/import/github/status.html.haml @@ -9,8 +9,8 @@ %hr %p = button_tag class: "btn btn-import btn-success js-import-all" do - = icon('spinner spin', class: 'loading-icon') Import all projects + = icon('spinner spin', class: 'loading-icon') .table-responsive %table.table.import-jobs @@ -48,8 +48,8 @@ = repo.full_name %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do - = icon('spinner spin', class: 'loading-icon') Import + = icon('spinner spin', class: 'loading-icon') :javascript new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}"); diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml index f20011f5684..8f79f385610 100644 --- a/app/views/import/gitlab/status.html.haml +++ b/app/views/import/gitlab/status.html.haml @@ -9,8 +9,8 @@ %hr %p = button_tag class: "btn btn-import btn-success js-import-all" do - = icon('spinner spin', class: 'loading-icon') Import all projects + = icon('spinner spin', class: 'loading-icon') .table-responsive %table.table.import-jobs @@ -48,8 +48,8 @@ = repo["path_with_namespace"] %td.import-actions.job-status = button_tag class: "btn js-add-to-import" do - = icon('spinner spin', class: 'loading-icon') Import + = icon('spinner spin', class: 'loading-icon') :javascript new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}"); diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml index 725910ed213..f0256e0f934 100644 --- a/app/views/import/gitorious/status.html.haml +++ b/app/views/import/gitorious/status.html.haml @@ -9,8 +9,8 @@ %hr %p = button_tag class: "btn btn-import btn-success js-import-all" do - = icon('spinner spin', class: 'loading-icon') Import all projects + = icon('spinner spin', class: 'loading-icon') .table-responsive %table.table.import-jobs @@ -48,8 +48,8 @@ = repo.full_name %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do - = icon('spinner spin', class: 'loading-icon') Import + = icon('spinner spin', class: 'loading-icon') :javascript new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}"); diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml index 2cb0931838b..c4ac1b4f9b7 100644 --- a/app/views/import/google_code/status.html.haml +++ b/app/views/import/google_code/status.html.haml @@ -15,12 +15,12 @@ %p - if @incompatible_repos.any? = button_tag class: "btn btn-import btn-success js-import-all" do - = icon('spinner spin', class: 'loading-icon') Import all compatible projects + = icon('spinner spin', class: 'loading-icon') - else = button_tag class: "btn btn-import btn-success js-import-all" do - = icon('spinner spin', class: 'loading-icon') Import all projects + = icon('spinner spin', class: 'loading-icon') .table-responsive %table.table.import-jobs @@ -58,8 +58,8 @@ = "#{current_user.username}/#{repo.name}" %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do - = icon('spinner spin', class: 'loading-icon') Import + = icon('spinner spin', class: 'loading-icon') - @incompatible_repos.each do |repo| %tr{id: "repo_#{repo.id}"} %td -- cgit v1.2.1 From e57a9551df0a6b6de218bf881322fcba5a77485b Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Wed, 13 Apr 2016 12:02:20 +0530 Subject: Don't populate the password field on signup validation errors. - Previously, we were pulling `params[:user][:password] as the default value for the password field. This is incorrect; we should be pulling it from `@user.password` or the like. --- app/views/devise/shared/_signup_box.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index cb93ff2465e..7f23dbfed99 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -17,7 +17,7 @@ %div = f.email_field :email, class: "form-control middle", value: user[:email], placeholder: "Email", required: true .form-group.append-bottom-20#password-strength - = f.password_field :password, class: "form-control bottom", value: user[:password], id: "user_password_sign_up", placeholder: "Password", required: true + = f.password_field :password, class: "form-control bottom", id: "user_password_sign_up", placeholder: "Password", required: true %div - if current_application_settings.recaptcha_enabled = recaptcha_tags -- cgit v1.2.1 From d5f44d8a4b23b20f8292147db9c7f7730de70a3b Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Wed, 13 Apr 2016 12:57:40 +0530 Subject: Don't retrieve default values from `params` - In the signup page. --- app/views/devise/shared/_signup_box.html.haml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index 7f23dbfed99..e5607dacd0d 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -6,16 +6,15 @@ .login-heading %h3 Create an account .login-body - - user = params[:user].present? ? params[:user] : {} = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| .devise-errors = devise_error_messages! %div - = f.text_field :name, class: "form-control top", value: user[:name], placeholder: "Name", required: true + = f.text_field :name, class: "form-control top", placeholder: "Name", required: true %div - = f.text_field :username, class: "form-control middle", value: user[:username], placeholder: "Username", required: true + = f.text_field :username, class: "form-control middle", placeholder: "Username", required: true %div - = f.email_field :email, class: "form-control middle", value: user[:email], placeholder: "Email", required: true + = f.email_field :email, class: "form-control middle", placeholder: "Email", required: true .form-group.append-bottom-20#password-strength = f.password_field :password, class: "form-control bottom", id: "user_password_sign_up", placeholder: "Password", required: true %div -- cgit v1.2.1 From 3d438870f34cb1bd5667bc5db2f848c4f82d5d25 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Apr 2016 09:32:02 +0100 Subject: Updated based on feedback --- app/assets/javascripts/importer_status.js.coffee | 20 ++++++++++---------- app/views/import/base/create.js.haml | 2 +- app/views/import/bitbucket/status.html.haml | 6 +++--- app/views/import/fogbugz/status.html.haml | 4 ++-- app/views/import/github/status.html.haml | 4 ++-- app/views/import/gitlab/status.html.haml | 4 ++-- app/views/import/gitorious/status.html.haml | 4 ++-- app/views/import/google_code/status.html.haml | 6 +++--- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/app/assets/javascripts/importer_status.js.coffee b/app/assets/javascripts/importer_status.js.coffee index c51c4a1a182..95f9f86c0ad 100644 --- a/app/assets/javascripts/importer_status.js.coffee +++ b/app/assets/javascripts/importer_status.js.coffee @@ -4,16 +4,16 @@ class @ImporterStatus this.setAutoUpdate() initStatusPage: -> - $(".js-add-to-import") + $('.js-add-to-import') .off 'click' .on 'click', (event) => new_namespace = null $btn = $(event.currentTarget) - $tr = $btn.closest("tr") - id = $tr.attr("id").replace("repo_", "") - if $tr.find(".import-target input").length > 0 - new_namespace = $tr.find(".import-target input").prop("value") - $tr.find(".import-target").empty().append(new_namespace + "/" + $tr.find(".import-target").data("project_name")) + $tr = $btn.closest('tr') + id = $tr.attr('id').replace('repo_', '') + if $tr.find('.import-target input').length > 0 + new_namespace = $tr.find('.import-target input').prop('value') + $tr.find('.import-target').empty().append("#{new_namespace} / #{$tr.find('.import-target').data('project_name')}") $btn .disable() @@ -21,15 +21,15 @@ class @ImporterStatus $.post @import_url, {repo_id: id, new_namespace: new_namespace}, dataType: 'script' - $(".js-import-all") + $('.js-import-all') .off 'click' - .on 'click', (event) => - $btn = $(event.currentTarget) + .on 'click', (e) => + $btn = $(e.currentTarget) $btn .disable() .addClass 'is-loading' - $(".js-add-to-import").each -> + $('.js-add-to-import').each -> $(this).click() setAutoUpdate: -> diff --git a/app/views/import/base/create.js.haml b/app/views/import/base/create.js.haml index ec7a2b86566..dfebf7768d9 100644 --- a/app/views/import/base/create.js.haml +++ b/app/views/import/base/create.js.haml @@ -26,4 +26,4 @@ - else :plain job = $("tr#repo_#{@repo_id}") - job.find(".import-actions").html(" Error saving project: #{escape_javascript(@project.errors.full_messages.join(','))}") + job.find(".import-actions").html(" Error saving project: #{escape_javascript(@project.errors.full_messages.join(','))}") diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml index e24c01f3e0f..6e993e58f0d 100644 --- a/app/views/import/bitbucket/status.html.haml +++ b/app/views/import/bitbucket/status.html.haml @@ -12,11 +12,11 @@ - if @incompatible_repos.any? = button_tag class: "btn btn-import btn-success js-import-all" do Import all compatible projects - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") - else = button_tag class: "btn btn-success js-import-all" do Import all projects - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") .table-responsive %table.table.import-jobs @@ -55,7 +55,7 @@ %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do Import - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") - @incompatible_repos.each do |repo| %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"} %td diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml index d842d1cbd94..d3d3c595c17 100644 --- a/app/views/import/fogbugz/status.html.haml +++ b/app/views/import/fogbugz/status.html.haml @@ -15,7 +15,7 @@ %p = button_tag class: 'btn btn-import btn-success js-import-all' do Import all projects - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") .table-responsive %table.table.import-jobs @@ -54,7 +54,7 @@ %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do Import - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") :javascript new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}"); diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml index d6fa0d8023b..9639da4cb58 100644 --- a/app/views/import/github/status.html.haml +++ b/app/views/import/github/status.html.haml @@ -10,7 +10,7 @@ %p = button_tag class: "btn btn-import btn-success js-import-all" do Import all projects - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") .table-responsive %table.table.import-jobs @@ -49,7 +49,7 @@ %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do Import - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") :javascript new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}"); diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml index 8f79f385610..e3a356b5379 100644 --- a/app/views/import/gitlab/status.html.haml +++ b/app/views/import/gitlab/status.html.haml @@ -10,7 +10,7 @@ %p = button_tag class: "btn btn-import btn-success js-import-all" do Import all projects - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") .table-responsive %table.table.import-jobs @@ -49,7 +49,7 @@ %td.import-actions.job-status = button_tag class: "btn js-add-to-import" do Import - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") :javascript new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}"); diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml index f0256e0f934..267eee4f262 100644 --- a/app/views/import/gitorious/status.html.haml +++ b/app/views/import/gitorious/status.html.haml @@ -10,7 +10,7 @@ %p = button_tag class: "btn btn-import btn-success js-import-all" do Import all projects - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") .table-responsive %table.table.import-jobs @@ -49,7 +49,7 @@ %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do Import - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") :javascript new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}"); diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml index c4ac1b4f9b7..5ada6b174eb 100644 --- a/app/views/import/google_code/status.html.haml +++ b/app/views/import/google_code/status.html.haml @@ -16,11 +16,11 @@ - if @incompatible_repos.any? = button_tag class: "btn btn-import btn-success js-import-all" do Import all compatible projects - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") - else = button_tag class: "btn btn-import btn-success js-import-all" do Import all projects - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") .table-responsive %table.table.import-jobs @@ -59,7 +59,7 @@ %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do Import - = icon('spinner spin', class: 'loading-icon') + = icon("spinner spin", class: "loading-icon") - @incompatible_repos.each do |repo| %tr{id: "repo_#{repo.id}"} %td -- cgit v1.2.1 From 65410e63ac8c2e4e25acabb73ede6a2dfdc3d829 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Apr 2016 10:15:38 +0100 Subject: Variable name --- app/assets/javascripts/importer_status.js.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/importer_status.js.coffee b/app/assets/javascripts/importer_status.js.coffee index 95f9f86c0ad..2eb151a641b 100644 --- a/app/assets/javascripts/importer_status.js.coffee +++ b/app/assets/javascripts/importer_status.js.coffee @@ -6,9 +6,9 @@ class @ImporterStatus initStatusPage: -> $('.js-add-to-import') .off 'click' - .on 'click', (event) => + .on 'click', (e) => new_namespace = null - $btn = $(event.currentTarget) + $btn = $(e.currentTarget) $tr = $btn.closest('tr') id = $tr.attr('id').replace('repo_', '') if $tr.find('.import-target input').length > 0 -- cgit v1.2.1 From e490a54105b6c820e330514aeb91d004997b031c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Apr 2016 14:50:48 +0100 Subject: Discussion notes update At the moment discussion notes are rendered in a list but arent actually a list item and that can cause overflow issues Moved the dates to be in the header like other notes Fixed overlapping issue on mobile --- app/assets/stylesheets/framework/timeline.scss | 3 +-- app/assets/stylesheets/pages/notes.scss | 6 ++++++ app/views/projects/notes/_discussion.html.haml | 23 +++++++++++----------- app/views/projects/notes/_notes.html.haml | 3 ++- .../projects/notes/discussions/_active.html.haml | 6 +----- .../projects/notes/discussions/_commit.html.haml | 9 +++------ .../projects/notes/discussions/_outdated.html.haml | 6 +----- 7 files changed, 25 insertions(+), 31 deletions(-) diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss index b91f2f6f898..f0ec250de2b 100644 --- a/app/assets/stylesheets/framework/timeline.scss +++ b/app/assets/stylesheets/framework/timeline.scss @@ -39,8 +39,7 @@ .diff-file { border: 1px solid $border-color; border-bottom: none; - margin-left: 0; - margin-right: 0; + margin: 0; } } diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index e421a31549a..7489d5de5f0 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -198,6 +198,12 @@ ul.notes { color: $notes-light-color; } +.discussion-headline-light { + a { + color: $gl-link-color; + } +} + /** * Actions for Discussions/Notes */ diff --git a/app/views/projects/notes/_discussion.html.haml b/app/views/projects/notes/_discussion.html.haml index b8068835b3a..b66fead09b7 100644 --- a/app/views/projects/notes/_discussion.html.haml +++ b/app/views/projects/notes/_discussion.html.haml @@ -1,13 +1,12 @@ - note = discussion_notes.first -.timeline-entry - .timeline-entry-inner - .timeline-icon - = link_to user_path(note.author) do - = image_tag avatar_icon(note.author_email), class: "avatar s40" - .timeline-content - - if note.for_merge_request? - - (active_notes, outdated_notes) = discussion_notes.partition(&:active?) - = render "projects/notes/discussions/active", discussion_notes: active_notes if active_notes.length > 0 - = render "projects/notes/discussions/outdated", discussion_notes: outdated_notes if outdated_notes.length > 0 - - else - = render "projects/notes/discussions/commit", discussion_notes: discussion_notes +.timeline-entry-inner + .timeline-icon + = link_to user_path(note.author) do + = image_tag avatar_icon(note.author_email), class: "avatar s40" + .timeline-content + - if note.for_merge_request? + - (active_notes, outdated_notes) = discussion_notes.partition(&:active?) + = render "projects/notes/discussions/active", discussion_notes: active_notes if active_notes.length > 0 + = render "projects/notes/discussions/outdated", discussion_notes: outdated_notes if outdated_notes.length > 0 + - else + = render "projects/notes/discussions/commit", discussion_notes: discussion_notes diff --git a/app/views/projects/notes/_notes.html.haml b/app/views/projects/notes/_notes.html.haml index 62db86fb181..4eeaf70e987 100644 --- a/app/views/projects/notes/_notes.html.haml +++ b/app/views/projects/notes/_notes.html.haml @@ -6,7 +6,8 @@ = render discussion_notes - else - = render 'projects/notes/discussion', discussion_notes: discussion_notes + %li.note.note-discussion.timeline-entry + = render 'projects/notes/discussion', discussion_notes: discussion_notes - else - @notes.each do |note| - next unless note.author diff --git a/app/views/projects/notes/discussions/_active.html.haml b/app/views/projects/notes/discussions/_active.html.haml index cd8a5f0bd02..0ea8862a684 100644 --- a/app/views/projects/notes/discussions/_active.html.haml +++ b/app/views/projects/notes/discussions/_active.html.haml @@ -6,15 +6,11 @@ = "#{note.author.to_reference} started a discussion" = link_to diffs_namespace_project_merge_request_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code) do on the diff + = time_ago_with_tooltip(note.created_at, placement: "bottom", html_class: "discussion_updated_ago") .discussion-actions = link_to "#", class: "discussion-action-button discussion-toggle-button js-toggle-button" do %i.fa.fa-chevron-up Show/hide discussion - .last-update.hide.js-toggle-content - - last_note = discussion_notes.last - last updated by - = link_to_member(@project, last_note.author, avatar: false) - #{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')} .discussion-body.js-toggle-content = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note diff --git a/app/views/projects/notes/discussions/_commit.html.haml b/app/views/projects/notes/discussions/_commit.html.haml index 46f2ba4bbcf..2a2ead58eeb 100644 --- a/app/views/projects/notes/discussions/_commit.html.haml +++ b/app/views/projects/notes/discussions/_commit.html.haml @@ -8,21 +8,18 @@ = "#{note.author.to_reference} started a discussion on #{commit_description}" - if commit = link_to(commit.short_id, namespace_project_commit_path(note.project.namespace, note.project, note.noteable), class: 'monospace') + = time_ago_with_tooltip(note.created_at, placement: "bottom", html_class: "discussion_updated_ago") .discussion-actions = link_to "#", class: "note-action-button discussion-toggle-button js-toggle-button" do %i.fa.fa-chevron-up Show/hide discussion - .last-update.hide.js-toggle-content - - last_note = discussion_notes.last - last updated by - = link_to_member(@project, last_note.author, avatar: false) - #{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')} .discussion-body.js-toggle-content - if note.for_diff_line? = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note - else .panel.panel-default .notes{ data: { discussion_id: discussion_notes.first.discussion_id } } - = render discussion_notes + %ul.notes.timeline + = render discussion_notes .discussion-reply-holder = link_to_reply_diff(discussion_notes.first) diff --git a/app/views/projects/notes/discussions/_outdated.html.haml b/app/views/projects/notes/discussions/_outdated.html.haml index f8e000b424f..45141bcd1df 100644 --- a/app/views/projects/notes/discussions/_outdated.html.haml +++ b/app/views/projects/notes/discussions/_outdated.html.haml @@ -5,14 +5,10 @@ .inline.discussion-headline-light = "#{note.author.to_reference} started a discussion" on the outdated diff + = time_ago_with_tooltip(note.created_at, placement: "bottom", html_class: "discussion_updated_ago") .discussion-actions = link_to "#", class: "note-action-button discussion-toggle-button js-toggle-button" do %i.fa.fa-chevron-down Show/hide discussion - .last-update.hide.js-toggle-content - - last_note = discussion_notes.last - last updated by - = link_to_member(@project, last_note.author, avatar: false) - #{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')} .discussion-body.js-toggle-content.hide = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note -- cgit v1.2.1 From 44f3f42bac143f87d756ed38fa7142f98c7be90d Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Apr 2016 14:56:05 +0100 Subject: Dicussion action mobile fix --- app/assets/stylesheets/pages/notes.scss | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 7489d5de5f0..e4f96c11aae 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -215,6 +215,17 @@ ul.notes { color: $notes-action-color; } +.discussion-actions { + @media (max-width: $screen-sm-max) { + float: none; + margin-left: 0; + + .note-action-button { + margin-left: 0; + } + } +} + .note-action-button, .discussion-action-button { display: inline-block; -- cgit v1.2.1 From 01f70fc97b887dcbab8d859d2fc6ded28a2c3718 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Apr 2016 15:07:38 +0100 Subject: Fixed issue with commit time not using timeago --- app/assets/javascripts/application.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index 6f435e4c542..5bac8eef1cb 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -174,7 +174,7 @@ $ -> $('.trigger-submit').on 'change', -> $(@).parents('form').submit() - gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), false) + gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true) # Flash if (flash = $(".flash-container")).length > 0 -- cgit v1.2.1 From 038e623042af614fb739f49a9302ec42cab9812a Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Apr 2016 17:26:32 +0100 Subject: Fixed tests --- app/views/projects/notes/_discussion.html.haml | 23 ++++++++++++----------- app/views/projects/notes/_notes.html.haml | 3 +-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/views/projects/notes/_discussion.html.haml b/app/views/projects/notes/_discussion.html.haml index b66fead09b7..572b00a38c7 100644 --- a/app/views/projects/notes/_discussion.html.haml +++ b/app/views/projects/notes/_discussion.html.haml @@ -1,12 +1,13 @@ - note = discussion_notes.first -.timeline-entry-inner - .timeline-icon - = link_to user_path(note.author) do - = image_tag avatar_icon(note.author_email), class: "avatar s40" - .timeline-content - - if note.for_merge_request? - - (active_notes, outdated_notes) = discussion_notes.partition(&:active?) - = render "projects/notes/discussions/active", discussion_notes: active_notes if active_notes.length > 0 - = render "projects/notes/discussions/outdated", discussion_notes: outdated_notes if outdated_notes.length > 0 - - else - = render "projects/notes/discussions/commit", discussion_notes: discussion_notes +%li.note.note-discussion.timeline-entry + .timeline-entry-inner + .timeline-icon + = link_to user_path(note.author) do + = image_tag avatar_icon(note.author_email), class: "avatar s40" + .timeline-content + - if note.for_merge_request? + - (active_notes, outdated_notes) = discussion_notes.partition(&:active?) + = render "projects/notes/discussions/active", discussion_notes: active_notes if active_notes.length > 0 + = render "projects/notes/discussions/outdated", discussion_notes: outdated_notes if outdated_notes.length > 0 + - else + = render "projects/notes/discussions/commit", discussion_notes: discussion_notes diff --git a/app/views/projects/notes/_notes.html.haml b/app/views/projects/notes/_notes.html.haml index 4eeaf70e987..62db86fb181 100644 --- a/app/views/projects/notes/_notes.html.haml +++ b/app/views/projects/notes/_notes.html.haml @@ -6,8 +6,7 @@ = render discussion_notes - else - %li.note.note-discussion.timeline-entry - = render 'projects/notes/discussion', discussion_notes: discussion_notes + = render 'projects/notes/discussion', discussion_notes: discussion_notes - else - @notes.each do |note| - next unless note.author -- cgit v1.2.1 From 101f57d9170f5ea8e736f17c2fd8294bbc15e142 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Thu, 14 Apr 2016 16:26:48 -0500 Subject: Wrap code in parallel view --- app/assets/stylesheets/pages/notes.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index e421a31549a..21eca0a036e 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -171,6 +171,11 @@ ul.notes { &.parallel { border-width: 1px; + + .code, + code { + white-space: pre-wrap; + } } .notes { -- cgit v1.2.1 From cfcd95b0c3c0c3699de8724e60cc2bce687a9132 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Fri, 15 Apr 2016 10:03:21 +0530 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 071e35167fa..963d2ad6814 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -43,6 +43,7 @@ v 8.7.0 (unreleased) - Update number of Todos in the sidebar when it's marked as "Done". !3600 - API: Expose 'updated_at' for issue, snippet, and merge request notes (Robert Schilling) - API: User can leave a project through the API when not master or owner. !3613 + - While signing up, don't persist the user password across form redisplays v 8.6.6 - Fix error on language detection when repository has no HEAD (e.g., master branch). !3654 (Jeroen Bobbeldijk) -- cgit v1.2.1 From fcf0612f38b719212a7b40cdaf6b026f5b5f59e7 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Apr 2016 09:47:46 +0100 Subject: Updated note form focus to better match form-control focus --- app/assets/stylesheets/pages/note_form.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index 07c707e7b77..c2371d79989 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -61,11 +61,11 @@ padding: $gl-padding-top $gl-padding; border: 1px solid $note-form-border-color; border-radius: $border-radius-base; + transition: border-color ease-in-out 0.15s, + box-shadow ease-in-out 0.15s; &.is-focused { - border-color: $focus-border-color; - box-shadow: 0 0 2px $black-transparent, - 0 0 4px rgba($focus-border-color, .4); + @extend .form-control:focus; .comment-toolbar, .nav-links { -- cgit v1.2.1 From 2c5ab1b61f3b75298381e3258e303322c58f4808 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Apr 2016 18:24:16 +0100 Subject: Removes dropzone focus class after dropping file --- app/assets/javascripts/dropzone_input.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/dropzone_input.js.coffee b/app/assets/javascripts/dropzone_input.js.coffee index 6eb8d27ee2b..e2194589b38 100644 --- a/app/assets/javascripts/dropzone_input.js.coffee +++ b/app/assets/javascripts/dropzone_input.js.coffee @@ -61,6 +61,7 @@ class @DropzoneInput return drop: -> + $mdArea.removeClass 'is-dropzone-hover' form.find(".div-dropzone-hover").css "opacity", 0 form_textarea.focus() return -- cgit v1.2.1 From f2d94c5d8627adee985e605a18cf147003ef16de Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Fri, 15 Apr 2016 16:05:37 -0400 Subject: Scroll to the last comment I made and edit it. --- app/assets/javascripts/notes.js.coffee | 27 ++++++++++++++++++++++++--- app/views/projects/notes/_note.html.haml | 9 +++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index fa91baa07c0..a3d0d212bed 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -75,6 +75,9 @@ class @Notes # when issue status changes, we need to refresh data $(document).on "issuable:change", @refresh + # when a key is clicked on the notes + $(document).on "keydown", ".js-note-text", @keydownNoteText + cleanBinding: -> $(document).off "ajax:success", ".js-main-target-form" $(document).off "ajax:success", ".js-discussion-note-form" @@ -92,10 +95,19 @@ class @Notes $(document).off "click", ".js-note-target-reopen" $(document).off "click", ".js-note-target-close" $(document).off "click", ".js-note-discard" + $(document).off "keydown", ".js-note-text" $('.note .js-task-list-container').taskList('disable') $(document).off 'tasklist:changed', '.note .js-task-list-container' + keydownNoteText: (e) -> + $this = $(this) + if $this.val() is '' and e.which is 38 #aka the up key + myLastNote = $("li.note[data-author-id='#{gon.current_user_id}'][data-editable]:last") + if myLastNote.length + myLastNoteEditBtn = myLastNote.find('.js-note-edit') + myLastNoteEditBtn.trigger('click', [true, myLastNote]) + initRefresh: -> clearInterval(Notes.interval) Notes.interval = setInterval => @@ -343,7 +355,7 @@ class @Notes Adds a hidden div with the original content of the note to fill the edit note form with if the user cancels ### - showEditForm: (e) -> + showEditForm: (e, scrollTo, myLastNote) -> e.preventDefault() note = $(this).closest(".note") note.addClass "is-editting" @@ -355,8 +367,17 @@ class @Notes note.find(".js-note-attachment-delete").show() new GLForm form - - form.find(".js-note-text").focus() + if scrollTo? and myLastNote? + # scroll to the bottom + # so the open of the last element doesn't make a jump + $('html, body').scrollTop($(document).height()); + $('html, body').animate({ + scrollTop: myLastNote.offset().top - 150 + }, 500, -> + form.find(".js-note-text").focus() + ); + else + form.find(".js-note-text").focus() ### Called in response to clicking the edit note link diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index 03a44ca99c0..6e9ecdf7649 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -1,4 +1,5 @@ -%li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)] } +- note_editable = note_editable?(note) +%li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)], data: {author_id: note.author.id, editable: note_editable} } .timeline-entry-inner .timeline-icon %a{href: user_path(note.author)} @@ -15,16 +16,16 @@ - if access %span.note-role = access - - if note_editable?(note) + - if note_editable = link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do = icon('pencil') = link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button js-note-delete danger' do = icon('trash-o') - .note-body{class: note_editable?(note) ? 'js-task-list-container' : ''} + .note-body{class: note_editable ? 'js-task-list-container' : ''} .note-text = preserve do = markdown(note.note, pipeline: :note, cache_key: [note, "note"]) - - if note_editable?(note) + - if note_editable = render 'projects/notes/edit_form', note: note = edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago', include_author: true) -- cgit v1.2.1 From 262ca7b651037e02d0de662b6462fe4edfa77e81 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Fri, 15 Apr 2016 16:36:25 -0400 Subject: When editing put the cursor at the end of the textarea --- app/assets/javascripts/notes.js.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index a3d0d212bed..c2e103ff857 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -374,7 +374,11 @@ class @Notes $('html, body').animate({ scrollTop: myLastNote.offset().top - 150 }, 500, -> - form.find(".js-note-text").focus() + $noteText = form.find(".js-note-text") + $noteText.focus() + # Neat little trick to put the cursor at the end + noteTextVal = $noteText.val() + $noteText.val('').val(noteTextVal); ); else form.find(".js-note-text").focus() -- cgit v1.2.1 From 0fcdcadd75514fd8f1526bff2f1becb43c6d25f6 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 15 Apr 2016 23:00:32 +0100 Subject: Fixed issue with dropzone not working on new issuable Closes #15295 --- app/views/shared/issuable/_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index aed2622a6da..bae15b7f844 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -4,7 +4,7 @@ = f.label :title, class: 'control-label' .col-sm-10 = f.text_field :title, maxlength: 255, autofocus: true, autocomplete: 'off', - class: 'form-control pad js-gfm-input', required: true + class: 'form-control pad', required: true - if issuable.is_a?(MergeRequest) %p.help-block -- cgit v1.2.1 From eceada9a6868d16d9a11ce8bc646623f20f58c95 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Sat, 16 Apr 2016 09:43:49 +0100 Subject: Fix issue with go full screen triggering attach file --- app/views/projects/_md_preview.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml index 7a78d61a611..8de44a6c914 100644 --- a/app/views/projects/_md_preview.html.haml +++ b/app/views/projects/_md_preview.html.haml @@ -1,6 +1,6 @@ .md-area .md-header - %ul.nav-links + %ul.nav-links.clearfix %li.active %a.js-md-write-button{ href: "#md-write-holder", tabindex: -1 } Write -- cgit v1.2.1 From ffd2416c5636917c0da0a3376342d6c465bb1954 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Sat, 16 Apr 2016 09:28:04 -0400 Subject: Make a user available for the user variable --- app/controllers/help_controller.rb | 6 ++++++ app/views/help/ui.html.haml | 12 ++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index 55050615473..406142f29c7 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -51,6 +51,12 @@ class HelpController < ApplicationController end def ui + # this will work on gitlab.com + @some_user = User.find_by(username: 'dzaporozhets') + if @some_user.nil? + # this will work in dev + @some_user = User.find(1) + end end private diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index d084559abc3..64414f5d8b2 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -345,11 +345,11 @@ %ul %li %a.dropdown-menu-user-link.is-active{href: "#"} - = link_to_member_avatar(current_user, size: 30) + = link_to_member_avatar(@some_user, size: 30) %strong.dropdown-menu-user-full-name - = current_user.name + = @some_user.name .dropdown-menu-user-username - = current_user.to_reference + = @some_user.to_reference .example %div @@ -372,11 +372,11 @@ %ul %li %a.dropdown-menu-user-link.is-active{href: "#"} - = link_to_member_avatar(current_user, size: 30) + = link_to_member_avatar(@some_user, size: 30) %strong.dropdown-menu-user-full-name - = current_user.name + = @some_user.name .dropdown-menu-user-username - = current_user.to_reference + = @some_user.to_reference .dropdown-page-two .dropdown-title %button.dropdown-title-button.dropdown-menu-back{aria: {label: "Go back"}} -- cgit v1.2.1 From b340b59743e8cd47fc1f4fa2020b400d82bfd86e Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sat, 16 Apr 2016 18:46:18 +0200 Subject: Implement finally_script which allows to do cleanups as part of the build process --- lib/ci/gitlab_ci_yaml_processor.rb | 10 ++++++++-- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 29 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index b7209c14148..be2462949f1 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -4,12 +4,12 @@ module Ci DEFAULT_STAGES = %w(build test deploy) DEFAULT_STAGE = 'test' - ALLOWED_YAML_KEYS = [:before_script, :image, :services, :types, :stages, :variables, :cache] + ALLOWED_YAML_KEYS = [:before_script, :finally_script, :image, :services, :types, :stages, :variables, :cache] ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when, :artifacts, :cache, :dependencies] - attr_reader :before_script, :image, :services, :variables, :path, :cache + attr_reader :before_script, :finally_script, :image, :services, :variables, :path, :cache def initialize(config, path = nil) @config = YAML.safe_load(config, [Symbol], [], true) @@ -44,6 +44,7 @@ module Ci def initial_parsing @before_script = @config[:before_script] || [] + @finally_script = @config[:finally_script] @image = @config[:image] @services = @config[:services] @stages = @config[:stages] || @config[:types] @@ -85,6 +86,7 @@ module Ci artifacts: job[:artifacts], cache: job[:cache] || @cache, dependencies: job[:dependencies], + finally_script: @finally_script, }.compact } end @@ -102,6 +104,10 @@ module Ci raise ValidationError, "before_script should be an array of strings" end + unless @finally_script.nil? || validate_array_of_strings(@finally_script) + raise ValidationError, "finally_script should be an array of strings" + end + unless @image.nil? || @image.is_a?(String) raise ValidationError, "image should be a string" end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index dcb8a3451bd..8e373ae55b0 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -286,6 +286,28 @@ module Ci end end + + describe "Scripts handling" do + let(:config_data) { YAML.dump(config) } + let(:config_processor) { GitlabCiYamlProcessor.new(config_data, path) } + + subject { config_processor.builds_for_stage_and_ref("test", "master").first } + + describe "finally_script" do + context "in global context" do + let(:config) { + { + finally_script: ["finally_script"], + test: { script: ["script"] } + } + } + + it "return finally_script in options" do + expect(subject[:options][:finally_script]).to eq(["finally_script"]) + end + end + end + end describe "Image and service handling" do it "returns image and service when defined" do @@ -607,6 +629,13 @@ EOT end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script should be an array of strings") end + it "returns errors if finally_script parameter is invalid" do + config = YAML.dump({ finally_script: "bundle update", rspec: { script: "test" } }) + expect do + GitlabCiYamlProcessor.new(config, path) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "finally_script should be an array of strings") + end + it "returns errors if image parameter is invalid" do config = YAML.dump({ image: ["test"], rspec: { script: "test" } }) expect do -- cgit v1.2.1 From 4cc9a02ee033564b62b45977571319d129df465b Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sat, 16 Apr 2016 18:49:15 +0200 Subject: Allow the before_script and finally_script to be overwritten in context of job --- lib/ci/gitlab_ci_yaml_processor.rb | 22 ++++----- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 73 ++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 14 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index be2462949f1..2e5b84a57d6 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -7,7 +7,7 @@ module Ci ALLOWED_YAML_KEYS = [:before_script, :finally_script, :image, :services, :types, :stages, :variables, :cache] ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when, :artifacts, :cache, - :dependencies] + :dependencies, :before_script, :finally_script] attr_reader :before_script, :finally_script, :image, :services, :variables, :path, :cache @@ -73,7 +73,7 @@ module Ci { stage_idx: stages.index(job[:stage]), stage: job[:stage], - commands: "#{@before_script.join("\n")}\n#{normalize_script(job[:script])}", + commands: [job[:before_script] || @before_script, job[:script]].flatten.join("\n"), tag_list: job[:tags] || [], name: name, only: job[:only], @@ -86,19 +86,11 @@ module Ci artifacts: job[:artifacts], cache: job[:cache] || @cache, dependencies: job[:dependencies], - finally_script: @finally_script, + finally_script: job[:finally_script] || @finally_script, }.compact } end - def normalize_script(script) - if script.is_a? Array - script.join("\n") - else - script - end - end - def validate! unless validate_array_of_strings(@before_script) raise ValidationError, "before_script should be an array of strings" @@ -177,6 +169,14 @@ module Ci raise ValidationError, "#{name} job: script should be a string or an array of a strings" end + if job[:before_script] && !validate_array_of_strings(job[:before_script]) + raise ValidationError, "#{name} job: before_script should be an array of strings" + end + + if job[:finally_script] && !validate_array_of_strings(job[:finally_script]) + raise ValidationError, "#{name} job: finally_script should be an array of strings" + end + if job[:image] && !validate_string(job[:image]) raise ValidationError, "#{name} job: image should be a string" end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 8e373ae55b0..a6a1a5e3bef 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -293,6 +293,46 @@ module Ci subject { config_processor.builds_for_stage_and_ref("test", "master").first } + describe "before_script" do + context "in global context" do + let(:config) { + { + before_script: ["global script"], + test: { script: ["script"] } + } + } + + it "return commands with scripts concencaced" do + expect(subject[:commands]).to eq("global script\nscript") + end + end + + context "overwritten in local context" do + let(:config) { + { + before_script: ["global script"], + test: { before_script: ["local script"], script: ["script"] } + } + } + + it "return commands with scripts concencaced" do + expect(subject[:commands]).to eq("local script\nscript") + end + end + end + + describe "script" do + let(:config) { + { + test: { script: ["script"] } + } + } + + it "return commands with scripts concencaced" do + expect(subject[:commands]).to eq("script") + end + end + describe "finally_script" do context "in global context" do let(:config) { @@ -306,6 +346,19 @@ module Ci expect(subject[:options][:finally_script]).to eq(["finally_script"]) end end + + context "overwritten in local context" do + let(:config) { + { + finally_script: ["local finally_script"], + test: { finally_script: ["local finally_script"], script: ["script"] } + } + } + + it "return finally_script in options" do + expect(subject[:options][:finally_script]).to eq(["local finally_script"]) + end + end end end @@ -558,7 +611,7 @@ module Ci stage_idx: 1, name: :normal_job, only: nil, - commands: "\ntest", + commands: "test", tag_list: [], options: {}, when: "on_success", @@ -585,7 +638,7 @@ EOT stage_idx: 1, name: :job1, only: nil, - commands: "\nexecute-script-for-job", + commands: "execute-script-for-job", tag_list: [], options: {}, when: "on_success", @@ -597,7 +650,7 @@ EOT stage_idx: 1, name: :job2, only: nil, - commands: "\nexecute-script-for-job", + commands: "execute-script-for-job", tag_list: [], options: {}, when: "on_success", @@ -629,6 +682,13 @@ EOT end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script should be an array of strings") end + it "returns errors if job before_script parameter is not an array of strings" do + config = YAML.dump({ rspec: { script: "test", before_script: [10, "test"] } }) + expect do + GitlabCiYamlProcessor.new(config, path) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: before_script should be an array of strings") + end + it "returns errors if finally_script parameter is invalid" do config = YAML.dump({ finally_script: "bundle update", rspec: { script: "test" } }) expect do @@ -636,6 +696,13 @@ EOT end.to raise_error(GitlabCiYamlProcessor::ValidationError, "finally_script should be an array of strings") end + it "returns errors if job finally_script parameter is not an array of strings" do + config = YAML.dump({ rspec: { script: "test", finally_script: [10, "test"] } }) + expect do + GitlabCiYamlProcessor.new(config, path) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: finally_script should be an array of strings") + end + it "returns errors if image parameter is invalid" do config = YAML.dump({ image: ["test"], rspec: { script: "test" } }) expect do -- cgit v1.2.1 From e79b0dd762719828203bd48c253a88d876bcf61a Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Sat, 16 Apr 2016 16:00:30 -0400 Subject: Simplify random user generation. --- app/controllers/help_controller.rb | 7 +------ app/views/help/ui.html.haml | 12 ++++++------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index 406142f29c7..9b5c43b17e2 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -51,12 +51,7 @@ class HelpController < ApplicationController end def ui - # this will work on gitlab.com - @some_user = User.find_by(username: 'dzaporozhets') - if @some_user.nil? - # this will work in dev - @some_user = User.find(1) - end + @user = User.new(id: 0, name: 'John Doe', username: '@johndoe') end private diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index 64414f5d8b2..f12df5c8ffe 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -345,11 +345,11 @@ %ul %li %a.dropdown-menu-user-link.is-active{href: "#"} - = link_to_member_avatar(@some_user, size: 30) + = link_to_member_avatar(@user, size: 30) %strong.dropdown-menu-user-full-name - = @some_user.name + = @user.name .dropdown-menu-user-username - = @some_user.to_reference + = @user.to_reference .example %div @@ -372,11 +372,11 @@ %ul %li %a.dropdown-menu-user-link.is-active{href: "#"} - = link_to_member_avatar(@some_user, size: 30) + = link_to_member_avatar(@user, size: 30) %strong.dropdown-menu-user-full-name - = @some_user.name + = @user.name .dropdown-menu-user-username - = @some_user.to_reference + = @user.to_reference .dropdown-page-two .dropdown-title %button.dropdown-title-button.dropdown-menu-back{aria: {label: "Go back"}} -- cgit v1.2.1 From dd0478656d877bea84a313826258f1a35f9b1ab4 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Sat, 16 Apr 2016 16:08:53 -0400 Subject: Add move cursor to last character for editing comment also. --- app/assets/javascripts/notes.js.coffee | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index c2e103ff857..82e210fed7d 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -366,6 +366,11 @@ class @Notes # Show the attachment delete link note.find(".js-note-attachment-delete").show() + done = ($noteText) -> + # Neat little trick to put the cursor at the end + noteTextVal = $noteText.val() + $noteText.val('').val(noteTextVal); + new GLForm form if scrollTo? and myLastNote? # scroll to the bottom @@ -376,12 +381,12 @@ class @Notes }, 500, -> $noteText = form.find(".js-note-text") $noteText.focus() - # Neat little trick to put the cursor at the end - noteTextVal = $noteText.val() - $noteText.val('').val(noteTextVal); + done($noteText) ); else - form.find(".js-note-text").focus() + $noteText = form.find('.js-note-text') + $noteText.focus() + done($noteText) ### Called in response to clicking the edit note link -- cgit v1.2.1 From fd42b0db02f7911c9aa1a1b0656b6547ad2c0841 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Apr 2016 11:55:26 +0100 Subject: Refactored issue header to work better for mobile This will also work better for when the title makes the buttons drop down a new line Closes #14228 --- app/assets/stylesheets/framework/issue_box.scss | 2 +- app/assets/stylesheets/framework/mobile.scss | 7 -- app/assets/stylesheets/pages/detail_page.scss | 5 -- app/assets/stylesheets/pages/issuable.scss | 51 ++++++++++- app/assets/stylesheets/pages/issues.scss | 40 --------- app/views/projects/issues/show.html.haml | 111 ++++++++++++------------ 6 files changed, 105 insertions(+), 111 deletions(-) diff --git a/app/assets/stylesheets/framework/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss index 7f7b7c806e7..8bfc0d583c5 100644 --- a/app/assets/stylesheets/framework/issue_box.scss +++ b/app/assets/stylesheets/framework/issue_box.scss @@ -5,7 +5,7 @@ */ .status-box { - + /* Extra small devices (phones, less than 768px) */ /* No media query since this is the default in Bootstrap */ padding: 5px 11px; diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss index 66180f38a4f..7eb451c124e 100644 --- a/app/assets/stylesheets/framework/mobile.scss +++ b/app/assets/stylesheets/framework/mobile.scss @@ -70,13 +70,6 @@ display: none; } - .issue-details { - .creator, - .page-title .btn-close { - display: none; - } - } - %ul.notes .note-role, .note-actions { display: none; } diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss index 5917f089720..89bdb9ae03e 100644 --- a/app/assets/stylesheets/pages/detail_page.scss +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -16,11 +16,6 @@ .issue_created_ago, .author_link { white-space: nowrap; } - - .issue-meta { - display: inline-block; - line-height: 20px; - } } .detail-page-description { diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 6bd90a23620..5bf44c1cdb6 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -273,10 +273,6 @@ } } -.btn-default.gutter-toggle { - margin-top: 4px; -} - .detail-page-description { small { color: $gray-darkest; @@ -322,3 +318,50 @@ padding-top: 7px; } } + +.issuable-status-box { + float: none; + display: inline-block; + margin-top: 0; + + @media (max-width: $screen-xs-max) { + position: absolute; + top: 0; + left: 0; + } +} + +.issuable-header { + position: relative; + padding-left: 45px; + padding-right: 45px; + line-height: 35px; + + @media (min-width: $screen-sm-min) { + float: left; + padding-left: 0; + padding-right: 0; + } +} + +.issuable-actions { + padding-top: 10px; + + @media (min-width: $screen-sm-min) { + float: right; + padding-top: 0; + } +} + +.issuable-gutter-toggle { + @media (max-width: $screen-sm-max) { + position: absolute; + top: 0; + right: 0; + } +} + +.issuable-meta { + display: inline-block; + line-height: 18px; +} diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 6a1d28590c2..fc9db97132d 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -86,41 +86,9 @@ form.edit-issue { @media (max-width: $screen-xs-max) { .issue-btn-group { width: 100%; - margin-top: 5px; - - .btn-group { - width: 100%; - - ul { - width: 100%; - text-align: center; - } - } .btn { width: 100%; - - &:first-child:not(:last-child) { - - } - - &:not(:first-child):not(:last-child) { - margin-top: 10px; - } - - &:last-child:not(:first-child) { - margin-top: 10px; - } - } - } - - .issue { - &:hover .issue-actions { - display: none !important; - } - - .issue-updated-at { - display: none; } } } @@ -133,11 +101,3 @@ form.edit-issue { color: $gl-text-color; margin-left: 52px; } - -.editor-details { - display: block; - - @media (min-width: $screen-sm-min) { - display: inline-block; - } -} diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 5fe5ddc0819..4f4e6c59d63 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -1,68 +1,73 @@ - page_title "#{@issue.title} (##{@issue.iid})", "Issues" - page_description @issue.description - page_card_attributes @issue.card_attributes +- header_title project_title(@project, "Issues", namespace_project_issues_path(@project.namespace, @project)) -= render "header_title" +.clearfix.detail-page-header + .issuable-header + .issuable-status-box.status-box.status-box-closed{ class: "#{issue_button_visibility(@issue, false)}" } + = icon('check', class: "hidden-sm hidden-md hidden-lg") + %span.hidden-xs + Closed + .issuable-status-box.status-box.status-box-open{ class: "#{issue_button_visibility(@issue, true)}"} + = icon('circle-o', class: "hidden-sm hidden-md hidden-lg") + %span.hidden-xs Open -.issue - .detail-page-header.issuable-header - .pull-left - .status-box{ class: "status-box-closed #{issue_button_visibility(@issue, false)}"} - %span.hidden-xs - Closed - %span.hidden-sm.hidden-md.hidden-lg - = icon('check') - .status-box{ class: "status-box-open #{issue_button_visibility(@issue, true)}"} - %span.hidden-xs - Open - %span.hidden-sm.hidden-md.hidden-lg - = icon('circle-o') - - %a.btn.btn-default.pull-right.visible-xs-block.gutter-toggle.js-sidebar-toggle{ href: "#" } + %a.btn.btn-default.pull-right.visible-xs-block.gutter-toggle.issuable-gutter-toggle.js-sidebar-toggle{ href: "#" } = icon('angle-double-left') - .issue-meta + .issuable-meta = confidential_icon(@issue) %strong.identifier - Issue ##{@issue.iid} - %span.creator - opened - .editor-details - .editor-details - = time_ago_with_tooltip(@issue.created_at) - by - %strong - = link_to_member(@project, @issue.author, size: 24, mobile_classes: "hidden-xs") - %strong - = link_to_member(@project, @issue.author, size: 24, mobile_classes: "hidden-sm hidden-md hidden-lg", - by_username: true, avatar: false) + Issue #{@issue.to_reference} + opened + = time_ago_with_tooltip(@issue.created_at) + by + %strong + = link_to_member(@project, @issue.author, size: 24, mobile_classes: "hidden-xs") + = link_to_member(@project, @issue.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg") - .pull-right.issue-btn-group + .issuable-actions + .clearfix.issue-btn-group.dropdown + %button.btn.btn-default.pull-left.hidden-md.hidden-lg{ data: { toggle: "dropdown" } } + %span.caret + Options + .dropdown-menu.dropdown-menu-align-right.hidden-lg + %ul + - if can?(current_user, :create_issue, @project) + %li + = link_to 'New issue', new_namespace_project_issue_path(@project.namespace, @project), title: 'New issue', id: 'new_issue_link' + - if can?(current_user, :update_issue, @issue) + %li + = link_to 'Reopen issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: " #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' + %li + = link_to 'Close issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "#{issue_button_visibility(@issue, true)}", title: 'Close issue' + %li + = link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue) - if can?(current_user, :create_issue, @project) - = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'btn btn-nr btn-grouped new-issue-link btn-success', title: 'New issue', id: 'new_issue_link' do + = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped new-issue-link btn-success', title: 'New issue', id: 'new_issue_link' do = icon('plus') New issue - if can?(current_user, :update_issue, @issue) - = link_to 'Reopen issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' - = link_to 'Close issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' - = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'btn btn-nr btn-grouped issuable-edit' do + = link_to 'Reopen issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' + = link_to 'Close issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' + = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit' do = icon('pencil-square-o') Edit - .issue-details.issuable-details - .detail-page-description.content-block - %h2.title - = markdown escape_once(@issue.title), pipeline: :single_line - %div - - if @issue.description.present? - .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''} - .wiki - = preserve do - = markdown(@issue.description, cache_key: [@issue, "description"]) - %textarea.hidden.js-task-list-field - = @issue.description - = edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue_edited_ago') +.issue-details.issuable-details + .detail-page-description.content-block + %h2.title + = markdown escape_once(@issue.title), pipeline: :single_line + - if @issue.description.present? + .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''} + .wiki + = preserve do + = markdown(@issue.description, cache_key: [@issue, "description"]) + %textarea.hidden.js-task-list-field + = @issue.description + = edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue_edited_ago') #merge-requests{'data-url' => referenced_merge_requests_namespace_project_issue_url(@project.namespace, @project, @issue)} // This element is filled in using JavaScript. @@ -70,13 +75,11 @@ #related-branches{'data-url' => related_branches_namespace_project_issue_url(@project.namespace, @project, @issue)} // This element is filled in using JavaScript. - .content-block.content-block-small - = render 'new_branch' - = render 'votes/votes_block', votable: @issue + .content-block.content-block-small + = render 'new_branch' + = render 'votes/votes_block', votable: @issue - .row - %section.col-md-12 - .issuable-discussion - = render 'projects/issues/discussion' + %section.issuable-discussion + = render 'projects/issues/discussion' = render 'shared/issuable/sidebar', issuable: @issue -- cgit v1.2.1 From 60bb7007c3a165543a1787aa7ee6543a0def2152 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Apr 2016 12:12:13 +0100 Subject: Merge request header markup now matches issue markup for consistancy --- app/views/projects/merge_requests/_show.html.haml | 3 +- .../merge_requests/show/_mr_title.html.haml | 72 ++++++++++++---------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 2c34f9c454b..285ad26316c 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -1,8 +1,7 @@ - page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests" - page_description @merge_request.description - page_card_attributes @merge_request.card_attributes - -= render "header_title" +- header_title project_title(@project, "Merge Requests", namespace_project_merge_requests_path(@project.namespace, @project)) - if params[:view] == 'parallel' - fluid_layout true diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index ab4b1f14be5..c4e57883259 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -1,35 +1,43 @@ -.detail-page-header - .status-box{ class: status_box_class(@merge_request) } - %span.hidden-xs - = @merge_request.state_human_name - %span.hidden-sm.hidden-md.hidden-lg - = icon(@merge_request.state_icon_name) - %a.btn.btn-default.pull-right.visible-xs-block.gutter-toggle.js-sidebar-toggle{ href: "#" } - = icon('angle-double-left') - .issue-meta - %strong.identifier - %span.hidden-sm.hidden-md.hidden-lg - MR +.clearfix.detail-page-header + .issuable-header + .issuable-status-box.status-box{ class: "#{status_box_class(@merge_request)}" } + = icon(@merge_request.state_icon_name, class: "hidden-sm hidden-md hidden-lg") %span.hidden-xs - Merge Request - !#{@merge_request.iid} - %span.creator + = @merge_request.state_human_name + + %a.btn.btn-default.pull-right.visible-xs-block.gutter-toggle.issuable-gutter-toggle.js-sidebar-toggle{ href: "#" } + = icon('angle-double-left') + + .issuable-meta + %strong.identifier + Merge Request #{@merge_request.to_reference} opened - .editor-details - = time_ago_with_tooltip(@merge_request.created_at) - by - %strong - = link_to_member(@project, @merge_request.author, size: 24, mobile_classes: "hidden-xs") - %strong - = link_to_member(@project, @merge_request.author, size: 24, mobile_classes: "hidden-sm hidden-md hidden-lg", - by_username: true, avatar: false) + = time_ago_with_tooltip(@merge_request.created_at) + by + %strong + = link_to_member(@project, @merge_request.author, size: 24, mobile_classes: "hidden-xs") + = link_to_member(@project, @merge_request.author, size: 24, mobile_classes: "hidden-sm hidden-md hidden-lg", by_username: true, avatar: false) - .issue-btn-group.pull-right - - if can?(current_user, :update_merge_request, @merge_request) - - if @merge_request.open? - = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: 'btn btn-nr btn-grouped btn-close', title: 'Close merge request' - = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn btn-nr btn-grouped issuable-edit', id: 'edit_merge_request' do - = icon('pencil-square-o') - Edit - - if @merge_request.closed? - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'btn btn-nr btn-grouped btn-reopen reopen-mr-link', title: 'Reopen merge request' + - if can?(current_user, :update_merge_request, @merge_request) + .issuable-actions + .clearfix.issue-btn-group.dropdown + %button.btn.btn-default.pull-left.hidden-md.hidden-lg{ data: { toggle: "dropdown" } } + %span.caret + Options + .dropdown-menu.dropdown-menu-align-right.hidden-lg + %ul + - if @merge_request.open? + %li + = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, title: 'Close merge request' + %li + = link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'issuable-edit', id: 'edit_merge_request' + - if @merge_request.closed? + %li + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request' + - if @merge_request.open? + = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: 'hidden-xs hidden-sm btn btn-nr btn-grouped btn-close', title: 'Close merge request' + = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit', id: 'edit_merge_request' do + = icon('pencil-square-o') + Edit + - if @merge_request.closed? + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen reopen-mr-link', title: 'Reopen merge request' -- cgit v1.2.1 From 6c949b2bf1c9ee47fb5b181f44021ad6eeb1cd5a Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Apr 2016 12:20:54 +0100 Subject: Moved meta information into an issuable helper method --- app/helpers/issuables_helper.rb | 11 +++++++++++ app/views/projects/issues/show.html.haml | 9 +-------- app/views/projects/merge_requests/show/_mr_title.html.haml | 11 ++--------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index b14b8218d02..94e1a4d2ec1 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -55,6 +55,17 @@ module IssuablesHelper h(milestone_title.presence || default_label) end + def issuable_meta(issuable, project, text) + output = content_tag :strong, "#{text} #{issuable.to_reference}", class: "identifier" + output << " opened " + output << time_ago_with_tooltip(issuable.created_at) + output << " by " + output << content_tag(:strong) do + author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs") + author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg") + end + end + private def sidebar_gutter_collapsed? diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 4f4e6c59d63..e3df2ec9241 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -18,14 +18,7 @@ .issuable-meta = confidential_icon(@issue) - %strong.identifier - Issue #{@issue.to_reference} - opened - = time_ago_with_tooltip(@issue.created_at) - by - %strong - = link_to_member(@project, @issue.author, size: 24, mobile_classes: "hidden-xs") - = link_to_member(@project, @issue.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg") + = issuable_meta(@issue, @project, "Issue") .issuable-actions .clearfix.issue-btn-group.dropdown diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index c4e57883259..e78fd2054ce 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -7,16 +7,9 @@ %a.btn.btn-default.pull-right.visible-xs-block.gutter-toggle.issuable-gutter-toggle.js-sidebar-toggle{ href: "#" } = icon('angle-double-left') - + .issuable-meta - %strong.identifier - Merge Request #{@merge_request.to_reference} - opened - = time_ago_with_tooltip(@merge_request.created_at) - by - %strong - = link_to_member(@project, @merge_request.author, size: 24, mobile_classes: "hidden-xs") - = link_to_member(@project, @merge_request.author, size: 24, mobile_classes: "hidden-sm hidden-md hidden-lg", by_username: true, avatar: false) + = issuable_meta(@merge_request, @project, "Merge Request") - if can?(current_user, :update_merge_request, @merge_request) .issuable-actions -- cgit v1.2.1 From ce2e37d446c113575b137f1a11d56df080d02148 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Apr 2016 13:44:22 +0100 Subject: Fixed tests --- features/steps/shared/issuable.rb | 2 +- spec/features/issues/move_spec.rb | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/features/steps/shared/issuable.rb b/features/steps/shared/issuable.rb index 24b3fb6eacb..a58b3cb7e16 100644 --- a/features/steps/shared/issuable.rb +++ b/features/steps/shared/issuable.rb @@ -2,7 +2,7 @@ module SharedIssuable include Spinach::DSL def edit_issuable - find(:css, '.issuable-edit').click + find('.issuable-edit', visible: true).click end step 'project "Community" has "Community issue" open issue' do diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index 6fda0c31866..caa7b0ec48a 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -42,11 +42,9 @@ feature 'issue move to another project' do expect(current_url).to include project_path(new_project) - page.within('.issue') do - expect(page).to have_content("Text with #{cross_reference}!1") - expect(page).to have_content("Moved from #{cross_reference}#1") - expect(page).to have_content(issue.title) - end + expect(page).to have_content("Text with #{cross_reference}!1") + expect(page).to have_content("Moved from #{cross_reference}#1") + expect(page).to have_content(issue.title) end context 'projects user does not have permission to move issue to exist' do @@ -74,7 +72,7 @@ feature 'issue move to another project' do def edit_issue(issue) visit issue_path(issue) - page.within('.issuable-header') { click_link 'Edit' } + page.within('.issuable-actions') { find('.issuable-edit').click } end def issue_path(issue) -- cgit v1.2.1 From 365f351a6c4679db8e7cda52c899d1ce14200097 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Apr 2016 14:43:42 +0100 Subject: Alignment with sidebar --- app/assets/stylesheets/pages/detail_page.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss index 89bdb9ae03e..2c2ac903f29 100644 --- a/app/assets/stylesheets/pages/detail_page.scss +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -1,5 +1,5 @@ .detail-page-header { - padding: 11px 0; + padding: $gl-padding-top 0; border-bottom: 1px solid $border-color; color: #5c5d5e; font-size: 16px; -- cgit v1.2.1 From 4b15a8ed262147ba38fcd2cddfda02fb481c37d1 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 12 Apr 2016 16:27:16 +0100 Subject: Fixed up based on feedback --- app/helpers/issuables_helper.rb | 4 +--- app/views/projects/issues/show.html.haml | 12 ++++++------ app/views/projects/merge_requests/show/_mr_title.html.haml | 2 +- spec/features/issues/move_spec.rb | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 94e1a4d2ec1..e1b5af242f2 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -57,9 +57,7 @@ module IssuablesHelper def issuable_meta(issuable, project, text) output = content_tag :strong, "#{text} #{issuable.to_reference}", class: "identifier" - output << " opened " - output << time_ago_with_tooltip(issuable.created_at) - output << " by " + output << " opened #{time_ago_with_tooltip(issuable.created_at, skip_js: true)} by".html_safe output << content_tag(:strong) do author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs") author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg") diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index e3df2ec9241..e07ac04baf6 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -5,11 +5,11 @@ .clearfix.detail-page-header .issuable-header - .issuable-status-box.status-box.status-box-closed{ class: "#{issue_button_visibility(@issue, false)}" } + .issuable-status-box.status-box.status-box-closed{ class: issue_button_visibility(@issue, false) } = icon('check', class: "hidden-sm hidden-md hidden-lg") %span.hidden-xs Closed - .issuable-status-box.status-box.status-box-open{ class: "#{issue_button_visibility(@issue, true)}"} + .issuable-status-box.status-box.status-box-open{ class: issue_button_visibility(@issue, true) } = icon('circle-o', class: "hidden-sm hidden-md hidden-lg") %span.hidden-xs Open @@ -32,9 +32,9 @@ = link_to 'New issue', new_namespace_project_issue_path(@project.namespace, @project), title: 'New issue', id: 'new_issue_link' - if can?(current_user, :update_issue, @issue) %li - = link_to 'Reopen issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: " #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' + = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' %li - = link_to 'Close issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "#{issue_button_visibility(@issue, true)}", title: 'Close issue' + = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' %li = link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue) - if can?(current_user, :create_issue, @project) @@ -42,8 +42,8 @@ = icon('plus') New issue - if can?(current_user, :update_issue, @issue) - = link_to 'Reopen issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' - = link_to 'Close issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' + = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' + = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit' do = icon('pencil-square-o') Edit diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index e78fd2054ce..42a9d463e98 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -1,6 +1,6 @@ .clearfix.detail-page-header .issuable-header - .issuable-status-box.status-box{ class: "#{status_box_class(@merge_request)}" } + .issuable-status-box.status-box{ class: status_box_class(@merge_request) } = icon(@merge_request.state_icon_name, class: "hidden-sm hidden-md hidden-lg") %span.hidden-xs = @merge_request.state_human_name diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index caa7b0ec48a..84c8e20ebaa 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -72,7 +72,7 @@ feature 'issue move to another project' do def edit_issue(issue) visit issue_path(issue) - page.within('.issuable-actions') { find('.issuable-edit').click } + page.within('.issuable-actions') { first(:link, 'Edit').click } end def issue_path(issue) -- cgit v1.2.1 From a716e8eadcb93779f1a89f05c0ed1a6b72a8dc6b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 13 Apr 2016 09:13:47 +0100 Subject: Added CHANGELOG item --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 5c375fcdb39..d8fbfafb72c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -80,6 +80,10 @@ v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 - Fix error on language detection when repository has no HEAD (e.g., master branch) (Jeroen Bobbeldijk). !3654 - Fix revoking of authorized OAuth applications (Connor Shea). !3690 + - Fix error on language detection when repository has no HEAD (e.g., master branch). !3654 (Jeroen Bobbeldijk) + - Project switcher uses new dropdown styling + - Issuable header is consistent between issues and merge requests + - Improved spacing in issuable header on mobile v 8.6.5 - Fix importing from GitHub Enterprise. !3529 -- cgit v1.2.1 From 2629ab4472c535416791cfc13b41c7f50d7d343c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Apr 2016 10:14:12 +0100 Subject: Fixed tests --- app/helpers/issuables_helper.rb | 2 +- app/views/projects/issues/show.html.haml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index e1b5af242f2..49b6b79ce35 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -57,7 +57,7 @@ module IssuablesHelper def issuable_meta(issuable, project, text) output = content_tag :strong, "#{text} #{issuable.to_reference}", class: "identifier" - output << " opened #{time_ago_with_tooltip(issuable.created_at, skip_js: true)} by".html_safe + output << " opened #{time_ago_with_tooltip(issuable.created_at)} by".html_safe output << content_tag(:strong) do author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs") author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg") diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index e07ac04baf6..9fce9c3f336 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -62,11 +62,11 @@ = @issue.description = edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue_edited_ago') - #merge-requests{'data-url' => referenced_merge_requests_namespace_project_issue_url(@project.namespace, @project, @issue)} - // This element is filled in using JavaScript. + #merge-requests{ data: { url: referenced_merge_requests_namespace_project_issue_url(@project.namespace, @project, @issue) } } + // This element is filled in using JavaScript. - #related-branches{'data-url' => related_branches_namespace_project_issue_url(@project.namespace, @project, @issue)} - // This element is filled in using JavaScript. + #related-branches{ data: { url: related_branches_namespace_project_issue_url(@project.namespace, @project, @issue) } } + // This element is filled in using JavaScript. .content-block.content-block-small = render 'new_branch' -- cgit v1.2.1 From 84fba4d16248de96dcea1ab7e6a56aae58668175 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Apr 2016 14:04:06 +0100 Subject: Updated some if statements --- app/views/projects/issues/show.html.haml | 57 +++++++++++----------- .../merge_requests/show/_mr_title.html.haml | 26 +++++----- 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 9fce9c3f336..bde80bbb54b 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -20,33 +20,34 @@ = confidential_icon(@issue) = issuable_meta(@issue, @project, "Issue") - .issuable-actions - .clearfix.issue-btn-group.dropdown - %button.btn.btn-default.pull-left.hidden-md.hidden-lg{ data: { toggle: "dropdown" } } - %span.caret - Options - .dropdown-menu.dropdown-menu-align-right.hidden-lg - %ul - - if can?(current_user, :create_issue, @project) - %li - = link_to 'New issue', new_namespace_project_issue_path(@project.namespace, @project), title: 'New issue', id: 'new_issue_link' - - if can?(current_user, :update_issue, @issue) - %li - = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' - %li - = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' - %li - = link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue) - - if can?(current_user, :create_issue, @project) - = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped new-issue-link btn-success', title: 'New issue', id: 'new_issue_link' do - = icon('plus') - New issue - - if can?(current_user, :update_issue, @issue) - = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' - = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' - = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit' do - = icon('pencil-square-o') - Edit + - if can?(current_user, :create_issue, @project) || can?(current_user, :update_issue, @issue) + .issuable-actions + .clearfix.issue-btn-group.dropdown + %button.btn.btn-default.pull-left.hidden-md.hidden-lg{ data: { toggle: "dropdown" } } + %span.caret + Options + .dropdown-menu.dropdown-menu-align-right.hidden-lg + %ul + - if can?(current_user, :create_issue, @project) + %li + = link_to 'New issue', new_namespace_project_issue_path(@project.namespace, @project), title: 'New issue', id: 'new_issue_link' + - if can?(current_user, :update_issue, @issue) + %li + = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' + %li + = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' + %li + = link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue) + - if can?(current_user, :create_issue, @project) + = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped new-issue-link btn-success', title: 'New issue', id: 'new_issue_link' do + = icon('plus') + New issue + - if can?(current_user, :update_issue, @issue) + = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' + = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' + = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit' do + = icon('pencil-square-o') + Edit .issue-details.issuable-details @@ -54,7 +55,7 @@ %h2.title = markdown escape_once(@issue.title), pipeline: :single_line - if @issue.description.present? - .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''} + .description{ class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : '' } .wiki = preserve do = markdown(@issue.description, cache_key: [@issue, "description"]) diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index 42a9d463e98..0a99e8c9591 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -19,18 +19,14 @@ Options .dropdown-menu.dropdown-menu-align-right.hidden-lg %ul - - if @merge_request.open? - %li - = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, title: 'Close merge request' - %li - = link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'issuable-edit', id: 'edit_merge_request' - - if @merge_request.closed? - %li - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request' - - if @merge_request.open? - = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: 'hidden-xs hidden-sm btn btn-nr btn-grouped btn-close', title: 'Close merge request' - = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit', id: 'edit_merge_request' do - = icon('pencil-square-o') - Edit - - if @merge_request.closed? - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen reopen-mr-link', title: 'Reopen merge request' + %li{ class: issue_button_visibility(@merge_request, true) } + = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, title: 'Close merge request' + %li{ class: issue_button_visibility(@merge_request, false) } + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request' + %li + = link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'issuable-edit', id: 'edit_merge_request' + = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@merge_request, true)}", title: 'Close merge request' + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen reopen-mr-link #{issue_button_visibility(@merge_request, false)}", title: 'Reopen merge request' + = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit", id: 'edit_merge_request' do + = icon('pencil-square-o') + Edit -- cgit v1.2.1 From fa7d99ebd4cd86134e33f9f79e2b92f50de3af6c Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Sat, 16 Apr 2016 10:23:36 +0200 Subject: API: Present an array of Gitlab::Git::Tag instead of array of rugged tags --- CHANGELOG | 1 + lib/api/tags.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index d8fbfafb72c..7fa1fce1f2e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -73,6 +73,7 @@ v 8.7.0 (unreleased) - Diffs load at the correct point when linking from from number - Selected diff rows highlight - Fix emoji categories in the emoji picker + - API: Properly display annotated tags for GET /projects/:id/repository/tags (Robert Schilling) - Add encrypted credentials for imported projects and migrate old ones - Author and participants are displayed first on users autocompletion diff --git a/lib/api/tags.rb b/lib/api/tags.rb index d1a10479e44..3e1ed3fe5c7 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -12,7 +12,7 @@ module API # Example Request: # GET /projects/:id/repository/tags get ":id/repository/tags" do - present user_project.repo.tags.sort_by(&:name).reverse, + present user_project.repository.tags.sort_by(&:name).reverse, with: Entities::RepoTag, project: user_project end -- cgit v1.2.1 From 0be158a0725c254629e7e4e5de194021322e2fa9 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Sun, 17 Apr 2016 12:15:45 +0100 Subject: Added upload file test to new issue form --- spec/features/issues_spec.rb | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 1ce0024e93c..35c8f93abc1 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -292,6 +292,23 @@ describe 'Issues', feature: true do end end + describe 'new issue' do + context 'dropzone upload file', js: true do + before do + visit new_namespace_project_issue_path(project.namespace, project) + end + + it 'should upload file when dragging into textarea' do + drop_in_dropzone test_image_file + + # Wait for the file to upload + sleep 1 + + expect(page.find_field("issue_description").value).to have_content 'banana_sample' + end + end + end + def first_issue page.all('ul.issues-list > li').first.text end @@ -299,4 +316,25 @@ describe 'Issues', feature: true do def last_issue page.all('ul.issues-list > li').last.text end + + def drop_in_dropzone(file_path) + # Generate a fake input selector + page.execute_script <<-JS + var fakeFileInput = window.$('').attr( + {id: 'fakeFileInput', type: 'file'} + ).appendTo('body'); + JS + # Attach the file to the fake input selector with Capybara + attach_file("fakeFileInput", file_path) + # Add the file to a fileList array and trigger the fake drop event + page.execute_script <<-JS + var fileList = [$('#fakeFileInput')[0].files[0]]; + var e = jQuery.Event('drop', { dataTransfer : { files : fileList } }); + $('.div-dropzone')[0].dropzone.listeners[0].events.drop(e); + JS + end + + def test_image_file + File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif') + end end -- cgit v1.2.1 From cc57d61023c6dd5ef274bac5d4e6cde1cae97d2c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 17 Apr 2016 08:59:57 -0400 Subject: Rename finally_script to after_script --- lib/ci/gitlab_ci_yaml_processor.rb | 12 ++++++------ spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index be2462949f1..a87329c296a 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -4,12 +4,12 @@ module Ci DEFAULT_STAGES = %w(build test deploy) DEFAULT_STAGE = 'test' - ALLOWED_YAML_KEYS = [:before_script, :finally_script, :image, :services, :types, :stages, :variables, :cache] + ALLOWED_YAML_KEYS = [:before_script, :after_script, :image, :services, :types, :stages, :variables, :cache] ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when, :artifacts, :cache, :dependencies] - attr_reader :before_script, :finally_script, :image, :services, :variables, :path, :cache + attr_reader :before_script, :after_script, :image, :services, :variables, :path, :cache def initialize(config, path = nil) @config = YAML.safe_load(config, [Symbol], [], true) @@ -44,7 +44,7 @@ module Ci def initial_parsing @before_script = @config[:before_script] || [] - @finally_script = @config[:finally_script] + @after_script = @config[:after_script] @image = @config[:image] @services = @config[:services] @stages = @config[:stages] || @config[:types] @@ -86,7 +86,7 @@ module Ci artifacts: job[:artifacts], cache: job[:cache] || @cache, dependencies: job[:dependencies], - finally_script: @finally_script, + after_script: @after_script, }.compact } end @@ -104,8 +104,8 @@ module Ci raise ValidationError, "before_script should be an array of strings" end - unless @finally_script.nil? || validate_array_of_strings(@finally_script) - raise ValidationError, "finally_script should be an array of strings" + unless @after_script.nil? || validate_array_of_strings(@after_script) + raise ValidationError, "after_script should be an array of strings" end unless @image.nil? || @image.is_a?(String) diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 8e373ae55b0..2421d6eee8f 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -293,17 +293,17 @@ module Ci subject { config_processor.builds_for_stage_and_ref("test", "master").first } - describe "finally_script" do + describe "after_script" do context "in global context" do let(:config) { { - finally_script: ["finally_script"], + after_script: ["after_script"], test: { script: ["script"] } } } - it "return finally_script in options" do - expect(subject[:options][:finally_script]).to eq(["finally_script"]) + it "return after_script in options" do + expect(subject[:options][:after_script]).to eq(["after_script"]) end end end @@ -629,11 +629,11 @@ EOT end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script should be an array of strings") end - it "returns errors if finally_script parameter is invalid" do - config = YAML.dump({ finally_script: "bundle update", rspec: { script: "test" } }) + it "returns errors if after_script parameter is invalid" do + config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } }) expect do GitlabCiYamlProcessor.new(config, path) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "finally_script should be an array of strings") + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "after_script should be an array of strings") end it "returns errors if image parameter is invalid" do -- cgit v1.2.1 From a0afeefd76ebfacae59343f48e127828b27ba77a Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 17 Apr 2016 09:02:42 -0400 Subject: Add CHANGELOG and documentation --- CHANGELOG | 1 + doc/ci/yaml/README.md | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index c948e8e5460..f52897892e5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -21,6 +21,7 @@ v 8.7.0 (unreleased) - Make /profile/keys/new redirect to /profile/keys for back-compat. !3717 - Preserve time notes/comments have been updated at when moving issue - Make HTTP(s) label consistent on clone bar (Stan Hu) + - Add support for `after_script`, requires Runner 1.2 (Kamil Trzciński) - Expose label description in API (Mariusz Jachimowicz) - API: Ability to update a group (Robert Schilling) - API: Ability to move issues (Robert Schilling) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index abb6e97e5e6..54b06f10b95 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -15,6 +15,7 @@ If you want a quick introduction to GitLab CI, follow our - [.gitlab-ci.yml](#gitlab-ci-yml) - [image and services](#image-and-services) - [before_script](#before_script) + - [after_script](#after_script) - [stages](#stages) - [types](#types) - [variables](#variables) @@ -80,6 +81,9 @@ services: before_script: - bundle install +after_script: + - rm secrets + stages: - build - test @@ -104,6 +108,7 @@ There are a few reserved `keywords` that **cannot** be used as job names: | stages | no | Define build stages | | types | no | Alias for `stages` | | before_script | no | Define commands that run before each job's script | +| after_script | no | Define commands that run after each job's script | | variables | no | Define build variables | | cache | no | Define list of files that should be cached between subsequent runs | @@ -118,6 +123,11 @@ used for time of the build. The configuration of this feature is covered in `before_script` is used to define the command that should be run before all builds, including deploy builds. This can be an array or a multi-line string. +### after_script + +`after_script` is used to define the command that will be run after for all +builds. This has to be an array or a multi-line string. + ### stages `stages` is used to define build stages that can be used by jobs. -- cgit v1.2.1 From 38b15e35d48550a5621b8fc292cabc5670897a44 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 17 Apr 2016 09:10:47 -0400 Subject: Update CHANGELOG and add documentation --- CHANGELOG | 1 + doc/ci/yaml/README.md | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index f52897892e5..df1887f7983 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -46,6 +46,7 @@ v 8.7.0 (unreleased) - Use rugged to change HEAD in Project#change_head (P.S.V.R) - API: Ability to filter milestones by state `active` and `closed` (Robert Schilling) - API: Fix milestone filtering by `iid` (Robert Schilling) + - Make before_script and after_script overridable on per-job (Kamil Trzciński) - API: Delete notes of issues, snippets, and merge requests (Robert Schilling) - Implement 'Groups View' as an option for dashboard preferences !3379 (Elias W.) - Better errors handling when creating milestones inside groups diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 54b06f10b95..c626bee5703 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -30,6 +30,7 @@ If you want a quick introduction to GitLab CI, follow our - [artifacts](#artifacts) - [artifacts:name](#artifacts-name) - [dependencies](#dependencies) + - [before_script and after_script](#before_script-and-after_script) - [Hidden jobs](#hidden-jobs) - [Special YAML features](#special-yaml-features) - [Anchors](#anchors) @@ -342,6 +343,8 @@ job_name: | dependencies | no | Define other builds that a build depends on so that you can pass artifacts between them| | artifacts | no | Define list build artifacts | | cache | no | Define list of files that should be cached between subsequent runs | +| before_script | no | Override a set of commands that are executed before build | +| after_script | no | Override a set of commands that are executed after build | ### script @@ -686,6 +689,23 @@ deploy: script: make deploy ``` +### before_script and after_script + +It's possible to overwrite globally defined `before_script` and `after_script`: + +```yaml +before_script +- global before script + +job: + before_script: + - execute this instead of global before script + script: + - my command + after_script: + - execute this after my script +``` + ## Hidden jobs >**Note:** -- cgit v1.2.1 From c764b57f09ac55d181d17db018bdea9587fadea8 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 17 Apr 2016 09:11:37 -0400 Subject: Add note about version --- doc/ci/yaml/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 54b06f10b95..697445bceea 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -125,6 +125,9 @@ builds, including deploy builds. This can be an array or a multi-line string. ### after_script +>**Note:** +Introduced in GitLab 8.7 and GitLab Runner v1.2. + `after_script` is used to define the command that will be run after for all builds. This has to be an array or a multi-line string. -- cgit v1.2.1 From a281f68b64c72bfad7796b8dc0ae3805583c66b6 Mon Sep 17 00:00:00 2001 From: BaldinoF Date: Sun, 17 Apr 2016 18:22:23 +0200 Subject: Add CHANGELOG entry --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index d8fbfafb72c..de520330781 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -75,6 +75,7 @@ v 8.7.0 (unreleased) - Fix emoji categories in the emoji picker - Add encrypted credentials for imported projects and migrate old ones - Author and participants are displayed first on users autocompletion + - Show number sign on external issue reference text (Florent Baldino) v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 -- cgit v1.2.1 From 40bc8e7677cb27f87fef7d4362fbd17bee8980ef Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Mon, 18 Apr 2016 12:19:11 +0530 Subject: Add acceptance test to check if the user password persists after form redisplays. - While signing up. --- spec/features/signup_spec.rb | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 spec/features/signup_spec.rb diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb new file mode 100644 index 00000000000..01472743b2a --- /dev/null +++ b/spec/features/signup_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +feature 'Signup', feature: true do + describe 'signup with no errors' do + it 'creates the user account and sends a confirmation email' do + user = build(:user) + + visit root_path + + fill_in 'user_name', with: user.name + fill_in 'user_username', with: user.username + fill_in 'user_email', with: user.email + fill_in 'user_password_sign_up', with: user.password + click_button "Sign up" + + expect(current_path).to eq user_session_path + expect(page).to have_content("A message with a confirmation link has been sent to your email address.") + end + end + + describe 'signup with errors' do + it "displays the errors" do + existing_user = create(:user) + user = build(:user) + + visit root_path + + fill_in 'user_name', with: user.name + fill_in 'user_username', with: user.username + fill_in 'user_email', with: existing_user.email + fill_in 'user_password_sign_up', with: user.password + click_button "Sign up" + + expect(current_path).to eq user_registration_path + expect(page).to have_content("error prohibited this user from being saved") + expect(page).to have_content("Email has already been taken") + end + + it 'does not redisplay the password' do + existing_user = create(:user) + user = build(:user) + + visit root_path + + fill_in 'user_name', with: user.name + fill_in 'user_username', with: user.username + fill_in 'user_email', with: existing_user.email + fill_in 'user_password_sign_up', with: user.password + click_button "Sign up" + + expect(current_path).to eq user_registration_path + expect(page.body).not_to match(/#{user.password}/) + end + end +end -- cgit v1.2.1 From 38557ec400d8c28ea73df4bc5142e156c7ab8855 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Mon, 18 Apr 2016 12:30:04 +0530 Subject: Move CHANGELOG entry to a random place. --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 225751cbb07..ede0c00e902 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -56,6 +56,7 @@ v 8.7.0 (unreleased) - Decouple membership and notifications - Fix creation of merge requests for orphaned branches (Stan Hu) - API: Ability to retrieve a single tag (Robert Schilling) + - While signing up, don't persist the user password across form redisplays - Fall back to `In-Reply-To` and `References` headers when sub-addressing is not available (David Padilla) - Remove "Congratulations!" tweet button on newly-created project. (Connor Shea) - Fix admin/projects when using visibility levels on search (PotHix) @@ -66,7 +67,6 @@ v 8.7.0 (unreleased) - Update number of Todos in the sidebar when it's marked as "Done". !3600 - API: Expose 'updated_at' for issue, snippet, and merge request notes (Robert Schilling) - API: User can leave a project through the API when not master or owner. !3613 - - While signing up, don't persist the user password across form redisplays - Fix repository cache invalidation issue when project is recreated with an empty repo (Stan Hu) - Fix: Allow empty recipients list for builds emails service when pushed is added (Frank Groeneveld) - Improved markdown forms -- cgit v1.2.1 From 6f31262f747b7c1ed0173b6615ef0990967a0db6 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 18 Apr 2016 08:48:41 +0100 Subject: Fixed overlap in header on mobile --- app/assets/stylesheets/framework/header.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 3f015427d07..c303380764b 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -71,7 +71,7 @@ header { .header-content { position: relative; height: $header-height; - padding-right: 20px; + padding-right: 40px; @media (min-width: $screen-sm-min) { padding-right: 0; @@ -122,6 +122,10 @@ header { } } + .project-item-select-holder { + display: inline; + } + .impersonation i { color: $red-normal; } -- cgit v1.2.1 From d7a4a2fe7577f2ca17d28f10d312ed98d5253ae4 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 18 Apr 2016 10:52:01 +0200 Subject: When a project wiki is disabled skip it for fsck --- .../repository_check/single_repository_worker.rb | 6 ++--- .../single_repository_worker_spec.rb | 30 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 spec/workers/repository_check/single_repository_worker_spec.rb diff --git a/app/workers/repository_check/single_repository_worker.rb b/app/workers/repository_check/single_repository_worker.rb index e54ae86d06c..a76729e3c74 100644 --- a/app/workers/repository_check/single_repository_worker.rb +++ b/app/workers/repository_check/single_repository_worker.rb @@ -15,10 +15,10 @@ module RepositoryCheck private def check(project) + repositories = [project.repository] + repositories << project.wiki.repository if project.wiki_enabled? # Use 'map do', not 'all? do', to prevent short-circuiting - [project.repository, project.wiki.repository].map do |repository| - git_fsck(repository.path_to_repo) - end.all? + repositories.map { |repository| git_fsck(repository.path_to_repo) }.all? end def git_fsck(path) diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb new file mode 100644 index 00000000000..3179dd70b0a --- /dev/null +++ b/spec/workers/repository_check/single_repository_worker_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' +require 'fileutils' + +describe RepositoryCheck::SingleRepositoryWorker do + subject { described_class.new } + + it 'fails if the wiki repository is broken' do + project = create(:project_empty_repo, wiki_enabled: true) + project.create_wiki + + # Test sanity: everything should be fine before the wiki repo is broken + subject.perform(project.id) + expect(project.reload.last_repository_check_failed).to eq(false) + + FileUtils.rm_rf(project.wiki.repository.path_to_repo) + subject.perform(project.id) + + expect(project.reload.last_repository_check_failed).to eq(true) + end + + it 'skips wikis when disabled' do + project = create(:project_empty_repo, wiki_enabled: false) + # Make sure the test would fail if it checked the wiki repo + FileUtils.rm_rf(project.wiki.repository.path_to_repo) + + subject.perform(project.id) + + expect(project.reload.last_repository_check_failed).to eq(false) + end +end -- cgit v1.2.1 From fdf6ca6c01ec54bf86ee72d5adbaf4ae3cff8483 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 18 Apr 2016 10:58:40 +0200 Subject: Improve 'auto fsck' admin emails --- app/mailers/repository_check_mailer.rb | 2 +- app/views/repository_check_mailer/notify.html.haml | 3 +++ app/views/repository_check_mailer/notify.text.haml | 3 +++ spec/mailers/repository_check_mailer_spec.rb | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/mailers/repository_check_mailer.rb b/app/mailers/repository_check_mailer.rb index 2bff5b63cc4..21db2fe04a0 100644 --- a/app/mailers/repository_check_mailer.rb +++ b/app/mailers/repository_check_mailer.rb @@ -8,7 +8,7 @@ class RepositoryCheckMailer < BaseMailer mail( to: User.admins.pluck(:email), - subject: @message + subject: "GitLab Admin | #{@message}" ) end end diff --git a/app/views/repository_check_mailer/notify.html.haml b/app/views/repository_check_mailer/notify.html.haml index df16f503570..a585147ddd1 100644 --- a/app/views/repository_check_mailer/notify.html.haml +++ b/app/views/repository_check_mailer/notify.html.haml @@ -3,3 +3,6 @@ %p = link_to "See the affected projects in the GitLab admin panel", admin_namespaces_projects_url(last_repository_check_failed: 1) + +%p + You are receiving this message because you are a GitLab administrator for #{Gitlab.config.gitlab.url}. diff --git a/app/views/repository_check_mailer/notify.text.haml b/app/views/repository_check_mailer/notify.text.haml index 02f3f80288a..93db151329e 100644 --- a/app/views/repository_check_mailer/notify.text.haml +++ b/app/views/repository_check_mailer/notify.text.haml @@ -1,3 +1,6 @@ #{@message}. \ View details: #{admin_namespaces_projects_url(last_repository_check_failed: 1)} + +You are receiving this message because you are a GitLab administrator +for #{Gitlab.config.gitlab.url}. diff --git a/spec/mailers/repository_check_mailer_spec.rb b/spec/mailers/repository_check_mailer_spec.rb index 583bf15176f..00613c7b671 100644 --- a/spec/mailers/repository_check_mailer_spec.rb +++ b/spec/mailers/repository_check_mailer_spec.rb @@ -15,7 +15,7 @@ describe RepositoryCheckMailer do it 'mentions the number of failed checks' do mail = described_class.notify(3) - expect(mail).to have_subject '3 projects failed their last repository check' + expect(mail).to have_subject 'GitLab Admin | 3 projects failed their last repository check' end end end -- cgit v1.2.1 From 1394ccfe834c4e34bed701d206c77961a594fa23 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 18 Apr 2016 11:03:53 +0200 Subject: Destroy wikis uniformly --- spec/workers/repository_check/single_repository_worker_spec.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb index 3179dd70b0a..087e4c667d8 100644 --- a/spec/workers/repository_check/single_repository_worker_spec.rb +++ b/spec/workers/repository_check/single_repository_worker_spec.rb @@ -12,7 +12,7 @@ describe RepositoryCheck::SingleRepositoryWorker do subject.perform(project.id) expect(project.reload.last_repository_check_failed).to eq(false) - FileUtils.rm_rf(project.wiki.repository.path_to_repo) + destroy_wiki(project) subject.perform(project.id) expect(project.reload.last_repository_check_failed).to eq(true) @@ -21,10 +21,14 @@ describe RepositoryCheck::SingleRepositoryWorker do it 'skips wikis when disabled' do project = create(:project_empty_repo, wiki_enabled: false) # Make sure the test would fail if it checked the wiki repo - FileUtils.rm_rf(project.wiki.repository.path_to_repo) + destroy_wiki(project) subject.perform(project.id) expect(project.reload.last_repository_check_failed).to eq(false) end + + def destroy_wiki(project) + FileUtils.rm_rf(project.wiki.repository.path_to_repo) + end end -- cgit v1.2.1 From 7b6785b3b1d03ef8512e098285744e9956ec0891 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 15 Apr 2016 18:31:01 +0200 Subject: Use Module#prepend for method instrumentation By using Module#prepend we can define a Module containing all proxy methods. This removes the need for setting up crazy method alias chains and in turn prevents us from having to deal with all that madness (e.g. methods calling each other recursively). Fixes gitlab-org/gitlab-ce#15281 --- CHANGELOG | 1 + lib/gitlab/metrics/instrumentation.rb | 37 +++++++++++++----- spec/lib/gitlab/metrics/instrumentation_spec.rb | 51 ++++++++++++++++++------- 3 files changed, 65 insertions(+), 24 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ede0c00e902..c29c207ca70 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.7.0 (unreleased) + - Method instrumentation now uses Module#prepend instead of aliasing methods - The Projects::HousekeepingService class has extra instrumentation - All service classes (those residing in app/services) are now instrumented - Developers can now add custom tags to transactions diff --git a/lib/gitlab/metrics/instrumentation.rb b/lib/gitlab/metrics/instrumentation.rb index face1921d2e..708ef79f304 100644 --- a/lib/gitlab/metrics/instrumentation.rb +++ b/lib/gitlab/metrics/instrumentation.rb @@ -11,6 +11,8 @@ module Gitlab module Instrumentation SERIES = 'method_calls' + PROXY_IVAR = :@__gitlab_instrumentation_proxy + def self.configure yield self end @@ -91,6 +93,18 @@ module Gitlab end end + # Returns true if a module is instrumented. + # + # mod - The module to check + def self.instrumented?(mod) + mod.instance_variable_defined?(PROXY_IVAR) + end + + # Returns the proxy module (if any) of `mod`. + def self.proxy_module(mod) + mod.instance_variable_get(PROXY_IVAR) + end + # Instruments a method. # # type - The type (:class or :instance) of method to instrument. @@ -99,9 +113,8 @@ module Gitlab def self.instrument(type, mod, name) return unless Metrics.enabled? - name = name.to_sym - alias_name = :"_original_#{name}" - target = type == :instance ? mod : mod.singleton_class + name = name.to_sym + target = type == :instance ? mod : mod.singleton_class if type == :instance target = mod @@ -113,6 +126,12 @@ module Gitlab method = mod.method(name) end + unless instrumented?(target) + target.instance_variable_set(PROXY_IVAR, Module.new) + end + + proxy_module = self.proxy_module(target) + # Some code out there (e.g. the "state_machine" Gem) checks the arity of # a method to make sure it only passes arguments when the method expects # any. If we were to always overwrite a method to take an `*args` @@ -125,17 +144,13 @@ module Gitlab args_signature = '*args, &block' end - send_signature = "__send__(#{alias_name.inspect}, #{args_signature})" - - target.class_eval <<-EOF, __FILE__, __LINE__ + 1 - alias_method #{alias_name.inspect}, #{name.inspect} - + proxy_module.class_eval <<-EOF, __FILE__, __LINE__ + 1 def #{name}(#{args_signature}) trans = Gitlab::Metrics::Instrumentation.transaction if trans start = Time.now - retval = #{send_signature} + retval = super duration = (Time.now - start) * 1000.0 if duration >= Gitlab::Metrics.method_call_threshold @@ -148,10 +163,12 @@ module Gitlab retval else - #{send_signature} + super end end EOF + + target.prepend(proxy_module) end # Small layer of indirection to make it easier to stub out the current diff --git a/spec/lib/gitlab/metrics/instrumentation_spec.rb b/spec/lib/gitlab/metrics/instrumentation_spec.rb index ad4290c43bb..5c885a7a982 100644 --- a/spec/lib/gitlab/metrics/instrumentation_spec.rb +++ b/spec/lib/gitlab/metrics/instrumentation_spec.rb @@ -33,8 +33,16 @@ describe Gitlab::Metrics::Instrumentation do described_class.instrument_method(@dummy, :foo) end - it 'renames the original method' do - expect(@dummy).to respond_to(:_original_foo) + it 'instruments the Class' do + target = @dummy.singleton_class + + expect(described_class.instrumented?(target)).to eq(true) + end + + it 'defines a proxy method' do + mod = described_class.proxy_module(@dummy.singleton_class) + + expect(mod.method_defined?(:foo)).to eq(true) end it 'calls the instrumented method with the correct arguments' do @@ -76,6 +84,14 @@ describe Gitlab::Metrics::Instrumentation do expect(dummy.method(:test).arity).to eq(0) end + + describe 'when a module is instrumented multiple times' do + it 'calls the instrumented method with the correct arguments' do + described_class.instrument_method(@dummy, :foo) + + expect(@dummy.foo).to eq('foo') + end + end end describe 'with metrics disabled' do @@ -86,7 +102,9 @@ describe Gitlab::Metrics::Instrumentation do it 'does not instrument the method' do described_class.instrument_method(@dummy, :foo) - expect(@dummy).to_not respond_to(:_original_foo) + target = @dummy.singleton_class + + expect(described_class.instrumented?(target)).to eq(false) end end end @@ -100,8 +118,14 @@ describe Gitlab::Metrics::Instrumentation do instrument_instance_method(@dummy, :bar) end - it 'renames the original method' do - expect(@dummy.method_defined?(:_original_bar)).to eq(true) + it 'instruments instances of the Class' do + expect(described_class.instrumented?(@dummy)).to eq(true) + end + + it 'defines a proxy method' do + mod = described_class.proxy_module(@dummy) + + expect(mod.method_defined?(:bar)).to eq(true) end it 'calls the instrumented method with the correct arguments' do @@ -144,7 +168,7 @@ describe Gitlab::Metrics::Instrumentation do described_class. instrument_instance_method(@dummy, :bar) - expect(@dummy.method_defined?(:_original_bar)).to eq(false) + expect(described_class.instrumented?(@dummy)).to eq(false) end end end @@ -167,18 +191,17 @@ describe Gitlab::Metrics::Instrumentation do it 'recursively instruments a class hierarchy' do described_class.instrument_class_hierarchy(@dummy) - expect(@child1).to respond_to(:_original_child1_foo) - expect(@child2).to respond_to(:_original_child2_foo) + expect(described_class.instrumented?(@child1.singleton_class)).to eq(true) + expect(described_class.instrumented?(@child2.singleton_class)).to eq(true) - expect(@child1.method_defined?(:_original_child1_bar)).to eq(true) - expect(@child2.method_defined?(:_original_child2_bar)).to eq(true) + expect(described_class.instrumented?(@child1)).to eq(true) + expect(described_class.instrumented?(@child2)).to eq(true) end it 'does not instrument the root module' do described_class.instrument_class_hierarchy(@dummy) - expect(@dummy).to_not respond_to(:_original_foo) - expect(@dummy.method_defined?(:_original_bar)).to eq(false) + expect(described_class.instrumented?(@dummy)).to eq(false) end end @@ -190,7 +213,7 @@ describe Gitlab::Metrics::Instrumentation do it 'instruments all public class methods' do described_class.instrument_methods(@dummy) - expect(@dummy).to respond_to(:_original_foo) + expect(described_class.instrumented?(@dummy.singleton_class)).to eq(true) end it 'only instruments methods directly defined in the module' do @@ -223,7 +246,7 @@ describe Gitlab::Metrics::Instrumentation do it 'instruments all public instance methods' do described_class.instrument_instance_methods(@dummy) - expect(@dummy.method_defined?(:_original_bar)).to eq(true) + expect(described_class.instrumented?(@dummy)).to eq(true) end it 'only instruments methods directly defined in the module' do -- cgit v1.2.1 From c24640c721aed987a22c2e097cada73145cfb12b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 18 Apr 2016 11:06:30 +0100 Subject: Fixed issue with tasklist toggling sidebar refresh Closes #15270 --- app/views/projects/issues/update.js.haml | 3 --- app/views/projects/merge_requests/update.js.haml | 3 --- 2 files changed, 6 deletions(-) diff --git a/app/views/projects/issues/update.js.haml b/app/views/projects/issues/update.js.haml index 986d8c220db..e69de29bb2d 100644 --- a/app/views/projects/issues/update.js.haml +++ b/app/views/projects/issues/update.js.haml @@ -1,3 +0,0 @@ -$('aside.right-sidebar')[0].outerHTML = "#{escape_javascript(render 'shared/issuable/sidebar', issuable: @issue)}"; -$('aside.right-sidebar').effect('highlight'); -new IssuableContext(); diff --git a/app/views/projects/merge_requests/update.js.haml b/app/views/projects/merge_requests/update.js.haml index 9cce5660e1c..e69de29bb2d 100644 --- a/app/views/projects/merge_requests/update.js.haml +++ b/app/views/projects/merge_requests/update.js.haml @@ -1,3 +0,0 @@ -$('aside.right-sidebar')[0].outerHTML = "#{escape_javascript(render 'shared/issuable/sidebar', issuable: @merge_request)}"; -$('aside.right-sidebar').effect('highlight'); -new IssuableContext(); -- cgit v1.2.1 From 651c3e841d6b0ca46edb6aa5cc62d42051a46d61 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 15 Apr 2016 12:14:27 +0200 Subject: Instrument Repository.clean_old_archives --- CHANGELOG | 1 + app/models/repository.rb | 8 +++++--- spec/models/repository_spec.rb | 25 ++++++++++++++++++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c29c207ca70..7ef374b04d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.7.0 (unreleased) - Method instrumentation now uses Module#prepend instead of aliasing methods + - Repository.clean_old_archives is now instrumented - The Projects::HousekeepingService class has extra instrumentation - All service classes (those residing in app/services) are now instrumented - Developers can now add custom tags to transactions diff --git a/app/models/repository.rb b/app/models/repository.rb index 308c590e3f8..589756f8531 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -12,11 +12,13 @@ class Repository attr_accessor :path_with_namespace, :project def self.clean_old_archives - repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path + Gitlab::Metrics.measure(:clean_old_archives) do + repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path - return unless File.directory?(repository_downloads_path) + return unless File.directory?(repository_downloads_path) - Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete)) + Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete)) + end end def initialize(path_with_namespace, project) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index c163001b7c1..f30a21e79ae 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -910,9 +910,32 @@ describe Repository, models: true do end end + describe '.clean_old_archives' do + let(:path) { Gitlab.config.gitlab.repository_downloads_path } + + context 'when the downloads directory does not exist' do + it 'does not remove any archives' do + expect(File).to receive(:directory?).with(path).and_return(false) + + expect(Gitlab::Popen).not_to receive(:popen) + + described_class.clean_old_archives + end + end + + context 'when the downloads directory exists' do + it 'removes old archives' do + expect(File).to receive(:directory?).with(path).and_return(true) + + expect(Gitlab::Popen).to receive(:popen) + + described_class.clean_old_archives + end + end + end + def create_remote_branch(remote_name, branch_name, target) rugged = repository.rugged rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", target) end - end -- cgit v1.2.1 From 1a57601d8cac0de35f301f8a8094c61fc94ed1cb Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 18 Apr 2016 12:00:20 +0100 Subject: Updated print style Closes #14201 --- app/assets/stylesheets/print.scss | 44 ++++++++++++++++------ .../projects/notes/_notes_with_form.html.haml | 2 +- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/print.scss b/app/assets/stylesheets/print.scss index 1be0551ad3b..a30b6492572 100644 --- a/app/assets/stylesheets/print.scss +++ b/app/assets/stylesheets/print.scss @@ -1,17 +1,37 @@ -/* Generic print styles */ -header, nav, nav.main-nav, nav.navbar-collapse, nav.navbar-collapse.collapse {display: none!important;} -.profiler-results {display: none;} - -/* Styles targeted specifically at printing files */ -.tree-ref-holder, .tree-holder .breadcrumb, .blob-commit-info {display: none;} -.file-title {display: none;} -.file-holder {border: none;} - .wiki h1, .wiki h2, .wiki h3, .wiki h4, .wiki h5, .wiki h6 {margin-top: 17px; } .wiki h1 {font-size: 30px;} .wiki h2 {font-size: 22px;} .wiki h3 {font-size: 18px; font-weight: bold; } -.sidebar-wrapper { display: none; } -.nav { display: none; } -.btn { display: none; } +header, +nav, +nav.main-nav, +nav.navbar-collapse, +nav.navbar-collapse.collapse, +.profiler-results, +.tree-ref-holder, +.tree-holder .breadcrumb, +.blob-commit-info, +.file-title, +.file-holder, +.sidebar-wrapper, +.nav, +.btn, +ul.notes-form, +.merge-request-ci-status .ci-status-link:after, +.issuable-gutter-toggle, +.gutter-toggle, +.issuable-details .content-block-small, +.edit-link, +.note-action-button { + display: none!important; +} + +.page-gutter { + padding-top: 0; + padding-left: 0; +} + +.right-sidebar { + top: 0; +} diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml index cc42aab5c52..1c39ce897a3 100644 --- a/app/views/projects/notes/_notes_with_form.html.haml +++ b/app/views/projects/notes/_notes_with_form.html.haml @@ -1,6 +1,6 @@ %ul#notes-list.notes.main-notes-list.timeline = render "projects/notes/notes" -%ul.notes.timeline +%ul.notes.notes-form.timeline %li.timeline-entry - if can? current_user, :create_note, @project .timeline-icon.hidden-xs.hidden-sm -- cgit v1.2.1 From 167fa5c459f275e17a4d8f7155f15004cc29c28d Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 18 Apr 2016 12:02:39 +0100 Subject: CHANGELOG item --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index de520330781..9deb0437878 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -76,6 +76,7 @@ v 8.7.0 (unreleased) - Add encrypted credentials for imported projects and migrate old ones - Author and participants are displayed first on users autocompletion - Show number sign on external issue reference text (Florent Baldino) + - Updated print style for issues v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 -- cgit v1.2.1 From a1363d39c6fe79d830dbce468c02880d2a5d7996 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 8 Apr 2016 11:02:26 +0200 Subject: Add `variables` keyword to job in CI config YAML --- app/models/ci/build.rb | 12 ++++++-- lib/ci/gitlab_ci_yaml_processor.rb | 3 +- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 44 ++++++++++++++++++++-------- spec/models/build_spec.rb | 16 ++++++++++ 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 7d33838044b..89a9eb76331 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -365,9 +365,11 @@ module Ci self.update(erased_by: user, erased_at: Time.now) end - private - def yaml_variables + global_yaml_variables + job_yaml_variables + end + + def global_yaml_variables if commit.config_processor commit.config_processor.variables.map do |key, value| { key: key, value: value, public: true } @@ -377,6 +379,12 @@ module Ci end end + def job_yaml_variables + options[:variables].to_h.map do |key, value| + { key: key, value: value, public: true } + end + end + def project_variables project.variables.map do |variable| { key: variable.key, value: variable.value, public: false } diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index b7209c14148..712dc4492c5 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -7,7 +7,7 @@ module Ci ALLOWED_YAML_KEYS = [:before_script, :image, :services, :types, :stages, :variables, :cache] ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when, :artifacts, :cache, - :dependencies] + :dependencies, :variables] attr_reader :before_script, :image, :services, :variables, :path, :cache @@ -85,6 +85,7 @@ module Ci artifacts: job[:artifacts], cache: job[:cache] || @cache, dependencies: job[:dependencies], + variables: job[:variables], }.compact } end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index dcb8a3451bd..a3a0d06e149 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -346,19 +346,39 @@ module Ci end describe "Variables" do - it "returns variables when defined" do - variables = { - var1: "value1", - var2: "value2", - } - config = YAML.dump({ - variables: variables, - before_script: ["pwd"], - rspec: { script: "rspec" } - }) + context 'when global variables are defined' do + it 'returns variables' do + variables = { + var1: "value1", + var2: "value2", + } + config = YAML.dump({ + variables: variables, + before_script: ["pwd"], + rspec: { script: "rspec" } + }) - config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config_processor.variables).to eq(variables) + config_processor = GitlabCiYamlProcessor.new(config, path) + expect(config_processor.variables).to eq(variables) + end + end + + context 'when job variables are defined' do + let(:job_variables) { { KEY1: 'value1', SOME_KEY_2: 'value2'} } + let(:yaml_config) do + YAML.dump( + { before_script: ['pwd'], + rspec: { + variables: job_variables, + script: 'rspec' } + }) + end + + it 'appends job variable to job attributes' do + config = GitlabCiYamlProcessor.new(yaml_config, path) + + expect(config.builds.first[:options][:variables]).to eq job_variables + end end end diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index b7457808040..ee44a4c5f12 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -238,6 +238,22 @@ describe Ci::Build, models: true do it { is_expected.to eq(predefined_variables + predefined_trigger_variable + yaml_variables + secure_variables + trigger_variables) } end + + context 'when job variables are defined' do + before { build.update_attribute(:options, variables: job_variables) } + + context 'when job variables are unique' do + let(:job_variables) { { KEY1: 'value1', KEY2: 'value2' } } + let(:resulting_variables) do + [{ key: :KEY1, value: 'value1', public: true }, + { key: :KEY2, value: 'value2', public: true }] + end + + it 'includes job variables' do + expect(subject).to include(*resulting_variables) + end + end + end end end end -- cgit v1.2.1 From b578fbfb8572860490cdfd0163bfbf5f999bb1e6 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 11 Apr 2016 13:09:46 +0200 Subject: Make it possible to override build variables --- app/models/ci/build.rb | 3 ++- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 2 +- spec/models/build_spec.rb | 24 +++++++++++++++++++----- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 89a9eb76331..61d39caeb79 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -147,7 +147,8 @@ module Ci end def variables - predefined_variables + yaml_variables + project_variables + trigger_variables + (predefined_variables + yaml_variables + project_variables + trigger_variables) + .reverse.uniq { |var| var[:key] }.reverse end def merge_request diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index a3a0d06e149..c2908f855e3 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -364,7 +364,7 @@ module Ci end context 'when job variables are defined' do - let(:job_variables) { { KEY1: 'value1', SOME_KEY_2: 'value2'} } + let(:job_variables) { { KEY1: 'value1', SOME_KEY_2: 'value2' } } let(:yaml_config) do YAML.dump( { before_script: ['pwd'], diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index ee44a4c5f12..94d51435f37 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -240,17 +240,31 @@ describe Ci::Build, models: true do end context 'when job variables are defined' do + def result_variables + job_variables.map do |key, value| + { key: key, value: value, public: true } + end + end + before { build.update_attribute(:options, variables: job_variables) } context 'when job variables are unique' do let(:job_variables) { { KEY1: 'value1', KEY2: 'value2' } } - let(:resulting_variables) do - [{ key: :KEY1, value: 'value1', public: true }, - { key: :KEY2, value: 'value2', public: true }] - end it 'includes job variables' do - expect(subject).to include(*resulting_variables) + expect(subject).to include(*result_variables) + end + end + + context 'when job variable has same key other variable has' do + let(:job_variables) { { CI_BUILD_NAME: 'overridden' } } + + it 'contains job yaml variable' do + expect(subject).to include(*result_variables) + end + + it 'contains only one variable with this key' do + expect(subject.count { |var| var[:key] == :CI_BUILD_NAME } ).to eq 1 end end end -- cgit v1.2.1 From b7946b50fc1b23b1974f7d0306c06f6d92cc8466 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 15 Apr 2016 12:18:46 +0200 Subject: Read job variables directly from gitlab CI config --- app/models/ci/build.rb | 8 ++++++-- lib/ci/gitlab_ci_yaml_processor.rb | 12 ++++++++++-- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 4 ++-- spec/models/build_spec.rb | 22 +++++++++------------- spec/support/gitlab_stubs/gitlab_ci.yml | 17 +++++++++++------ 5 files changed, 38 insertions(+), 25 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 61d39caeb79..6c4ee2a0d44 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -381,8 +381,12 @@ module Ci end def job_yaml_variables - options[:variables].to_h.map do |key, value| - { key: key, value: value, public: true } + if commit.config_processor + commit.config_processor.job_variables(name).map do |key, value| + { key: key, value: value, public: true } + end + else + [] end end diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 712dc4492c5..548c6250e04 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -9,7 +9,7 @@ module Ci :allow_failure, :type, :stage, :when, :artifacts, :cache, :dependencies, :variables] - attr_reader :before_script, :image, :services, :variables, :path, :cache + attr_reader :before_script, :image, :services, :path, :cache def initialize(config, path = nil) @config = YAML.safe_load(config, [Symbol], [], true) @@ -40,6 +40,15 @@ module Ci @stages || DEFAULT_STAGES end + def variables + @variables + end + + def job_variables(name) + job = @jobs[name.to_sym] + job ? job[:variables] : [] + end + private def initial_parsing @@ -85,7 +94,6 @@ module Ci artifacts: job[:artifacts], cache: job[:cache] || @cache, dependencies: job[:dependencies], - variables: job[:variables], }.compact } end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index c2908f855e3..04b1d8baeb2 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -374,10 +374,10 @@ module Ci }) end - it 'appends job variable to job attributes' do + it 'returns job variables' do config = GitlabCiYamlProcessor.new(yaml_config, path) - expect(config.builds.first[:options][:variables]).to eq job_variables + expect(config.job_variables(:rspec)).to eq job_variables end end end diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index 94d51435f37..26a063de1e1 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -240,31 +240,27 @@ describe Ci::Build, models: true do end context 'when job variables are defined' do - def result_variables - job_variables.map do |key, value| - { key: key, value: value, public: true } - end - end - - before { build.update_attribute(:options, variables: job_variables) } - context 'when job variables are unique' do - let(:job_variables) { { KEY1: 'value1', KEY2: 'value2' } } + before { allow(build).to receive(:name) { 'staging' } } it 'includes job variables' do - expect(subject).to include(*result_variables) + expect(subject).to include( + { key: :KEY1, value: 'value1', public: true }, + { key: :KEY2, value: 'value2', public: true } + ) end end context 'when job variable has same key other variable has' do - let(:job_variables) { { CI_BUILD_NAME: 'overridden' } } + before { allow(build).to receive(:name) { 'production' } } it 'contains job yaml variable' do - expect(subject).to include(*result_variables) + expect(subject).to include(key: :DB_NAME, value: 'mysql', + public: true) end it 'contains only one variable with this key' do - expect(subject.count { |var| var[:key] == :CI_BUILD_NAME } ).to eq 1 + expect(subject.count { |var| var[:key] == :DB_NAME } ).to eq 1 end end end diff --git a/spec/support/gitlab_stubs/gitlab_ci.yml b/spec/support/gitlab_stubs/gitlab_ci.yml index a5b256bd3ec..e55a61b2b94 100644 --- a/spec/support/gitlab_stubs/gitlab_ci.yml +++ b/spec/support/gitlab_stubs/gitlab_ci.yml @@ -4,7 +4,7 @@ services: before_script: - gem install bundler - - bundle install + - bundle install - bundle exec rake db:create variables: @@ -17,7 +17,7 @@ types: rspec: script: "rake spec" - tags: + tags: - ruby - postgres only: @@ -26,27 +26,32 @@ rspec: spinach: script: "rake spinach" allow_failure: true - tags: + tags: - ruby - mysql except: - tags staging: + variables: + KEY1: value1 + KEY2: value2 script: "cap deploy stating" type: deploy - tags: + tags: - ruby - mysql except: - stable production: + variables: + DB_NAME: mysql type: deploy - script: + script: - cap deploy production - cap notify - tags: + tags: - ruby - mysql only: -- cgit v1.2.1 From 3dec6e262984faa18b235db4bbd669ccdc80fc3f Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 15 Apr 2016 12:28:27 +0200 Subject: Rename method that returns global envs in CI conf --- app/models/ci/build.rb | 2 +- lib/ci/gitlab_ci_yaml_processor.rb | 2 +- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 6c4ee2a0d44..1146028b9a9 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -372,7 +372,7 @@ module Ci def global_yaml_variables if commit.config_processor - commit.config_processor.variables.map do |key, value| + commit.config_processor.global_variables.map do |key, value| { key: key, value: value, public: true } end else diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 548c6250e04..f69b861c989 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -40,7 +40,7 @@ module Ci @stages || DEFAULT_STAGES end - def variables + def global_variables @variables end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 04b1d8baeb2..ba5f7b0e09a 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -359,7 +359,7 @@ module Ci }) config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config_processor.variables).to eq(variables) + expect(config_processor.global_variables).to eq(variables) end end -- cgit v1.2.1 From 1f3248644ef98879a8a4c31d5be0de9a774cc32a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 15 Apr 2016 14:57:22 +0200 Subject: Make CI config return empty array if no job variables --- lib/ci/gitlab_ci_yaml_processor.rb | 7 +++++-- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index f69b861c989..e152de590de 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -45,8 +45,11 @@ module Ci end def job_variables(name) - job = @jobs[name.to_sym] - job ? job[:variables] : [] + if job = @jobs[name.to_sym] + job[:variables] || [] + else + [] + end end private diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index ba5f7b0e09a..45f08c95cc3 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -380,6 +380,18 @@ module Ci expect(config.job_variables(:rspec)).to eq job_variables end end + + context 'when job variables are not defined' do + it 'returns empty array' do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec" } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + expect(config_processor.job_variables(:rspec)).to eq [] + end + end end describe "When" do -- cgit v1.2.1 From bdb06fa0437ebc1b03377d95763d1fefdcfd0441 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 15 Apr 2016 20:43:23 +0200 Subject: Improve build specs for job environment variables --- spec/models/build_spec.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index 26a063de1e1..5ee40c22536 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -240,8 +240,11 @@ describe Ci::Build, models: true do end context 'when job variables are defined' do + ## + # Job-level variables are defined in gitlab_ci.yml fixture + # context 'when job variables are unique' do - before { allow(build).to receive(:name) { 'staging' } } + let(:build) { create(:ci_build, name: 'staging') } it 'includes job variables' do expect(subject).to include( @@ -252,7 +255,7 @@ describe Ci::Build, models: true do end context 'when job variable has same key other variable has' do - before { allow(build).to receive(:name) { 'production' } } + let(:build) { create(:ci_build, name: 'production') } it 'contains job yaml variable' do expect(subject).to include(key: :DB_NAME, value: 'mysql', -- cgit v1.2.1 From 9a74b92d2afe028453c3fde7221fce20bcb073d9 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 15 Apr 2016 20:45:18 +0200 Subject: Add Changelog entry for job-level variables --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 7ef374b04d8..b929f1fd7b9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.7.0 (unreleased) - Method instrumentation now uses Module#prepend instead of aliasing methods - Repository.clean_old_archives is now instrumented + - Add support for environment variables on a job level in CI configuration file - The Projects::HousekeepingService class has extra instrumentation - All service classes (those residing in app/services) are now instrumented - Developers can now add custom tags to transactions -- cgit v1.2.1 From a6260b1eb7b4f30817d0cc5dbd80c860b5ed8a31 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sat, 16 Apr 2016 20:21:01 +0200 Subject: Remove code that removes duplicate CI variables At this point this is being handled by GitLab Runner and we need to introduce this as a separate merge request. --- app/models/ci/build.rb | 3 +-- spec/models/build_spec.rb | 13 ------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 1146028b9a9..85ef0523b31 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -147,8 +147,7 @@ module Ci end def variables - (predefined_variables + yaml_variables + project_variables + trigger_variables) - .reverse.uniq { |var| var[:key] }.reverse + predefined_variables + yaml_variables + project_variables + trigger_variables end def merge_request diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index 5ee40c22536..b5d356aa066 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -253,19 +253,6 @@ describe Ci::Build, models: true do ) end end - - context 'when job variable has same key other variable has' do - let(:build) { create(:ci_build, name: 'production') } - - it 'contains job yaml variable' do - expect(subject).to include(key: :DB_NAME, value: 'mysql', - public: true) - end - - it 'contains only one variable with this key' do - expect(subject.count { |var| var[:key] == :DB_NAME } ).to eq 1 - end - end end end end -- cgit v1.2.1 From cf3e3effb01215c2556ba509d3cb4debe1d901e8 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sat, 16 Apr 2016 20:52:01 +0200 Subject: Minor refactoring in code related to job variables --- lib/ci/gitlab_ci_yaml_processor.rb | 6 +--- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 43 ++++++++++++++++------------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index e152de590de..209da7ad81f 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -45,11 +45,7 @@ module Ci end def job_variables(name) - if job = @jobs[name.to_sym] - job[:variables] || [] - else - [] - end + @jobs[name.to_sym].try(:fetch, :variables, []) || [] end private diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 45f08c95cc3..9a014c4b6c6 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -345,50 +345,55 @@ module Ci end end - describe "Variables" do + describe 'Variables' do context 'when global variables are defined' do - it 'returns variables' do + it 'returns global variables' do variables = { - var1: "value1", - var2: "value2", + VAR1: 'value1', + VAR2: 'value2', } + config = YAML.dump({ - variables: variables, - before_script: ["pwd"], - rspec: { script: "rspec" } - }) + variables: variables, + before_script: ['pwd'], + rspec: { script: 'rspec' } + }) config_processor = GitlabCiYamlProcessor.new(config, path) + expect(config_processor.global_variables).to eq(variables) end end context 'when job variables are defined' do - let(:job_variables) { { KEY1: 'value1', SOME_KEY_2: 'value2' } } - let(:yaml_config) do - YAML.dump( + it 'returns job variables' do + variables = { + KEY1: 'value1', + SOME_KEY_2: 'value2' + } + + config = YAML.dump( { before_script: ['pwd'], rspec: { - variables: job_variables, + variables: variables, script: 'rspec' } }) - end - it 'returns job variables' do - config = GitlabCiYamlProcessor.new(yaml_config, path) + config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config.job_variables(:rspec)).to eq job_variables + expect(config_processor.job_variables(:rspec)).to eq variables end end context 'when job variables are not defined' do it 'returns empty array' do config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec" } - }) + before_script: ['pwd'], + rspec: { script: 'rspec' } + }) config_processor = GitlabCiYamlProcessor.new(config, path) + expect(config_processor.job_variables(:rspec)).to eq [] end end -- cgit v1.2.1 From 5d89bdb16a9340c7d8b43efc03dba623f8fb4d31 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sat, 16 Apr 2016 21:17:05 +0200 Subject: Add documentation for job-level build variables --- doc/ci/variables/README.md | 4 +++- doc/ci/yaml/README.md | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index b0e53cbc261..35dac4c9337 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -70,12 +70,14 @@ These variables can be later used in all executed commands and scripts. The YAML-defined variables are also set to all created service containers, thus allowing to fine tune them. +Variables can be defined on a global level, but also on a job level. + More information about Docker integration can be found in [Using Docker Images](../docker/using_docker_images.md). ### User-defined variables (Secure Variables) **This feature requires GitLab Runner 0.4.0 or higher** -GitLab CI allows you to define per-project **Secure Variables** that are set in build environment. +GitLab CI allows you to define per-project **Secure Variables** that are set in build environment. The secure variables are stored out of the repository (the `.gitlab-ci.yml`). The variables are securely passed to GitLab Runner and are available in build environment. It's desired method to use them for storing passwords, secret keys or whatever you want. diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index abb6e97e5e6..ea7d6dfa465 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -23,6 +23,7 @@ If you want a quick introduction to GitLab CI, follow our - [Jobs](#jobs) - [script](#script) - [stage](#stage) + - [job variables](#job-variables) - [only and except](#only-and-except) - [tags](#tags) - [when](#when) @@ -174,6 +175,8 @@ These variables can be later used in all executed commands and scripts. The YAML-defined variables are also set to all created service containers, thus allowing to fine tune them. +Variables can be also defined on [job level](#job-variables). + ### cache >**Note:** @@ -324,6 +327,7 @@ job_name: | services | no | Use docker services, covered in [Using Docker Images](../docker/using_docker_images.md#define-image-and-services-from-gitlab-ciyml) | | stage | no | Defines a build stage (default: `test`) | | type | no | Alias for `stage` | +| variables | no | Define build variables on a job level | | only | no | Defines a list of git refs for which build is created | | except | no | Defines a list of git refs for which build is not created | | tags | no | Defines a list of tags which are used to select Runner | @@ -414,6 +418,23 @@ job: The above example will run `job` for all branches on `gitlab-org/gitlab-ce`, except master. +### job variables + +It is possible to define build variables using a `variables` keyword on a job +level. It works basically the same way like it's global-level equivalent but +allows you to define a job specific build variables. + +When `variables` keyword is used on a job level, it can override global YAML +build variables and predefined variables. + +Build variables priority is defined as follows: + +* predefined variables +* global YAML variables +* job YAML variables +* secure variables +* trigger variables + ### tags `tags` is used to select specific Runners from the list of all Runners that are -- cgit v1.2.1 From a2649739055842ce519fab5a8b0c68dbf23cb35a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sat, 16 Apr 2016 22:04:59 +0200 Subject: Improve grammar in CI documentation for build vars --- doc/ci/variables/README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index 35dac4c9337..f321a618f3b 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -70,17 +70,20 @@ These variables can be later used in all executed commands and scripts. The YAML-defined variables are also set to all created service containers, thus allowing to fine tune them. -Variables can be defined on a global level, but also on a job level. +Variables can be defined at a global level, but also at a job level. More information about Docker integration can be found in [Using Docker Images](../docker/using_docker_images.md). ### User-defined variables (Secure Variables) **This feature requires GitLab Runner 0.4.0 or higher** -GitLab CI allows you to define per-project **Secure Variables** that are set in build environment. +GitLab CI allows you to define per-project **Secure Variables** that are set in +the build environment. The secure variables are stored out of the repository (the `.gitlab-ci.yml`). -The variables are securely passed to GitLab Runner and are available in build environment. -It's desired method to use them for storing passwords, secret keys or whatever you want. +The variables are securely passed to GitLab Runner and are available in the +build environment. +It's desired method to use them for storing passwords, secret keys or whatever +you want. **The value of the variable can be shown in build log if explicitly asked to do so.** If your project is public or internal you can make the builds private. -- cgit v1.2.1 From a2957291b3a28eff3988dfc8bdcff4b99b20a1b3 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sun, 17 Apr 2016 20:08:02 +0200 Subject: Update documentation on job level build variables --- doc/ci/variables/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index f321a618f3b..e1df9e5f543 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -1,17 +1,19 @@ ## Variables + When receiving a build from GitLab CI, the runner prepares the build environment. It starts by setting a list of **predefined variables** (Environment Variables) and a list of **user-defined variables** The variables can be overwritten. They take precedence over each other in this order: 1. Secure variables -1. YAML-defined variables +1. YAML-defined job-leve variables +1. YAML-defined global variables 1. Predefined variables For example, if you define: -1. API_TOKEN=SECURE as Secure Variable -1. API_TOKEN=YAML as YAML-defined variable +1. `API_TOKEN=SECURE` as Secure Variable +1. `API_TOKEN=YAML` as YAML-defined variable -The API_TOKEN will take the Secure Variable value: `SECURE`. +The `API_TOKEN` will take the Secure Variable value: `SECURE`. ### Predefined variables (Environment Variables) -- cgit v1.2.1 From 2b1c08be8fa5c18f1fe151feb2a0938734086481 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sun, 17 Apr 2016 20:23:42 +0200 Subject: Validate job-level variables in YAML config file --- lib/ci/gitlab_ci_yaml_processor.rb | 8 +++++ spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 45 ++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 209da7ad81f..ddf34b60a85 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -153,6 +153,7 @@ module Ci validate_job_types!(name, job) validate_job_stage!(name, job) if job[:stage] + validate_job_variables!(name, job) if job[:variables] validate_job_cache!(name, job) if job[:cache] validate_job_artifacts!(name, job) if job[:artifacts] validate_job_dependencies!(name, job) if job[:dependencies] @@ -214,6 +215,13 @@ module Ci end end + def validate_job_variables!(name, job) + if job[:variables] && !validate_variables(job[:variables]) + raise ValidationError, + "#{name} job: variables should be a map of key-valued strings" + end + end + def validate_job_cache!(name, job) if job[:cache][:key] && !validate_string(job[:cache][:key]) raise ValidationError, "#{name} job: cache:key parameter should be a string" diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 9a014c4b6c6..8813a724774 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -366,22 +366,41 @@ module Ci end context 'when job variables are defined' do - it 'returns job variables' do - variables = { - KEY1: 'value1', - SOME_KEY_2: 'value2' - } + context 'when syntax is correct' do + it 'returns job variables' do + variables = { + KEY1: 'value1', + SOME_KEY_2: 'value2' + } - config = YAML.dump( - { before_script: ['pwd'], - rspec: { - variables: variables, - script: 'rspec' } - }) + config = YAML.dump( + { before_script: ['pwd'], + rspec: { + variables: variables, + script: 'rspec' } + }) - config_processor = GitlabCiYamlProcessor.new(config, path) + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.job_variables(:rspec)).to eq variables + end + end - expect(config_processor.job_variables(:rspec)).to eq variables + context 'when syntax is incorrect' do + it 'raises error' do + variables = [:KEY1, 'value1', :KEY2, 'value2'] + + config = YAML.dump( + { before_script: ['pwd'], + rspec: { + variables: variables, + script: 'rspec' } + }) + + expect { GitlabCiYamlProcessor.new(config, path) } + .to raise_error(GitlabCiYamlProcessor::ValidationError, + /job: variables should be a map/) + end end end -- cgit v1.2.1 From 2972a991df0e7a0071de1803205814f2d105df46 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 18 Apr 2016 12:29:36 +0200 Subject: Add minor fixes in docs for job-specific variables --- doc/ci/variables/README.md | 3 ++- doc/ci/yaml/README.md | 15 +++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index e1df9e5f543..70fb81492d6 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -4,8 +4,9 @@ When receiving a build from GitLab CI, the runner prepares the build environment It starts by setting a list of **predefined variables** (Environment Variables) and a list of **user-defined variables** The variables can be overwritten. They take precedence over each other in this order: +1. Trigger variables 1. Secure variables -1. YAML-defined job-leve variables +1. YAML-defined job-level variables 1. YAML-defined global variables 1. Predefined variables diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index ea7d6dfa465..61475b45988 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -421,19 +421,14 @@ except master. ### job variables It is possible to define build variables using a `variables` keyword on a job -level. It works basically the same way like it's global-level equivalent but -allows you to define a job specific build variables. +level. It works basically the same way as its global-level equivalent but +allows you to define job-specific build variables. -When `variables` keyword is used on a job level, it can override global YAML +When the `variables` keyword is used on a job level, it overrides global YAML build variables and predefined variables. -Build variables priority is defined as follows: - -* predefined variables -* global YAML variables -* job YAML variables -* secure variables -* trigger variables +Build variables priority is defined in +[variables documentation](../variables/README.md). ### tags -- cgit v1.2.1 From 0592112c6e9cebfcae6869c8fa273d7c13b74c16 Mon Sep 17 00:00:00 2001 From: Arinde Eniola Date: Mon, 18 Apr 2016 12:36:15 +0100 Subject: change the link color of the target branch in a merge rquest --- app/views/projects/merge_requests/_show.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 285ad26316c..7125d7d9d1c 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -31,7 +31,8 @@ %span Request to merge %span.label-branch= source_branch_with_namespace(@merge_request) %span into - = link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" + %span.label-branch + = link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch) - if @merge_request.open? && @merge_request.diverged_from_target_branch? %span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind) -- cgit v1.2.1 From 1339fda1cd3325c0186b5f1b53444e7319ad3cb6 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 18 Apr 2016 12:41:13 +0200 Subject: Minor refactorings in CI config --- lib/ci/gitlab_ci_yaml_processor.rb | 11 +++++++---- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index ddf34b60a85..b8ede3a7edc 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -45,7 +45,10 @@ module Ci end def job_variables(name) - @jobs[name.to_sym].try(:fetch, :variables, []) || [] + job = @jobs[name.to_sym] + return [] unless job + + job.fetch(:variables, []) end private @@ -123,7 +126,7 @@ module Ci end unless @variables.nil? || validate_variables(@variables) - raise ValidationError, "variables should be a map of key-valued strings" + raise ValidationError, "variables should be a map of key-value strings" end if @cache @@ -216,9 +219,9 @@ module Ci end def validate_job_variables!(name, job) - if job[:variables] && !validate_variables(job[:variables]) + unless validate_variables(job[:variables]) raise ValidationError, - "#{name} job: variables should be a map of key-valued strings" + "#{name} job: variables should be a map of key-value strings" end end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 8813a724774..5f4b63bcafb 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -786,14 +786,14 @@ EOT config = YAML.dump({ variables: "test", rspec: { script: "test" } }) expect do GitlabCiYamlProcessor.new(config, path) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-value strings") end - it "returns errors if variables is not a map of key-valued strings" do + it "returns errors if variables is not a map of key-value strings" do config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } }) expect do GitlabCiYamlProcessor.new(config, path) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-value strings") end it "returns errors if job when is not on_success, on_failure or always" do -- cgit v1.2.1 From 63bd1f92d96c9d023723a78259be3c86846e30a5 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 18 Apr 2016 07:51:49 -0400 Subject: Fix rubocop complains --- lib/ci/gitlab_ci_yaml_processor.rb | 60 +++++++++++++++------------- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 4 +- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index a87329c296a..f1d6f2be1e0 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -100,6 +100,29 @@ module Ci end def validate! + validate_global! + + @jobs.each do |name, job| + validate_job!(name, job) + end + + true + end + + def validate_job!(name, job) + validate_job_name!(name) + validate_job_keys!(name, job) + validate_job_types!(name, job) + + validate_job_stage!(name, job) if job[:stage] + validate_job_cache!(name, job) if job[:cache] + validate_job_artifacts!(name, job) if job[:artifacts] + validate_job_dependencies!(name, job) if job[:dependencies] + end + + private + + def validate_global! unless validate_array_of_strings(@before_script) raise ValidationError, "before_script should be an array of strings" end @@ -124,40 +147,23 @@ module Ci raise ValidationError, "variables should be a map of key-valued strings" end - if @cache - if @cache[:key] && !validate_string(@cache[:key]) - raise ValidationError, "cache:key parameter should be a string" - end - - if @cache[:untracked] && !validate_boolean(@cache[:untracked]) - raise ValidationError, "cache:untracked parameter should be an boolean" - end + validate_global_cache! if @cache + end - if @cache[:paths] && !validate_array_of_strings(@cache[:paths]) - raise ValidationError, "cache:paths parameter should be an array of strings" - end + def validate_global_cache! + if @cache[:key] && !validate_string(@cache[:key]) + raise ValidationError, "cache:key parameter should be a string" end - @jobs.each do |name, job| - validate_job!(name, job) + if @cache[:untracked] && !validate_boolean(@cache[:untracked]) + raise ValidationError, "cache:untracked parameter should be an boolean" end - true - end - - def validate_job!(name, job) - validate_job_name!(name) - validate_job_keys!(name, job) - validate_job_types!(name, job) - - validate_job_stage!(name, job) if job[:stage] - validate_job_cache!(name, job) if job[:cache] - validate_job_artifacts!(name, job) if job[:artifacts] - validate_job_dependencies!(name, job) if job[:dependencies] + if @cache[:paths] && !validate_array_of_strings(@cache[:paths]) + raise ValidationError, "cache:paths parameter should be an array of strings" + end end - private - def validate_job_name!(name) if name.blank? || !validate_string(name) raise ValidationError, "job name should be non-empty string" diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 2421d6eee8f..b94fec2ddfd 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -295,12 +295,12 @@ module Ci describe "after_script" do context "in global context" do - let(:config) { + let(:config) do { after_script: ["after_script"], test: { script: ["script"] } } - } + end it "return after_script in options" do expect(subject[:options][:after_script]).to eq(["after_script"]) -- cgit v1.2.1 From fe3ac403b97eb8dbe45189ba3737537a536b8956 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 18 Apr 2016 13:45:26 +0100 Subject: Addressed feedback --- app/assets/javascripts/importer_status.js.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/importer_status.js.coffee b/app/assets/javascripts/importer_status.js.coffee index 2eb151a641b..b0edc895649 100644 --- a/app/assets/javascripts/importer_status.js.coffee +++ b/app/assets/javascripts/importer_status.js.coffee @@ -23,14 +23,14 @@ class @ImporterStatus $('.js-import-all') .off 'click' - .on 'click', (e) => - $btn = $(e.currentTarget) + .on 'click', (e) -> + $btn = $(@) $btn .disable() .addClass 'is-loading' $('.js-add-to-import').each -> - $(this).click() + $(this).trigger('click') setAutoUpdate: -> setInterval (=> -- cgit v1.2.1 From 7e6f0ac0e04c3fa05a8d952bf86463001dc48487 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 18 Apr 2016 12:07:40 +0200 Subject: Count the number of SQL queries per transaction Fixes gitlab-org/gitlab-ce#15335 --- CHANGELOG | 1 + lib/gitlab/metrics/subscribers/active_record.rb | 1 + spec/lib/gitlab/metrics/subscribers/active_record_spec.rb | 3 +++ 3 files changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index b929f1fd7b9..502ed0e9590 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.7.0 (unreleased) - Method instrumentation now uses Module#prepend instead of aliasing methods - Repository.clean_old_archives is now instrumented - Add support for environment variables on a job level in CI configuration file + - SQL query counts are now tracked per transaction - The Projects::HousekeepingService class has extra instrumentation - All service classes (those residing in app/services) are now instrumented - Developers can now add custom tags to transactions diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb index 8008b3bc895..96cad941d5c 100644 --- a/lib/gitlab/metrics/subscribers/active_record.rb +++ b/lib/gitlab/metrics/subscribers/active_record.rb @@ -9,6 +9,7 @@ module Gitlab return unless current_transaction current_transaction.increment(:sql_duration, event.duration) + current_transaction.increment(:sql_count, 1) end private diff --git a/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb b/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb index 7bc070a4d09..e3293a01207 100644 --- a/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb +++ b/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb @@ -28,6 +28,9 @@ describe Gitlab::Metrics::Subscribers::ActiveRecord do expect(transaction).to receive(:increment). with(:sql_duration, 0.2) + expect(transaction).to receive(:increment). + with(:sql_count, 1) + subscriber.sql(event) end end -- cgit v1.2.1 From 6b124d42d9861a5f8c3dd5add7cabc864fa3673c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 15 Apr 2016 15:51:41 +0200 Subject: Add configurable shared runners text --- CHANGELOG | 2 ++ app/controllers/admin/application_settings_controller.rb | 1 + app/helpers/application_settings_helper.rb | 4 ++++ app/views/admin/application_settings/_form.html.haml | 6 +++++- app/views/projects/runners/_shared_runners.html.haml | 7 +++++-- ...40_add_shared_runners_text_to_application_settings.rb | 5 +++++ db/schema.rb | 3 ++- spec/features/runners_spec.rb | 16 ++++++++++++++++ 8 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20160415133440_add_shared_runners_text_to_application_settings.rb diff --git a/CHANGELOG b/CHANGELOG index 571c31e63a2..d1b20a34b17 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,8 @@ v 8.7.0 (unreleased) - Allow projects to be transfered to a lower visibility level group - Fix `signed_in_ip` being set to 127.0.0.1 when using a reverse proxy !3524 - Improved Markdown rendering performance !3389 + - Improved Markdown rendering performance !3389 (Yorick Peterse) + - Make shared runners text in box configurable (Kamil Trzciński) - Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu) - API: Ability to subscribe and unsubscribe from issues and merge requests (Robert Schilling) - Expose project badges in project settings diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index b4a28b8dd3f..2520d4452a2 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -75,6 +75,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :admin_notification_email, :user_oauth_applications, :shared_runners_enabled, + :shared_runners_text, :max_artifacts_size, :metrics_enabled, :metrics_host, diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 60a0ff32c9c..914b0ef6042 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -15,6 +15,10 @@ module ApplicationSettingsHelper current_application_settings.sign_in_text end + def shared_runners_text + current_application_settings.shared_runners_text + end + def user_oauth_applications? current_application_settings.user_oauth_applications end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 555aea554f0..e5bc7d4fdbe 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -153,7 +153,11 @@ = f.label :shared_runners_enabled do = f.check_box :shared_runners_enabled Enable shared runners for new projects - + .form-group + = f.label :shared_runners_text, class: 'control-label col-sm-2' + .col-sm-10 + = f.text_area :shared_runners_text, class: 'form-control', rows: 4 + .help-block Markdown enabled .form-group = f.label :max_artifacts_size, 'Maximum artifacts size (MB)', class: 'control-label col-sm-2' .col-sm-10 diff --git a/app/views/projects/runners/_shared_runners.html.haml b/app/views/projects/runners/_shared_runners.html.haml index 6a37f444bb7..ec47ed79e55 100644 --- a/app/views/projects/runners/_shared_runners.html.haml +++ b/app/views/projects/runners/_shared_runners.html.haml @@ -1,7 +1,10 @@ %h3 Shared runners -.bs-callout.bs-callout-warning - GitLab Runners do not offer secure isolation between projects that they do builds for. You are TRUSTING all GitLab users who can push code to project A, B or C to run shell scripts on the machine hosting runner X. +.bs-callout.bs-callout-warning.shared-runners-description + - if shared_runners_text.present? + = markdown(shared_runners_text) + - else + GitLab Runners do not offer secure isolation between projects that they do builds for. You are TRUSTING all GitLab users who can push code to project A, B or C to run shell scripts on the machine hosting runner X. %hr - if @project.shared_runners_enabled? = link_to toggle_shared_runners_namespace_project_runners_path(@project.namespace, @project), class: 'btn btn-warning', method: :post do diff --git a/db/migrate/20160415133440_add_shared_runners_text_to_application_settings.rb b/db/migrate/20160415133440_add_shared_runners_text_to_application_settings.rb new file mode 100644 index 00000000000..d493044c67b --- /dev/null +++ b/db/migrate/20160415133440_add_shared_runners_text_to_application_settings.rb @@ -0,0 +1,5 @@ +class AddSharedRunnersTextToApplicationSettings < ActiveRecord::Migration + def change + add_column :application_settings, :shared_runners_text, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 42c261003bb..0ab32cab8b4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160412140240) do +ActiveRecord::Schema.define(version: 20160415133440) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -78,6 +78,7 @@ ActiveRecord::Schema.define(version: 20160412140240) do t.boolean "email_author_in_body", default: false t.integer "default_group_visibility" t.boolean "repository_checks_enabled", default: true + t.text "shared_runners_text" end create_table "audit_events", force: :cascade do |t| diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index e8886e7edf9..1fe7645250c 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -80,6 +80,22 @@ describe "Runners" do end end + describe "shared runners description" do + let(:shared_runners_text) { 'custom shared runners description' } + + before { stub_application_setting(shared_runners_text: shared_runners_text) } + + before do + @project = FactoryGirl.create :empty_project, shared_runners_enabled: false + @project.team << [user, :master] + visit runners_path(@project) + end + + it "sees shared runners description" do + expect(page.find(".shared-runners-description")).to have_content(shared_runners_text) + end + end + describe "show page" do before do @project = FactoryGirl.create :empty_project -- cgit v1.2.1 From 21041525af5a678053cc47e082dc7484a67dfdf5 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 18 Apr 2016 09:56:38 -0400 Subject: Update according to review comments --- CHANGELOG | 2 +- spec/features/runners_spec.rb | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d1b20a34b17..d691113e198 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,7 +19,7 @@ v 8.7.0 (unreleased) - Fix `signed_in_ip` being set to 127.0.0.1 when using a reverse proxy !3524 - Improved Markdown rendering performance !3389 - Improved Markdown rendering performance !3389 (Yorick Peterse) - - Make shared runners text in box configurable (Kamil Trzciński) + - Make shared runners text in box configurable - Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu) - API: Ability to subscribe and unsubscribe from issues and merge requests (Robert Schilling) - Expose project badges in project settings diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index 1fe7645250c..789b06d7c67 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -83,12 +83,11 @@ describe "Runners" do describe "shared runners description" do let(:shared_runners_text) { 'custom shared runners description' } - before { stub_application_setting(shared_runners_text: shared_runners_text) } - before do - @project = FactoryGirl.create :empty_project, shared_runners_enabled: false - @project.team << [user, :master] - visit runners_path(@project) + stub_application_setting(shared_runners_text: shared_runners_text) + project = FactoryGirl.create :empty_project, shared_runners_enabled: false + project.team << [user, :master] + visit runners_path(project) end it "sees shared runners description" do -- cgit v1.2.1 From b05f0a48584ea45cc89a8efaafd8e54642b8497c Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Thu, 24 Mar 2016 12:55:04 -0300 Subject: Restrict user profiles based on restricted visibility levels --- app/controllers/users_controller.rb | 4 ++++ app/models/user.rb | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 8e7956da48f..49ddcfed7b1 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,6 +1,7 @@ class UsersController < ApplicationController skip_before_action :authenticate_user! before_action :set_user + before_filter :authorize_read_user, only: [:show] def show respond_to do |format| @@ -74,6 +75,9 @@ class UsersController < ApplicationController end private + def authorize_read_user + render_404 unless @user.public? + end def set_user @user = User.find_by_username!(params[:username]) diff --git a/app/models/user.rb b/app/models/user.rb index 031315debd7..e2b602d598b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -835,6 +835,10 @@ class User < ActiveRecord::Base notification_settings.find_or_initialize_by(source: source) end + def public? + current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + end + private def projects_union -- cgit v1.2.1 From 57519565f167cb771ffed504feefe7b0eb37c027 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Tue, 29 Mar 2016 12:24:42 -0300 Subject: Move verification to abilities --- app/controllers/groups/group_members_controller.rb | 7 +++++ .../projects/project_members_controller.rb | 7 +++++ app/controllers/users_controller.rb | 8 ++++-- app/models/ability.rb | 33 ++++++++++++++++++---- app/models/user.rb | 4 --- 5 files changed, 47 insertions(+), 12 deletions(-) diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index d5ef33888c6..50398d5d3b4 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -1,6 +1,7 @@ class Groups::GroupMembersController < Groups::ApplicationController # Authorize before_action :authorize_admin_group_member!, except: [:index, :leave] + before_action :authorize_read_group_members, only: [:index] def index @project = @group.projects.find(params[:project_id]) if params[:project_id] @@ -79,4 +80,10 @@ class Groups::GroupMembersController < Groups::ApplicationController def member_params params.require(:group_member).permit(:access_level, :user_id) end + + private + + def authorize_read_group_members + render_404 unless can?(current_user, :read_group_members, @group) + end end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index e457db2f0b7..7badbb47d0c 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -1,6 +1,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController # Authorize before_action :authorize_admin_project_member!, except: :leave + before_action :authorize_read_project_members, only: :index def index @project_members = @project.project_members @@ -112,4 +113,10 @@ class Projects::ProjectMembersController < Projects::ApplicationController def member_params params.require(:project_member).permit(:user_id, :access_level) end + + private + + def authorize_read_project_members + can?(current_user, :read_project_members, @project) + end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 49ddcfed7b1..69b66e161cf 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,7 +1,8 @@ class UsersController < ApplicationController skip_before_action :authenticate_user! - before_action :set_user - before_filter :authorize_read_user, only: [:show] + #TO-DO Remove this "set_user" before action. It is not good to use before filters for loading database records. + before_action :set_user, except: [:show] + before_action :authorize_read_user, only: [:show] def show respond_to do |format| @@ -76,7 +77,8 @@ class UsersController < ApplicationController private def authorize_read_user - render_404 unless @user.public? + set_user + render_404 unless can?(current_user, :read_user, @user) end def set_user diff --git a/app/models/ability.rb b/app/models/ability.rb index c0bf6def7c5..d3e724b84ec 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -18,6 +18,7 @@ class Ability when Namespace then namespace_abilities(user, subject) when GroupMember then group_member_abilities(user, subject) when ProjectMember then project_member_abilities(user, subject) + when User then user_abilities() else [] end.concat(global_abilities(user)) end @@ -35,6 +36,8 @@ class Ability anonymous_project_abilities(subject) when subject.is_a?(Group) || subject.respond_to?(:group) anonymous_group_abilities(subject) + when subject.is_a?(User) + anonymous_user_abilities() else [] end @@ -67,6 +70,10 @@ class Ability # Allow to read issues by anonymous user if issue is not confidential rules << :read_issue unless subject.is_a?(Issue) && subject.confidential? + # Allow anonymous users to read project members if public is not a restricted level + restricted_public_level = current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + rules << :read_project_member unless restricted_public_level + rules - project_disabled_features_rules(project) else [] @@ -81,17 +88,23 @@ class Ability end def anonymous_group_abilities(subject) + rules = [] + group = if subject.is_a?(Group) subject else subject.group end - if group && group.public? - [:read_group] - else - [] + if group + rules << [:read_group] if group.public? + + # Allow anonymous users to read project members if public is not a restricted level + restricted_public_level = current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + rules << [:read_group_members] unless restricted_public_level end + + rules end def anonymous_personal_snippet_abilities(snippet) @@ -110,6 +123,11 @@ class Ability end end + def anonymous_user_abilities() + restricted_by_public = current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + [:read_user] unless restricted_by_public + end + def global_abilities(user) rules = [] rules << :create_group if user.can_create_group @@ -164,6 +182,7 @@ class Ability :download_code, :fork_project, :read_commit_status, + :read_project_members ] end @@ -285,7 +304,7 @@ class Ability def group_abilities(user, group) rules = [] - rules << :read_group if can_read_group?(user, group) + rules << [:read_group, :read_group_members] if can_read_group?(user, group) # Only group masters and group owners can create new projects if group.has_master?(user) || group.has_owner?(user) || user.admin? @@ -456,6 +475,10 @@ class Ability rules end + def user_abilities() + [:read_user] + end + def abilities @abilities ||= begin abilities = Six.new diff --git a/app/models/user.rb b/app/models/user.rb index e2b602d598b..031315debd7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -835,10 +835,6 @@ class User < ActiveRecord::Base notification_settings.find_or_initialize_by(source: source) end - def public? - current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) - end - private def projects_union -- cgit v1.2.1 From 668d6ffa437aa5c920e987beb5de4e8dacbfd00c Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Wed, 30 Mar 2016 17:14:21 -0300 Subject: Add specs and fix code --- app/controllers/users_controller.rb | 2 +- app/models/ability.rb | 25 ++++++++++++---------- app/views/layouts/nav/_group.html.haml | 13 ++++++----- app/views/layouts/nav/_project.html.haml | 2 +- .../groups/group_members_controller_spec.rb | 19 ++++++++++++++++ spec/controllers/users_controller_spec.rb | 22 +++++++++++++++++++ 6 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 spec/controllers/groups/group_members_controller_spec.rb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 69b66e161cf..642f5eea1de 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,6 +1,6 @@ class UsersController < ApplicationController skip_before_action :authenticate_user! - #TO-DO Remove this "set_user" before action. It is not good to use before filters for loading database records. + #TODO felipe_artur: Remove this "set_user" before action. It is not good to use before filters for loading database records. before_action :set_user, except: [:show] before_action :authorize_read_user, only: [:show] diff --git a/app/models/ability.rb b/app/models/ability.rb index d3e724b84ec..2914ca16b2d 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -1,4 +1,6 @@ class Ability + @public_restricted = nil + class << self def allowed(user, subject) return anonymous_abilities(user, subject) if user.nil? @@ -18,7 +20,7 @@ class Ability when Namespace then namespace_abilities(user, subject) when GroupMember then group_member_abilities(user, subject) when ProjectMember then project_member_abilities(user, subject) - when User then user_abilities() + when User then user_abilities else [] end.concat(global_abilities(user)) end @@ -37,7 +39,7 @@ class Ability when subject.is_a?(Group) || subject.respond_to?(:group) anonymous_group_abilities(subject) when subject.is_a?(User) - anonymous_user_abilities() + anonymous_user_abilities else [] end @@ -71,8 +73,7 @@ class Ability rules << :read_issue unless subject.is_a?(Issue) && subject.confidential? # Allow anonymous users to read project members if public is not a restricted level - restricted_public_level = current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) - rules << :read_project_member unless restricted_public_level + rules << :read_project_member unless restricted_public_level? rules - project_disabled_features_rules(project) else @@ -100,8 +101,7 @@ class Ability rules << [:read_group] if group.public? # Allow anonymous users to read project members if public is not a restricted level - restricted_public_level = current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) - rules << [:read_group_members] unless restricted_public_level + rules << [:read_group_members] unless restricted_public_level? end rules @@ -123,9 +123,8 @@ class Ability end end - def anonymous_user_abilities() - restricted_by_public = current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) - [:read_user] unless restricted_by_public + def anonymous_user_abilities + [:read_user] unless restricted_public_level? end def global_abilities(user) @@ -303,7 +302,6 @@ class Ability def group_abilities(user, group) rules = [] - rules << [:read_group, :read_group_members] if can_read_group?(user, group) # Only group masters and group owners can create new projects @@ -475,7 +473,7 @@ class Ability rules end - def user_abilities() + def user_abilities [:read_user] end @@ -493,6 +491,11 @@ class Ability private + def restricted_public_level? + @public_restricted ||= current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + @public_restricted + end + def named_abilities(name) [ :"read_#{name}", diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml index 55940741dc0..927f61c89fa 100644 --- a/app/views/layouts/nav/_group.html.haml +++ b/app/views/layouts/nav/_group.html.haml @@ -36,11 +36,14 @@ Merge Requests - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute %span.count= number_with_delimiter(merge_requests.count) - = nav_link(controller: [:group_members]) do - = link_to group_group_members_path(@group), title: 'Members' do - = icon('users fw') - %span - Members + + - if can?(current_user, :read_group_members, @group) + = nav_link(controller: [:group_members]) do + = link_to group_group_members_path(@group), title: 'Members' do + = icon('users fw') + %span + Members + - if can?(current_user, :admin_group, @group) = nav_link(html_options: { class: "separate-item" }) do = link_to edit_group_path(@group), title: 'Settings' do diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 86b46e8c75e..d651de0fbe0 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -77,7 +77,7 @@ Merge Requests %span.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count) - - if project_nav_tab? :settings + - if project_nav_tab?(:settings) && can?(current_user, :read_project_members, @project) = nav_link(controller: [:project_members, :teams]) do = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do = icon('users fw') diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb new file mode 100644 index 00000000000..3a4dd2bf1fa --- /dev/null +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe Groups::GroupMembersController do + let(:user) { create(:user) } + let(:group) { create(:group) } + + + context "When public visibility level is restricted" do + before do + group.add_owner(user) + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + it 'does not show group members' do + get :index, group_id: group.path + expect(response.status).to eq(404) + end + end +end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 7337ff58be1..f6235c29a17 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -38,6 +38,28 @@ describe UsersController do end end end + + context 'When public visibility level is restricted' do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + context 'when logged out' do + it 'renders 404' do + get :show, username: user.username + expect(response.status).to eq(404) + end + end + + context 'when logged in' do + before { sign_in(user) } + + it 'renders 404' do + get :show, username: user.username + expect(response.status).to eq(200) + end + end + end end describe 'GET #calendar' do -- cgit v1.2.1 From e8a77c0aee3eaf99793b3678a0eb97194244b339 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Thu, 31 Mar 2016 11:36:40 -0300 Subject: Fix code --- app/controllers/groups/group_members_controller.rb | 4 ++-- app/controllers/users_controller.rb | 6 +++--- app/models/ability.rb | 4 ---- spec/controllers/groups/group_members_controller_spec.rb | 3 +-- spec/controllers/users_controller_spec.rb | 3 ++- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 50398d5d3b4..9fc72635806 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -1,7 +1,7 @@ class Groups::GroupMembersController < Groups::ApplicationController # Authorize before_action :authorize_admin_group_member!, except: [:index, :leave] - before_action :authorize_read_group_members, only: [:index] + before_action :authorize_read_group_members!, only: [:index] def index @project = @group.projects.find(params[:project_id]) if params[:project_id] @@ -83,7 +83,7 @@ class Groups::GroupMembersController < Groups::ApplicationController private - def authorize_read_group_members + def authorize_read_group_members! render_404 unless can?(current_user, :read_group_members, @group) end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 642f5eea1de..233dca54b99 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,8 +1,7 @@ class UsersController < ApplicationController skip_before_action :authenticate_user! - #TODO felipe_artur: Remove this "set_user" before action. It is not good to use before filters for loading database records. before_action :set_user, except: [:show] - before_action :authorize_read_user, only: [:show] + before_action :authorize_read_user!, only: [:show] def show respond_to do |format| @@ -76,7 +75,8 @@ class UsersController < ApplicationController end private - def authorize_read_user + + def authorize_read_user! set_user render_404 unless can?(current_user, :read_user, @user) end diff --git a/app/models/ability.rb b/app/models/ability.rb index 2914ca16b2d..874ec360944 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -1,5 +1,4 @@ class Ability - @public_restricted = nil class << self def allowed(user, subject) @@ -72,7 +71,6 @@ class Ability # Allow to read issues by anonymous user if issue is not confidential rules << :read_issue unless subject.is_a?(Issue) && subject.confidential? - # Allow anonymous users to read project members if public is not a restricted level rules << :read_project_member unless restricted_public_level? rules - project_disabled_features_rules(project) @@ -100,7 +98,6 @@ class Ability if group rules << [:read_group] if group.public? - # Allow anonymous users to read project members if public is not a restricted level rules << [:read_group_members] unless restricted_public_level? end @@ -493,7 +490,6 @@ class Ability def restricted_public_level? @public_restricted ||= current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) - @public_restricted end def named_abilities(name) diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index 3a4dd2bf1fa..cf8f2a28052 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -4,8 +4,7 @@ describe Groups::GroupMembersController do let(:user) { create(:user) } let(:group) { create(:group) } - - context "When public visibility level is restricted" do + context "when public visibility level is restricted" do before do group.add_owner(user) stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index f6235c29a17..26acfd3bd96 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -54,9 +54,10 @@ describe UsersController do context 'when logged in' do before { sign_in(user) } - it 'renders 404' do + it 'renders show' do get :show, username: user.username expect(response.status).to eq(200) + expect(response).to render_template('show') end end end -- cgit v1.2.1 From 147879ae66fd742d13bbb5b72d492788bc48c8d9 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Fri, 1 Apr 2016 16:50:18 -0300 Subject: Fix specs --- app/models/ability.rb | 4 ++-- spec/controllers/users_controller_spec.rb | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 874ec360944..684834aa394 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -156,6 +156,7 @@ class Ability rules -= project_archived_rules end + rules << :read_project_members rules - project_disabled_features_rules(project) end end @@ -177,8 +178,7 @@ class Ability @public_project_rules ||= project_guest_rules + [ :download_code, :fork_project, - :read_commit_status, - :read_project_members + :read_commit_status ] end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 26acfd3bd96..7701da9747a 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -30,10 +30,12 @@ describe UsersController do end describe 'when logged out' do + before { stub_application_setting(restricted_visibility_levels: []) } + it 'renders the show template' do get :show, username: user.username - expect(response).to be_success + expect(response.status).to eq(200) expect(response).to render_template('show') end end -- cgit v1.2.1 From 07b38c3b389b8b0b6a3d6af7a38555c189e71afe Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Tue, 5 Apr 2016 18:56:07 -0300 Subject: Code fixes --- .../projects/project_members_controller.rb | 7 ------- app/controllers/users_controller.rb | 21 ++++++++++----------- app/models/ability.rb | 10 ++-------- app/views/layouts/nav/_project.html.haml | 2 +- spec/controllers/users_controller_spec.rb | 2 +- 5 files changed, 14 insertions(+), 28 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 7badbb47d0c..e457db2f0b7 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -1,7 +1,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController # Authorize before_action :authorize_admin_project_member!, except: :leave - before_action :authorize_read_project_members, only: :index def index @project_members = @project.project_members @@ -113,10 +112,4 @@ class Projects::ProjectMembersController < Projects::ApplicationController def member_params params.require(:project_member).permit(:user_id, :access_level) end - - private - - def authorize_read_project_members - can?(current_user, :read_project_members, @project) - end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 233dca54b99..2ae180c8a12 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,6 +1,6 @@ class UsersController < ApplicationController skip_before_action :authenticate_user! - before_action :set_user, except: [:show] + before_action :user before_action :authorize_read_user!, only: [:show] def show @@ -77,26 +77,25 @@ class UsersController < ApplicationController private def authorize_read_user! - set_user - render_404 unless can?(current_user, :read_user, @user) + render_404 unless can?(current_user, :read_user, user) end - def set_user - @user = User.find_by_username!(params[:username]) + def user + @user ||= User.find_by_username!(params[:username]) end def contributed_projects - ContributedProjectsFinder.new(@user).execute(current_user) + ContributedProjectsFinder.new(user).execute(current_user) end def contributions_calendar @contributions_calendar ||= Gitlab::ContributionsCalendar. - new(contributed_projects, @user) + new(contributed_projects, user) end def load_events # Get user activity feed for projects common for both users - @events = @user.recent_events. + @events = user.recent_events. merge(projects_for_current_user). references(:project). with_associations. @@ -105,16 +104,16 @@ class UsersController < ApplicationController def load_projects @projects = - PersonalProjectsFinder.new(@user).execute(current_user) + PersonalProjectsFinder.new(user).execute(current_user) .page(params[:page]) end def load_contributed_projects - @contributed_projects = contributed_projects.joined(@user) + @contributed_projects = contributed_projects.joined(user) end def load_groups - @groups = JoinedGroupsFinder.new(@user).execute(current_user) + @groups = JoinedGroupsFinder.new(user).execute(current_user) end def projects_for_current_user diff --git a/app/models/ability.rb b/app/models/ability.rb index 684834aa394..7c452c69d14 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -1,5 +1,4 @@ class Ability - class << self def allowed(user, subject) return anonymous_abilities(user, subject) if user.nil? @@ -58,7 +57,6 @@ class Ability :read_label, :read_milestone, :read_project_snippet, - :read_project_member, :read_merge_request, :read_note, :read_commit_status, @@ -71,8 +69,6 @@ class Ability # Allow to read issues by anonymous user if issue is not confidential rules << :read_issue unless subject.is_a?(Issue) && subject.confidential? - rules << :read_project_member unless restricted_public_level? - rules - project_disabled_features_rules(project) else [] @@ -96,9 +92,8 @@ class Ability end if group - rules << [:read_group] if group.public? - - rules << [:read_group_members] unless restricted_public_level? + rules << :read_group if group.public? + rules << :read_group_members unless restricted_public_level? end rules @@ -156,7 +151,6 @@ class Ability rules -= project_archived_rules end - rules << :read_project_members rules - project_disabled_features_rules(project) end end diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index d651de0fbe0..2c9e2159486 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -77,7 +77,7 @@ Merge Requests %span.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count) - - if project_nav_tab?(:settings) && can?(current_user, :read_project_members, @project) + - if project_nav_tab?(:settings) = nav_link(controller: [:project_members, :teams]) do = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do = icon('users fw') diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 7701da9747a..948935bc10d 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -41,7 +41,7 @@ describe UsersController do end end - context 'When public visibility level is restricted' do + context 'when public visibility level is restricted' do before do stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) end -- cgit v1.2.1 From ce96d482d9056e9acdfea02d055c2706653cba92 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Wed, 6 Apr 2016 18:09:24 -0300 Subject: Insert users check into api --- app/models/ability.rb | 6 +++--- lib/api/api_guard.rb | 4 ++++ lib/api/users.rb | 10 ++++++++-- spec/controllers/users_controller_spec.rb | 2 -- spec/requests/api/users_spec.rb | 18 ++++++++++++++++++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 7c452c69d14..e327d4eef28 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -91,8 +91,8 @@ class Ability subject.group end - if group - rules << :read_group if group.public? + if group.public? + rules << :read_group rules << :read_group_members unless restricted_public_level? end @@ -483,7 +483,7 @@ class Ability private def restricted_public_level? - @public_restricted ||= current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) end def named_abilities(name) diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb index b9994fcefda..6ce5529abfa 100644 --- a/lib/api/api_guard.rb +++ b/lib/api/api_guard.rb @@ -79,6 +79,10 @@ module APIGuard @current_user end + def public_access_restricted? + current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + end + private def find_access_token @access_token ||= Doorkeeper.authenticate(doorkeeper_request, Doorkeeper.configuration.access_token_methods) diff --git a/lib/api/users.rb b/lib/api/users.rb index 0a14bac07c0..9647a40686e 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -11,6 +11,10 @@ module API # GET /users?search=Admin # GET /users?username=root get do + if !current_user && public_access_restricted? + render_api_error!("Not authorized.", 403) + end + if params[:username].present? @users = User.where(username: params[:username]) else @@ -36,10 +40,12 @@ module API get ":id" do @user = User.find(params[:id]) - if current_user.is_admin? + if current_user.present? && current_user.is_admin? present @user, with: Entities::UserFull - else + elsif can?(current_user, :read_user, @user) present @user, with: Entities::User + else + render_api_error!("User not found.", 404) end end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 948935bc10d..8045c8b940d 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -30,8 +30,6 @@ describe UsersController do end describe 'when logged out' do - before { stub_application_setting(restricted_visibility_levels: []) } - it 'renders the show template' do get :show, username: user.username diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 679227bf881..40b24c125b5 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -20,6 +20,24 @@ describe API::API, api: true do end context "when authenticated" do + #These specs are written just in case API authentication is not required anymore + context "when public level is restricted" do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + allow_any_instance_of(API::Helpers).to receive(:authenticate!).and_return(true) + end + + it "renders 403" do + get api("/users") + expect(response.status).to eq(403) + end + + it "renders 404" do + get api("/users/#{user.id}") + expect(response.status).to eq(404) + end + end + it "should return an array of users" do get api("/users", user) expect(response.status).to eq(200) -- cgit v1.2.1 From 09c8cf9de68c5d6f1250d6717b00f3b7e2008d3f Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Thu, 7 Apr 2016 16:36:26 -0300 Subject: Remove group members check --- app/controllers/groups/group_members_controller.rb | 7 ------- app/models/ability.rb | 8 +++----- app/views/layouts/nav/_group.html.haml | 13 +++++-------- app/views/layouts/nav/_project.html.haml | 2 +- spec/controllers/groups/group_members_controller_spec.rb | 8 +++++--- 5 files changed, 14 insertions(+), 24 deletions(-) diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 9fc72635806..d5ef33888c6 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -1,7 +1,6 @@ class Groups::GroupMembersController < Groups::ApplicationController # Authorize before_action :authorize_admin_group_member!, except: [:index, :leave] - before_action :authorize_read_group_members!, only: [:index] def index @project = @group.projects.find(params[:project_id]) if params[:project_id] @@ -80,10 +79,4 @@ class Groups::GroupMembersController < Groups::ApplicationController def member_params params.require(:group_member).permit(:access_level, :user_id) end - - private - - def authorize_read_group_members! - render_404 unless can?(current_user, :read_group_members, @group) - end end diff --git a/app/models/ability.rb b/app/models/ability.rb index e327d4eef28..a4bde72d991 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -57,6 +57,7 @@ class Ability :read_label, :read_milestone, :read_project_snippet, + :read_project_member, :read_merge_request, :read_note, :read_commit_status, @@ -91,10 +92,7 @@ class Ability subject.group end - if group.public? - rules << :read_group - rules << :read_group_members unless restricted_public_level? - end + rules << :read_group if group.public? rules end @@ -293,7 +291,7 @@ class Ability def group_abilities(user, group) rules = [] - rules << [:read_group, :read_group_members] if can_read_group?(user, group) + rules << :read_group if can_read_group?(user, group) # Only group masters and group owners can create new projects if group.has_master?(user) || group.has_owner?(user) || user.admin? diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml index 927f61c89fa..55940741dc0 100644 --- a/app/views/layouts/nav/_group.html.haml +++ b/app/views/layouts/nav/_group.html.haml @@ -36,14 +36,11 @@ Merge Requests - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute %span.count= number_with_delimiter(merge_requests.count) - - - if can?(current_user, :read_group_members, @group) - = nav_link(controller: [:group_members]) do - = link_to group_group_members_path(@group), title: 'Members' do - = icon('users fw') - %span - Members - + = nav_link(controller: [:group_members]) do + = link_to group_group_members_path(@group), title: 'Members' do + = icon('users fw') + %span + Members - if can?(current_user, :admin_group, @group) = nav_link(html_options: { class: "separate-item" }) do = link_to edit_group_path(@group), title: 'Settings' do diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 2c9e2159486..86b46e8c75e 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -77,7 +77,7 @@ Merge Requests %span.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count) - - if project_nav_tab?(:settings) + - if project_nav_tab? :settings = nav_link(controller: [:project_members, :teams]) do = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do = icon('users fw') diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index cf8f2a28052..a5986598715 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -4,15 +4,17 @@ describe Groups::GroupMembersController do let(:user) { create(:user) } let(:group) { create(:group) } - context "when public visibility level is restricted" do + context "index" do before do group.add_owner(user) stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) end - it 'does not show group members' do + it 'renders index with group members' do get :index, group_id: group.path - expect(response.status).to eq(404) + + expect(response.status).to eq(200) + expect(response).to render_template(:index) end end end -- cgit v1.2.1 From 7d54e721da0ccd21f0150bbb6ab60b51970033c2 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Thu, 7 Apr 2016 17:44:46 -0300 Subject: Insert instructions in admin page and permissions document --- app/views/admin/application_settings/_form.html.haml | 4 +++- doc/permissions/permissions.md | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 555aea554f0..37b07c348d4 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -26,7 +26,9 @@ .btn-group{ data: data_attrs } - restricted_level_checkboxes('restricted-visibility-help').each do |level| = level - %span.help-block#restricted-visibility-help Selected levels cannot be used by non-admin users for projects or snippets + %span.help-block#restricted-visibility-help + Selected levels cannot be used by non-admin users for projects or snippets. + If public level is restricted user profiles are not accessible to not logged users. .form-group = f.label :import_sources, class: 'control-label col-sm-2' .col-sm-10 diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md index 6219693b8a8..f8cfd2898f0 100644 --- a/doc/permissions/permissions.md +++ b/doc/permissions/permissions.md @@ -93,3 +93,10 @@ An administrator can flag a user as external [through the API](../api/users.md) or by checking the checkbox on the admin panel. As an administrator, navigate to **Admin > Users** to create a new user or edit an existing one. There, you will find the option to flag the user as external. + +## Restricted visibility levels + +Visibility levels can be restricted in admin settings page by administrator, when +restricting a visibility level groups, projects and snippets are not allowed to be +created with that visibility setting. If the public visibility level is restricted +user profiles are accessible to not logged users. -- cgit v1.2.1 From 820c08cefd78e593e94012061be29000d523ffd0 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Tue, 12 Apr 2016 12:04:33 -0300 Subject: Fix documentation and improve permissions code --- app/models/ability.rb | 1 + app/views/admin/application_settings/_form.html.haml | 2 +- doc/permissions/permissions.md | 7 ------- doc/public_access/public_access.md | 3 +++ lib/api/api_guard.rb | 4 ---- lib/api/users.rb | 2 +- 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index a4bde72d991..6103a2947e2 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -120,6 +120,7 @@ class Ability def global_abilities(user) rules = [] rules << :create_group if user.can_create_group + rules << :read_users_list rules end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 37b07c348d4..aadd2c54f20 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -28,7 +28,7 @@ = level %span.help-block#restricted-visibility-help Selected levels cannot be used by non-admin users for projects or snippets. - If public level is restricted user profiles are not accessible to not logged users. + If the public level is restricted, user profiles are only visible to logged in users. .form-group = f.label :import_sources, class: 'control-label col-sm-2' .col-sm-10 diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md index f8cfd2898f0..6219693b8a8 100644 --- a/doc/permissions/permissions.md +++ b/doc/permissions/permissions.md @@ -93,10 +93,3 @@ An administrator can flag a user as external [through the API](../api/users.md) or by checking the checkbox on the admin panel. As an administrator, navigate to **Admin > Users** to create a new user or edit an existing one. There, you will find the option to flag the user as external. - -## Restricted visibility levels - -Visibility levels can be restricted in admin settings page by administrator, when -restricting a visibility level groups, projects and snippets are not allowed to be -created with that visibility setting. If the public visibility level is restricted -user profiles are accessible to not logged users. diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md index 20aa90f0d69..17bb75ececd 100644 --- a/doc/public_access/public_access.md +++ b/doc/public_access/public_access.md @@ -58,6 +58,9 @@ you are logged in or not. When visiting the public page of a user, you can only see the projects which you are privileged to. +If the public level is restricted, user profiles are only visible to logged in users. + + ## Restricting the use of public or internal projects In the Admin area under **Settings** (`/admin/application_settings`), you can diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb index 6ce5529abfa..b9994fcefda 100644 --- a/lib/api/api_guard.rb +++ b/lib/api/api_guard.rb @@ -79,10 +79,6 @@ module APIGuard @current_user end - def public_access_restricted? - current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) - end - private def find_access_token @access_token ||= Doorkeeper.authenticate(doorkeeper_request, Doorkeeper.configuration.access_token_methods) diff --git a/lib/api/users.rb b/lib/api/users.rb index 9647a40686e..315268fc0ca 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -11,7 +11,7 @@ module API # GET /users?search=Admin # GET /users?username=root get do - if !current_user && public_access_restricted? + unless can?(current_user, :read_users_list, nil) render_api_error!("Not authorized.", 403) end -- cgit v1.2.1 From 2366768d3b28ea70c91fc49c471e66152650d442 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Wed, 13 Apr 2016 15:37:17 -0300 Subject: Add changelog entry --- CHANGELOG | 1 + lib/api/users.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 571c31e63a2..3cb89582d53 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ v 8.7.0 (unreleased) - Project switcher uses new dropdown styling - Load award emoji images separately unless opening the full picker. Saves several hundred KBs of data for most pages. (Connor Shea) - Do not include award_emojis in issue and merge_request comment_count !3610 (Lucas Charles) + - Restrict user profiles when public visibility level is restricted. - All images in discussions and wikis now link to their source files !3464 (Connor Shea). - Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu) - Add setting for customizing the list of trusted proxies !3524 diff --git a/lib/api/users.rb b/lib/api/users.rb index 315268fc0ca..ea6fa2dc8a8 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -40,7 +40,7 @@ module API get ":id" do @user = User.find(params[:id]) - if current_user.present? && current_user.is_admin? + if current_user && current_user.is_admin? present @user, with: Entities::UserFull elsif can?(current_user, :read_user, @user) present @user, with: Entities::User -- cgit v1.2.1 From 0ce5cc99621c84dfc61f6105d177ced4d9a4ed85 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 18 Apr 2016 10:18:46 -0400 Subject: Resolve merge --- lib/ci/gitlab_ci_yaml_processor.rb | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 2a228845ec0..d8a7fcfe15e 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -120,17 +120,6 @@ module Ci true end - def validate_job!(name, job) - validate_job_name!(name) - validate_job_keys!(name, job) - validate_job_types!(name, job) - - validate_job_stage!(name, job) if job[:stage] - validate_job_cache!(name, job) if job[:cache] - validate_job_artifacts!(name, job) if job[:artifacts] - validate_job_dependencies!(name, job) if job[:dependencies] - end - private def validate_global! @@ -170,12 +159,9 @@ module Ci raise ValidationError, "cache:untracked parameter should be an boolean" end -<<<<<<< HEAD if @cache[:paths] && !validate_array_of_strings(@cache[:paths]) raise ValidationError, "cache:paths parameter should be an array of strings" end -======= - true end def validate_job!(name, job) @@ -188,7 +174,6 @@ module Ci validate_job_cache!(name, job) if job[:cache] validate_job_artifacts!(name, job) if job[:artifacts] validate_job_dependencies!(name, job) if job[:dependencies] ->>>>>>> origin/master end def validate_job_name!(name) -- cgit v1.2.1 From d13bba44f0de0aa5df00c37b4f743504d187bb03 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Fri, 15 Apr 2016 18:14:41 -0300 Subject: Use GitHub Issue/PR number as iid to keep references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With these changes we don’t lost the issue/pr references when importing them to GitLab. --- app/models/concerns/internal_id.rb | 10 ++++++---- lib/gitlab/github_import/issue_formatter.rb | 1 + lib/gitlab/github_import/pull_request_formatter.rb | 1 + spec/lib/gitlab/github_import/issue_formatter_spec.rb | 2 ++ spec/lib/gitlab/github_import/pull_request_formatter_spec.rb | 3 +++ 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/models/concerns/internal_id.rb b/app/models/concerns/internal_id.rb index 51288094ef1..5382dde6765 100644 --- a/app/models/concerns/internal_id.rb +++ b/app/models/concerns/internal_id.rb @@ -7,11 +7,13 @@ module InternalId end def set_iid - records = project.send(self.class.name.tableize) - records = records.with_deleted if self.paranoid? - max_iid = records.maximum(:iid) + if iid.blank? + records = project.send(self.class.name.tableize) + records = records.with_deleted if self.paranoid? + max_iid = records.maximum(:iid) - self.iid = max_iid.to_i + 1 + self.iid = max_iid.to_i + 1 + end end def to_param diff --git a/lib/gitlab/github_import/issue_formatter.rb b/lib/gitlab/github_import/issue_formatter.rb index 1e3ba44f27c..acb332cb0cb 100644 --- a/lib/gitlab/github_import/issue_formatter.rb +++ b/lib/gitlab/github_import/issue_formatter.rb @@ -3,6 +3,7 @@ module Gitlab class IssueFormatter < BaseFormatter def attributes { + iid: number, project: project, title: raw_data.title, description: description, diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb index 4e507b090e8..5ee8a14624a 100644 --- a/lib/gitlab/github_import/pull_request_formatter.rb +++ b/lib/gitlab/github_import/pull_request_formatter.rb @@ -3,6 +3,7 @@ module Gitlab class PullRequestFormatter < BaseFormatter def attributes { + iid: number, title: raw_data.title, description: description, source_project: source_project, diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb index fd05428b322..4f3d7f4405b 100644 --- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb @@ -30,6 +30,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do it 'returns formatted attributes' do expected = { + iid: 1347, project: project, title: 'Found a bug', description: "*Created by: octocat*\n\nI'm having a problem with this.", @@ -50,6 +51,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do it 'returns formatted attributes' do expected = { + iid: 1347, project: project, title: 'Found a bug', description: "*Created by: octocat*\n\nI'm having a problem with this.", diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb index e49dcb42342..11249e57ca8 100644 --- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb @@ -35,6 +35,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do it 'returns formatted attributes' do expected = { + iid: 1347, title: 'New feature', description: "*Created by: octocat*\n\nPlease pull these awesome changes", source_project: project, @@ -58,6 +59,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do it 'returns formatted attributes' do expected = { + iid: 1347, title: 'New feature', description: "*Created by: octocat*\n\nPlease pull these awesome changes", source_project: project, @@ -81,6 +83,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do it 'returns formatted attributes' do expected = { + iid: 1347, title: 'New feature', description: "*Created by: octocat*\n\nPlease pull these awesome changes", source_project: project, -- cgit v1.2.1 From c9f2fc3c1802aabf913df3094aebf2d020b19f2a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Fri, 15 Apr 2016 18:16:11 -0300 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index e641adbfcef..330b500dee5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -82,6 +82,7 @@ v 8.7.0 (unreleased) - Author and participants are displayed first on users autocompletion - Show number sign on external issue reference text (Florent Baldino) - Updated print style for issues + - Use GitHub Issue/PR number as iid to keep references v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 -- cgit v1.2.1 From b9698d2b4512cca4687579aafba6a4403cbc6067 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 18 Apr 2016 17:42:48 +0200 Subject: Add "action" tag to /internal/allowed API This allows us to re-use any other analytics that rely on the "action" tag having a value set. --- CHANGELOG | 1 + lib/api/internal.rb | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 350be45627f..9a6f1bbfef5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.7.0 (unreleased) + - Transactions for /internal/allowed now have an "action" tag set - Method instrumentation now uses Module#prepend instead of aliasing methods - Repository.clean_old_archives is now instrumented - Add support for environment variables on a job level in CI configuration file diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 2200208b946..8cfa1f1556b 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -23,9 +23,11 @@ module API end post "/allowed" do + Gitlab::Metrics.tag_transaction('action', 'Grape#/internal/allowed') + status 200 - actor = + actor = if params[:key_id] Key.find_by(id: params[:key_id]) elsif params[:user_id] @@ -33,7 +35,7 @@ module API end project_path = params[:project] - + # Check for *.wiki repositories. # Strip out the .wiki from the pathname before finding the # project. This applies the correct project permissions to -- cgit v1.2.1 From ea7114541838652fe3e6dcf3bdc4c3812f013e7b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 18 Apr 2016 16:45:49 +0100 Subject: Fixed issue with multi select not working with arrow keys --- app/assets/javascripts/gl_dropdown.js.coffee | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 2dc37257e22..fac928ef202 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -32,10 +32,8 @@ class GitLabDropdownFilter else if @input.val() is "" and $inputContainer.hasClass HAS_VALUE_CLASS $inputContainer.removeClass HAS_VALUE_CLASS - if keyCode is 13 and @input.val() isnt "" - if @options.enterCallback - @options.enterCallback() - return + if keyCode is 13 + return false clearTimeout timeout timeout = setTimeout => @@ -132,7 +130,6 @@ class GitLabDropdown @filterInput = @getElement(FILTER_INPUT) @highlight = false @filterInputBlur = true - @enterCallback = true } = @options self = @ @@ -178,9 +175,6 @@ class GitLabDropdown callback: (data) => currentIndex = -1 @parseData data - enterCallback: => - if @enterCallback - @selectRowAtIndex 0 # Event listeners -- cgit v1.2.1 From 872d31d6e9566f55f9eadd12d496d07e86c13f0a Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 18 Apr 2016 16:56:48 +0100 Subject: Fixed issue with spinner not hiding on diff changes --- app/assets/javascripts/merge_request_tabs.js.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index 1ab6e5114bc..e8613cab72b 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -183,9 +183,10 @@ class @MergeRequestTabs else $diffLine = $('td', $diffLine) - $diffLine.addClass 'hll' - diffLineTop = $diffLine.offset().top - navBarHeight = $('.navbar-gitlab').outerHeight() + if $diffLine.length + $diffLine.addClass 'hll' + diffLineTop = $diffLine.offset().top + navBarHeight = $('.navbar-gitlab').outerHeight() loadBuilds: (source) -> return if @buildsLoaded -- cgit v1.2.1 From fe603d4d314ddb584d160913ae52bac813abbaad Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 18 Apr 2016 17:53:38 +0100 Subject: Removed aside toggle on profile pages Closes #13943 --- app/views/users/show.html.haml | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 0c4b6a5618b..3028491e5b6 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -6,8 +6,6 @@ = content_for :meta_tags do = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") -= render 'shared/show_aside' - .user-profile .cover-block .cover-controls -- cgit v1.2.1 -- cgit v1.2.1 From 7fa3a1c05c9ab04d59c9000e69881cd1cbeeaf1d Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Mon, 18 Apr 2016 20:01:32 +0200 Subject: Ensure that annoation is presented properly --- spec/requests/api/tags_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index 9f9c3b1cf4c..edcb2bedbf7 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -32,9 +32,11 @@ describe API::API, api: true do it "should return an array of project tags with release info" do get api("/projects/#{project.id}/repository/tags", user) + expect(response.status).to eq(200) expect(json_response).to be_an Array expect(json_response.first['name']).to eq(tag_name) + expect(json_response.first['message']).to eq('Version 1.1.0') expect(json_response.first['release']['description']).to eq(description) end end -- cgit v1.2.1 From beb32f31fba16e84c6bcfb59d538379db2d2a842 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 18 Apr 2016 13:04:36 -0500 Subject: Add null check to formData.append --- app/assets/javascripts/profile.js.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee index f4a2562885d..26a12423521 100644 --- a/app/assets/javascripts/profile.js.coffee +++ b/app/assets/javascripts/profile.js.coffee @@ -45,9 +45,10 @@ class @Profile saveForm: -> self = @ - formData = new FormData(@form[0]) - formData.append('user[avatar]', @avatarGlCrop.getBlob(), 'avatar.png') + + avatarBlob = @avatarGlCrop.getBlob() + formData.append('user[avatar]', avatarBlob, 'avatar.png') if avatarBlob? $.ajax url: @form.attr('action') -- cgit v1.2.1 From f30053ba608ccc7a9edc8ca720ba09ab15a8f1f5 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 18 Apr 2016 07:42:26 -0700 Subject: Use raw SQL commands for 20140502125220 MigrateRepoSize Partial fix for #15210 --- db/migrate/20140502125220_migrate_repo_size.rb | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/db/migrate/20140502125220_migrate_repo_size.rb b/db/migrate/20140502125220_migrate_repo_size.rb index eed6d366814..efdf53112fd 100644 --- a/db/migrate/20140502125220_migrate_repo_size.rb +++ b/db/migrate/20140502125220_migrate_repo_size.rb @@ -1,19 +1,26 @@ class MigrateRepoSize < ActiveRecord::Migration def up - Project.reset_column_information - Project.find_each(batch_size: 500) do |project| + project_data = execute('SELECT projects.id, namespaces.path AS namespace_path, projects.path AS project_path FROM projects LEFT JOIN namespaces ON projects.namespace_id = namespaces.id') + + project_data.each do |project| + id = project['id'] + namespace_path = project['namespace_path'] || '' + path = File.join(Gitlab.config.gitlab_shell.repos_path, namespace_path, project['project_path'] + '.git') + begin - if project.empty_repo? + repo = Gitlab::Git::Repository.new(path) + if repo.empty? print '-' else - project.update_repository_size + size = repo.size print '.' + execute("UPDATE projects SET repository_size = #{size} WHERE id = #{id}") end - rescue - print 'F' + rescue => e + puts "\nFailed to update project #{id}: #{e}" end end - puts 'Done' + puts "\nDone" end def down -- cgit v1.2.1 From 1a8fd9d7a5dfd43cc7e3f6b159f8852f722ba4e4 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 18 Apr 2016 15:15:57 -0400 Subject: Fix CHANGELOG --- CHANGELOG | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index d691113e198..0b3d1003b5f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,7 +18,6 @@ v 8.7.0 (unreleased) - Allow projects to be transfered to a lower visibility level group - Fix `signed_in_ip` being set to 127.0.0.1 when using a reverse proxy !3524 - Improved Markdown rendering performance !3389 - - Improved Markdown rendering performance !3389 (Yorick Peterse) - Make shared runners text in box configurable - Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu) - API: Ability to subscribe and unsubscribe from issues and merge requests (Robert Schilling) -- cgit v1.2.1 From 3f66f4470a7399a5079de04b8b2506edc159b90a Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 18 Apr 2016 15:19:24 -0400 Subject: Make rubocop happy --- lib/ci/gitlab_ci_yaml_processor.rb | 27 +++++++++++++++------------ spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 16 ++++++++-------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 88d6ce01b03..ff9887cba1e 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -160,6 +160,7 @@ module Ci validate_job_name!(name) validate_job_keys!(name, job) validate_job_types!(name, job) + validate_job_script!(name, job) validate_job_stage!(name, job) if job[:stage] validate_job_variables!(name, job) if job[:variables] @@ -183,18 +184,6 @@ module Ci end def validate_job_types!(name, job) - if !validate_string(job[:script]) && !validate_array_of_strings(job[:script]) - raise ValidationError, "#{name} job: script should be a string or an array of a strings" - end - - if job[:before_script] && !validate_array_of_strings(job[:before_script]) - raise ValidationError, "#{name} job: before_script should be an array of strings" - end - - if job[:after_script] && !validate_array_of_strings(job[:after_script]) - raise ValidationError, "#{name} job: after_script should be an array of strings" - end - if job[:image] && !validate_string(job[:image]) raise ValidationError, "#{name} job: image should be a string" end @@ -224,6 +213,20 @@ module Ci end end + def validate_job_script!(name, job) + if !validate_string(job[:script]) && !validate_array_of_strings(job[:script]) + raise ValidationError, "#{name} job: script should be a string or an array of a strings" + end + + if job[:before_script] && !validate_array_of_strings(job[:before_script]) + raise ValidationError, "#{name} job: before_script should be an array of strings" + end + + if job[:after_script] && !validate_array_of_strings(job[:after_script]) + raise ValidationError, "#{name} job: after_script should be an array of strings" + end + end + def validate_job_stage!(name, job) unless job[:stage].is_a?(String) && job[:stage].in?(stages) raise ValidationError, "#{name} job: stage parameter should be #{stages.join(", ")}" diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index a20b9ead559..643acf0303c 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -295,12 +295,12 @@ module Ci describe "before_script" do context "in global context" do - let(:config) { + let(:config) do { before_script: ["global script"], test: { script: ["script"] } } - } + end it "return commands with scripts concencaced" do expect(subject[:commands]).to eq("global script\nscript") @@ -308,12 +308,12 @@ module Ci end context "overwritten in local context" do - let(:config) { + let(:config) do { before_script: ["global script"], test: { before_script: ["local script"], script: ["script"] } } - } + end it "return commands with scripts concencaced" do expect(subject[:commands]).to eq("local script\nscript") @@ -322,11 +322,11 @@ module Ci end describe "script" do - let(:config) { + let(:config) do { test: { script: ["script"] } } - } + end it "return commands with scripts concencaced" do expect(subject[:commands]).to eq("script") @@ -348,12 +348,12 @@ module Ci end context "overwritten in local context" do - let(:config) { + let(:config) do { after_script: ["local after_script"], test: { after_script: ["local after_script"], script: ["script"] } } - } + end it "return after_script in options" do expect(subject[:options][:after_script]).to eq(["local after_script"]) -- cgit v1.2.1 From 5f39729c19fa22836686dab32fbcf7c34f32fd41 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Sun, 17 Apr 2016 12:32:31 -0300 Subject: Update octokit gem to version 4.3.0 --- Gemfile | 2 +- Gemfile.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index 199ef65d922..8caa749a8d4 100644 --- a/Gemfile +++ b/Gemfile @@ -315,7 +315,7 @@ end gem "newrelic_rpm", '~> 3.14' -gem 'octokit', '~> 3.8.0' +gem 'octokit', '~> 4.3.0' gem "mail_room", "~> 0.6.1" diff --git a/Gemfile.lock b/Gemfile.lock index ad7d7c18559..958824f7ed9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -485,8 +485,8 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (~> 1.2) - octokit (3.8.0) - sawyer (~> 0.6.0, >= 0.5.3) + octokit (4.3.0) + sawyer (~> 0.7.0, >= 0.5.3) omniauth (1.3.1) hashie (>= 1.2, < 4) rack (>= 1.0, < 3) @@ -712,8 +712,8 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - sawyer (0.6.0) - addressable (~> 2.3.5) + sawyer (0.7.0) + addressable (>= 2.3.5, < 2.5) faraday (~> 0.8, < 0.10) scss_lint (0.47.1) rake (>= 0.9, < 11) @@ -968,7 +968,7 @@ DEPENDENCIES newrelic_rpm (~> 3.14) nokogiri (~> 1.6.7, >= 1.6.7.2) oauth2 (~> 1.0.0) - octokit (~> 3.8.0) + octokit (~> 4.3.0) omniauth (~> 1.3.1) omniauth-auth0 (~> 1.4.1) omniauth-azure-oauth2 (~> 0.0.6) -- cgit v1.2.1 From 05a4f444c368593216ab335db93ca98ce2218e94 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Sun, 17 Apr 2016 23:52:34 -0300 Subject: Import labels from GitHub --- lib/gitlab/github_import/importer.rb | 12 ++++++++++- lib/gitlab/github_import/label_formatter.rb | 23 ++++++++++++++++++++++ .../gitlab/github_import/label_formatter_spec.rb | 19 ++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 lib/gitlab/github_import/label_formatter.rb create mode 100644 spec/lib/gitlab/github_import/label_formatter_spec.rb diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 0b1ed510229..e406a0283b9 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -16,7 +16,7 @@ module Gitlab end def execute - import_issues && import_pull_requests && import_wiki + import_labels && import_issues && import_pull_requests && import_wiki end private @@ -25,6 +25,16 @@ module Gitlab @import_data_credentials ||= project.import_data.credentials if project.import_data end + def import_labels + client.labels(project.import_source).each do |raw_data| + Label.create!(LabelFormatter.new(project, raw_data).attributes) + end + + true + rescue ActiveRecord::RecordInvalid => e + raise Projects::ImportService::Error, e.message + end + def import_issues client.list_issues(project.import_source, state: :all, sort: :created, diff --git a/lib/gitlab/github_import/label_formatter.rb b/lib/gitlab/github_import/label_formatter.rb new file mode 100644 index 00000000000..c2b9d40b511 --- /dev/null +++ b/lib/gitlab/github_import/label_formatter.rb @@ -0,0 +1,23 @@ +module Gitlab + module GithubImport + class LabelFormatter < BaseFormatter + def attributes + { + project: project, + title: title, + color: color + } + end + + private + + def color + "##{raw_data.color}" + end + + def title + raw_data.name + end + end + end +end diff --git a/spec/lib/gitlab/github_import/label_formatter_spec.rb b/spec/lib/gitlab/github_import/label_formatter_spec.rb new file mode 100644 index 00000000000..e94440a7fb0 --- /dev/null +++ b/spec/lib/gitlab/github_import/label_formatter_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::LabelFormatter, lib: true do + + describe '#attributes' do + it 'returns formatted attributes' do + project = create(:project) + raw = double(name: 'improvements', color: 'e6e6e6') + + formatter = described_class.new(project, raw) + + expect(formatter.attributes).to eq({ + project: project, + title: 'improvements', + color: '#e6e6e6' + }) + end + end +end -- cgit v1.2.1 From 7462a8f90a719e4850a28d9c6d2f223ce1e29b69 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 18 Apr 2016 01:02:22 -0300 Subject: Apply GitHub labels to Issue/Merge Request that were imported --- lib/gitlab/github_import/importer.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index e406a0283b9..7f70ab63f37 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -43,6 +43,7 @@ module Gitlab if gh_issue.valid? issue = Issue.create!(gh_issue.attributes) + apply_labels(gh_issue.number, issue) if gh_issue.has_comments? import_comments(gh_issue.number, issue) @@ -65,6 +66,7 @@ module Gitlab merge_request = MergeRequest.new(pull_request.attributes) if merge_request.save + apply_labels(pull_request.number, merge_request) import_comments(pull_request.number, merge_request) import_comments_on_diff(pull_request.number, merge_request) end @@ -76,6 +78,18 @@ module Gitlab raise Projects::ImportService::Error, e.message end + def apply_labels(number, issuable) + issue = client.issue(project.import_source, number) + + if issue.labels.count > 0 + label_ids = issue.labels.map do |raw| + Label.find_by(LabelFormatter.new(project, raw).attributes).try(:id) + end + + issuable.update_attribute(:label_ids, label_ids) + end + end + def import_comments(issue_number, noteable) comments = client.issue_comments(project.import_source, issue_number) create_comments(comments, noteable) -- cgit v1.2.1 From 696b1e965732e229f9b0f6f49297e78265379bb4 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 18 Apr 2016 01:02:50 -0300 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 2882a81afc2..290c9568149 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -85,6 +85,7 @@ v 8.7.0 (unreleased) - Show number sign on external issue reference text (Florent Baldino) - Updated print style for issues - Use GitHub Issue/PR number as iid to keep references + - Import GitHub labels v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 -- cgit v1.2.1 From 06ec511164b37cadbfdf069037745c108486162c Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 18 Apr 2016 13:44:27 -0300 Subject: Import milestones from GitHub --- lib/gitlab/github_import/importer.rb | 13 +++- lib/gitlab/github_import/milestone_formatter.rb | 48 +++++++++++++ .../github_import/milestone_formatter_spec.rb | 82 ++++++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 lib/gitlab/github_import/milestone_formatter.rb create mode 100644 spec/lib/gitlab/github_import/milestone_formatter_spec.rb diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 7f70ab63f37..0f9e3ee14ee 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -16,7 +16,8 @@ module Gitlab end def execute - import_labels && import_issues && import_pull_requests && import_wiki + import_labels && import_milestones && import_issues && + import_pull_requests && import_wiki end private @@ -35,6 +36,16 @@ module Gitlab raise Projects::ImportService::Error, e.message end + def import_milestones + client.list_milestones(project.import_source, state: :all).each do |raw_data| + Milestone.create!(MilestoneFormatter.new(project, raw_data).attributes) + end + + true + rescue ActiveRecord::RecordInvalid => e + raise Projects::ImportService::Error, e.message + end + def import_issues client.list_issues(project.import_source, state: :all, sort: :created, diff --git a/lib/gitlab/github_import/milestone_formatter.rb b/lib/gitlab/github_import/milestone_formatter.rb new file mode 100644 index 00000000000..e91a7e328cf --- /dev/null +++ b/lib/gitlab/github_import/milestone_formatter.rb @@ -0,0 +1,48 @@ +module Gitlab + module GithubImport + class MilestoneFormatter < BaseFormatter + def attributes + { + iid: number, + project: project, + title: title, + description: description, + due_date: due_date, + state: state, + created_at: created_at, + updated_at: updated_at + } + end + + private + + def number + raw_data.number + end + + def title + raw_data.title + end + + def description + raw_data.description + end + + def due_date + raw_data.due_on + end + + def state + raw_data.state == 'closed' ? 'closed' : 'active' + end + + def created_at + raw_data.created_at + end + + def updated_at + state == 'closed' ? raw_data.closed_at : raw_data.updated_at + end + end + end +end diff --git a/spec/lib/gitlab/github_import/milestone_formatter_spec.rb b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb new file mode 100644 index 00000000000..5a421e50581 --- /dev/null +++ b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::MilestoneFormatter, lib: true do + let(:project) { create(:empty_project) } + let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } + let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } + let(:base_data) do + { + number: 1347, + state: 'open', + title: '1.0', + description: 'Version 1.0', + due_on: nil, + created_at: created_at, + updated_at: updated_at, + closed_at: nil + } + end + + subject(:formatter) { described_class.new(project, raw_data)} + + describe '#attributes' do + context 'when milestone is open' do + let(:raw_data) { double(base_data.merge(state: 'open')) } + + it 'returns formatted attributes' do + expected = { + iid: 1347, + project: project, + title: '1.0', + description: 'Version 1.0', + state: 'active', + due_date: nil, + created_at: created_at, + updated_at: updated_at + } + + expect(formatter.attributes).to eq(expected) + end + end + + context 'when milestone is closed' do + let(:closed_at) { DateTime.strptime('2011-01-28T19:01:12Z') } + let(:raw_data) { double(base_data.merge(state: 'closed', closed_at: closed_at)) } + + it 'returns formatted attributes' do + expected = { + iid: 1347, + project: project, + title: '1.0', + description: 'Version 1.0', + state: 'closed', + due_date: nil, + created_at: created_at, + updated_at: closed_at + } + + expect(formatter.attributes).to eq(expected) + end + end + + context 'when milestone has a due date' do + let(:due_date) { DateTime.strptime('2011-01-28T19:01:12Z') } + let(:raw_data) { double(base_data.merge(due_on: due_date)) } + + it 'returns formatted attributes' do + expected = { + iid: 1347, + project: project, + title: '1.0', + description: 'Version 1.0', + state: 'active', + due_date: due_date, + created_at: created_at, + updated_at: updated_at + } + + expect(formatter.attributes).to eq(expected) + end + end + end +end -- cgit v1.2.1 From f2fe4af19da9d477e9b0df6ec530d4bcc1ca2a5f Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 18 Apr 2016 14:08:35 -0300 Subject: Set GitHub milestones to Issue/Merge Request that were imported --- lib/gitlab/github_import/issue_formatter.rb | 7 +++++++ lib/gitlab/github_import/pull_request_formatter.rb | 7 +++++++ spec/lib/gitlab/github_import/issue_formatter_spec.rb | 17 +++++++++++++++++ .../github_import/pull_request_formatter_spec.rb | 18 ++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/lib/gitlab/github_import/issue_formatter.rb b/lib/gitlab/github_import/issue_formatter.rb index acb332cb0cb..c8173913b4e 100644 --- a/lib/gitlab/github_import/issue_formatter.rb +++ b/lib/gitlab/github_import/issue_formatter.rb @@ -5,6 +5,7 @@ module Gitlab { iid: number, project: project, + milestone: milestone, title: raw_data.title, description: description, state: state, @@ -55,6 +56,12 @@ module Gitlab @formatter.author_line(author) + body end + def milestone + if raw_data.milestone.present? + project.milestones.find_by(iid: raw_data.milestone.number) + end + end + def state raw_data.state == 'closed' ? 'closed' : 'opened' end diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb index 5ee8a14624a..d21b942ad4b 100644 --- a/lib/gitlab/github_import/pull_request_formatter.rb +++ b/lib/gitlab/github_import/pull_request_formatter.rb @@ -11,6 +11,7 @@ module Gitlab target_project: target_project, target_branch: target_branch.name, state: state, + milestone: milestone, author_id: author_id, assignee_id: assignee_id, created_at: raw_data.created_at, @@ -58,6 +59,12 @@ module Gitlab formatter.author_line(author) + body end + def milestone + if raw_data.milestone.present? + project.milestones.find_by(iid: raw_data.milestone.number) + end + end + def source_project project end diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb index 4f3d7f4405b..46899b529b2 100644 --- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb @@ -32,6 +32,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do expected = { iid: 1347, project: project, + milestone: nil, title: 'Found a bug', description: "*Created by: octocat*\n\nI'm having a problem with this.", state: 'opened', @@ -53,6 +54,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do expected = { iid: 1347, project: project, + milestone: nil, title: 'Found a bug', description: "*Created by: octocat*\n\nI'm having a problem with this.", state: 'closed', @@ -80,6 +82,21 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end end + context 'when it has a milestone' do + let(:milestone) { OpenStruct.new(number: 45) } + let(:raw_data) { OpenStruct.new(base_data.merge(milestone: milestone)) } + + it 'returns nil when milestone does not exist' do + expect(issue.attributes.fetch(:milestone)).to be_nil + end + + it 'returns milestone when it exists' do + milestone = create(:milestone, project: project, iid: 45) + + expect(issue.attributes.fetch(:milestone)).to eq milestone + end + end + context 'when author is a GitLab user' do let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb index 11249e57ca8..590085718c7 100644 --- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb @@ -43,6 +43,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do target_project: project, target_branch: 'master', state: 'opened', + milestone: nil, author_id: project.creator_id, assignee_id: nil, created_at: created_at, @@ -67,6 +68,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do target_project: project, target_branch: 'master', state: 'closed', + milestone: nil, author_id: project.creator_id, assignee_id: nil, created_at: created_at, @@ -91,6 +93,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do target_project: project, target_branch: 'master', state: 'merged', + milestone: nil, author_id: project.creator_id, assignee_id: nil, created_at: created_at, @@ -128,6 +131,21 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id end end + + context 'when it has a milestone' do + let(:milestone) { OpenStruct.new(number: 45) } + let(:raw_data) { OpenStruct.new(base_data.merge(milestone: milestone)) } + + it 'returns nil when milestone does not exists' do + expect(pull_request.attributes.fetch(:milestone)).to be_nil + end + + it 'returns milestone when is exists' do + milestone = create(:milestone, project: project, iid: 45) + + expect(pull_request.attributes.fetch(:milestone)).to eq milestone + end + end end describe '#number' do -- cgit v1.2.1 From 3225f78fdbe80bf2d6624508b2d75bcd0a285351 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 18 Apr 2016 14:08:58 -0300 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 290c9568149..1a4b367e474 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -86,6 +86,7 @@ v 8.7.0 (unreleased) - Updated print style for issues - Use GitHub Issue/PR number as iid to keep references - Import GitHub labels + - Import GitHub milestones v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 -- cgit v1.2.1 From 0ed07587359aba66543dc0c620affe1086e80b60 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 18 Apr 2016 17:28:14 -0300 Subject: Use double instead of OpenStruct in the Issue/PR formatters specs --- .../gitlab/github_import/issue_formatter_spec.rb | 25 ++++++------- .../github_import/pull_request_formatter_spec.rb | 41 +++++++++++----------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb index 46899b529b2..0e7ffbe9b8e 100644 --- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb @@ -2,13 +2,14 @@ require 'spec_helper' describe Gitlab::GithubImport::IssueFormatter, lib: true do let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) } - let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') } + let(:octocat) { double(id: 123456, login: 'octocat') } let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } let(:base_data) do { number: 1347, + milestone: nil, state: 'open', title: 'Found a bug', body: "I'm having a problem with this.", @@ -26,7 +27,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do describe '#attributes' do context 'when issue is open' do - let(:raw_data) { OpenStruct.new(base_data.merge(state: 'open')) } + let(:raw_data) { double(base_data.merge(state: 'open')) } it 'returns formatted attributes' do expected = { @@ -48,7 +49,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do context 'when issue is closed' do let(:closed_at) { DateTime.strptime('2011-01-28T19:01:12Z') } - let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', closed_at: closed_at)) } + let(:raw_data) { double(base_data.merge(state: 'closed', closed_at: closed_at)) } it 'returns formatted attributes' do expected = { @@ -69,7 +70,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end context 'when it is assigned to someone' do - let(:raw_data) { OpenStruct.new(base_data.merge(assignee: octocat)) } + let(:raw_data) { double(base_data.merge(assignee: octocat)) } it 'returns nil as assignee_id when is not a GitLab user' do expect(issue.attributes.fetch(:assignee_id)).to be_nil @@ -83,8 +84,8 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end context 'when it has a milestone' do - let(:milestone) { OpenStruct.new(number: 45) } - let(:raw_data) { OpenStruct.new(base_data.merge(milestone: milestone)) } + let(:milestone) { double(number: 45) } + let(:raw_data) { double(base_data.merge(milestone: milestone)) } it 'returns nil when milestone does not exist' do expect(issue.attributes.fetch(:milestone)).to be_nil @@ -98,7 +99,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end context 'when author is a GitLab user' do - let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } + let(:raw_data) { double(base_data.merge(user: octocat)) } it 'returns project#creator_id as author_id when is not a GitLab user' do expect(issue.attributes.fetch(:author_id)).to eq project.creator_id @@ -114,7 +115,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do describe '#has_comments?' do context 'when number of comments is greater than zero' do - let(:raw_data) { OpenStruct.new(base_data.merge(comments: 1)) } + let(:raw_data) { double(base_data.merge(comments: 1)) } it 'returns true' do expect(issue.has_comments?).to eq true @@ -122,7 +123,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end context 'when number of comments is equal to zero' do - let(:raw_data) { OpenStruct.new(base_data.merge(comments: 0)) } + let(:raw_data) { double(base_data.merge(comments: 0)) } it 'returns false' do expect(issue.has_comments?).to eq false @@ -131,7 +132,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end describe '#number' do - let(:raw_data) { OpenStruct.new(base_data.merge(number: 1347)) } + let(:raw_data) { double(base_data.merge(number: 1347)) } it 'returns pull request number' do expect(issue.number).to eq 1347 @@ -140,7 +141,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do describe '#valid?' do context 'when mention a pull request' do - let(:raw_data) { OpenStruct.new(base_data.merge(pull_request: OpenStruct.new)) } + let(:raw_data) { double(base_data.merge(pull_request: double)) } it 'returns false' do expect(issue.valid?).to eq false @@ -148,7 +149,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end context 'when does not mention a pull request' do - let(:raw_data) { OpenStruct.new(base_data.merge(pull_request: nil)) } + let(:raw_data) { double(base_data.merge(pull_request: nil)) } it 'returns true' do expect(issue.valid?).to eq true diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb index 590085718c7..e59c0ca110e 100644 --- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb @@ -2,17 +2,18 @@ require 'spec_helper' describe Gitlab::GithubImport::PullRequestFormatter, lib: true do let(:project) { create(:project) } - let(:repository) { OpenStruct.new(id: 1, fork: false) } + let(:repository) { double(id: 1, fork: false) } let(:source_repo) { repository } - let(:source_branch) { OpenStruct.new(ref: 'feature', repo: source_repo) } + let(:source_branch) { double(ref: 'feature', repo: source_repo) } let(:target_repo) { repository } - let(:target_branch) { OpenStruct.new(ref: 'master', repo: target_repo) } - let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') } + let(:target_branch) { double(ref: 'master', repo: target_repo) } + let(:octocat) { double(id: 123456, login: 'octocat') } let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } let(:base_data) do { number: 1347, + milestone: nil, state: 'open', title: 'New feature', body: 'Please pull these awesome changes', @@ -31,7 +32,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do describe '#attributes' do context 'when pull request is open' do - let(:raw_data) { OpenStruct.new(base_data.merge(state: 'open')) } + let(:raw_data) { double(base_data.merge(state: 'open')) } it 'returns formatted attributes' do expected = { @@ -56,7 +57,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do context 'when pull request is closed' do let(:closed_at) { DateTime.strptime('2011-01-28T19:01:12Z') } - let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', closed_at: closed_at)) } + let(:raw_data) { double(base_data.merge(state: 'closed', closed_at: closed_at)) } it 'returns formatted attributes' do expected = { @@ -81,7 +82,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do context 'when pull request is merged' do let(:merged_at) { DateTime.strptime('2011-01-28T13:01:12Z') } - let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', merged_at: merged_at)) } + let(:raw_data) { double(base_data.merge(state: 'closed', merged_at: merged_at)) } it 'returns formatted attributes' do expected = { @@ -105,7 +106,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end context 'when it is assigned to someone' do - let(:raw_data) { OpenStruct.new(base_data.merge(assignee: octocat)) } + let(:raw_data) { double(base_data.merge(assignee: octocat)) } it 'returns nil as assignee_id when is not a GitLab user' do expect(pull_request.attributes.fetch(:assignee_id)).to be_nil @@ -119,7 +120,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end context 'when author is a GitLab user' do - let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } + let(:raw_data) { double(base_data.merge(user: octocat)) } it 'returns project#creator_id as author_id when is not a GitLab user' do expect(pull_request.attributes.fetch(:author_id)).to eq project.creator_id @@ -133,8 +134,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end context 'when it has a milestone' do - let(:milestone) { OpenStruct.new(number: 45) } - let(:raw_data) { OpenStruct.new(base_data.merge(milestone: milestone)) } + let(:milestone) { double(number: 45) } + let(:raw_data) { double(base_data.merge(milestone: milestone)) } it 'returns nil when milestone does not exists' do expect(pull_request.attributes.fetch(:milestone)).to be_nil @@ -149,7 +150,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end describe '#number' do - let(:raw_data) { OpenStruct.new(base_data.merge(number: 1347)) } + let(:raw_data) { double(base_data.merge(number: 1347)) } it 'returns pull request number' do expect(pull_request.number).to eq 1347 @@ -157,11 +158,11 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end describe '#valid?' do - let(:invalid_branch) { OpenStruct.new(ref: 'invalid-branch') } + let(:invalid_branch) { double(ref: 'invalid-branch').as_null_object } context 'when source, and target repositories are the same' do context 'and source and target branches exists' do - let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch, base: target_branch)) } + let(:raw_data) { double(base_data.merge(head: source_branch, base: target_branch)) } it 'returns true' do expect(pull_request.valid?).to eq true @@ -169,7 +170,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end context 'and source branch doesn not exists' do - let(:raw_data) { OpenStruct.new(base_data.merge(head: invalid_branch, base: target_branch)) } + let(:raw_data) { double(base_data.merge(head: invalid_branch, base: target_branch)) } it 'returns false' do expect(pull_request.valid?).to eq false @@ -177,7 +178,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end context 'and target branch doesn not exists' do - let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch, base: invalid_branch)) } + let(:raw_data) { double(base_data.merge(head: source_branch, base: invalid_branch)) } it 'returns false' do expect(pull_request.valid?).to eq false @@ -186,8 +187,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end context 'when source repo is a fork' do - let(:source_repo) { OpenStruct.new(id: 2, fork: true) } - let(:raw_data) { OpenStruct.new(base_data) } + let(:source_repo) { double(id: 2, fork: true) } + let(:raw_data) { double(base_data) } it 'returns false' do expect(pull_request.valid?).to eq false @@ -195,8 +196,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end context 'when target repo is a fork' do - let(:target_repo) { OpenStruct.new(id: 2, fork: true) } - let(:raw_data) { OpenStruct.new(base_data) } + let(:target_repo) { double(id: 2, fork: true) } + let(:raw_data) { double(base_data) } it 'returns false' do expect(pull_request.valid?).to eq false -- cgit v1.2.1 From ee1090e2b2bc7b3762f6e2775f3fd15e92ae212b Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Fri, 15 Apr 2016 08:08:22 -0300 Subject: Added System Hooks for push and tag_push Code is based on Project Webhooks, removing deprecations and without commits listing. --- app/models/hooks/system_hook.rb | 6 ++ app/models/project.rb | 21 ++++--- app/services/git_push_service.rb | 6 ++ app/services/git_tag_push_service.rb | 6 ++ app/services/system_hooks_service.rb | 12 ++-- doc/system_hooks/system_hooks.md | 77 ++++++++++++++++++++++++ doc/web_hooks/web_hooks.md | 4 +- lib/gitlab/push_data_builder.rb | 22 ++++++- spec/lib/gitlab/push_data_builder_spec.rb | 31 +++++++++- spec/support/project_hook_data_shared_example.rb | 17 +++++- 10 files changed, 181 insertions(+), 21 deletions(-) diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb index c147d8762a9..bacd42ec60a 100644 --- a/app/models/hooks/system_hook.rb +++ b/app/models/hooks/system_hook.rb @@ -19,4 +19,10 @@ # class SystemHook < WebHook + scope :push_hooks, -> { where(push_events: true) } + scope :tag_push_hooks, -> { where(tag_push_events: true) } + + def async_execute(data, hook_name) + Sidekiq::Client.enqueue(SystemHookWorker, id, data, hook_name) + end end diff --git a/app/models/project.rb b/app/models/project.rb index 8f20922e3c5..e7dac23a122 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -831,8 +831,8 @@ class Project < ActiveRecord::Base end end - def hook_attrs - { + def hook_attrs(backward: true) + attrs = { name: name, description: description, web_url: web_url, @@ -843,12 +843,19 @@ class Project < ActiveRecord::Base visibility_level: visibility_level, path_with_namespace: path_with_namespace, default_branch: default_branch, - # Backward compatibility - homepage: web_url, - url: url_to_repo, - ssh_url: ssh_url_to_repo, - http_url: http_url_to_repo } + + # Backward compatibility + if backward + attrs.merge!({ + homepage: web_url, + url: url_to_repo, + ssh_url: ssh_url_to_repo, + http_url: http_url_to_repo + }) + end + + attrs end # Reset events cache related to this project diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index dc74c02760b..25d8e2cf052 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -73,6 +73,7 @@ class GitPushService < BaseService @project.update_merge_requests(params[:oldrev], params[:newrev], params[:ref], current_user) EventCreateService.new.push(@project, current_user, build_push_data) + SystemHooksService.new.execute_hooks(build_push_data_system_hook.dup, :push_hooks) @project.execute_hooks(build_push_data.dup, :push_hooks) @project.execute_services(build_push_data.dup, :push_hooks) CreateCommitBuildsService.new.execute(@project, current_user, build_push_data) @@ -138,6 +139,11 @@ class GitPushService < BaseService build(@project, current_user, params[:oldrev], params[:newrev], params[:ref], push_commits) end + def build_push_data_system_hook + @push_data_system ||= Gitlab::PushDataBuilder. + build_system(@project, current_user, params[:oldrev], params[:newrev], params[:ref]) + end + def push_to_existing_branch? # Return if this is not a push to a branch (e.g. new commits) Gitlab::Git.branch_ref?(params[:ref]) && !Gitlab::Git.blank_ref?(params[:oldrev]) diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index c88c7672805..81ba68fa674 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -8,6 +8,7 @@ class GitTagPushService @push_data = build_push_data(oldrev, newrev, ref) EventCreateService.new.push(project, user, @push_data) + SystemHooksService.new.execute_hooks(build_system_push_data.dup, :tag_push_hooks) project.execute_hooks(@push_data.dup, :tag_push_hooks) project.execute_services(@push_data.dup, :tag_push_hooks) CreateCommitBuildsService.new.execute(project, @user, @push_data) @@ -35,4 +36,9 @@ class GitTagPushService Gitlab::PushDataBuilder. build(project, user, oldrev, newrev, ref, commits, message) end + + def build_system_push_data(oldrev, newrev, ref) + Gitlab::PushDataBuilder. + build_system(project, user, oldrev, newrev, ref) + end end diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index f0615ec7420..e43b5b51e5b 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -3,17 +3,13 @@ class SystemHooksService execute_hooks(build_event_data(model, event)) end - private - - def execute_hooks(data) - SystemHook.all.each do |sh| - async_execute_hook(sh, data, 'system_hooks') + def execute_hooks(data, hooks_scope = :all) + SystemHook.send(hooks_scope).each do |hook| + hook.async_execute(data, 'system_hooks') end end - def async_execute_hook(hook, data, hook_name) - Sidekiq::Client.enqueue(SystemHookWorker, hook.id, data, hook_name) - end + private def build_event_data(model, event) data = { diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md index 612376e3a49..4c5a9e366cf 100644 --- a/doc/system_hooks/system_hooks.md +++ b/doc/system_hooks/system_hooks.md @@ -240,3 +240,80 @@ X-Gitlab-Event: System Hook "user_id": 41 } ``` + +## Push events + +Triggered when you push to the repository except when pushing tags. + +**Request header**: + +``` +X-Gitlab-Event: System Hook +``` + +**Request body:** + +```json +{ + "event_name": "push", + "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", + "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "ref": "refs/heads/master", + "checkout_sha": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "user_id": 4, + "user_name": "John Smith", + "user_email": "john@example.com", + "user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80", + "project_id": 15, + "project":{ + "name":"Diaspora", + "description":"", + "web_url":"http://example.com/mike/diaspora", + "avatar_url":null, + "git_ssh_url":"git@example.com:mike/diaspora.git", + "git_http_url":"http://example.com/mike/diaspora.git", + "namespace":"Mike", + "visibility_level":0, + "path_with_namespace":"mike/diaspora", + "default_branch":"master", + } +} +``` + +## Tag events + +Triggered when you create (or delete) tags to the repository. + +**Request header**: + +``` +X-Gitlab-Event: System Hook +``` + +**Request body:** + +```json +{ + "event_name": "tag_push", + "before": "0000000000000000000000000000000000000000", + "after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7", + "ref": "refs/tags/v1.0.0", + "checkout_sha": "5937ac0a7beb003549fc5fd26fc247adbce4a52e", + "user_id": 1, + "user_name": "John Smith", + "user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80", + "project_id": 1, + "project":{ + "name":"Example", + "description":"", + "web_url":"http://example.com/jsmith/example", + "avatar_url":null, + "git_ssh_url":"git@example.com:jsmith/example.git", + "git_http_url":"http://example.com/jsmith/example.git", + "namespace":"Jsmith", + "visibility_level":0, + "path_with_namespace":"jsmith/example", + "default_branch":"master", + } +} +``` diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md index 22e207b6d32..c1c51302e79 100644 --- a/doc/web_hooks/web_hooks.md +++ b/doc/web_hooks/web_hooks.md @@ -41,6 +41,7 @@ X-Gitlab-Event: Push Hook "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "ref": "refs/heads/master", + "checkout_sha": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "user_id": 4, "user_name": "John Smith", "user_email": "john@example.com", @@ -118,9 +119,10 @@ X-Gitlab-Event: Tag Push Hook ```json { "object_kind": "tag_push", - "ref": "refs/tags/v1.0.0", "before": "0000000000000000000000000000000000000000", "after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7", + "ref": "refs/tags/v1.0.0", + "checkout_sha": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7", "user_id": 1, "user_name": "John Smith", "user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80", diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb index 97d1edab9c1..eb8e45040bc 100644 --- a/lib/gitlab/push_data_builder.rb +++ b/lib/gitlab/push_data_builder.rb @@ -36,7 +36,7 @@ module Gitlab commit.hook_attrs(with_changed_files: true) end - type = Gitlab::Git.tag_ref?(ref) ? "tag_push" : "push" + type = Gitlab::Git.tag_ref?(ref) ? 'tag_push' : 'push' # Hash to be passed as post_receive_data data = { @@ -62,6 +62,26 @@ module Gitlab data end + def build_system(project, user, oldrev, newrev, ref) + type = Gitlab::Git.tag_ref?(ref) ? 'tag_push' : 'push' + + data = { + event_name: type, + before: oldrev, + after: newrev, + ref: ref, + checkout_sha: checkout_sha(project.repository, newrev, ref), + user_id: user.id, + user_name: user.name, + user_email: user.email, + user_avatar: user.avatar_url, + project_id: project.id, + project: project.hook_attrs(backward: false) + } + + data + end + # This method provide a sample data generated with # existing project and commits to test webhooks def build_sample(project, user) diff --git a/spec/lib/gitlab/push_data_builder_spec.rb b/spec/lib/gitlab/push_data_builder_spec.rb index 961022b9d12..d6fb65e6948 100644 --- a/spec/lib/gitlab/push_data_builder_spec.rb +++ b/spec/lib/gitlab/push_data_builder_spec.rb @@ -14,11 +14,11 @@ describe Gitlab::PushDataBuilder, lib: true do it { expect(data[:ref]).to eq('refs/heads/master') } it { expect(data[:commits].size).to eq(3) } it { expect(data[:total_commits_count]).to eq(3) } - it { expect(data[:commits].first[:added]).to eq(["gitlab-grack"]) } - it { expect(data[:commits].first[:modified]).to eq([".gitmodules"]) } + it { expect(data[:commits].first[:added]).to eq(['gitlab-grack']) } + it { expect(data[:commits].first[:modified]).to eq(['.gitmodules']) } it { expect(data[:commits].first[:removed]).to eq([]) } - include_examples 'project hook data' + include_examples 'project hook data with deprecateds' include_examples 'deprecated repository hook data' end @@ -37,9 +37,34 @@ describe Gitlab::PushDataBuilder, lib: true do it { expect(data[:commits]).to be_empty } it { expect(data[:total_commits_count]).to be_zero } + include_examples 'project hook data with deprecateds' + include_examples 'deprecated repository hook data' + it 'does not raise an error when given nil commits' do expect { described_class.build(spy, spy, spy, spy, spy, nil) }. not_to raise_error end end + + describe '.build_system' do + let(:data) do + described_class.build_system(project, user, Gitlab::Git::BLANK_SHA, + '8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b', + 'refs/tags/v1.1.0') + end + + it { expect(data).to be_a(Hash) } + it { expect(data[:before]).to eq(Gitlab::Git::BLANK_SHA) } + it { expect(data[:checkout_sha]).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } + it { expect(data[:after]).to eq('8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b') } + it { expect(data[:ref]).to eq('refs/tags/v1.1.0') } + it { expect(data[:user_id]).to eq(user.id) } + it { expect(data[:user_name]).to eq(user.name) } + it { expect(data[:user_email]).to eq(user.email) } + it { expect(data[:user_avatar]).to eq(user.avatar_url) } + it { expect(data[:project_id]).to eq(project.id) } + it { expect(data[:project]).to be_a(Hash) } + + include_examples 'project hook data' + end end diff --git a/spec/support/project_hook_data_shared_example.rb b/spec/support/project_hook_data_shared_example.rb index 422083875d7..7dbaa6a6459 100644 --- a/spec/support/project_hook_data_shared_example.rb +++ b/spec/support/project_hook_data_shared_example.rb @@ -1,4 +1,4 @@ -RSpec.shared_examples 'project hook data' do |project_key: :project| +RSpec.shared_examples 'project hook data with deprecateds' do |project_key: :project| it 'contains project data' do expect(data[project_key][:name]).to eq(project.name) expect(data[project_key][:description]).to eq(project.description) @@ -17,6 +17,21 @@ RSpec.shared_examples 'project hook data' do |project_key: :project| end end +RSpec.shared_examples 'project hook data' do |project_key: :project| + it 'contains project data' do + expect(data[project_key][:name]).to eq(project.name) + expect(data[project_key][:description]).to eq(project.description) + expect(data[project_key][:web_url]).to eq(project.web_url) + expect(data[project_key][:avatar_url]).to eq(project.avatar_url) + expect(data[project_key][:git_http_url]).to eq(project.http_url_to_repo) + expect(data[project_key][:git_ssh_url]).to eq(project.ssh_url_to_repo) + expect(data[project_key][:namespace]).to eq(project.namespace.name) + expect(data[project_key][:visibility_level]).to eq(project.visibility_level) + expect(data[project_key][:path_with_namespace]).to eq(project.path_with_namespace) + expect(data[project_key][:default_branch]).to eq(project.default_branch) + end +end + RSpec.shared_examples 'deprecated repository hook data' do |project_key: :project| it 'contains deprecated repository data' do expect(data[:repository][:name]).to eq(project.name) -- cgit v1.2.1 From 2384bed4d8e3f79461664911715e5f2a2a66c008 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Fri, 15 Apr 2016 09:26:27 -0300 Subject: Refactor GitTagPushService and fig tags_push system event hook --- app/services/git_tag_push_service.rb | 27 +++++++++++++-------------- app/workers/post_receive.rb | 4 ++-- spec/services/git_tag_push_service_spec.rb | 24 ++++++++++++------------ 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index 81ba68fa674..f4a1d0da5d8 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -1,17 +1,16 @@ -class GitTagPushService - attr_accessor :project, :user, :push_data +class GitTagPushService < BaseService + attr_accessor :push_data - def execute(project, user, oldrev, newrev, ref) + def execute project.repository.before_push_tag - @project, @user = project, user - @push_data = build_push_data(oldrev, newrev, ref) + @push_data = build_push_data - EventCreateService.new.push(project, user, @push_data) + EventCreateService.new.push(project, current_user, @push_data) SystemHooksService.new.execute_hooks(build_system_push_data.dup, :tag_push_hooks) project.execute_hooks(@push_data.dup, :tag_push_hooks) project.execute_services(@push_data.dup, :tag_push_hooks) - CreateCommitBuildsService.new.execute(project, @user, @push_data) + CreateCommitBuildsService.new.execute(project, current_user, @push_data) ProjectCacheWorker.perform_async(project.id) true @@ -19,14 +18,14 @@ class GitTagPushService private - def build_push_data(oldrev, newrev, ref) + def build_push_data commits = [] message = nil - if !Gitlab::Git.blank_ref?(newrev) - tag_name = Gitlab::Git.ref_name(ref) + if !Gitlab::Git.blank_ref?(params[:newrev]) + tag_name = Gitlab::Git.ref_name(params[:ref]) tag = project.repository.find_tag(tag_name) - if tag && tag.target == newrev + if tag && tag.target == params[:newrev] commit = project.commit(tag.target) commits = [commit].compact message = tag.message @@ -34,11 +33,11 @@ class GitTagPushService end Gitlab::PushDataBuilder. - build(project, user, oldrev, newrev, ref, commits, message) + build(project, current_user, params[:oldrev], params[:newrev], params[:ref], commits, message) end - def build_system_push_data(oldrev, newrev, ref) + def build_system_push_data Gitlab::PushDataBuilder. - build_system(project, user, oldrev, newrev, ref) + build_system(project, current_user, params[:oldrev], params[:newrev], params[:ref]) end end diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 9e1215b21a6..f3327ca9e61 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -39,7 +39,7 @@ class PostReceive end if Gitlab::Git.tag_ref?(ref) - GitTagPushService.new.execute(post_received.project, @user, oldrev, newrev, ref) + GitTagPushService.new(post_received.project, @user, oldrev: oldrev, newrev: newrev, ref: ref).execute elsif Gitlab::Git.branch_ref?(ref) GitPushService.new(post_received.project, @user, oldrev: oldrev, newrev: newrev, ref: ref).execute end @@ -47,7 +47,7 @@ class PostReceive end private - + def log(message) Gitlab::GitLogger.error("POST-RECEIVE: #{message}") end diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb index cc780587e74..a63656e6268 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git_tag_push_service_spec.rb @@ -5,19 +5,17 @@ describe GitTagPushService, services: true do let(:user) { create :user } let(:project) { create :project } - let(:service) { GitTagPushService.new } + let(:service) { GitTagPushService.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) } - before do - @oldrev = Gitlab::Git::BLANK_SHA - @newrev = "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" # gitlab-test: git rev-parse refs/tags/v1.1.0 - @ref = 'refs/tags/v1.1.0' - end + let(:oldrev) { Gitlab::Git::BLANK_SHA } + let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0 + let(:ref) { 'refs/tags/v1.1.0' } describe "Git Tag Push Data" do before do - service.execute(project, user, @oldrev, @newrev, @ref) + service.execute @push_data = service.push_data - @tag_name = Gitlab::Git.ref_name(@ref) + @tag_name = Gitlab::Git.ref_name(ref) @tag = project.repository.find_tag(@tag_name) @commit = project.commit(@tag.target) end @@ -25,9 +23,9 @@ describe GitTagPushService, services: true do subject { @push_data } it { is_expected.to include(object_kind: 'tag_push') } - it { is_expected.to include(ref: @ref) } - it { is_expected.to include(before: @oldrev) } - it { is_expected.to include(after: @newrev) } + it { is_expected.to include(ref: ref) } + it { is_expected.to include(before: oldrev) } + it { is_expected.to include(after: newrev) } it { is_expected.to include(message: @tag.message) } it { is_expected.to include(user_id: user.id) } it { is_expected.to include(user_name: user.name) } @@ -80,9 +78,11 @@ describe GitTagPushService, services: true do describe "Webhooks" do context "execute webhooks" do + let(:service) { GitTagPushService.new(project, user, oldrev: 'oldrev', newrev: 'newrev', ref: 'refs/tags/v1.0.0') } + it "when pushing tags" do expect(project).to receive(:execute_hooks) - service.execute(project, user, 'oldrev', 'newrev', 'refs/tags/v1.0.0') + service.execute end end end -- cgit v1.2.1 From 5330af3fa69d4c47437ce27480c7f3b74652b2ca Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Mon, 18 Apr 2016 21:52:43 -0300 Subject: Using single builder for push and tag events --- app/services/git_push_service.rb | 2 +- app/services/git_tag_push_service.rb | 2 +- doc/system_hooks/system_hooks.md | 40 +++++++++++++++++++++++++++++-- lib/gitlab/push_data_builder.rb | 21 +--------------- spec/lib/gitlab/push_data_builder_spec.rb | 28 +++++----------------- 5 files changed, 47 insertions(+), 46 deletions(-) diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 25d8e2cf052..1e1be8cd04b 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -141,7 +141,7 @@ class GitPushService < BaseService def build_push_data_system_hook @push_data_system ||= Gitlab::PushDataBuilder. - build_system(@project, current_user, params[:oldrev], params[:newrev], params[:ref]) + build(@project, current_user, params[:oldrev], params[:newrev], params[:ref], []) end def push_to_existing_branch? diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index f4a1d0da5d8..64271d8bc5c 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -38,6 +38,6 @@ class GitTagPushService < BaseService def build_system_push_data Gitlab::PushDataBuilder. - build_system(project, current_user, params[:oldrev], params[:newrev], params[:ref]) + build(project, current_user, params[:oldrev], params[:newrev], params[:ref], [], '') end end diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md index 4c5a9e366cf..c44930a4ceb 100644 --- a/doc/system_hooks/system_hooks.md +++ b/doc/system_hooks/system_hooks.md @@ -4,6 +4,12 @@ Your GitLab instance can perform HTTP POST requests on the following events: `pr System hooks can be used, e.g. for logging or changing information in a LDAP server. +> **Note:** +> +> We follow the same structure from Webhooks for Push and Tag events, but we never display commits. +> +> Same deprecations from Webhooks are valid here. + ## Hooks request example **Request header**: @@ -276,7 +282,22 @@ X-Gitlab-Event: System Hook "visibility_level":0, "path_with_namespace":"mike/diaspora", "default_branch":"master", - } + "homepage":"http://example.com/mike/diaspora", + "url":"git@example.com:mike/diaspora.git", + "ssh_url":"git@example.com:mike/diaspora.git", + "http_url":"http://example.com/mike/diaspora.git" + }, + "repository":{ + "name": "Diaspora", + "url": "git@example.com:mike/diaspora.git", + "description": "", + "homepage": "http://example.com/mike/diaspora", + "git_http_url":"http://example.com/mike/diaspora.git", + "git_ssh_url":"git@example.com:mike/diaspora.git", + "visibility_level":0 + }, + "commits": [], + "total_commits_count": 0 } ``` @@ -314,6 +335,21 @@ X-Gitlab-Event: System Hook "visibility_level":0, "path_with_namespace":"jsmith/example", "default_branch":"master", - } + "homepage":"http://example.com/jsmith/example", + "url":"git@example.com:jsmith/example.git", + "ssh_url":"git@example.com:jsmith/example.git", + "http_url":"http://example.com/jsmith/example.git" + }, + "repository":{ + "name": "Example", + "url": "ssh://git@example.com/jsmith/example.git", + "description": "", + "homepage": "http://example.com/jsmith/example", + "git_http_url":"http://example.com/jsmith/example.git", + "git_ssh_url":"git@example.com:jsmith/example.git", + "visibility_level":0 + }, + "commits": [], + "total_commits_count": 0 } ``` diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb index eb8e45040bc..67622f321a6 100644 --- a/lib/gitlab/push_data_builder.rb +++ b/lib/gitlab/push_data_builder.rb @@ -41,6 +41,7 @@ module Gitlab # Hash to be passed as post_receive_data data = { object_kind: type, + event_name: type, before: oldrev, after: newrev, ref: ref, @@ -62,26 +63,6 @@ module Gitlab data end - def build_system(project, user, oldrev, newrev, ref) - type = Gitlab::Git.tag_ref?(ref) ? 'tag_push' : 'push' - - data = { - event_name: type, - before: oldrev, - after: newrev, - ref: ref, - checkout_sha: checkout_sha(project.repository, newrev, ref), - user_id: user.id, - user_name: user.name, - user_email: user.email, - user_avatar: user.avatar_url, - project_id: project.id, - project: project.hook_attrs(backward: false) - } - - data - end - # This method provide a sample data generated with # existing project and commits to test webhooks def build_sample(project, user) diff --git a/spec/lib/gitlab/push_data_builder_spec.rb b/spec/lib/gitlab/push_data_builder_spec.rb index d6fb65e6948..7fc34139eff 100644 --- a/spec/lib/gitlab/push_data_builder_spec.rb +++ b/spec/lib/gitlab/push_data_builder_spec.rb @@ -34,6 +34,12 @@ describe Gitlab::PushDataBuilder, lib: true do it { expect(data[:checkout_sha]).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } it { expect(data[:after]).to eq('8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b') } it { expect(data[:ref]).to eq('refs/tags/v1.1.0') } + it { expect(data[:user_id]).to eq(user.id) } + it { expect(data[:user_name]).to eq(user.name) } + it { expect(data[:user_email]).to eq(user.email) } + it { expect(data[:user_avatar]).to eq(user.avatar_url) } + it { expect(data[:project_id]).to eq(project.id) } + it { expect(data[:project]).to be_a(Hash) } it { expect(data[:commits]).to be_empty } it { expect(data[:total_commits_count]).to be_zero } @@ -45,26 +51,4 @@ describe Gitlab::PushDataBuilder, lib: true do not_to raise_error end end - - describe '.build_system' do - let(:data) do - described_class.build_system(project, user, Gitlab::Git::BLANK_SHA, - '8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b', - 'refs/tags/v1.1.0') - end - - it { expect(data).to be_a(Hash) } - it { expect(data[:before]).to eq(Gitlab::Git::BLANK_SHA) } - it { expect(data[:checkout_sha]).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } - it { expect(data[:after]).to eq('8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b') } - it { expect(data[:ref]).to eq('refs/tags/v1.1.0') } - it { expect(data[:user_id]).to eq(user.id) } - it { expect(data[:user_name]).to eq(user.name) } - it { expect(data[:user_email]).to eq(user.email) } - it { expect(data[:user_avatar]).to eq(user.avatar_url) } - it { expect(data[:project_id]).to eq(project.id) } - it { expect(data[:project]).to be_a(Hash) } - - include_examples 'project hook data' - end end -- cgit v1.2.1 From f6fa18668a8618d3677afd15ebbcda41d3329247 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Mon, 18 Apr 2016 21:53:41 -0300 Subject: moving overlapping scopes to webhook --- app/models/hooks/project_hook.rb | 2 -- app/models/hooks/system_hook.rb | 3 --- app/models/hooks/web_hook.rb | 3 +++ 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb index fe923fafbe0..7365e360de2 100644 --- a/app/models/hooks/project_hook.rb +++ b/app/models/hooks/project_hook.rb @@ -21,8 +21,6 @@ class ProjectHook < WebHook belongs_to :project - scope :push_hooks, -> { where(push_events: true) } - scope :tag_push_hooks, -> { where(tag_push_events: true) } scope :issue_hooks, -> { where(issues_events: true) } scope :note_hooks, -> { where(note_events: true) } scope :merge_request_hooks, -> { where(merge_requests_events: true) } diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb index bacd42ec60a..15dddcc2447 100644 --- a/app/models/hooks/system_hook.rb +++ b/app/models/hooks/system_hook.rb @@ -19,9 +19,6 @@ # class SystemHook < WebHook - scope :push_hooks, -> { where(push_events: true) } - scope :tag_push_hooks, -> { where(tag_push_events: true) } - def async_execute(data, hook_name) Sidekiq::Client.enqueue(SystemHookWorker, id, data, hook_name) end diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index 7a13c3f0a39..3a2e4f546f7 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -30,6 +30,9 @@ class WebHook < ActiveRecord::Base default_value_for :build_events, false default_value_for :enable_ssl_verification, true + scope :push_hooks, -> { where(push_events: true) } + scope :tag_push_hooks, -> { where(tag_push_events: true) } + # HTTParty timeout default_timeout Gitlab.config.gitlab.webhook_timeout -- cgit v1.2.1 From 8ead3d0d183338eeef9390eda0d2da07770b9274 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Apr 2016 10:41:01 +0200 Subject: Add CHANGELOG item Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 1a4b367e474..3f23b183202 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -87,6 +87,8 @@ v 8.7.0 (unreleased) - Use GitHub Issue/PR number as iid to keep references - Import GitHub labels - Import GitHub milestones + - Fix emoji catgories in the emoji picker + - Execute system web hooks on push to the project v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 -- cgit v1.2.1 From 8614ff758492ecd90cf0dafce98b858901c0ea4a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Apr 2016 11:08:02 +0200 Subject: Allow enable/disable push events for system hooks Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + app/views/admin/hooks/index.html.haml | 36 ++++++++++++++++++++++++++------ app/views/projects/hooks/index.html.haml | 11 +++++----- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3f23b183202..3ced5aa3f89 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -89,6 +89,7 @@ v 8.7.0 (unreleased) - Import GitHub milestones - Fix emoji catgories in the emoji picker - Execute system web hooks on push to the project + - Allow enable/disable push events for system hooks v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index ad952052f25..67d23c80233 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -16,6 +16,27 @@ = f.label :url, "URL:", class: 'control-label' .col-sm-10 = f.text_field :url, class: "form-control" + .form-group + = f.label :url, "Trigger", class: 'control-label' + .col-sm-10.prepend-top-10 + %div + System hook will be triggered on set of events like creating project + or adding ssh key. But you can also enable extra triggers like Push events. + + %div.prepend-top-default + = f.check_box :push_events, class: 'pull-left' + .prepend-left-20 + = f.label :push_events, class: 'list-label' do + %strong Push events + %p.light + This url will be triggered by a push to the repository + %div + = f.check_box :tag_push_events, class: 'pull-left' + .prepend-left-20 + = f.label :tag_push_events, class: 'list-label' do + %strong Tag push events + %p.light + This url will be triggered when a new tag is pushed to the repository .form-group = f.label :enable_ssl_verification, "SSL verification", class: 'control-label checkbox' .col-sm-10 @@ -31,13 +52,16 @@ .panel.panel-default .panel-heading System hooks (#{@hooks.count}) - %ul.well-list + %ul.content-list - @hooks.each do |hook| %li - .list-item-name - %strong= hook.url - %p SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"} - - .pull-right + .controls = link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-sm" = link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm" + .monospace= hook.url + %div + - %w(push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger| + - if hook.send(trigger) + %span.label.label-gray= trigger.titleize + %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"} + diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml index e39224d86c6..aae3abcad4b 100644 --- a/app/views/projects/hooks/index.html.haml +++ b/app/views/projects/hooks/index.html.haml @@ -74,16 +74,15 @@ .panel.panel-default .panel-heading Webhooks (#{@hooks.count}) - %ul.well-list + %ul.content-list - @hooks.each do |hook| %li - .pull-right + .controls = link_to 'Test Hook', test_namespace_project_hook_path(@project.namespace, @project, hook), class: "btn btn-sm btn-grouped" = link_to 'Remove', namespace_project_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped" - .clearfix - %span.monospace= hook.url - %p + .monospace= hook.url + %div - %w(push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger| - if hook.send(trigger) %span.label.label-gray= trigger.titleize - SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"} + %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"} -- cgit v1.2.1 From d1b2e7b440e03e9ad5cac72fe767b16bf11d05cc Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 19 Apr 2016 10:26:07 +0100 Subject: Trigger filtering after ajax is complete in dropdown Closes #15186 --- app/assets/javascripts/gl_dropdown.js.coffee | 3 +++ app/views/shared/issuable/_sidebar.html.haml | 1 + 2 files changed, 4 insertions(+) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index fac928ef202..641141072f4 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -154,6 +154,9 @@ class GitLabDropdown @fullData = data @parseData @fullData + + if @options.filterable + @filterInput.trigger 'keyup' } # Init filterable diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 08bfd93f4e6..55d7a38cce2 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -118,6 +118,7 @@ Manage labels - else View labels + = dropdown_loading = render "shared/issuable/participants", participants: issuable.participants(current_user) - if current_user -- cgit v1.2.1 From 45525edd5b8eea87a2e0ef48907b71439587361d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Apr 2016 11:42:39 +0200 Subject: Add push events to permit params in system hooks Signed-off-by: Dmitriy Zaporozhets --- app/controllers/admin/hooks_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb index 0bd19c49d8f..93c4894ea0f 100644 --- a/app/controllers/admin/hooks_controller.rb +++ b/app/controllers/admin/hooks_controller.rb @@ -39,6 +39,6 @@ class Admin::HooksController < Admin::ApplicationController end def hook_params - params.require(:hook).permit(:url, :enable_ssl_verification) + params.require(:hook).permit(:url, :enable_ssl_verification, :push_events, :tag_push_events) end end -- cgit v1.2.1 From b3a5f636446376d73d7ec3206a333251ef93cf57 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 19 Apr 2016 11:57:10 +0200 Subject: Fix prepare build execution in docker environment --- scripts/prepare_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh index 4a7ee7dbb64..247383aa46c 100755 --- a/scripts/prepare_build.sh +++ b/scripts/prepare_build.sh @@ -11,7 +11,7 @@ retry() { return 1 } -if [ -f /.dockerinit ]; then +if [ -f /.dockerenv ] || [ -f ./dockerinit ]; then mkdir -p vendor # Install phantomjs package -- cgit v1.2.1 From f2e3868124c1b0acef4eb57ffc42577b74fab334 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 18 Apr 2016 10:56:10 +0200 Subject: Check permissions when sharing project with group Closes #15330 --- app/controllers/projects/group_links_controller.rb | 14 ++++-- .../projects/group_links_controller_spec.rb | 50 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 spec/controllers/projects/group_links_controller_spec.rb diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index 4159e53bfa9..92113b9dd87 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -7,10 +7,16 @@ class Projects::GroupLinksController < Projects::ApplicationController end def create - link = project.project_group_links.new - link.group_id = params[:link_group_id] - link.group_access = params[:link_group_access] - link.save + group = Group.find(params[:link_group_id]) + + if can?(current_user, :read_group, group) + link = project.project_group_links.new + link.group_id = params[:link_group_id] + link.group_access = params[:link_group_access] + link.save + else + return render_404 + end redirect_to namespace_project_group_links_path(project.namespace, project) end diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb new file mode 100644 index 00000000000..40bd83af861 --- /dev/null +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe Projects::GroupLinksController do + let(:project) { create(:project, :private) } + let(:group) { create(:group, :private) } + let(:user) { create(:user) } + + before do + project.team << [user, :master] + sign_in(user) + end + + describe '#create' do + shared_context 'link project to group' do + before do + post(:create, namespace_id: project.namespace.to_param, + project_id: project.to_param, + link_group_id: group.id, + link_group_access: ProjectGroupLink.default_access) + end + end + + context 'when user has access to group he want to link project to' do + before { group.add_developer(user) } + include_context 'link project to group' + + it 'links project with selected group' do + expect(group.shared_projects).to include project + end + + it 'redirects to project group links page'do + expect(response).to redirect_to( + namespace_project_group_links_path(project.namespace, project) + ) + end + end + + context 'when user doers not have access to group he want to link to' do + include_context 'link project to group' + + it 'renders 404' do + expect(response.status).to eq 404 + end + + it 'does not share project with that group' do + expect(group.shared_projects).to_not include project + end + end + end +end -- cgit v1.2.1 From d177abb32b0b31ec27c51d0eb42e1ea131d64a03 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 18 Apr 2016 11:17:55 +0200 Subject: Refactor method that shares project with a group --- app/controllers/projects/group_links_controller.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index 92113b9dd87..cd0f081cd7d 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -10,10 +10,9 @@ class Projects::GroupLinksController < Projects::ApplicationController group = Group.find(params[:link_group_id]) if can?(current_user, :read_group, group) - link = project.project_group_links.new - link.group_id = params[:link_group_id] - link.group_access = params[:link_group_access] - link.save + project.project_group_links.create( + group: group, group_access: params[:link_group_access] + ) else return render_404 end -- cgit v1.2.1 From 66b6d82a3e2f3ea32cdd534f8bcbba8ed515ce2d Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 18 Apr 2016 12:00:47 +0200 Subject: Use guard clause to check ability to share project --- app/controllers/projects/group_links_controller.rb | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index cd0f081cd7d..606552fa853 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -8,14 +8,11 @@ class Projects::GroupLinksController < Projects::ApplicationController def create group = Group.find(params[:link_group_id]) + return render_404 unless can?(current_user, :read_group, group) - if can?(current_user, :read_group, group) - project.project_group_links.create( - group: group, group_access: params[:link_group_access] - ) - else - return render_404 - end + project.project_group_links.create( + group: group, group_access: params[:link_group_access] + ) redirect_to namespace_project_group_links_path(project.namespace, project) end -- cgit v1.2.1 From b9e13c2481a4cc8c25a94a095c795ce9a1d61f4d Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 18 Apr 2016 14:39:32 +0200 Subject: Add Changelog entry for group link permissions fix --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 3f23b183202..1a6d80231b0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -90,6 +90,9 @@ v 8.7.0 (unreleased) - Fix emoji catgories in the emoji picker - Execute system web hooks on push to the project +v 8.6.7 (unreleased) + - Fix vulnerability that made it possible to enumerate private projects belonging to group + v 8.6.6 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 - Fix error on language detection when repository has no HEAD (e.g., master branch) (Jeroen Bobbeldijk). !3654 -- cgit v1.2.1 From d58d88fbd5dca6efdb95d5e07ad0b1c6f43bb565 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 19 Apr 2016 07:39:53 -0400 Subject: Use different markdown --- app/views/projects/runners/_shared_runners.html.haml | 2 +- spec/features/runners_spec.rb | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/projects/runners/_shared_runners.html.haml b/app/views/projects/runners/_shared_runners.html.haml index ec47ed79e55..b31fcfea763 100644 --- a/app/views/projects/runners/_shared_runners.html.haml +++ b/app/views/projects/runners/_shared_runners.html.haml @@ -2,7 +2,7 @@ .bs-callout.bs-callout-warning.shared-runners-description - if shared_runners_text.present? - = markdown(shared_runners_text) + = markdown(shared_runners_text, pipeline: 'plain_markdown') - else GitLab Runners do not offer secure isolation between projects that they do builds for. You are TRUSTING all GitLab users who can push code to project A, B or C to run shell scripts on the machine hosting runner X. %hr diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index 789b06d7c67..8edeb8d18af 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -81,7 +81,8 @@ describe "Runners" do end describe "shared runners description" do - let(:shared_runners_text) { 'custom shared runners description' } + let(:shared_runners_text) { 'custom **shared** runners description' } + let(:shared_runners_html) { 'custom shared runners description' } before do stub_application_setting(shared_runners_text: shared_runners_text) @@ -91,7 +92,7 @@ describe "Runners" do end it "sees shared runners description" do - expect(page.find(".shared-runners-description")).to have_content(shared_runners_text) + expect(page.find(".shared-runners-description")).to have_content(shared_runners_html) end end -- cgit v1.2.1