summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/issue_templates/Security developer workflow.md56
-rw-r--r--.gitlab/merge_request_templates/Security Release.md30
-rw-r--r--app/assets/javascripts/error_tracking_settings/store/actions.js4
-rw-r--r--app/assets/stylesheets/framework/buttons.scss2
-rw-r--r--app/controllers/projects/blame_controller.rb1
-rw-r--r--app/controllers/projects/blob_controller.rb1
-rw-r--r--app/controllers/projects/commit_controller.rb2
-rw-r--r--app/controllers/projects/compare_controller.rb1
-rw-r--r--app/controllers/projects/error_tracking/projects_controller.rb41
-rw-r--r--app/controllers/projects/error_tracking_controller.rb40
-rw-r--r--app/controllers/projects/merge_requests/creations_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb2
-rw-r--r--app/finders/environments_finder.rb40
-rw-r--r--app/finders/events_finder.rb12
-rw-r--r--app/helpers/dashboard_helper.rb4
-rw-r--r--app/models/environment.rb15
-rw-r--r--app/models/event_collection.rb11
-rw-r--r--app/models/merge_request.rb18
-rw-r--r--app/services/projects/operations/update_service.rb2
-rw-r--r--app/views/layouts/instance_statistics.html.haml4
-rw-r--r--app/views/layouts/nav/_analytics_link.html.haml4
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml7
-rw-r--r--app/views/layouts/nav/sidebar/_analytics_link.html.haml4
-rw-r--r--app/views/layouts/nav/sidebar/_instance_statistics.html.haml29
-rw-r--r--app/views/layouts/nav/sidebar/_instance_statistics_links.html.haml25
-rw-r--r--app/views/projects/settings/operations/_error_tracking.html.haml2
-rw-r--r--changelogs/unreleased/18999-add-dashboard-activity-to-events-endpoint.yml5
-rw-r--r--changelogs/unreleased/36017-move-analytics-out-of-more-in-top-navbar.yml5
-rw-r--r--changelogs/unreleased/sh-optimize-commit-is-ancestor-env.yml5
-rw-r--r--config/routes/project.rb5
-rw-r--r--doc/api/events.md3
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/controllers/projects/error_tracking/projects_controller_spec.rb122
-rw-r--r--spec/controllers/projects/error_tracking_controller_spec.rb107
-rw-r--r--spec/features/dashboard/instance_statistics_spec.rb22
-rw-r--r--spec/finders/environments_finder_spec.rb28
-rw-r--r--spec/finders/events_finder_spec.rb26
-rw-r--r--spec/frontend/error_tracking_settings/store/actions_spec.js8
-rw-r--r--spec/models/environment_spec.rb6
-rw-r--r--spec/models/merge_request_spec.rb16
-rw-r--r--spec/requests/api/events_spec.rb15
41 files changed, 445 insertions, 290 deletions
diff --git a/.gitlab/issue_templates/Security developer workflow.md b/.gitlab/issue_templates/Security developer workflow.md
index e06a6fb0cff..1b6a1f87216 100644
--- a/.gitlab/issue_templates/Security developer workflow.md
+++ b/.gitlab/issue_templates/Security developer workflow.md
@@ -1,60 +1,59 @@
<!--
# Read me first!
-Create this issue under https://dev.gitlab.org/gitlab/gitlabhq
+Create this issue under https://gitlab.com/gitlab-org/security
Set the title to: `Description of the original issue`
-->
-### Prior to starting the security release work
+## Prior to starting the security release work
- [ ] Read the [security process for developers] if you are not familiar with it.
-- [ ] Link to the original issue adding it to the [links section](#links)
-- [ ] Run `scripts/security-harness` in the CE, EE, and/or Omnibus to prevent pushing to any remote besides `dev.gitlab.org`
-- [ ] Create a new branch prefixing it with `security-`
-- [ ] Create a MR targeting `dev.gitlab.org` `master`
-- [ ] Add a link to this issue in the original security issue on `gitlab.com`.
+- [ ] Link this issue in the Security Release issue on GitLab.com. You can find this issue in the topic of the `#releases` channel.
+- [ ] Add a link to the confidential `gitlab-org/gitlab` issue describing the vulnerability next to **Original issue** in the [links table](#links).
+- [ ] Add a link to the confidential `gitlab-org/gitlab` Security release issue next to **Security release issue** in the [links table](#links).
+- [ ] Run `scripts/security-harness` in your local repository to prevent accidentally pushing to any remote besides `gitlab.com/gitlab-org/security`.
-#### Backports
+## Development
-- [ ] Once the MR is ready to be merged, create MRs targeting the latest 3 stable branches
- - [ ] At this point, it might be easy to squash the commits from the MR into one
- - You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation]
- - [ ] Create each MR targeting the stable branch `X-Y-stable`, using the "Security Release" merge request template.
- - Every merge request will have its own set of TODOs, so make sure to
- complete those.
-- [ ] Make sure all MRs have a link in the [links section](#links)
+- [ ] Create a new branch prefixing it with `security-`.
+- [ ] Create a merge request targeting `master` on `gitlab.com/gitlab-org/security` and use the [Security Release merge request template].
+- [ ] Follow the same [code review process]: Assign to a reviewer, then to a maintainer.
-[secpick documentation]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#secpick-script
+After your merge request has being approved according to our [approval guidelines], you're ready to prepare the backports
+
+## Backports
-#### Documentation and final details
+- [ ] Once the MR is ready to be merged, create MRs targeting the latest 3 stable branches
+ * At this point, it might be easy to squash the commits from the MR into one
+ * You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation]
+- [ ] Create each MR targeting the stable branch `X-Y-stable`, using the [Security Release merge request template].
+ * Every merge request will have its own set of TODOs, so make sure to complete those.
+- [ ] Make sure all MRs are linked in the [Links section](#links)
+
+## Documentation and final details
-- [ ] Check the topic on #releases to see when the next release is going to happen and add a link to the [links section](#links)
-- [ ] Add links to this issue and your MRs in the description of the security release issue
+- [ ] Ensure the [Links section](#links) is completed.
- [ ] Find out the versions affected (the Git history of the files affected may help you with this) and add them to the [details section](#details)
- [ ] Fill in any upgrade notes that users may need to take into account in the [details section](#details)
- [ ] Add Yes/No and further details if needed to the migration and settings columns in the [details section](#details)
- [ ] Add the nickname of the external user who found the issue (and/or HackerOne profile) to the Thanks row in the [details section](#details)
- [ ] Once your `master` MR is merged, comment on the original security issue with a link to that MR indicating the issue is fixed.
-### Summary
+## Summary
-#### Links
+### Links
| Description | Link |
| -------- | -------- |
| Original issue | #TODO |
| Security release issue | #TODO |
| `master` MR | !TODO |
-| `master` MR (EE) | !TODO |
| `Backport X.Y` MR | !TODO |
| `Backport X.Y` MR | !TODO |
| `Backport X.Y` MR | !TODO |
-| `Backport X.Y` MR (EE) | !TODO |
-| `Backport X.Y` MR (EE) | !TODO |
-| `Backport X.Y` MR (EE) | !TODO |
-#### Details
+### Details
| Description | Details | Further details|
| -------- | -------- | -------- |
@@ -65,6 +64,9 @@ Set the title to: `Description of the original issue`
| Thanks | | |
[security process for developers]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md
-[RM list]: https://about.gitlab.com/release-managers/
+[secpick documentation]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#secpick-script
+[security Release merge request template]: https://gitlab.com/gitlab-org/security/gitlab/blob/master/.gitlab/merge_request_templates/Security%20Release.md
+[code review process]: https://docs.gitlab.com/ee/development/code_review.html
+[approval guidelines]: https://docs.gitlab.com/ee/development/code_review.html#approval-guidelines
/label ~security
diff --git a/.gitlab/merge_request_templates/Security Release.md b/.gitlab/merge_request_templates/Security Release.md
index 42314f9b2dd..6556b9c9a72 100644
--- a/.gitlab/merge_request_templates/Security Release.md
+++ b/.gitlab/merge_request_templates/Security Release.md
@@ -1,31 +1,27 @@
<!--
# README first!
-This MR should be created on `dev.gitlab.org`.
+This MR should be created on `gitlab.com/gitlab-org/security/gitlab`.
See [the general developer security release guidelines](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md).
-This merge request _must not_ close the corresponding security issue _unless_ it
-targets master.
-
-When submitting a merge request for CE, a corresponding EE merge request is
-always required. This makes it easier to merge security merge requests, as
-manually merging CE into EE is no longer required.
-
-->
+
## Related issues
<!-- Mention the issue(s) this MR is related to -->
## Developer checklist
-- [ ] Link to the developer security workflow issue on `dev.gitlab.org`
-- [ ] MR targets `master`, or `X-Y-stable` for backports
-- [ ] Milestone is set for the version this MR applies to
-- [ ] Title of this MR is the same as for all backports
+- [ ] Link this MR in the `links` section of the related issue on [GitLab Security].
+- [ ] Merge request targets `master`, or `X-Y-stable` for backports.
+- [ ] Milestone is set for the version this merge request applies to.
+- [ ] Title of this merge request is the same as for all backports.
- [ ] A [CHANGELOG entry](https://docs.gitlab.com/ee/development/changelog.html) is added without a `merge_request` value, with `type` set to `security`
-- [ ] Add a link to this MR in the `links` section of related issue
-- [ ] Set up an EE MR (always required for CE merge requests): EE_MR_LINK_HERE
-- [ ] Assign to a reviewer (that is not a release manager)
+- [ ] Assign to a reviewer and maintainer, per our [Code Review process].
+- [ ] If this merge request targets `master`, ensure it's approved according to our [Approval Guidelines].
+- [ ] Merge request _must not_ close the corresponding security issue, _unless_ it targets `master`.
+
+**Note:** Reviewer/maintainer should not be a Release Manager
## Reviewer checklist
@@ -33,3 +29,7 @@ manually merging CE into EE is no longer required.
- [ ] Assigned to `@gitlab-release-tools-bot` with passing CI pipelines
/label ~security
+
+[GitLab Security]: https://gitlab.com/gitlab-org/security/gitlab
+[approval guidelines]: https://docs.gitlab.com/ee/development/code_review.html#approval-guidelines
+[Code Review process]: https://docs.gitlab.com/ee/development/code_review.html
diff --git a/app/assets/javascripts/error_tracking_settings/store/actions.js b/app/assets/javascripts/error_tracking_settings/store/actions.js
index 6b540ea7dfd..3f1ac426278 100644
--- a/app/assets/javascripts/error_tracking_settings/store/actions.js
+++ b/app/assets/javascripts/error_tracking_settings/store/actions.js
@@ -25,8 +25,8 @@ export const receiveProjectsError = ({ commit }) => {
export const fetchProjects = ({ dispatch, state }) => {
dispatch('requestProjects');
return axios
- .post(state.listProjectsEndpoint, {
- error_tracking_setting: {
+ .get(state.listProjectsEndpoint, {
+ params: {
api_host: state.apiHost,
token: state.token,
},
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 767832e242c..1b549c0a4f0 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -29,7 +29,7 @@
&:focus,
&:active {
background-color: $btn-active-gray;
- box-shadow: $gl-btn-active-background;
+ box-shadow: none;
}
}
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index 92655d593dd..b62ce940e9c 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -17,6 +17,7 @@ class Projects::BlameController < Projects::ApplicationController
end
environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
+ environment_params[:find_latest] = true
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
@blame_groups = Gitlab::Blame.new(@blob, @commit).groups
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 7c97f771a70..acd3ddf2d05 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -205,6 +205,7 @@ class Projects::BlobController < Projects::ApplicationController
def show_html
environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
+ environment_params[:find_latest] = true
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
@last_commit = @repository.last_commit_for_path(@commit.id, @blob.path)
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index afb670b687b..5c5bdb867bd 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -151,7 +151,7 @@ class Projects::CommitController < Projects::ApplicationController
@diffs = commit.diffs(opts)
@notes_count = commit.notes.count
- @environment = EnvironmentsFinder.new(@project, current_user, commit: @commit).execute.last
+ @environment = EnvironmentsFinder.new(@project, current_user, commit: @commit, find_latest: true).execute.last
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index 5586c2fc631..943277afe95 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -101,6 +101,7 @@ class Projects::CompareController < Projects::ApplicationController
def define_environment
if compare
environment_params = @repository.branch_exists?(head_ref) ? { ref: head_ref } : { commit: compare.commit }
+ environment_params[:find_latest] = true
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
end
end
diff --git a/app/controllers/projects/error_tracking/projects_controller.rb b/app/controllers/projects/error_tracking/projects_controller.rb
new file mode 100644
index 00000000000..75a2c976d8b
--- /dev/null
+++ b/app/controllers/projects/error_tracking/projects_controller.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Projects
+ module ErrorTracking
+ class ProjectsController < Projects::ApplicationController
+ respond_to :json
+
+ before_action :authorize_read_sentry_issue!
+
+ def index
+ service = ::ErrorTracking::ListProjectsService.new(
+ project,
+ current_user,
+ list_projects_params
+ )
+ result = service.execute
+
+ if result[:status] == :success
+ render json: { projects: serialize_projects(result[:projects]) }
+ else
+ render(
+ status: result[:http_status] || :bad_request,
+ json: { message: result[:message] }
+ )
+ end
+ end
+
+ private
+
+ def list_projects_params
+ { api_host: params[:api_host], token: params[:token] }
+ end
+
+ def serialize_projects(projects)
+ ::ErrorTracking::ProjectSerializer
+ .new(project: project, user: current_user)
+ .represent(projects)
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/error_tracking_controller.rb b/app/controllers/projects/error_tracking_controller.rb
index ba21ccfb169..d1253d85758 100644
--- a/app/controllers/projects/error_tracking_controller.rb
+++ b/app/controllers/projects/error_tracking_controller.rb
@@ -33,14 +33,6 @@ class Projects::ErrorTrackingController < Projects::ApplicationController
end
end
- def list_projects
- respond_to do |format|
- format.json do
- render_project_list_json
- end
- end
- end
-
private
def render_index_json
@@ -84,28 +76,6 @@ class Projects::ErrorTrackingController < Projects::ApplicationController
}
end
- def render_project_list_json
- service = ErrorTracking::ListProjectsService.new(
- project,
- current_user,
- list_projects_params
- )
- result = service.execute
-
- if result[:status] == :success
- render json: {
- projects: serialize_projects(result[:projects])
- }
- else
- return render(
- status: result[:http_status] || :bad_request,
- json: {
- message: result[:message]
- }
- )
- end
- end
-
def handle_errors(result)
unless result[:status] == :success
render json: { message: result[:message] },
@@ -117,10 +87,6 @@ class Projects::ErrorTrackingController < Projects::ApplicationController
params.permit(:search_term, :sort, :cursor)
end
- def list_projects_params
- params.require(:error_tracking_setting).permit([:api_host, :token])
- end
-
def issue_details_params
params.permit(:issue_id)
end
@@ -150,10 +116,4 @@ class Projects::ErrorTrackingController < Projects::ApplicationController
.new(project: project, user: current_user)
.represent(event)
end
-
- def serialize_projects(projects)
- ErrorTracking::ProjectSerializer
- .new(project: project, user: current_user)
- .represent(projects)
- end
end
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index 78dc196b08e..c6473391477 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -52,7 +52,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
@diff_notes_disabled = true
- @environment = @merge_request.environments_for(current_user).last
+ @environment = @merge_request.environments_for(current_user, latest: true).last
render json: { html: view_to_html_string('projects/merge_requests/creations/_diffs', diffs: @diffs, environment: @environment) }
end
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 37d90ecdc00..c0c8474232a 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -51,7 +51,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
# Deprecated: https://gitlab.com/gitlab-org/gitlab/issues/37735
def render_diffs
diffs = @compare.diffs(diff_options)
- @environment = @merge_request.environments_for(current_user).last
+ @environment = @merge_request.environments_for(current_user, latest: true).last
diffs.unfold_diff_files(note_positions.unfoldable)
diffs.write_cache
diff --git a/app/finders/environments_finder.rb b/app/finders/environments_finder.rb
index d4e803beb4e..32942c46208 100644
--- a/app/finders/environments_finder.rb
+++ b/app/finders/environments_finder.rb
@@ -25,25 +25,13 @@ class EnvironmentsFinder
.select(:environment_id)
environments = project.environments.available
- .where(id: environment_ids).order_by_last_deployed_at.to_a
+ .where(id: environment_ids)
- environments.select! do |environment|
- Ability.allowed?(current_user, :read_environment, environment)
- end
-
- if ref && commit
- environments.select! do |environment|
- environment.includes_commit?(commit)
- end
- end
-
- if ref && params[:recently_updated]
- environments.select! do |environment|
- environment.recently_updated_on_branch?(ref)
- end
+ if params[:find_latest]
+ find_one(environments.order_by_last_deployed_at_desc)
+ else
+ find_all(environments.order_by_last_deployed_at.to_a)
end
-
- environments
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -62,6 +50,24 @@ class EnvironmentsFinder
private
+ def find_one(environments)
+ [environments.find { |environment| valid_environment?(environment) }].compact
+ end
+
+ def find_all(environments)
+ environments.select { |environment| valid_environment?(environment) }
+ end
+
+ def valid_environment?(environment)
+ # Go in order of cost: SQL calls are cheaper than Gitaly calls
+ return false unless Ability.allowed?(current_user, :read_environment, environment)
+
+ return false if ref && params[:recently_updated] && !environment.recently_updated_on_branch?(ref)
+ return false if ref && commit && !environment.includes_commit?(commit)
+
+ true
+ end
+
def ref
params[:ref].try(:to_s)
end
diff --git a/app/finders/events_finder.rb b/app/finders/events_finder.rb
index 234b7090fd9..6d059e10d05 100644
--- a/app/finders/events_finder.rb
+++ b/app/finders/events_finder.rb
@@ -6,7 +6,7 @@ class EventsFinder
MAX_PER_PAGE = 100
- attr_reader :source, :params, :current_user
+ attr_reader :source, :params, :current_user, :scope
requires_cross_project_access unless: -> { source.is_a?(Project) }, model: Event
@@ -15,6 +15,7 @@ class EventsFinder
# Arguments:
# source - which user or project to looks for events on
# current_user - only return events for projects visible to this user
+ # scope - return all events across a user's projects
# params:
# action: string
# target_type: string
@@ -27,11 +28,12 @@ class EventsFinder
def initialize(params = {})
@source = params.delete(:source)
@current_user = params.delete(:current_user)
+ @scope = params.delete(:scope)
@params = params
end
def execute
- events = source.events
+ events = get_events
events = by_current_user_access(events)
events = by_action(events)
@@ -47,6 +49,12 @@ class EventsFinder
private
+ def get_events
+ return EventCollection.new(current_user.authorized_projects).all_project_events if scope == 'all'
+
+ source.events
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def by_current_user_access(events)
events.merge(Project.public_or_visible_to_user(current_user))
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index 679622897aa..99ede8c3557 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -58,6 +58,10 @@ module DashboardHelper
links += [:activity, :milestones]
end
+ if can?(current_user, :read_instance_statistics)
+ links << :analytics
+ end
+
links
end
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index b928dcb21a6..82bf0f9a615 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -48,13 +48,14 @@ class Environment < ApplicationRecord
scope :available, -> { with_state(:available) }
scope :stopped, -> { with_state(:stopped) }
+
scope :order_by_last_deployed_at, -> do
- max_deployment_id_sql =
- Deployment.select(Deployment.arel_table[:id].maximum)
- .where(Deployment.arel_table[:environment_id].eq(arel_table[:id]))
- .to_sql
order(Gitlab::Database.nulls_first_order("(#{max_deployment_id_sql})", 'ASC'))
end
+ scope :order_by_last_deployed_at_desc, -> do
+ order(Gitlab::Database.nulls_last_order("(#{max_deployment_id_sql})", 'DESC'))
+ end
+
scope :in_review_folder, -> { where(environment_type: "review") }
scope :for_name, -> (name) { where(name: name) }
scope :preload_cluster, -> { preload(last_deployment: :cluster) }
@@ -90,6 +91,12 @@ class Environment < ApplicationRecord
end
end
+ def self.max_deployment_id_sql
+ Deployment.select(Deployment.arel_table[:id].maximum)
+ .where(Deployment.arel_table[:environment_id].eq(arel_table[:id]))
+ .to_sql
+ end
+
def self.pluck_names
pluck(:name)
end
diff --git a/app/models/event_collection.rb b/app/models/event_collection.rb
index 4778f74568e..4768506b8fa 100644
--- a/app/models/event_collection.rb
+++ b/app/models/event_collection.rb
@@ -30,17 +30,24 @@ class EventCollection
relation = if groups
project_and_group_events
else
- relation_with_join_lateral('project_id', projects)
+ project_events
end
relation = paginate_events(relation)
relation.with_associations.to_a
end
+ def all_project_events
+ Event.from_union([project_events]).recent
+ end
+
private
+ def project_events
+ relation_with_join_lateral('project_id', projects)
+ end
+
def project_and_group_events
- project_events = relation_with_join_lateral('project_id', projects)
group_events = relation_with_join_lateral('group_id', groups)
Event.from_union([project_events, group_events]).recent
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 2280c5280d5..cdb6205cd51 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1122,22 +1122,18 @@ class MergeRequest < ApplicationRecord
actual_head_pipeline.success?
end
- def environments_for(current_user)
+ def environments_for(current_user, latest: false)
return [] unless diff_head_commit
- @environments ||= Hash.new do |h, current_user|
- envs = EnvironmentsFinder.new(target_project, current_user,
- ref: target_branch, commit: diff_head_commit, with_tags: true).execute
+ envs = EnvironmentsFinder.new(target_project, current_user,
+ ref: target_branch, commit: diff_head_commit, with_tags: true, find_latest: latest).execute
- if source_project
- envs.concat EnvironmentsFinder.new(source_project, current_user,
- ref: source_branch, commit: diff_head_commit).execute
- end
-
- h[current_user] = envs.uniq
+ if source_project
+ envs.concat EnvironmentsFinder.new(source_project, current_user,
+ ref: source_branch, commit: diff_head_commit, find_latest: latest).execute
end
- @environments[current_user]
+ envs.uniq
end
##
diff --git a/app/services/projects/operations/update_service.rb b/app/services/projects/operations/update_service.rb
index 0ca89664304..706a6f01a75 100644
--- a/app/services/projects/operations/update_service.rb
+++ b/app/services/projects/operations/update_service.rb
@@ -30,7 +30,7 @@ module Projects
settings = params[:error_tracking_setting_attributes]
return {} if settings.blank?
- api_url = ErrorTracking::ProjectErrorTrackingSetting.build_api_url_from(
+ api_url = ::ErrorTracking::ProjectErrorTrackingSetting.build_api_url_from(
api_host: settings[:api_host],
project_slug: settings.dig(:project, :slug),
organization_slug: settings.dig(:project, :organization_slug)
diff --git a/app/views/layouts/instance_statistics.html.haml b/app/views/layouts/instance_statistics.html.haml
index bebd9c4536f..1de6b385c86 100644
--- a/app/views/layouts/instance_statistics.html.haml
+++ b/app/views/layouts/instance_statistics.html.haml
@@ -1,5 +1,5 @@
-- page_title _('Instance Statistics')
-- header_title _('Instance Statistics'), instance_statistics_root_path
+- page_title _('Analytics')
+- header_title _('Analytics'), instance_statistics_root_path
- nav 'instance_statistics'
- @left_sidebar = true
diff --git a/app/views/layouts/nav/_analytics_link.html.haml b/app/views/layouts/nav/_analytics_link.html.haml
new file mode 100644
index 00000000000..f481aeecc1b
--- /dev/null
+++ b/app/views/layouts/nav/_analytics_link.html.haml
@@ -0,0 +1,4 @@
+- return unless dashboard_nav_link?(:analytics)
+= nav_link(controller: [:dev_ops_score, :cohorts], html_options: { class: "d-none d-xl-block"}) do
+ = link_to instance_statistics_root_path, class: 'chart-icon', title: _('Analytics'), aria: { label: _('Analytics') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
+ = sprite_icon('chart', size: 18)
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 9a839765286..9ae06ae77f1 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -47,10 +47,7 @@
%li.dropdown
= render_if_exists 'dashboard/nav_link_list'
- - if can?(current_user, :read_instance_statistics)
- = nav_link(controller: [:dev_ops_score, :cohorts]) do
- = link_to instance_statistics_root_path do
- = _('Instance Statistics')
+
- if current_user.admin?
= nav_link(controller: 'admin/dashboard') do
= link_to admin_root_path, class: 'admin-icon qa-admin-area-link d-xl-none' do
@@ -69,6 +66,8 @@
= link_to sherlock_transactions_path, class: 'admin-icon' do
= _('Sherlock Transactions')
+ = render_if_exists 'layouts/nav/analytics_link'
+
- if current_user.admin?
= nav_link(controller: 'admin/dashboard', html_options: { class: "d-none d-xl-block"}) do
= link_to admin_root_path, class: 'admin-icon qa-admin-area-link', title: _('Admin Area'), aria: { label: _('Admin Area') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
diff --git a/app/views/layouts/nav/sidebar/_analytics_link.html.haml b/app/views/layouts/nav/sidebar/_analytics_link.html.haml
new file mode 100644
index 00000000000..9e5ae422e2d
--- /dev/null
+++ b/app/views/layouts/nav/sidebar/_analytics_link.html.haml
@@ -0,0 +1,4 @@
+- return unless dashboard_nav_link?(:analytics)
+= nav_link(controller: [:dev_ops_score, :cohorts]) do
+ = link_to instance_statistics_root_path, class: 'd-xl-none' do
+ = _('Analytics')
diff --git a/app/views/layouts/nav/sidebar/_instance_statistics.html.haml b/app/views/layouts/nav/sidebar/_instance_statistics.html.haml
index 0a84e952442..979d98ec382 100644
--- a/app/views/layouts/nav/sidebar/_instance_statistics.html.haml
+++ b/app/views/layouts/nav/sidebar/_instance_statistics.html.haml
@@ -1,34 +1,11 @@
.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
.nav-sidebar-inner-scroll
.context-header
- = link_to instance_statistics_root_path, title: _('Instance Statistics') do
+ = link_to instance_statistics_root_path, title: _('Analytics') do
.avatar-container.s40.settings-avatar
= sprite_icon('chart', size: 24)
- .sidebar-context-title= _('Instance Statistics')
+ .sidebar-context-title= _('Analytics')
%ul.sidebar-top-level-items
- = nav_link(controller: :dev_ops_score) do
- = link_to instance_statistics_dev_ops_score_index_path do
- .nav-icon-container
- = sprite_icon('comment')
- %span.nav-item-name
- = _('DevOps Score')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :dev_ops_score, html_options: { class: "fly-out-top-item" } ) do
- = link_to instance_statistics_dev_ops_score_index_path do
- %strong.fly-out-top-item-name
- = _('DevOps Score')
-
- - if Gitlab::CurrentSettings.usage_ping_enabled
- = nav_link(controller: :cohorts) do
- = link_to instance_statistics_cohorts_path do
- .nav-icon-container
- = sprite_icon('users')
- %span.nav-item-name
- = _('Cohorts')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :cohorts, html_options: { class: "fly-out-top-item" } ) do
- = link_to instance_statistics_cohorts_path do
- %strong.fly-out-top-item-name
- = _('Cohorts')
+ = render 'layouts/nav/sidebar/instance_statistics_links'
= render 'shared/sidebar_toggle_button'
diff --git a/app/views/layouts/nav/sidebar/_instance_statistics_links.html.haml b/app/views/layouts/nav/sidebar/_instance_statistics_links.html.haml
new file mode 100644
index 00000000000..580a25db171
--- /dev/null
+++ b/app/views/layouts/nav/sidebar/_instance_statistics_links.html.haml
@@ -0,0 +1,25 @@
+- return unless dashboard_nav_link?(:analytics)
+= nav_link(controller: :dev_ops_score) do
+ = link_to instance_statistics_dev_ops_score_index_path do
+ .nav-icon-container
+ = sprite_icon('comment')
+ %span.nav-item-name
+ = _('DevOps Score')
+ %ul.sidebar-sub-level-items.is-fly-out-only
+ = nav_link(controller: :dev_ops_score, html_options: { class: "fly-out-top-item" } ) do
+ = link_to instance_statistics_dev_ops_score_index_path do
+ %strong.fly-out-top-item-name
+ = _('DevOps Score')
+
+- if Gitlab::CurrentSettings.usage_ping_enabled
+ = nav_link(controller: :cohorts) do
+ = link_to instance_statistics_cohorts_path do
+ .nav-icon-container
+ = sprite_icon('users')
+ %span.nav-item-name
+ = _('Cohorts')
+ %ul.sidebar-sub-level-items.is-fly-out-only
+ = nav_link(controller: :cohorts, html_options: { class: "fly-out-top-item" } ) do
+ = link_to instance_statistics_cohorts_path do
+ %strong.fly-out-top-item-name
+ = _('Cohorts')
diff --git a/app/views/projects/settings/operations/_error_tracking.html.haml b/app/views/projects/settings/operations/_error_tracking.html.haml
index 589d3037eba..06b5243dfd9 100644
--- a/app/views/projects/settings/operations/_error_tracking.html.haml
+++ b/app/views/projects/settings/operations/_error_tracking.html.haml
@@ -12,7 +12,7 @@
= _('To link Sentry to GitLab, enter your Sentry URL and Auth Token.')
= link_to _('More information'), help_page_path('user/project/operations/error_tracking'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
- .js-error-tracking-form{ data: { list_projects_endpoint: list_projects_project_error_tracking_index_path(@project, format: :json),
+ .js-error-tracking-form{ data: { list_projects_endpoint: project_error_tracking_projects_path(@project, format: :json),
operations_settings_endpoint: project_settings_operations_path(@project),
project: error_tracking_setting_project_json,
api_host: setting.api_host,
diff --git a/changelogs/unreleased/18999-add-dashboard-activity-to-events-endpoint.yml b/changelogs/unreleased/18999-add-dashboard-activity-to-events-endpoint.yml
new file mode 100644
index 00000000000..62f7b9d5602
--- /dev/null
+++ b/changelogs/unreleased/18999-add-dashboard-activity-to-events-endpoint.yml
@@ -0,0 +1,5 @@
+---
+title: Add activity across all projects to /events endpoint
+merge_request: 19816
+author: briankabiro
+type: changed
diff --git a/changelogs/unreleased/36017-move-analytics-out-of-more-in-top-navbar.yml b/changelogs/unreleased/36017-move-analytics-out-of-more-in-top-navbar.yml
new file mode 100644
index 00000000000..c4cf6d4c174
--- /dev/null
+++ b/changelogs/unreleased/36017-move-analytics-out-of-more-in-top-navbar.yml
@@ -0,0 +1,5 @@
+---
+title: Move instance statistics into analytics namespace
+merge_request: 21112
+author:
+type: changed
diff --git a/changelogs/unreleased/sh-optimize-commit-is-ancestor-env.yml b/changelogs/unreleased/sh-optimize-commit-is-ancestor-env.yml
new file mode 100644
index 00000000000..454303fdaab
--- /dev/null
+++ b/changelogs/unreleased/sh-optimize-commit-is-ancestor-env.yml
@@ -0,0 +1,5 @@
+---
+title: Reduce CommitIsAncestor RPCs with environments
+merge_request: 21778
+author:
+type: performance
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 6c2dcafd1ab..6ee6715facf 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -256,6 +256,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
+ namespace :error_tracking do
+ resources :projects, only: :index
+ end
+
resources :error_tracking, only: [:index], controller: :error_tracking do
collection do
get ':issue_id/details',
@@ -264,7 +268,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get ':issue_id/stack_trace',
to: 'error_tracking#stack_trace',
as: 'stack_trace'
- post :list_projects
end
end
diff --git a/doc/api/events.md b/doc/api/events.md
index 1cd7047b867..1dc0b054ee6 100644
--- a/doc/api/events.md
+++ b/doc/api/events.md
@@ -66,12 +66,13 @@ Parameters:
| `target_type` | string | no | Include only events of a particular [target type][target-types] |
| `before` | date | no | Include only events created before a particular date. Please see [here for the supported format][date-formatting] |
| `after` | date | no | Include only events created after a particular date. Please see [here for the supported format][date-formatting] |
+| `scope` | string | no | Include all events across a user's projects. |
| `sort` | string | no | Sort events in `asc` or `desc` order by `created_at`. Default is `desc` |
Example request:
```bash
-curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/events?target_type=issue&action=created&after=2017-01-31&before=2017-03-01&scope=all
```
Example response:
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 3dbf9478be9..7c743709773 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -9776,9 +9776,6 @@ msgid_plural "Instances"
msgstr[0] ""
msgstr[1] ""
-msgid "Instance Statistics"
-msgstr ""
-
msgid "Instance Statistics visibility"
msgstr ""
diff --git a/spec/controllers/projects/error_tracking/projects_controller_spec.rb b/spec/controllers/projects/error_tracking/projects_controller_spec.rb
new file mode 100644
index 00000000000..e55495700c2
--- /dev/null
+++ b/spec/controllers/projects/error_tracking/projects_controller_spec.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::ErrorTracking::ProjectsController do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ project.add_maintainer(user)
+ end
+
+ describe 'POST #index' do
+ context 'with insufficient permissions' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns 404' do
+ get :index, params: list_projects_params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'with an anonymous user' do
+ before do
+ sign_out(user)
+ end
+
+ it 'redirects to sign-in page' do
+ get :index, params: list_projects_params
+
+ expect(response).to have_gitlab_http_status(:redirect)
+ end
+ end
+
+ context 'with authorized user' do
+ let(:list_projects_service) { spy(:list_projects_service) }
+ let(:sentry_project) { build(:error_tracking_project) }
+
+ let(:query_params) do
+ list_projects_params.slice(:api_host, :token)
+ end
+
+ before do
+ allow(ErrorTracking::ListProjectsService)
+ .to receive(:new).with(project, user, query_params)
+ .and_return(list_projects_service)
+ end
+
+ context 'service result is successful' do
+ before do
+ expect(list_projects_service).to receive(:execute)
+ .and_return(status: :success, projects: [sentry_project])
+ end
+
+ it 'returns a list of projects' do
+ get :index, params: list_projects_params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('error_tracking/list_projects')
+ expect(json_response['projects']).to eq([sentry_project].as_json)
+ end
+ end
+
+ context 'service result is erroneous' do
+ let(:error_message) { 'error message' }
+
+ context 'without http_status' do
+ before do
+ expect(list_projects_service).to receive(:execute)
+ .and_return(status: :error, message: error_message)
+ end
+
+ it 'returns 400 with message' do
+ get :index, params: list_projects_params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq(error_message)
+ end
+ end
+
+ context 'with explicit http_status' do
+ let(:http_status) { :no_content }
+
+ before do
+ expect(list_projects_service).to receive(:execute).and_return(
+ status: :error,
+ message: error_message,
+ http_status: http_status
+ )
+ end
+
+ it 'returns http_status with message' do
+ get :index, params: list_projects_params
+
+ expect(response).to have_gitlab_http_status(http_status)
+ expect(json_response['message']).to eq(error_message)
+ end
+ end
+ end
+ end
+
+ private
+
+ def list_projects_params(opts = {})
+ project_params(
+ format: :json,
+ api_host: 'gitlab.com',
+ token: 'token'
+ )
+ end
+ end
+
+ private
+
+ def project_params(opts = {})
+ opts.reverse_merge(namespace_id: project.namespace, project_id: project)
+ end
+end
diff --git a/spec/controllers/projects/error_tracking_controller_spec.rb b/spec/controllers/projects/error_tracking_controller_spec.rb
index e5585d7b52d..b1f7c7178c1 100644
--- a/spec/controllers/projects/error_tracking_controller_spec.rb
+++ b/spec/controllers/projects/error_tracking_controller_spec.rb
@@ -179,113 +179,6 @@ describe Projects::ErrorTrackingController do
end
end
- describe 'POST #list_projects' do
- context 'with insufficient permissions' do
- before do
- project.add_guest(user)
- end
-
- it 'returns 404' do
- post :list_projects, params: list_projects_params
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'with an anonymous user' do
- before do
- sign_out(user)
- end
-
- it 'redirects to sign-in page' do
- post :list_projects, params: list_projects_params
-
- expect(response).to have_gitlab_http_status(:redirect)
- end
- end
-
- context 'with authorized user' do
- let(:list_projects_service) { spy(:list_projects_service) }
- let(:sentry_project) { build(:error_tracking_project) }
-
- let(:permitted_params) do
- ActionController::Parameters.new(
- list_projects_params[:error_tracking_setting]
- ).permit!
- end
-
- before do
- allow(ErrorTracking::ListProjectsService)
- .to receive(:new).with(project, user, permitted_params)
- .and_return(list_projects_service)
- end
-
- context 'service result is successful' do
- before do
- expect(list_projects_service).to receive(:execute)
- .and_return(status: :success, projects: [sentry_project])
- end
-
- it 'returns a list of projects' do
- post :list_projects, params: list_projects_params
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('error_tracking/list_projects')
- expect(json_response['projects']).to eq([sentry_project].as_json)
- end
- end
-
- context 'service result is erroneous' do
- let(:error_message) { 'error message' }
-
- context 'without http_status' do
- before do
- expect(list_projects_service).to receive(:execute)
- .and_return(status: :error, message: error_message)
- end
-
- it 'returns 400 with message' do
- get :list_projects, params: list_projects_params
-
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['message']).to eq(error_message)
- end
- end
-
- context 'with explicit http_status' do
- let(:http_status) { :no_content }
-
- before do
- expect(list_projects_service).to receive(:execute).and_return(
- status: :error,
- message: error_message,
- http_status: http_status
- )
- end
-
- it 'returns http_status with message' do
- get :list_projects, params: list_projects_params
-
- expect(response).to have_gitlab_http_status(http_status)
- expect(json_response['message']).to eq(error_message)
- end
- end
- end
- end
-
- private
-
- def list_projects_params(opts = {})
- project_params(
- format: :json,
- error_tracking_setting: {
- api_host: 'gitlab.com',
- token: 'token'
- }
- )
- end
- end
-
describe 'GET #issue_details' do
let_it_be(:issue_id) { 1234 }
diff --git a/spec/features/dashboard/instance_statistics_spec.rb b/spec/features/dashboard/instance_statistics_spec.rb
index 21ee2796bd8..feb568d8ef4 100644
--- a/spec/features/dashboard/instance_statistics_spec.rb
+++ b/spec/features/dashboard/instance_statistics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe 'Showing instance statistics' do
+describe 'Showing analytics' do
before do
sign_in user if user
end
@@ -13,10 +13,10 @@ describe 'Showing instance statistics' do
context 'for unauthenticated users' do
let(:user) { nil }
- it 'does not show the instance statistics link' do
+ it 'does not show the Analytics link' do
subject
- expect(page).not_to have_link('Instance Statistics')
+ expect(page).not_to have_link('Analytics')
end
end
@@ -28,10 +28,10 @@ describe 'Showing instance statistics' do
stub_application_setting(instance_statistics_visibility_private: false)
end
- it 'shows the instance statistics link' do
+ it 'shows the analytics link' do
subject
- expect(page).to have_link('Instance Statistics')
+ expect(page).to have_link('Analytics')
end
end
@@ -40,10 +40,14 @@ describe 'Showing instance statistics' do
stub_application_setting(instance_statistics_visibility_private: true)
end
- it 'shows the instance statistics link' do
+ it 'does not show the analytics link' do
subject
- expect(page).not_to have_link('Instance Statistics')
+ # Skipping this test on EE as there is an EE specifc spec for this functionality
+ # ee/spec/features/dashboards/analytics_spec.rb
+ skip if Gitlab.ee?
+
+ expect(page).not_to have_link('Analytics')
end
end
end
@@ -51,10 +55,10 @@ describe 'Showing instance statistics' do
context 'for admins' do
let(:user) { create(:admin) }
- it 'shows the instance statistics link' do
+ it 'shows the analytics link' do
subject
- expect(page).to have_link('Instance Statistics')
+ expect(page).to have_link('Analytics')
end
end
end
diff --git a/spec/finders/environments_finder_spec.rb b/spec/finders/environments_finder_spec.rb
index 69687eaa99f..7100376478a 100644
--- a/spec/finders/environments_finder_spec.rb
+++ b/spec/finders/environments_finder_spec.rb
@@ -13,17 +13,22 @@ describe EnvironmentsFinder do
end
context 'tagged deployment' do
+ let(:environment_two) { create(:environment, project: project) }
+ # Environments need to include commits, so rewind two commits to fit
+ let(:commit) { project.commit('HEAD~2') }
+
before do
- create(:deployment, :success, environment: environment, ref: 'v1.1.0', tag: true, sha: project.commit.id)
+ create(:deployment, :success, environment: environment, ref: 'v1.0.0', tag: true, sha: project.commit.id)
+ create(:deployment, :success, environment: environment_two, ref: 'v1.1.0', tag: true, sha: project.commit('HEAD~1').id)
end
it 'returns environment when with_tags is set' do
- expect(described_class.new(project, user, ref: 'master', commit: project.commit, with_tags: true).execute)
- .to contain_exactly(environment)
+ expect(described_class.new(project, user, ref: 'master', commit: commit, with_tags: true).execute)
+ .to contain_exactly(environment, environment_two)
end
it 'does not return environment when no with_tags is set' do
- expect(described_class.new(project, user, ref: 'master', commit: project.commit).execute)
+ expect(described_class.new(project, user, ref: 'master', commit: commit).execute)
.to be_empty
end
@@ -31,6 +36,21 @@ describe EnvironmentsFinder do
expect(described_class.new(project, user, ref: 'master', commit: project.commit('feature')).execute)
.to be_empty
end
+
+ it 'returns environment when with_tags is set' do
+ expect(described_class.new(project, user, ref: 'master', commit: commit, with_tags: true).execute)
+ .to contain_exactly(environment, environment_two)
+ end
+
+ # We expect two Gitaly calls: FindCommit, CommitIsAncestor
+ # This tests to ensure we don't call one CommitIsAncestor per environment
+ it 'only calls Gitaly twice when multiple environments are present', :request_store do
+ expect do
+ result = described_class.new(project, user, ref: 'master', commit: commit, with_tags: true, find_latest: true).execute
+
+ expect(result).to contain_exactly(environment_two)
+ end.to change { Gitlab::GitalyClient.get_request_count }.by(2)
+ end
end
context 'branch deployment' do
diff --git a/spec/finders/events_finder_spec.rb b/spec/finders/events_finder_spec.rb
index 848030262cd..5c28b31e8c8 100644
--- a/spec/finders/events_finder_spec.rb
+++ b/spec/finders/events_finder_spec.rb
@@ -5,8 +5,10 @@ require 'spec_helper'
describe EventsFinder do
let(:user) { create(:user) }
let(:other_user) { create(:user) }
+
let(:project1) { create(:project, :private, creator_id: user.id, namespace: user.namespace) }
let(:project2) { create(:project, :private, creator_id: user.id, namespace: user.namespace) }
+
let(:closed_issue) { create(:closed_issue, project: project1, author: user) }
let(:opened_merge_request) { create(:merge_request, source_project: project2, author: user) }
let!(:closed_issue_event) { create(:event, project: project1, author: user, target: closed_issue, action: Event::CLOSED, created_at: Date.new(2016, 12, 30)) }
@@ -15,6 +17,8 @@ describe EventsFinder do
let(:opened_merge_request2) { create(:merge_request, source_project: project2, author: user) }
let!(:closed_issue_event2) { create(:event, project: project1, author: user, target: closed_issue, action: Event::CLOSED, created_at: Date.new(2016, 2, 2)) }
let!(:opened_merge_request_event2) { create(:event, project: project2, author: user, target: opened_merge_request, action: Event::CREATED, created_at: Date.new(2017, 2, 2)) }
+ let(:opened_merge_request3) { create(:merge_request, source_project: project1, author: other_user) }
+ let!(:other_developer_event) { create(:event, project: project1, author: other_user, target: opened_merge_request3, action: Event::CREATED) }
let(:public_project) { create(:project, :public, creator_id: user.id, namespace: user.namespace) }
let(:confidential_issue) { create(:closed_issue, confidential: true, project: public_project, author: user) }
@@ -55,6 +59,28 @@ describe EventsFinder do
end
end
+ context 'dashboard events' do
+ before do
+ project1.add_developer(other_user)
+ end
+
+ context 'scope is `all`' do
+ it 'includes activity of other users' do
+ events = described_class.new(source: user, current_user: user, scope: 'all').execute
+
+ expect(events).to include(other_developer_event)
+ end
+ end
+
+ context 'scope is not `all`' do
+ it 'does not include activity of other users' do
+ events = described_class.new(source: user, current_user: user, scope: '').execute
+
+ expect(events).not_to include(other_developer_event)
+ end
+ end
+ end
+
context 'when targeting a project' do
it 'returns project events between specified dates filtered on action and type' do
events = described_class.new(source: project1, current_user: user, action: 'closed', target_type: 'issue', after: Date.new(2016, 12, 1), before: Date.new(2017, 1, 1)).execute
diff --git a/spec/frontend/error_tracking_settings/store/actions_spec.js b/spec/frontend/error_tracking_settings/store/actions_spec.js
index e12c4e20f58..b076e6ecd31 100644
--- a/spec/frontend/error_tracking_settings/store/actions_spec.js
+++ b/spec/frontend/error_tracking_settings/store/actions_spec.js
@@ -28,7 +28,7 @@ describe('error tracking settings actions', () => {
});
it('should request and transform the project list', done => {
- mock.onPost(TEST_HOST).reply(() => [200, { projects: projectList }]);
+ mock.onGet(TEST_HOST).reply(() => [200, { projects: projectList }]);
testAction(
actions.fetchProjects,
null,
@@ -42,14 +42,14 @@ describe('error tracking settings actions', () => {
},
],
() => {
- expect(mock.history.post.length).toBe(1);
+ expect(mock.history.get.length).toBe(1);
done();
},
);
});
it('should handle a server error', done => {
- mock.onPost(`${TEST_HOST}.json`).reply(() => [400]);
+ mock.onGet(`${TEST_HOST}.json`).reply(() => [400]);
testAction(
actions.fetchProjects,
null,
@@ -62,7 +62,7 @@ describe('error tracking settings actions', () => {
},
],
() => {
- expect(mock.history.post.length).toBe(1);
+ expect(mock.history.get.length).toBe(1);
done();
},
);
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 0537220fcd2..b82a9e9aa9d 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -36,9 +36,13 @@ describe Environment, :use_clean_rails_memory_store_caching do
let!(:deployment2) { create(:deployment, environment: environment2) }
let!(:deployment3) { create(:deployment, environment: environment1) }
- it 'returns the environments in order of having been last deployed' do
+ it 'returns the environments in ascending order of having been last deployed' do
expect(project.environments.order_by_last_deployed_at.to_a).to eq([environment3, environment2, environment1])
end
+
+ it 'returns the environments in descending order of having been last deployed' do
+ expect(project.environments.order_by_last_deployed_at_desc.to_a).to eq([environment1, environment2, environment3])
+ end
end
describe 'state machine' do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index bf6fa20dc17..bf90fa53aba 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -2322,6 +2322,10 @@ describe MergeRequest do
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:source_branch) { merge_request.source_branch }
+ let(:target_branch) { merge_request.target_branch }
+ let(:source_oid) { project.commit(source_branch).id }
+ let(:target_oid) { project.commit(target_branch).id }
before do
merge_request.source_project.add_maintainer(user)
@@ -2332,13 +2336,21 @@ describe MergeRequest do
let(:environments) { create_list(:environment, 3, project: project) }
before do
- create(:deployment, :success, environment: environments.first, ref: 'master', sha: project.commit('master').id)
- create(:deployment, :success, environment: environments.second, ref: 'feature', sha: project.commit('feature').id)
+ create(:deployment, :success, environment: environments.first, ref: source_branch, sha: source_oid)
+ create(:deployment, :success, environment: environments.second, ref: target_branch, sha: target_oid)
end
it 'selects deployed environments' do
expect(merge_request.environments_for(user)).to contain_exactly(environments.first)
end
+
+ it 'selects latest deployed environment' do
+ latest_environment = create(:environment, project: project)
+ create(:deployment, :success, environment: latest_environment, ref: source_branch, sha: source_oid)
+
+ expect(merge_request.environments_for(user)).to eq([environments.first, latest_environment])
+ expect(merge_request.environments_for(user, latest: true)).to contain_exactly(latest_environment)
+ end
end
context 'with environments on source project' do
diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb
index 9f8d254a00c..240f9a02877 100644
--- a/spec/requests/api/events_spec.rb
+++ b/spec/requests/api/events_spec.rb
@@ -8,6 +8,8 @@ describe API::Events do
let(:private_project) { create(:project, :private, creator_id: user.id, namespace: user.namespace) }
let(:closed_issue) { create(:closed_issue, project: private_project, author: user) }
let!(:closed_issue_event) { create(:event, project: private_project, author: user, target: closed_issue, action: Event::CLOSED, created_at: Date.new(2016, 12, 30)) }
+ let(:closed_issue2) { create(:closed_issue, project: private_project, author: non_member) }
+ let!(:closed_issue_event2) { create(:event, project: private_project, author: non_member, target: closed_issue2, action: Event::CLOSED, created_at: Date.new(2016, 12, 30)) }
describe 'GET /events' do
context 'when unauthenticated' do
@@ -27,6 +29,19 @@ describe API::Events do
expect(json_response).to be_an Array
expect(json_response.size).to eq(1)
end
+
+ context 'when scope is passed' do
+ it 'returns all events across projects' do
+ private_project.add_developer(non_member)
+
+ get api('/events?action=closed&target_type=issue&after=2016-12-1&before=2016-12-31&scope=all', user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(2)
+ end
+ end
end
context 'when the requesting token has "read_user" scope' do