Commit bda6d700 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'master' into 27994-fix-mr-widget-jump

* master: (26 commits)
  Revert "Merge branch 'add-additional-checks-to-ca-data' into 'master'"
  Fix broken test to use trigger in order to not take tooltip overlaping in consideration
  Fix job to pipeline renaming
  Added env external link and light web terminal spec
  Don't perform Devise trackable updates on blocked User records
  Replace teaspoon references with Karma
  Add changelog
  Only show MR widget graph if there are stages
  Remove orange caret icon from mr widget
  Add index to ci_trigger_requests for commit_id
  rspec_profiling: Discover the correct branch name in GitLab CI
  Show parent group members for nested group
  Fix tooltip scss for anchors. Adds css for button's tooltips to have similar behavior. Removes padding from mini graph table cell to guarantee stages don't break line on hover
  Updated protected branches dropdown image in docs
  Fix admin_labels_spec.rb transient failure
  Make sure events have most properties defined
  Restore exposure of legend property for events
  moved hyperlink reference section at the end of the content
  Make sure our current .gitlab-ci.yml is valid
  adds changelog
  ...
parents 0335619a 58131ac9
......@@ -272,7 +272,7 @@ header {
.header-user {
.dropdown-menu-nav {
width: 140px;
min-width: 140px;
margin-top: -5px;
}
}
......
......@@ -96,13 +96,6 @@
padding-right: 4px;
}
&.ci-success_with_warnings {
i {
color: $gl-warning;
}
}
@media (max-width: $screen-xs-max) {
flex-wrap: wrap;
}
......
......@@ -94,6 +94,10 @@
padding: 10px 8px;
}
td.stage-cell {
padding: 10px 0;
}
.commit-link {
padding: 9px 8px 10px;
}
......@@ -291,12 +295,14 @@
height: 22px;
margin: 3px 6px 3px 0;
.tooltip {
white-space: nowrap;
// Hack to show a button tooltip inline
button.has-tooltip + .tooltip {
min-width: 105px;
}
.tooltip-inner {
padding: 3px 4px;
// Bootstrap way of showing the content inline for anchors.
a.has-tooltip {
white-space: nowrap;
}
&:not(:last-child) {
......
......@@ -12,7 +12,6 @@ class ApplicationController < ActionController::Base
before_action :authenticate_user_from_private_token!
before_action :authenticate_user!
before_action :validate_user_service_ticket!
before_action :reject_blocked!
before_action :check_password_expiration
before_action :check_2fa_requirement
before_action :ldap_security_check
......@@ -87,22 +86,8 @@ class ApplicationController < ActionController::Base
logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
end
def reject_blocked!
if current_user && current_user.blocked?
sign_out current_user
flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
redirect_to new_user_session_path
end
end
def after_sign_in_path_for(resource)
if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked?
sign_out resource
flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
new_user_session_path
else
stored_location_for(:redirect) || stored_location_for(resource) || root_path
end
stored_location_for(:redirect) || stored_location_for(resource) || root_path
end
def after_sign_out_path_for(resource)
......
class Explore::ApplicationController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked!
skip_before_action :authenticate_user!
layout 'explore'
end
......@@ -9,7 +9,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
@sort = params[:sort].presence || sort_value_name
@project = @group.projects.find(params[:project_id]) if params[:project_id]
@members = @group.group_members
@members = GroupMembersFinder.new(@group).execute
@members = @members.non_invite unless can?(current_user, :admin_group, @group)
@members = @members.search(params[:search]) if params[:search].present?
@members = @members.sort(@sort)
......
class HelpController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked!
skip_before_action :authenticate_user!
layout 'help'
......
class KodingController < ApplicationController
before_action :check_integration!, :authenticate_user!, :reject_blocked!
before_action :check_integration!
layout 'koding'
def index
......
class Projects::UploadsController < Projects::ApplicationController
skip_before_action :reject_blocked!, :project,
:repository, if: -> { action_name == 'show' && image_or_video? }
skip_before_action :project, :repository,
if: -> { action_name == 'show' && image_or_video? }
before_action :authorize_upload_file!, only: [:create]
......
class SearchController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked!
skip_before_action :authenticate_user!
include SearchHelper
......
class GroupMembersFinder < Projects::ApplicationController
def initialize(group)
@group = group
end
def execute
group_members = @group.members
return group_members unless @group.parent
parents_members = GroupMember.non_request.
where(source_id: @group.ancestors.select(:id)).
where.not(user_id: @group.users.select(:id))
wheres = ["members.id IN (#{group_members.select(:id).to_sql})"]
wheres << "members.id IN (#{parents_members.select(:id).to_sql})"
GroupMember.where(wheres.join(' OR '))
end
end
......@@ -206,7 +206,7 @@ class Group < Namespace
end
def members_with_parents
GroupMember.where(requested_at: nil, source_id: ancestors.map(&:id).push(id))
GroupMember.non_request.where(source_id: ancestors.map(&:id).push(id))
end
def users_with_parents
......
......@@ -47,6 +47,7 @@ class Member < ActiveRecord::Base
scope :invite, -> { where.not(invite_token: nil) }
scope :non_invite, -> { where(invite_token: nil) }
scope :request, -> { where.not(requested_at: nil) }
scope :non_request, -> { where(requested_at: nil) }
scope :has_access, -> { active.where('access_level > 0') }
......
......@@ -167,6 +167,15 @@ class User < ActiveRecord::Base
def blocked?
true
end
def active_for_authentication?
false
end
def inactive_message
"Your account has been blocked. Please contact your GitLab " \
"administrator if you think this is an error."
end
end
end
......
......@@ -15,7 +15,7 @@
- else
%span.api.monospace API
- if pipeline.latest?
%span.label.label-success.has-tooltip{ title: 'Latest job for this branch' } latest
%span.label.label-success.has-tooltip{ title: 'Latest pipeline for this branch' } latest
- if pipeline.triggered?
%span.label.label-primary triggered
- if pipeline.yaml_errors.present?
......@@ -61,7 +61,7 @@
.btn-group.inline
- if actions.any?
.btn-group
%button.dropdown-toggle.btn.btn-default.has-tooltip.js-pipeline-dropdown-manual-actions{ type: 'button', title: 'Manual job', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Manual job' }
%button.dropdown-toggle.btn.btn-default.has-tooltip.js-pipeline-dropdown-manual-actions{ type: 'button', title: 'Manual pipeline', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Manual pipeline' }
= custom_icon('icon_play')
= icon('caret-down', 'aria-hidden' => 'true')
%ul.dropdown-menu.dropdown-menu-align-right
......
......@@ -16,6 +16,8 @@
.col-sm-6
.nav-controls
= link_to @environment.external_url, class: 'btn btn-default' do
= icon('external-link')
= render 'projects/deployments/actions', deployment: @environment.last_deployment
.terminal-container{ class: container_class }
......
......@@ -9,8 +9,9 @@
Pipeline
= link_to "##{@pipeline.id}", namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'pipeline'
= ci_label_for_status(status)
.mr-widget-pipeline-graph
= render 'shared/mini_pipeline_graph', pipeline: @pipeline, klass: 'js-pipeline-inline-mr-widget-graph'
- if @pipeline.stages.any?
.mr-widget-pipeline-graph
= render 'shared/mini_pipeline_graph', pipeline: @pipeline, klass: 'js-pipeline-inline-mr-widget-graph'
%span
for
= succeed "." do
......
......@@ -16,13 +16,13 @@
gitlab_icon: "#{asset_path 'gitlab_logo.png'}",
ci_status: "#{@merge_request.head_pipeline ? @merge_request.head_pipeline.status : ''}",
ci_message: {
normal: "Job {{status}} for \"{{title}}\"",
preparing: "{{status}} job for \"{{title}}\""
normal: "Pipeline {{status}} for \"{{title}}\"",
preparing: "{{status}} pipeline for \"{{title}}\""
},
ci_enable: #{@project.ci_service ? "true" : "false"},
ci_title: {
preparing: "{{status}} job",
normal: "Job {{status}}"
preparing: "{{status}} pipeline",
normal: "Pipeline {{status}}"
},
ci_sha: "#{@merge_request.head_pipeline ? @merge_request.head_pipeline.short_sha : ''}",
ci_pipeline: #{@merge_request.head_pipeline.try(:id).to_json},
......
%h4
= icon('exclamation-triangle')
The job for this merge request failed
The pipeline for this merge request failed
%p
Please retry the job or push a new commit to fix the failure.
......@@ -94,9 +94,8 @@
.form-group.project-visibility-level-holder
= f.label :visibility_level, class: 'label-light' do
Visibility Level
= link_to "(?)", help_page_path("public_access/public_access")
= render 'shared/visibility_level', f: f, visibility_level: default_project_visibility, can_change_visibility_level: true, form_model: @project
= link_to icon('question-circle'), help_page_path("public_access/public_access")
= render 'shared/visibility_level', f: f, visibility_level: default_project_visibility, can_change_visibility_level: true, form_model: @project, with_label: false
= f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
= link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel'
......
......@@ -65,7 +65,7 @@
In the
%code .gitlab-ci.yml
of another project, include the following snippet.
The project will be rebuilt at the end of the job.
The project will be rebuilt at the end of the pipeline.
%pre
:plain
......@@ -89,7 +89,7 @@
%p.light
Add
%code variables[VARIABLE]=VALUE
to an API request. Variable values can be used to distinguish between triggered jobs and normal jobs.
to an API request. Variable values can be used to distinguish between triggered pipelines and normal pipelines.
With cURL:
......
- with_label = local_assigns.fetch(:with_label, true)
.form-group.project-visibility-level-holder
= f.label :visibility_level, class: 'control-label' do
Visibility Level
= link_to icon('question-circle'), help_page_path("public_access/public_access")
.col-sm-10
- if with_label
= f.label :visibility_level, class: 'control-label' do
Visibility Level
= link_to icon('question-circle'), help_page_path("public_access/public_access")
%div{ :class => ("col-sm-10" if with_label) }
- if can_change_visibility_level
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model)
- else
......
......@@ -19,9 +19,9 @@
%label.label.label-danger
%strong Blocked
- if source.instance_of?(Group) && !@group
- if source.instance_of?(Group) && source != @group
&middot;
= link_to source.name, source, class: "member-group-link"
= link_to source.full_name, source, class: "member-group-link"
.hidden-xs.cgray
- if member.request?
......@@ -44,8 +44,9 @@
= link_to member.created_by.name, user_path(member.created_by)
= time_ago_with_tooltip(member.created_at)
- if show_roles
- current_resource = @project || @group
.controls.member-controls
- if show_controls && (member.respond_to?(:group) && @group) || (member.respond_to?(:project) && @project)
- if show_controls && member.source == current_resource
- if user != current_user
= form_for member, remote: true, html: { class: 'form-horizontal js-edit-member-form' } do |f|
= f.hidden_field :access_level
......
---
title: Optionally make users created via the API set their password
merge_request: 8957
author: Joost Rijneveld
---
title: Added external environment link to web terminal view
merge_request: 8303
author:
---
title: Fixes FE Doc broken link
merge_request: 9120
author:
---
title: Show Pipeline(not Job) in MR desktop notification
merge_request:
author:
---
title: Fix tooltips in mini pipeline graph
merge_request:
author:
---
title: Show pipeline graph in MR widget if there are any stages
merge_request:
author:
---
title: Fix icon colors in merge request widget mini graph
merge_request:
author:
---
title: Fix job to pipeline renaming
merge_request: 9147
author:
---
title: Removed duplicate "Visibility Level" label on New Project page
merge_request:
author: Robert Marcano
---
title: Don't perform Devise trackable updates on blocked User records
merge_request: 8915
author:
---
title: Add index to ci_trigger_requests for commit_id
merge_request:
author:
......@@ -4,6 +4,12 @@ module RspecProfilingConnection
end
end
module RspecProfilingGitBranchCi
def branch
ENV['CI_BUILD_REF_NAME'] || super
end
end
if Rails.env.test?
RspecProfiling.configure do |config|
if ENV['RSPEC_PROFILING_POSTGRES_URL']
......@@ -11,4 +17,6 @@ if Rails.env.test?
config.collector = RspecProfiling::Collectors::PSQL
end
end
RspecProfiling::VCS::Git.prepend(RspecProfilingGitBranchCi) if ENV.has_key?('CI')
end
class AddIndexToCiTriggerRequestsForCommitId < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def change
add_concurrent_index :ci_trigger_requests, :commit_id
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170206101030) do
ActiveRecord::Schema.define(version: 20170210075922) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -367,6 +367,8 @@ ActiveRecord::Schema.define(version: 20170206101030) do
t.integer "commit_id"
end
add_index "ci_trigger_requests", ["commit_id"], name: "index_ci_trigger_requests_on_commit_id", using: :btree
create_table "ci_triggers", force: :cascade do |t|
t.string "token"
t.integer "project_id"
......
......@@ -216,7 +216,7 @@ Parameters:
## User creation
Creates a new user. Note only administrators can create new users.
Creates a new user. Note only administrators can create new users. Either `password` or `reset_password` should be specified (`reset_password` takes priority).
```
POST /users
......@@ -225,7 +225,8 @@ POST /users
Parameters:
- `email` (required) - Email
- `password` (required) - Password
- `password` (optional) - Password
- `reset_password` (optional) - Send user password reset link - true or false(default)
- `username` (required) - Username
- `name` (required) - Name
- `skype` (optional) - Skype ID
......
......@@ -50,7 +50,7 @@ Let's look into each of them:
This is the index file of your new feature. This is where the root Vue instance
of the new feature should be.
Don't forget to follow [these steps.][page-specific-javascript]
Don't forget to follow [these steps.][page_specific_javascript]
**A folder for Components**
......@@ -250,23 +250,17 @@ information.
### Running frontend tests
`rake teaspoon` runs the frontend-only (JavaScript) tests.
`rake karma` runs the frontend-only (JavaScript) tests.
It consists of two subtasks:
- `rake teaspoon:fixtures` (re-)generates fixtures
- `rake teaspoon:tests` actually executes the tests
- `rake karma:fixtures` (re-)generates fixtures
- `rake karma:tests` actually executes the tests
As long as the fixtures don't change, `rake teaspoon:tests` is sufficient
As long as the fixtures don't change, `rake karma:tests` is sufficient
(and saves you some time).
If you need to debug your tests and/or application code while they're
running, navigate to [localhost:3000/teaspoon](http://localhost:3000/teaspoon)
in your browser, open DevTools, and run tests for individual files by clicking
on them. This is also much faster than setting up and running tests from the
command line.
Please note: Not all of the frontend fixtures are generated. Some are still static
files. These will not be touched by `rake teaspoon:fixtures`.
files. These will not be touched by `rake karma:fixtures`.
## Design Patterns
......@@ -323,54 +317,13 @@ gl.MyThing = MyThing;
For our currently-supported browsers, see our [requirements][requirements].
[rails]: http://rubyonrails.org/
[haml]: http://haml.info/
[hamlit]: https://github.com/k0kubun/hamlit
[hamlit-limits]: https://github.com/k0kubun/hamlit/blob/master/REFERENCE.md#limitations
[scss]: http://sass-lang.com/
[es6]: https://babeljs.io/
[sprockets]: https://github.com/rails/sprockets
[jquery]: https://jquery.com/
[vue]: http://vuejs.org/
[vue-docs]: http://vuejs.org/guide/index.html
[web-page-test]: http://www.webpagetest.org/
[pagespeed-insights]: https://developers.google.com/speed/pagespeed/insights/
[google-devtools-profiling]: https://developers.google.com/web/tools/chrome-devtools/profile/?hl=en
[browser-diet]: https://browserdiet.com/
[d3]: https://d3js.org/
[chartjs]: http://www.chartjs.org/
[page-specific-js-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/13bb9ed77f405c5f6ee4fdbc964ecf635c9a223f/app/views/projects/graphs/_head.html.haml#L6-8
[chrome-accessibility-developer-tools]: https://github.com/GoogleChrome/accessibility-developer-tools
[audit-rules]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules
[observatory-cli]: https://github.com/mozilla/http-observatory-cli
[qualys-ssl]: https://www.ssllabs.com/ssltest/analyze.html
[secure_headers]: https://github.com/twitter/secureheaders
[mdn-csp]: https://developer.mozilla.org/en-US/docs/Web/Security/CSP
[github-eng-csp]: http://githubengineering.com/githubs-csp-journey/
[dropbox-csp-1]: https://blogs.dropbox.com/tech/2015/09/on-csp-reporting-and-filtering/
[dropbox-csp-2]: https://blogs.dropbox.com/tech/2015/09/unsafe-inline-and-nonce-deployment/
[dropbox-csp-3]: https://blogs.dropbox.com/tech/2015/09/csp-the-unexpected-eval/
[dropbox-csp-4]: https://blogs.dropbox.com/tech/2015/09/csp-third-party-integrations-and-privilege-separation/
[mdn-sri]: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
[github-eng-sri]: http://githubengineering.com/subresource-integrity/
[sprockets-sri]: https://github.com/rails/sprockets-rails#sri-support
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
[scss-style-guide]: scss_styleguide.md
[requirements]: ../install/requirements.md#supported-web-browsers
[issue-boards]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/boards
[environments-table]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/environments
[page_specific_javascript]: https://docs.gitlab.com/ce/development/frontend.html#page-specific-javascript
[component-system]: https://vuejs.org/v2/guide/#Composing-with-Components
[state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch
[vue-resource-repo]: https://github.com/pagekit/vue-resource
[issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6
## Gotchas
### Spec errors due to use of ES6 features in `.js` files
If you see very generic JavaScript errors (e.g. `jQuery is undefined`) being
thrown in Teaspoon, Spinach, or Rspec tests but can't reproduce them manually,
thrown in Karma, Spinach, or Rspec tests but can't reproduce them manually,
you may have included `ES6`-style JavaScript in files that don't have the
`.js.es6` file extension. Either use ES5-friendly JavaScript or rename the file
you're working in (`git mv <file.js> <file.js.es6>`).
......@@ -438,3 +391,46 @@ Scenario: Developer can approve merge request
Then I should see approved merge request "Bug NS-04"
```
[rails]: http://rubyonrails.org/
[haml]: http://haml.info/
[hamlit]: https://github.com/k0kubun/hamlit
[hamlit-limits]: https://github.com/k0kubun/hamlit/blob/master/REFERENCE.md#limitations
[scss]: http://sass-lang.com/
[es6]: https://babeljs.io/
[sprockets]: https://github.com/rails/sprockets
[jquery]: https://jquery.com/
[vue]: http://vuejs.org/
[vue-docs]: http://vuejs.org/guide/index.html
[web-page-test]: http://www.webpagetest.org/
[pagespeed-insights]: https://developers.google.com/speed/pagespeed/insights/
[google-devtools-profiling]: https://developers.google.com/web/tools/chrome-devtools/profile/?hl=en
[browser-diet]: https://browserdiet.com/
[d3]: https://d3js.org/
[chartjs]: http://www.chartjs.org/
[page-specific-js-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/13bb9ed77f405c5f6ee4fdbc964ecf635c9a223f/app/views/projects/graphs/_head.html.haml#L6-8
[chrome-accessibility-developer-tools]: https://github.com/GoogleChrome/accessibility-developer-tools
[audit-rules]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules
[observatory-cli]: https://github.com/mozilla/http-observatory-cli
[qualys-ssl]: https://www.ssllabs.com/ssltest/analyze.html
[secure_headers]: https://github.com/twitter/secureheaders
[mdn-csp]: https://developer.mozilla.org/en-US/docs/Web/Security/CSP
[github-eng-csp]: http://githubengineering.com/githubs-csp-journey/
[dropbox-csp-1]: https://blogs.dropbox.com/tech/2015/09/on-csp-reporting-and-filtering/
[dropbox-csp-2]: https://blogs.dropbox.com/tech/2015/09/unsafe-inline-and-nonce-deployment/
[dropbox-csp-3]: https://blogs.dropbox.com/tech/2015/09/csp-the-unexpected-eval/
[dropbox-csp-4]: https://blogs.dropbox.com/tech/2015/09/csp-third-party-integrations-and-privilege-separation/
[mdn-sri]: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
[github-eng-sri]: http://githubengineering.com/subresource-integrity/
[sprockets-sri]: https://github.com/rails/sprockets-rails#sri-support
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
[scss-style-guide]: scss_styleguide.md
[requirements]: ../install/requirements.md#supported-web-browsers
[issue-boards]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/boards
[environments-table]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/environments
[page_specific_javascript]: https://docs.gitlab.com/ce/development/frontend.html#page-specific-javascript
[component-system]: https://vuejs.org/v2/guide/#Composing-with-Components
[state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch
[vue-resource-repo]: https://github.com/pagekit/vue-resource
[issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6
......@@ -17,14 +17,14 @@ Note: `db:setup` calls `db:seed` but this does nothing.
In order to run the test you can use the following commands:
- `rake spinach` to run the spinach suite
- `rake spec` to run the rspec suite
- `rake teaspoon` to run the teaspoon test suite
- `rake karma` to run the karma test suite
- `rake gitlab:test` to run all the tests
Note: Both `rake spinach` and `rake spec` takes significant time to pass.
Note: Both `rake spinach` and `rake spec` takes significant time to pass.
Instead of running full test suite locally you can save a lot of time by running
a single test or directory related to your changes. After you submit merge request
CI will run full test suite for you. Green CI status in the merge request means
full test suite is passed.
a single test or directory related to your changes. After you submit merge request
CI will run full test suite for you. Green CI status in the merge request means
full test suite is passed.
Note: You can't run `rspec .` since this will try to run all the `_spec.rb`
files it can find, also the ones in `/tmp`
......
......@@ -31,9 +31,8 @@ GitLab uses [factory_girl] as a test fixture replacement.
## JavaScript
GitLab uses [Teaspoon] to run its [Jasmine] JavaScript specs. They can be run on
the command line via `bundle exec teaspoon`, or via a web browser at
`http://localhost:3000/teaspoon` when the Rails server is running.
GitLab uses [Karma] to run its [Jasmine] JavaScript specs. They can be run on
the command line via `bundle exec karma`.
- JavaScript tests live in `spec/javascripts/`, matching the folder structure of
`app/assets/javascripts/`: `app/assets/javascripts/behaviors/autosize.js.es6` has a corresponding
......@@ -51,7 +50,7 @@ the command line via `bundle exec teaspoon`, or via a web browser at
[`Notification`](https://developer.mozilla.org/en-US/docs/Web/API/notification),
which will have to be stubbed.
[Teaspoon]: https://github.com/modeset/teaspoon
[Karma]: https://github.com/karma-runner/karma
[Jasmine]: https://github.com/jasmine/jasmine
## RSpec
......
......@@ -82,7 +82,9 @@ module API
end
params do
requires :email, type: String, desc: 'The email of the user'
requires :password, type: String, desc: 'The password of the new user'
optional :password, type: String, desc: 'The password of the new user'
optional :reset_password, type: Boolean, desc: 'Flag indicating the user will be sent a password reset token'
at_least_one_of :password, :reset_password
requires :name, type: String, desc: 'The name of the user'
requires :username, type: String, desc: 'The username of the user'
use :optional_attributes
......@@ -94,8 +96,18 @@ module API
user_params = declared_params(include_missing: false)
identity_attrs = user_params.slice(:provider, :extern_uid)
confirm = user_params.delete(:confirm)
user = User.new(user_params.except(:extern_uid, :provider, :reset_password))
if user_params.delete(:reset_password)
user.attributes = {
force_random_password: true,
password_expires_at: nil,
created_by_id: current_user.id
}
user.generate_password
user.generate_reset_token
end
user = User.new(user_params.except(:extern_uid, :provider))
user.skip_confirmation! unless confirm
if identity_attrs.any?
......
......@@ -170,68 +170,24 @@ describe Projects::UploadsController do
project.team << [user, :master]
end
context "when the user is blocked" do
context "when the file exists" do
before do
user.block
project.team << [user, :master]
end
context "when the file exists" do
before do
allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
allow(jpg).to receive(:exists?).and_return(true)
end
context "when the file is an image" do
before do
allow_any_instance_of(FileUploader).to receive(:image?).and_return(true)
end
it "responds with status 200" do
go
expect(response).to have_http_status(200)
end
end
context "when the file is not an image" do
it "redirects to the sign in page" do
go
expect(response).to redirect_to(new_user_session_path)
end
end
allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
allow(jpg).to receive(:exists?).and_return(true)
end
context "when the file doesn't exist" do
it "redirects to the sign in page" do
go
it "responds with status 200" do
go
expect(response).to redirect_to(new_user_session_path)
end
expect(response).to have_http_status(200)
end
end
context "when the user isn't blocked" do
context "when the file exists" do
before do
allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
allow(jpg).to receive(:exists?).and_return(true)
end
it "responds with status 200" do
go
expect(response).to have_http_status(200)
end
end
context "when the file doesn't exist" do
it "responds with status 404" do
go
context "when the file doesn't exist" do
it "responds with status 404" do
go
expect(response).to have_http_status(404)
end
expect(response).to have_http_status(404)
end
end
end
......
......@@ -14,6 +14,14 @@ FactoryGirl.define do
admin true
end
trait :blocked do
after(:build) { |user, _| user.block! }
end
trait :external do
external true
end
trait :two_factor do
two_factor_via_otp
end
......
......@@ -35,15 +35,16 @@ RSpec.describe 'admin issues labels' do
it 'deletes all labels', js: true do
page.within '.labels' do
page.all('.btn-remove').each do |remove|
wait_for_ajax
remove.click
wait_for_ajax
end
end
page.within '.manage-labels-list' do
expect(page).not_to have_content('bug')
expect(page).not_to have_content('feature_label')
end
wait_for_ajax
expect(page).to have_content("There are no labels yet")
expect(page).not_to have_content('bug')
expect(page).not_to have_content('feature_label')
end
end
......
......@@ -101,6 +101,22 @@ feature 'Environment', :feature do
scenario 'it shows the terminal button' do
expect(page).to have_terminal_button
end
context 'web terminal', :js do
before do
# Stub #terminals as it causes js-enabled feature specs to render the page incorrectly
allow_any_instance_of(Environment).to receive(:terminals) { nil }
visit terminal_namespace_project_environment_path(project.namespace, project, environment)
end
it 'displays a web terminal' do
expect(page).to have_selector('#terminal')
end
it 'displays a link to the environment external url' do
expect(page).to have_link(nil, href: environment.external_url)
end
end
end
context 'for developer' do
......
require 'spec_helper'
feature 'Groups members list', feature: true do
let(:user1) { create(:user, name: 'John Doe') }
let(:user2) { create(:user, name: 'Mary Jane') }
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
background do
login_as(user1)
end
scenario 'show members from current group and parent' do
group.add_developer(user1)
nested_group.add_developer(user2)
visit group_group_members_path(nested_group)
expect(first_row.text).to include(user1.name)
expect(second_row.text).to include(user2.name)
end
scenario 'show user once if member of both current group and parent' do
group.add_developer(user1)
nested_group.add_developer(user1)
visit group_group_members_path(nested_group)
expect(first_row.text).to include(user1.name)
expect(second_row).to be_blank
end
def first_row
page.all('ul.content-list > li')[0]
end
def second_row
page.all('ul.content-list > li')[1]
end
end
......@@ -32,6 +32,22 @@ feature 'Login', feature: true do
end
end
describe 'with a blocked account' do
it 'prevents the user from logging in' do
user = create(:user, :blocked)
login_with(user)
expect(page).to have_content('Your account has been blocked.')
end
it 'does not update Devise trackable attributes' do
user = create(:user, :blocked)
expect { login_with(user) }.not_to change { user.reload.sign_in_count }
end
end
describe 'with two-factor authentication' do
def enter_code(code)
fill_in 'user_otp_attempt', with: code
......
......@@ -66,7 +66,7 @@ feature 'Mini Pipeline Graph', :js, :feature do
end
it 'should close when toggle is clicked again' do
toggle.click
toggle.trigger('click')
expect(toggle.find(:xpath, '..')).not_to have_selector('.mini-pipeline-graph-dropdown-menu')
end
......
require 'spec_helper'
describe GroupMembersFinder, '#execute' do
let(:group) { create(:group) }
let(:nested_group) { create(:group, :access_requestable, parent: group) }
let(:user1) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
let(:user4) { create(:user) }
it 'returns members for top-level group' do
member1 = group.add_master(user1)
member2 = group.add_master(user2)
member3 = group.add_master(user3)
result = described_class.new(group).execute
expect(result.to_a).to eq([member3, member2, member1])
end
it 'returns members for nested group' do
group.add_master(user2)
nested_group.request_access(user4)
member1 = group.add_master(user1)
member3 = nested_group.add_master(user2)
member4 = nested_group.add_master(user3)
result = described_class.new(nested_group).execute
expect(result.to_a).to eq([member4, member3, member1])
end
end
......@@ -40,7 +40,7 @@ require('~/behaviors/quick_submit');
expect($('input[type=submit]')).toBeDisabled();
return expect($('button[type=submit]')).toBeDisabled();
});
// We cannot stub `navigator.userAgent` for CI's `rake teaspoon` task, so we'll
// We cannot stub `navigator.userAgent` for CI's `rake karma` task, so we'll
// only run the tests that apply to the current platform
if (navigator.userAgent.match(/Macintosh/)) {
it('responds to Meta+Enter', function() {
......
......@@ -4,6 +4,16 @@ module Ci
describe GitlabCiYamlProcessor, lib: true do
let(:path) { 'path' }
describe 'our current .gitlab-ci.yml' do
let(:config) { File.read("#{Rails.root}/.gitlab-ci.yml") }
it 'is valid' do
error_message = described_class.validation_message(config)
expect(error_message).to be_nil
end
end
describe '#build_attributes' do
describe 'coverage entry' do
subject { described_class.new(config, path).build_attributes(:rspec) }
......
......@@ -129,6 +129,14 @@ describe Member, models: true do
it { expect(described_class.request).not_to include @accepted_request_member }
end
describe '.non_request' do
it { expect(described_class.non_request).to include @master }
it { expect(described_class.non_request).to include @invited_member }
it { expect(described_class.non_request).to include @accepted_invite_member }
it { expect(described_class.non_request).not_to include @requested_member }
it { expect(described_class.non_request).to include @accepted_request_member }
end
describe '.developers' do
subject { described_class.developers.to_a }
......
......@@ -35,7 +35,8 @@ describe API::Groups, api: true do
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['name']).to eq(group1.name)
expect(json_response)
.to satisfy_one { |group| group['name'] == group1.name }
end
it "does not include statistics" do
......@@ -70,7 +71,7 @@ describe API::Groups, api: true do
repository_size: 123,
lfs_objects_size: 234,
build_artifacts_size: 345,
}
}.stringify_keys
project1.statistics.update!(attributes)
......@@ -78,7 +79,8 @@ describe API::Groups, api: true do
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.first['statistics']).to eq attributes.stringify_keys
expect(json_response)
.to satisfy_one { |group| group['statistics'] == attributes }
end
end
......
......@@ -190,6 +190,18 @@ describe API::Users, api: true do
expect(new_user.external).to be_truthy
end
it "creates user with reset password" do
post api('/users', admin), attributes_for(:user, reset_password: true).except(:password)
expect(response).to have_http_status(201)
user_id = json_response['id']
new_user = User.find(user_id)
expect(new_user).not_to eq(nil)
expect(new_user.recently_sent_password_reset?).to eq(true)
end
it "does not create user with invalid email" do
post api('/users', admin),
email: 'invalid email',
......
# These matchers are a syntactic hack to provide more readable expectations for
# an Enumerable object.
#
# They take advantage of the `all?`, `none?`, and `one?` methods, and the fact
# that RSpec provides a `be_something` matcher for all predicates.
#
# Example:
#
# # Ensure exactly one object in an Array satisfies a condition
# expect(users.one? { |u| u.admin? }).to eq true
#
# # The same thing, but using the `be_one` matcher
# expect(users).to be_one { |u| u.admin? }
#
# # The same thing again, but using `satisfy_one` for improved readability
# expect(users).to satisfy_one { |u| u.admin? }
RSpec::Matchers.alias_matcher :satisfy_all, :be_all
RSpec::Matchers.alias_matcher :satisfy_none, :be_none
RSpec::Matchers.alias_matcher :satisfy_one, :be_one
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment