Commit bce9f31c authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'master' into 27932-merge-request-pipelines-displays-json

* master: (32 commits)
  Fix contribution activity alignment
  Adds a null check to build notifications
  Add a spec for our custom GemFetcher cop
  add CHANGELOG.md entry for !9078
  approve new dependencies
  update karma deps to work with webpack 2
  upgrade to webpack 2.2.x
  add CHANGELOG.md entry for !9072
  approve MIT license for wordwrap submodule
  fix failing karma test
  upgrade babel to v6
  exclude node_modules from imports-loader wrapper
  Allow copying a created branch name to the clipboard.
  Uses shared vue resource interceptor
  Refactored diff notes Vue app
  Fix expand_collapse_diffs specs
  Update the rspec_profiling gem to 0.0.5
  Fix menu link in CONTRIBUTING
  adds max-width only for new filter dropdown
  adds changelog
  ...
parents 5d0c5663 57d5a549
...@@ -163,64 +163,7 @@ spinach 7 10: *spinach-knapsack ...@@ -163,64 +163,7 @@ spinach 7 10: *spinach-knapsack
spinach 8 10: *spinach-knapsack spinach 8 10: *spinach-knapsack
spinach 9 10: *spinach-knapsack spinach 9 10: *spinach-knapsack
# Execute all testing suites against Ruby 2.1
.ruby-21: &ruby-21
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.1-git-2.7-phantomjs-2.1"
<<: *use-db
only:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
cache:
key: "ruby21"
paths:
- vendor/ruby
.rspec-knapsack-ruby21: &rspec-knapsack-ruby21
<<: *rspec-knapsack
<<: *dedicated-runner
<<: *ruby-21
.spinach-knapsack-ruby21: &spinach-knapsack-ruby21
<<: *spinach-knapsack
<<: *dedicated-runner
<<: *ruby-21
rspec 0 20 ruby21: *rspec-knapsack-ruby21
rspec 1 20 ruby21: *rspec-knapsack-ruby21
rspec 2 20 ruby21: *rspec-knapsack-ruby21
rspec 3 20 ruby21: *rspec-knapsack-ruby21
rspec 4 20 ruby21: *rspec-knapsack-ruby21
rspec 5 20 ruby21: *rspec-knapsack-ruby21
rspec 6 20 ruby21: *rspec-knapsack-ruby21
rspec 7 20 ruby21: *rspec-knapsack-ruby21
rspec 8 20 ruby21: *rspec-knapsack-ruby21
rspec 9 20 ruby21: *rspec-knapsack-ruby21
rspec 10 20 ruby21: *rspec-knapsack-ruby21
rspec 11 20 ruby21: *rspec-knapsack-ruby21
rspec 12 20 ruby21: *rspec-knapsack-ruby21
rspec 13 20 ruby21: *rspec-knapsack-ruby21
rspec 14 20 ruby21: *rspec-knapsack-ruby21
rspec 15 20 ruby21: *rspec-knapsack-ruby21
rspec 16 20 ruby21: *rspec-knapsack-ruby21
rspec 17 20 ruby21: *rspec-knapsack-ruby21
rspec 18 20 ruby21: *rspec-knapsack-ruby21
rspec 19 20 ruby21: *rspec-knapsack-ruby21
spinach 0 10 ruby21: *spinach-knapsack-ruby21
spinach 1 10 ruby21: *spinach-knapsack-ruby21
spinach 2 10 ruby21: *spinach-knapsack-ruby21
spinach 3 10 ruby21: *spinach-knapsack-ruby21
spinach 4 10 ruby21: *spinach-knapsack-ruby21
spinach 5 10 ruby21: *spinach-knapsack-ruby21
spinach 6 10 ruby21: *spinach-knapsack-ruby21
spinach 7 10 ruby21: *spinach-knapsack-ruby21
spinach 8 10 ruby21: *spinach-knapsack-ruby21
spinach 9 10 ruby21: *spinach-knapsack-ruby21
# Other generic tests # Other generic tests
.ruby-static-analysis: &ruby-static-analysis .ruby-static-analysis: &ruby-static-analysis
variables: variables:
SIMPLECOV: "false" SIMPLECOV: "false"
......
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
(How one can reproduce the issue - this is very important) (How one can reproduce the issue - this is very important)
### Expected behavior ### What is the current *bug* behavior?
(What you should see instead) (What actually happens)
### Actual behavior ### What is the expected *correct* behavior?
(What actually happens) (What you should see instead)
### Relevant logs and/or screenshots ### Relevant logs and/or screenshots
...@@ -23,23 +23,23 @@ logs, and code as it's very hard to read otherwise.) ...@@ -23,23 +23,23 @@ logs, and code as it's very hard to read otherwise.)
(If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com) (If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com)
#### Results of GitLab application Check #### Results of GitLab environment info
(For installations with omnibus-gitlab package run and paste the output of: (For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:check SANITIZE=true`) `sudo gitlab-rake gitlab:env:info`)
(For installations from source run and paste the output of: (For installations from source run and paste the output of:
`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`) `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
(we will only investigate if the tests are passing)
#### Results of GitLab environment info #### Results of GitLab application Check
(For installations with omnibus-gitlab package run and paste the output of: (For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:env:info`) `sudo gitlab-rake gitlab:check SANITIZE=true`)
(For installations from source run and paste the output of: (For installations from source run and paste the output of:
`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`) `sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`)
(we will only investigate if the tests are passing)
### Possible fixes ### Possible fixes
......
...@@ -31,8 +31,7 @@ AllCops: ...@@ -31,8 +31,7 @@ AllCops:
- 'lib/gitlab/seeder.rb' - 'lib/gitlab/seeder.rb'
- 'generator_templates/**/*' - 'generator_templates/**/*'
# Style #######################################################################
##################### Style ##################################
# Check indentation of private/protected visibility modifiers. # Check indentation of private/protected visibility modifiers.
Style/AccessModifierIndentation: Style/AccessModifierIndentation:
...@@ -471,7 +470,7 @@ Style/WhileUntilModifier: ...@@ -471,7 +470,7 @@ Style/WhileUntilModifier:
Style/WordArray: Style/WordArray:
Enabled: false Enabled: false
#################### Metrics ################################ # Metrics #####################################################################
# A calculated magnitude based on number of assignments, # A calculated magnitude based on number of assignments,
# branches, and conditions. # branches, and conditions.
...@@ -516,8 +515,7 @@ Metrics/PerceivedComplexity: ...@@ -516,8 +515,7 @@ Metrics/PerceivedComplexity:
Enabled: true Enabled: true
Max: 18 Max: 18
# Lint ########################################################################
#################### Lint ################################
# Checks for useless access modifiers. # Checks for useless access modifiers.
Lint/UselessAccessModifier: Lint/UselessAccessModifier:
...@@ -679,8 +677,7 @@ Lint/UselessSetterCall: ...@@ -679,8 +677,7 @@ Lint/UselessSetterCall:
Lint/Void: Lint/Void:
Enabled: true Enabled: true
# Performance #################################################################
##################### Performance ############################
# Use `casecmp` rather than `downcase ==`. # Use `casecmp` rather than `downcase ==`.
Performance/Casecmp: Performance/Casecmp:
...@@ -718,8 +715,7 @@ Performance/StringReplacement: ...@@ -718,8 +715,7 @@ Performance/StringReplacement:
Performance/TimesMap: Performance/TimesMap:
Enabled: true Enabled: true
# Rails #######################################################################
##################### Rails ##################################
# Enables Rails cops. # Enables Rails cops.
Rails: Rails:
...@@ -767,7 +763,7 @@ Rails/ReadWriteAttribute: ...@@ -767,7 +763,7 @@ Rails/ReadWriteAttribute:
Rails/ScopeArgs: Rails/ScopeArgs:
Enabled: true Enabled: true
##################### RSpec ################################## # RSpec #######################################################################
# Check that instances are not being stubbed globally. # Check that instances are not being stubbed globally.
RSpec/AnyInstance: RSpec/AnyInstance:
...@@ -828,3 +824,9 @@ RSpec/NotToNot: ...@@ -828,3 +824,9 @@ RSpec/NotToNot:
# Prefer using verifying doubles over normal doubles. # Prefer using verifying doubles over normal doubles.
RSpec/VerifiedDoubles: RSpec/VerifiedDoubles:
Enabled: false Enabled: false
# Custom ######################################################################
# Disallow the `git` and `github` arguments in the Gemfile.
GemFetcher:
Enabled: true
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
- [Issue weight](#issue-weight) - [Issue weight](#issue-weight)
- [Regression issues](#regression-issues) - [Regression issues](#regression-issues)
- [Technical debt](#technical-debt) - [Technical debt](#technical-debt)
- [Stewardship][#stewardship] - [Stewardship](#stewardship)
- [Merge requests](#merge-requests) - [Merge requests](#merge-requests)
- [Merge request guidelines](#merge-request-guidelines) - [Merge request guidelines](#merge-request-guidelines)
- [Contribution acceptance criteria](#contribution-acceptance-criteria) - [Contribution acceptance criteria](#contribution-acceptance-criteria)
......
...@@ -284,7 +284,7 @@ group :development, :test do ...@@ -284,7 +284,7 @@ group :development, :test do
gem 'rspec-retry', '~> 0.4.5' gem 'rspec-retry', '~> 0.4.5'
gem 'spinach-rails', '~> 0.2.1' gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2' gem 'spinach-rerun-reporter', '~> 0.0.2'
gem 'rspec_profiling' gem 'rspec_profiling', '~> 0.0.5'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826) # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.7.0' gem 'minitest', '~> 5.7.0'
......
...@@ -638,7 +638,7 @@ GEM ...@@ -638,7 +638,7 @@ GEM
rspec-retry (0.4.5) rspec-retry (0.4.5)
rspec-core rspec-core
rspec-support (3.5.0) rspec-support (3.5.0)
rspec_profiling (0.0.4) rspec_profiling (0.0.5)
activerecord activerecord
pg pg
rails rails
...@@ -738,7 +738,7 @@ GEM ...@@ -738,7 +738,7 @@ GEM
actionpack (>= 4.0) actionpack (>= 4.0)
activesupport (>= 4.0) activesupport (>= 4.0)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
sqlite3 (1.3.11) sqlite3 (1.3.13)
stackprof (0.2.10) stackprof (0.2.10)
state_machines (0.4.0) state_machines (0.4.0)
state_machines-activemodel (0.4.0) state_machines-activemodel (0.4.0)
...@@ -962,7 +962,7 @@ DEPENDENCIES ...@@ -962,7 +962,7 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0) rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5) rspec-retry (~> 0.4.5)
rspec_profiling rspec_profiling (~> 0.0.5)
rubocop (~> 0.46.0) rubocop (~> 0.46.0)
rubocop-rspec (~> 1.9.1) rubocop-rspec (~> 1.9.1)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
...@@ -1011,4 +1011,4 @@ DEPENDENCIES ...@@ -1011,4 +1011,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.14.2 1.14.3
Copyright (c) 2011-2016 GitLab B.V. Copyright (c) 2011-2017 GitLab B.V.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
...@@ -76,7 +76,7 @@ require('./lib/utils/url_utility'); ...@@ -76,7 +76,7 @@ require('./lib/utils/url_utility');
const diffFile = diffTitle.closest('.diff-file'); const diffFile = diffTitle.closest('.diff-file');
const nothingHereBlock = $('.nothing-here-block:visible', diffFile); const nothingHereBlock = $('.nothing-here-block:visible', diffFile);
if (nothingHereBlock.length) { if (nothingHereBlock.length) {
const clickTarget = $('.file-title, .click-to-expand', diffFile); const clickTarget = $('.js-file-title, .click-to-expand', diffFile);
diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => { diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => {
this.highlighSelectedLine(); this.highlighSelectedLine();
if (cb) cb(); if (cb) cb();
......
/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, quotes, no-lonely-if, max-len */ /* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, quotes, no-lonely-if, max-len */
/* global Vue */
/* global CommentsStore */ /* global CommentsStore */
const Vue = require('vue');
(() => { (() => {
const CommentAndResolveBtn = Vue.extend({ const CommentAndResolveBtn = Vue.extend({
...@@ -9,13 +9,11 @@ ...@@ -9,13 +9,11 @@
}, },
data() { data() {
return { return {
textareaIsEmpty: true textareaIsEmpty: true,
discussion: {},
}; };
}, },
computed: { computed: {
discussion: function () {
return CommentsStore.state[this.discussionId];
},
showButton: function () { showButton: function () {
if (this.discussion) { if (this.discussion) {
return this.discussion.isResolvable(); return this.discussion.isResolvable();
...@@ -42,6 +40,9 @@ ...@@ -42,6 +40,9 @@
} }
} }
}, },
created() {
this.discussion = CommentsStore.state[this.discussionId];
},
mounted: function () { mounted: function () {
const $textarea = $(`#new-discussion-note-form-${this.discussionId} .note-textarea`); const $textarea = $(`#new-discussion-note-form-${this.discussionId} .note-textarea`);
this.textareaIsEmpty = $textarea.val() === ''; this.textareaIsEmpty = $textarea.val() === '';
......
/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, one-var, space-before-function-paren, no-lonely-if, no-continue, brace-style, max-len, quotes */ /* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, one-var, space-before-function-paren, no-lonely-if, no-continue, brace-style, max-len, quotes */
/* global Vue */
/* global DiscussionMixins */ /* global DiscussionMixins */
/* global CommentsStore */ /* global CommentsStore */
const Vue = require('vue');
(() => { (() => {
const JumpToDiscussion = Vue.extend({ const JumpToDiscussion = Vue.extend({
...@@ -12,12 +12,10 @@ ...@@ -12,12 +12,10 @@
data: function () { data: function () {
return { return {
discussions: CommentsStore.state, discussions: CommentsStore.state,
discussion: {},
}; };
}, },
computed: { computed: {
discussion: function () {
return this.discussions[this.discussionId];
},
allResolved: function () { allResolved: function () {
return this.unresolvedDiscussionCount === 0; return this.unresolvedDiscussionCount === 0;
}, },
...@@ -186,7 +184,10 @@ ...@@ -186,7 +184,10 @@
offset: -($('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight()) offset: -($('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight())
}); });
} }
} },
created() {
this.discussion = this.discussions[this.discussionId];
},
}); });
Vue.component('jump-to-discussion', JumpToDiscussion); Vue.component('jump-to-discussion', JumpToDiscussion);
......
/* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, no-new, max-len */ /* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, no-new, max-len */
/* global Vue */
/* global CommentsStore */ /* global CommentsStore */
/* global ResolveService */ /* global ResolveService */
/* global Flash */ /* global Flash */
const Vue = require('vue');
(() => { (() => {
const ResolveBtn = Vue.extend({ const ResolveBtn = Vue.extend({
...@@ -10,14 +10,14 @@ ...@@ -10,14 +10,14 @@
noteId: Number, noteId: Number,
discussionId: String, discussionId: String,
resolved: Boolean, resolved: Boolean,
projectPath: String,
canResolve: Boolean, canResolve: Boolean,
resolvedBy: String resolvedBy: String
}, },
data: function () { data: function () {
return { return {
discussions: CommentsStore.state, discussions: CommentsStore.state,
loading: false loading: false,
note: {},
}; };
}, },
watch: { watch: {
...@@ -30,13 +30,6 @@ ...@@ -30,13 +30,6 @@
discussion: function () { discussion: function () {
return this.discussions[this.discussionId]; return this.discussions[this.discussionId];
}, },
note: function () {
if (this.discussion) {
return this.discussion.getNote(this.noteId);
} else {
return undefined;
}
},
buttonText: function () { buttonText: function () {
if (this.isResolved) { if (this.isResolved) {
return `Resolved by ${this.resolvedByName}`; return `Resolved by ${this.resolvedByName}`;
...@@ -73,10 +66,10 @@ ...@@ -73,10 +66,10 @@
if (this.isResolved) { if (this.isResolved) {
promise = ResolveService promise = ResolveService
.unresolve(this.projectPath, this.noteId); .unresolve(this.noteId);
} else { } else {
promise = ResolveService promise = ResolveService
.resolve(this.projectPath, this.noteId); .resolve(this.noteId);
} }
promise.then((response) => { promise.then((response) => {
...@@ -106,6 +99,8 @@ ...@@ -106,6 +99,8 @@
}, },
created: function () { created: function () {
CommentsStore.create(this.discussionId, this.noteId, this.canResolve, this.resolved, this.resolvedBy); CommentsStore.create(this.discussionId, this.noteId, this.canResolve, this.resolved, this.resolvedBy);
this.note = this.discussion.getNote(this.noteId);
} }
}); });
......
/* eslint-disable comma-dangle, object-shorthand, func-names, no-param-reassign */ /* eslint-disable comma-dangle, object-shorthand, func-names, no-param-reassign */
/* global Vue */
/* global DiscussionMixins */ /* global DiscussionMixins */
/* global CommentsStore */ /* global CommentsStore */
const Vue = require('vue');
((w) => { ((w) => {
w.ResolveCount = Vue.extend({ w.ResolveCount = Vue.extend({
......
/* eslint-disable object-shorthand, func-names, space-before-function-paren, comma-dangle, no-else-return, quotes, max-len */ /* eslint-disable object-shorthand, func-names, space-before-function-paren, comma-dangle, no-else-return, quotes, max-len */
/* global Vue */
/* global CommentsStore */ /* global CommentsStore */
/* global ResolveService */ /* global ResolveService */
const Vue = require('vue');
(() => { (() => {
const ResolveDiscussionBtn = Vue.extend({ const ResolveDiscussionBtn = Vue.extend({
props: { props: {
discussionId: String, discussionId: String,
mergeRequestId: Number, mergeRequestId: Number,
projectPath: String,
canResolve: Boolean, canResolve: Boolean,
}, },
data: function() { data: function() {
return { return {
discussions: CommentsStore.state discussion: {},
}; };
}, },
computed: { computed: {
discussion: function () {
return this.discussions[this.discussionId];
},
showButton: function () { showButton: function () {
if (this.discussion) { if (this.discussion) {
return this.discussion.isResolvable(); return this.discussion.isResolvable();
...@@ -51,11 +48,13 @@ ...@@ -51,11 +48,13 @@
}, },
methods: { methods: {
resolve: function () { resolve: function () {
ResolveService.toggleResolveForDiscussion(this.projectPath, this.mergeRequestId, this.discussionId); ResolveService.toggleResolveForDiscussion(this.mergeRequestId, this.discussionId);
} }
}, },
created: function () { created: function () {
CommentsStore.createDiscussion(this.discussionId, this.canResolve); CommentsStore.createDiscussion(this.discussionId, this.canResolve);
this.discussion = CommentsStore.state[this.discussionId];
} }
}); });
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
/* global ResolveCount */ /* global ResolveCount */
function requireAll(context) { return context.keys().map(context); } function requireAll(context) { return context.keys().map(context); }
const Vue = require('vue');
requireAll(require.context('./models', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./models', false, /^\.\/.*\.(js|es6)$/));
requireAll(require.context('./stores', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./stores', false, /^\.\/.*\.(js|es6)$/));
requireAll(require.context('./services', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./services', false, /^\.\/.*\.(js|es6)$/));
...@@ -10,11 +11,14 @@ requireAll(require.context('./mixins', false, /^\.\/.*\.(js|es6)$/)); ...@@ -10,11 +11,14 @@ requireAll(require.context('./mixins', false, /^\.\/.*\.(js|es6)$/));
requireAll(require.context('./components', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./components', false, /^\.\/.*\.(js|es6)$/));
$(() => { $(() => {
const projectPath = document.querySelector('.merge-request').dataset.projectPath;
const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn'; const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn';
window.gl = window.gl || {}; window.gl = window.gl || {};
window.gl.diffNoteApps = {}; window.gl.diffNoteApps = {};
window.ResolveService = new gl.DiffNotesResolveServiceClass(projectPath);
gl.diffNotesCompileComponents = () => { gl.diffNotesCompileComponents = () => {
const $components = $(COMPONENT_SELECTOR).filter(function () { const $components = $(COMPONENT_SELECTOR).filter(function () {
return $(this).closest('resolve-count').length !== 1; return $(this).closest('resolve-count').length !== 1;
......
/* eslint-disable class-methods-use-this, one-var, camelcase, no-new, comma-dangle, no-param-reassign, max-len */ /* eslint-disable class-methods-use-this, one-var, camelcase, no-new, comma-dangle, no-param-reassign, max-len */
/* global Vue */
/* global Flash */ /* global Flash */
/* global CommentsStore */ /* global CommentsStore */
((w) => { const Vue = window.Vue = require('vue');
class ResolveServiceClass { window.Vue.use(require('vue-resource'));
constructor() { require('../../vue_shared/vue_resource_interceptor');
this.noteResource = Vue.resource('notes{/noteId}/resolve');
this.discussionResource = Vue.resource('merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve');
}
setCSRF() { (() => {
Vue.http.headers.common['X-CSRF-Token'] = $.rails.csrfToken(); window.gl = window.gl || {};
}
prepareRequest(root) { class ResolveServiceClass {
this.setCSRF(); constructor(root) {
Vue.http.options.root = root; this.noteResource = Vue.resource(`${root}/notes{/noteId}/resolve`);
this.discussionResource = Vue.resource(`${root}/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve`);
} }
resolve(projectPath, noteId) { resolve(noteId) {
this.prepareRequest(projectPath);
return this.noteResource.save({ noteId }, {}); return this.noteResource.save({ noteId }, {});
} }
unresolve(projectPath, noteId) { unresolve(noteId) {
this.prepareRequest(projectPath);
return this.noteResource.delete({ noteId }, {}); return this.noteResource.delete({ noteId }, {});
} }
toggleResolveForDiscussion(projectPath, mergeRequestId, discussionId) { toggleResolveForDiscussion(mergeRequestId, discussionId) {
const discussion = CommentsStore.state[discussionId]; const discussion = CommentsStore.state[discussionId];
const isResolved = discussion.isResolved(); const isResolved = discussion.isResolved();
let promise; let promise;
if (isResolved) { if (isResolved) {
promise = this.unResolveAll(projectPath, mergeRequestId, discussionId); promise = this.unResolveAll(mergeRequestId, discussionId);
} else { } else {
promise = this.resolveAll(projectPath, mergeRequestId, discussionId); promise = this.resolveAll(mergeRequestId, discussionId);
} }
promise.then((response) => { promise.then((response) => {
...@@ -62,11 +54,9 @@ ...@@ -62,11 +54,9 @@
}); });
} }
resolveAll(projectPath, mergeRequestId, discussionId) { resolveAll(mergeRequestId, discussionId) {
const discussion = CommentsStore.state[discussionId]; const discussion = CommentsStore.state[discussionId];
this.prepareRequest(projectPath);
discussion.loading = true; discussion.loading = true;
return this.discussionResource.save({ return this.discussionResource.save({
...@@ -75,11 +65,9 @@ ...@@ -75,11 +65,9 @@
}, {}); }, {});
} }
unResolveAll(projectPath, mergeRequestId, discussionId) { unResolveAll(mergeRequestId, discussionId) {
const discussion = CommentsStore.state[discussionId]; const discussion = CommentsStore.state[discussionId];
this.prepareRequest(projectPath);
discussion.loading = true; discussion.loading = true;
return this.discussionResource.delete({ return this.discussionResource.delete({
...@@ -89,5 +77,5 @@ ...@@ -89,5 +77,5 @@
} }
} }
w.ResolveService = new ResolveServiceClass(); gl.DiffNotesResolveServiceClass = ResolveServiceClass;
})(window); })();
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
class FilteredSearchDropdown { class FilteredSearchDropdown {
constructor(droplab, dropdown, input, filter) { constructor(droplab, dropdown, input, filter) {
this.droplab = droplab; this.droplab = droplab;
this.hookId = input.getAttribute('data-id'); this.hookId = input && input.getAttribute('data-id');
this.input = input; this.input = input;
this.filter = filter; this.filter = filter;
this.dropdown = dropdown; this.dropdown = dropdown;
......
...@@ -154,7 +154,7 @@ require('./smart_interval'); ...@@ -154,7 +154,7 @@ require('./smart_interval');
return $.getJSON(this.opts.ci_status_url, (function(_this) { return $.getJSON(this.opts.ci_status_url, (function(_this) {
return function(data) { return function(data) {
var message, status, title; var message, status, title;
if (data.status === '') { if (!data.status) {
return; return;
} }
if (data.environments && data.environments.length) _this.renderEnvironments(data.environments); if (data.environments && data.environments.length) _this.renderEnvironments(data.environments);
......
...@@ -455,7 +455,7 @@ require('vendor/task_list'); ...@@ -455,7 +455,7 @@ require('vendor/task_list');
var mergeRequestId = $form.data('noteable-iid'); var mergeRequestId = $form.data('noteable-iid');
if (ResolveService != null) { if (ResolveService != null) {
ResolveService.toggleResolveForDiscussion(projectPath, mergeRequestId, discussionId); ResolveService.toggleResolveForDiscussion(mergeRequestId, discussionId);
} }
} }
......
...@@ -33,13 +33,13 @@ ...@@ -33,13 +33,13 @@
this.$toggleIcon.addClass('fa-caret-down'); this.$toggleIcon.addClass('fa-caret-down');
} }
$('.file-title, .click-to-expand', this.file).on('click', (function (e) { $('.js-file-title, .click-to-expand', this.file).on('click', (function (e) {
this.toggleDiff($(e.target)); this.toggleDiff($(e.target));
}).bind(this)); }).bind(this));
} }
SingleFileDiff.prototype.toggleDiff = function($target, cb) { SingleFileDiff.prototype.toggleDiff = function($target, cb) {
if (!$target.hasClass('file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return; if (!$target.hasClass('js-file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
if (!this.isOpen && !this.hasError) { if (!this.isOpen && !this.hasError) {
this.content.hide(); this.content.hide();
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
} }
.user-calendar-activities { .user-calendar-activities {
direction: ltr;
.str-truncated { .str-truncated {
max-width: 70%; max-width: 70%;
} }
......
...@@ -125,7 +125,6 @@ ...@@ -125,7 +125,6 @@
top: 100%; top: 100%;
left: 0; left: 0;
z-index: 9; z-index: 9;
max-width: 280px;
min-width: 240px; min-width: 240px;
margin-top: 2px; margin-top: 2px;
margin-bottom: 0; margin-bottom: 0;
...@@ -137,6 +136,10 @@ ...@@ -137,6 +136,10 @@
border-radius: $border-radius-base; border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color; box-shadow: 0 2px 4px $dropdown-shadow-color;
.filtered-search-input-container & {
max-width: 280px;
}
&.is-loading { &.is-loading {
.dropdown-content { .dropdown-content {
display: none; display: none;
......
...@@ -231,3 +231,46 @@ span.idiff { ...@@ -231,3 +231,46 @@ span.idiff {
} }
} }
} }
.file-title-flex-parent {
display: flex;
align-items: center;
justify-content: space-between;
background-color: $gray-light;
border-bottom: 1px solid $border-color;
padding: 5px $gl-padding;
margin: 0;
border-radius: 3px 3px 0 0;
.file-header-content {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 30px;
position: relative;
}
.btn-clipboard {
position: absolute;
right: 0;
}
a {
color: $gl-text-color;
}
small {
margin: 0 10px 0 0;
}
.file-actions {
white-space: nowrap;
.btn {
padding: 0 10px;
font-size: 13px;
line-height: 28px;
display: inline-block;
}
}
}
...@@ -34,9 +34,14 @@ ...@@ -34,9 +34,14 @@
} }
} }
.file-title { .file-title,
.file-title-flex-parent {
cursor: pointer; cursor: pointer;
a:hover {
text-decoration: none;
}
&:hover { &:hover {
background-color: $gray-normal; background-color: $gray-normal;
} }
......
...@@ -68,8 +68,12 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController ...@@ -68,8 +68,12 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
def access_levels_options def access_levels_options
{ {
push_access_levels: ProtectedBranch::PushAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } }, push_access_levels: {
merge_access_levels: ProtectedBranch::MergeAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } } "Roles" => ProtectedBranch::PushAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } },
},
merge_access_levels: {
"Roles" => ProtectedBranch::MergeAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } }
}
} }
end end
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
.tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''), .tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''),
id: klass::file_name_noext } id: klass::file_name_noext }
.file-holder#README .file-holder#README
.file-title .js-file-title.file-title
%i.fa.fa-file %i.fa.fa-file
= klass::file_name = klass::file_name
.pull-right .pull-right
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
.form-group .form-group
.col-sm-12 .col-sm-12
.file-holder .file-holder
.file-title.clearfix .js-file-title.file-title.clearfix
Content of .gitlab-ci.yml Content of .gitlab-ci.yml
#ci-editor.ci-editor= @content #ci-editor.ci-editor= @content
= text_area_tag(:content, @content, class: 'hidden form-control span1', rows: 7, require: true) = text_area_tag(:content, @content, class: 'hidden form-control span1', rows: 7, require: true)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- blob = discussion.blob - blob = discussion.blob
.diff-file.file-holder .diff-file.file-holder
.file-title .js-file-title.file-title
= render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: discussion.project, url: discussion_diff_path(discussion) = render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: discussion.project, url: discussion_diff_path(discussion)
.diff-content.code.js-syntax-highlight .diff-content.code.js-syntax-highlight
......
- if discussion.for_merge_request? - if discussion.for_merge_request?
%resolve-discussion-btn{ ":project-path" => "'#{project_path(discussion.project)}'", %resolve-discussion-btn{ ":discussion-id" => "'#{discussion.id}'",
":discussion-id" => "'#{discussion.id}'",
":merge-request-id" => discussion.noteable.iid, ":merge-request-id" => discussion.noteable.iid,
":can-resolve" => discussion.can_resolve?(current_user), ":can-resolve" => discussion.can_resolve?(current_user),
"inline-template" => true } "inline-template" => true }
......
...@@ -528,7 +528,7 @@ ...@@ -528,7 +528,7 @@
- blob = Snippet.new(content: "Wow\nSuch\nFile") - blob = Snippet.new(content: "Wow\nSuch\nFile")
.example .example
.file-holder .file-holder
.file-title .js-file-title.file-title
Awesome file Awesome file
.file-actions .file-actions
.btn-group .btn-group
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
- if @project && event.project != @project - if @project && event.project != @project
%span at %span at
%strong= link_to_project event.project %strong= link_to_project event.project
= clipboard_button(clipboard_text: event.ref_name, class: 'btn-clipboard btn-transparent', title: 'Copy branch to clipboard')
#{time_ago_with_tooltip(event.created_at)} #{time_ago_with_tooltip(event.created_at)}
.pull-right .pull-right
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#blob-content-holder.tree-holder #blob-content-holder.tree-holder
.file-holder .file-holder
.file-title .js-file-title.file-title
= blob_icon @blob.mode, @blob.name = blob_icon @blob.mode, @blob.name
%strong %strong
= @path = @path
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#blob-content-holder.blob-content-holder #blob-content-holder.blob-content-holder
%article.file-holder %article.file-holder
.file-title .js-file-title.file-title
= blob_icon blob.mode, blob.name = blob_icon blob.mode, blob.name
%strong %strong
= blob.name = blob.name
......
.file-holder.file.append-bottom-default .file-holder.file.append-bottom-default
.file-title.clearfix .js-file-title.file-title.clearfix
.editor-ref .editor-ref
= icon('code-fork') = icon('code-fork')
= ref = ref
......
- environment = local_assigns.fetch(:environment, nil) - environment = local_assigns.fetch(:environment, nil)
.diff-file.file-holder{ id: file_hash, data: diff_file_html_data(project, diff_file.file_path, diff_commit.id) } .diff-file.file-holder{ id: file_hash, data: diff_file_html_data(project, diff_file.file_path, diff_commit.id) }
.file-title .js-file-title.file-title-flex-parent
.file-header-content
= render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_commit, project: project, url: "##{file_hash}" = render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_commit, project: project, url: "##{file_hash}"
- unless diff_file.submodule? - unless diff_file.submodule?
......
...@@ -10,13 +10,13 @@ ...@@ -10,13 +10,13 @@
- if diff_file.renamed_file - if diff_file.renamed_file
- old_path, new_path = mark_inline_diffs(diff_file.old_path, diff_file.new_path) - old_path, new_path = mark_inline_diffs(diff_file.old_path, diff_file.new_path)
%strong %strong.file-title-name.has-tooltip{ data: { title: old_path } }
= old_path = old_path
&rarr; &rarr;
%strong %strong.file-title-name.has-tooltip{ data: { title: new_path } }
= new_path = new_path
- else - else
%strong %strong.file-title-name.has-tooltip{ data: { title: diff_file.new_path } }
= diff_file.new_path = diff_file.new_path
- if diff_file.deleted_file - if diff_file.deleted_file
deleted deleted
......
...@@ -3,10 +3,9 @@ ...@@ -3,10 +3,9 @@
- page_description @merge_request.description - page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes - page_card_attributes @merge_request.card_attributes
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('lib_vue')
= page_specific_javascript_bundle_tag('diff_notes') = page_specific_javascript_bundle_tag('diff_notes')
.merge-request{ 'data-url' => merge_request_path(@merge_request) } .merge-request{ 'data-url' => merge_request_path(@merge_request), 'data-project-path' => project_path(@merge_request.project) }
= render "projects/merge_requests/show/mr_title" = render "projects/merge_requests/show/mr_title"
.merge-request-details.issuable-details{ data: { id: @merge_request.project.id } } .merge-request-details.issuable-details{ data: { id: @merge_request.project.id } }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
.files-wrapper{ "v-if" => "!isLoading && !hasError" } .files-wrapper{ "v-if" => "!isLoading && !hasError" }
.files .files
.diff-file.file-holder.conflict{ "v-for" => "file in conflictsData.files" } .diff-file.file-holder.conflict{ "v-for" => "file in conflictsData.files" }
.file-title .js-file-title.file-title
%i.fa.fa-fw{ ":class" => "file.iconClass" } %i.fa.fa-fw{ ":class" => "file.iconClass" }
%strong {{file.filePath}} %strong {{file.filePath}}
= render partial: 'projects/merge_requests/conflicts/file_actions' = render partial: 'projects/merge_requests/conflicts/file_actions'
......
...@@ -30,8 +30,7 @@ ...@@ -30,8 +30,7 @@
- if note.resolvable? - if note.resolvable?
- can_resolve = can?(current_user, :resolve_note, note) - can_resolve = can?(current_user, :resolve_note, note)
%resolve-btn{ "project-path" => "#{project_path(note.project)}", %resolve-btn{ "discussion-id" => "#{note.discussion_id}",
"discussion-id" => "#{note.discussion_id}",
":note-id" => note.id, ":note-id" => note.id,
":resolved" => note.resolved?, ":resolved" => note.resolved?,
":can-resolve" => can_resolve, ":can-resolve" => can_resolve,
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
.project-snippets .project-snippets
%article.file-holder.snippet-file-content %article.file-holder.snippet-file-content
.file-title .js-file-title.file-title
= blob_icon 0, @snippet.file_name = blob_icon 0, @snippet.file_name
= @snippet.file_name = @snippet.file_name
.file-actions .file-actions
......
%article.file-holder.readme-holder %article.file-holder.readme-holder
.file-title .js-file-title.file-title
= blob_icon readme.mode, readme.name = blob_icon readme.mode, readme.name
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, @path, readme.name)) do = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, @path, readme.name)) do
%strong %strong
......
- file_name, blob = blob - file_name, blob = blob
.blob-result .blob-result
.file-holder .file-holder
.file-title .js-file-title.file-title
- ref = @search_results.repository_ref - ref = @search_results.repository_ref
- blob_link = namespace_project_blob_path(@project.namespace, @project, tree_join(ref, file_name)) - blob_link = namespace_project_blob_path(@project.namespace, @project, tree_join(ref, file_name))
= link_to blob_link do = link_to blob_link do
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
- snippet_path = reliable_snippet_path(snippet) - snippet_path = reliable_snippet_path(snippet)
= link_to snippet_path do = link_to snippet_path do
.file-holder .file-holder
.file-title .js-file-title.file-title
%i.fa.fa-file %i.fa.fa-file
%strong= snippet.file_name %strong= snippet.file_name
- if markup?(snippet.file_name) - if markup?(snippet.file_name)
......
- wiki_blob = parse_search_result(wiki_blob) - wiki_blob = parse_search_result(wiki_blob)
.blob-result .blob-result
.file-holder .file-holder
.file-title .js-file-title.file-title
= link_to namespace_project_wiki_path(@project.namespace, @project, wiki_blob.basename) do = link_to namespace_project_wiki_path(@project.namespace, @project, wiki_blob.basename) do
%i.fa.fa-file %i.fa.fa-file
%strong %strong
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
= f.label :file_name, "File", class: 'control-label' = f.label :file_name, "File", class: 'control-label'
.col-sm-10 .col-sm-10
.file-holder.snippet .file-holder.snippet
.file-title .js-file-title.file-title
= f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name' = f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name'
.file-content.code .file-content.code
%pre#editor= @snippet.content %pre#editor= @snippet.content
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
= @file_sample.events = @file_sample.events
%article.file-holder %article.file-holder
.file-title .js-file-title.file-title
%i.fa.fa-file-text-o.fa-fw %i.fa.fa-file-text-o.fa-fw
%strong %strong
= @file_sample.file = @file_sample.file
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
= render 'shared/snippets/header' = render 'shared/snippets/header'
%article.file-holder.snippet-file-content %article.file-holder.snippet-file-content
.file-title .js-file-title.file-title
= blob_icon 0, @snippet.file_name = blob_icon 0, @snippet.file_name
= @snippet.file_name = @snippet.file_name
.file-actions .file-actions
......
---
title: Responsive title in diffs inline, side by side, with and without sidebar
merge_request: 8475
author:
---
title: Fixes dropdown width in admin project page
merge_request: 9002
author:
---
title: Fix contribution activity alignment
merge_request:
author:
---
title: Added the ability to copy a branch name to the clipboard
merge_request: 9103
author: Glenn Sayers
---
title: Update API docs for new namespace format
merge_request: 9073
author: Markus Koller
---
title: Added headers to protected branch access dropdowns
merge_request:
author:
---
title: upgrade babel 5.8.x to babel 6.22.x
merge_request: 9072
author:
---
title: upgrade to webpack v2.2
merge_request: 9078
author:
...@@ -302,3 +302,21 @@ ...@@ -302,3 +302,21 @@
:why: https://github.com/dchest/tweetnacl-js/blob/master/LICENSE :why: https://github.com/dchest/tweetnacl-js/blob/master/LICENSE
:versions: [] :versions: []
:when: 2017-01-14 20:10:57.812077000 Z :when: 2017-01-14 20:10:57.812077000 Z
- - :approve
- wordwrap
- :who: Mike Greiling
:why: https://github.com/substack/node-wordwrap/blob/0.0.3/LICENSE
:versions: []
:when: 2017-02-08 20:17:13.084968000 Z
- - :approve
- spdx-expression-parse
- :who: Mike Greiling
:why: https://github.com/kemitchell/spdx-expression-parse.js/blob/v1.0.4/LICENSE
:versions: []
:when: 2017-02-08 22:33:01.806977000 Z
- - :approve
- spdx-license-ids
- :who: Mike Greiling
:why: https://github.com/shinnn/spdx-license-ids/blob/v1.2.2/LICENSE
:versions: []
:when: 2017-02-08 22:35:00.225232000 Z
...@@ -48,26 +48,23 @@ var config = { ...@@ -48,26 +48,23 @@ var config = {
devtool: 'inline-source-map', devtool: 'inline-source-map',
module: { module: {
loaders: [ rules: [
{ {
test: /\.(js|es6)$/, test: /\.(js|es6)$/,
exclude: /(node_modules|vendor\/assets)/, exclude: /(node_modules|vendor\/assets)/,
loader: 'babel-loader', loader: 'babel-loader',
query: { options: {
// 'use strict' was broken in sprockets-es6 due to sprockets concatination method. presets: [
// many es5 strict errors which were never caught ended up in our es6 assets as a result. ["es2015", {"modules": false}],
// this hack is necessary until they can be fixed. 'stage-2'
blacklist: ['useStrict'] ]
} }
}, },
{ {
test: /\.(js|es6)$/, test: /\.(js|es6)$/,
exclude: /node_modules/,
loader: 'imports-loader', loader: 'imports-loader',
query: 'this=>window' options: 'this=>window'
},
{
test: /\.json$/,
loader: 'json-loader'
} }
] ]
}, },
...@@ -88,7 +85,7 @@ var config = { ...@@ -88,7 +85,7 @@ var config = {
], ],
resolve: { resolve: {
extensions: ['', '.js', '.es6', '.js.es6'], extensions: ['.js', '.es6', '.js.es6'],
alias: { alias: {
'~': path.join(ROOT_PATH, 'app/assets/javascripts'), '~': path.join(ROOT_PATH, 'app/assets/javascripts'),
'bootstrap/js': 'bootstrap-sass/assets/javascripts/bootstrap', 'bootstrap/js': 'bootstrap-sass/assets/javascripts/bootstrap',
...@@ -104,14 +101,16 @@ if (IS_PRODUCTION) { ...@@ -104,14 +101,16 @@ if (IS_PRODUCTION) {
config.devtool = 'source-map'; config.devtool = 'source-map';
config.plugins.push( config.plugins.push(
new webpack.NoErrorsPlugin(), new webpack.NoErrorsPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({ new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false } sourceMap: true
}), }),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify('production') } 'process.env': { NODE_ENV: JSON.stringify('production') }
}), })
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurrenceOrderPlugin()
); );
} }
......
...@@ -106,15 +106,7 @@ Example response: ...@@ -106,15 +106,7 @@ Example response:
"id": 5, "id": 5,
"name": "Experimental", "name": "Experimental",
"path": "h5bp", "path": "h5bp",
"owner_id": null, "kind": "group"
"created_at": "2016-04-05T21:40:49.152Z",
"updated_at": "2016-04-07T08:07:48.466Z",
"description": "foo",
"avatar": {
"url": null
},
"share_with_group_lock": false,
"visibility_level": 10
}, },
"avatar_url": null, "avatar_url": null,
"star_count": 1, "star_count": 1,
...@@ -190,15 +182,7 @@ Example response: ...@@ -190,15 +182,7 @@ Example response:
"id": 4, "id": 4,
"name": "Twitter", "name": "Twitter",
"path": "twitter", "path": "twitter",
"owner_id": null, "kind": "group"
"created_at": "2016-06-17T07:47:24.216Z",
"updated_at": "2016-06-17T07:47:24.216Z",
"description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
"avatar": {
"url": null
},
"share_with_group_lock": false,
"visibility_level": 20
}, },
"avatar_url": null, "avatar_url": null,
"star_count": 0, "star_count": 0,
...@@ -237,15 +221,7 @@ Example response: ...@@ -237,15 +221,7 @@ Example response:
"id": 4, "id": 4,
"name": "Twitter", "name": "Twitter",
"path": "twitter", "path": "twitter",
"owner_id": null, "kind": "group"
"created_at": "2016-06-17T07:47:24.216Z",
"updated_at": "2016-06-17T07:47:24.216Z",
"description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
"avatar": {
"url": null
},
"share_with_group_lock": false,
"visibility_level": 20
}, },
"avatar_url": null, "avatar_url": null,
"star_count": 0, "star_count": 0,
...@@ -286,15 +262,7 @@ Example response: ...@@ -286,15 +262,7 @@ Example response:
"id": 5, "id": 5,
"name": "H5bp", "name": "H5bp",
"path": "h5bp", "path": "h5bp",
"owner_id": null, "kind": "group"
"created_at": "2016-06-17T07:47:26.621Z",
"updated_at": "2016-06-17T07:47:26.621Z",
"description": "Id consequatur rem vel qui doloremque saepe.",
"avatar": {
"url": null
},
"share_with_group_lock": false,
"visibility_level": 20
}, },
"avatar_url": null, "avatar_url": null,
"star_count": 0, "star_count": 0,
...@@ -416,15 +384,7 @@ Example response: ...@@ -416,15 +384,7 @@ Example response:
"id": 5, "id": 5,
"name": "Experimental", "name": "Experimental",
"path": "h5bp", "path": "h5bp",
"owner_id": null, "kind": "group"
"created_at": "2016-04-05T21:40:49.152Z",
"updated_at": "2016-04-07T08:07:48.466Z",
"description": "foo",
"avatar": {
"url": null
},
"share_with_group_lock": false,
"visibility_level": 10
}, },
"avatar_url": null, "avatar_url": null,
"star_count": 1, "star_count": 1,
......
...@@ -57,7 +57,7 @@ Once you have the authorization code you can request an `access_token` using the ...@@ -57,7 +57,7 @@ Once you have the authorization code you can request an `access_token` using the
``` ```
parameters = 'client_id=APP_ID&client_secret=APP_SECRET&code=RETURNED_CODE&grant_type=authorization_code&redirect_uri=REDIRECT_URI' parameters = 'client_id=APP_ID&client_secret=APP_SECRET&code=RETURNED_CODE&grant_type=authorization_code&redirect_uri=REDIRECT_URI'
RestClient.post 'http://localhost:3000/oauth/token', parameters RestClient.post 'http://gitlab.example.com/oauth/token', parameters
# The response will be # The response will be
{ {
...@@ -77,13 +77,13 @@ You can now make requests to the API with the access token returned. ...@@ -77,13 +77,13 @@ You can now make requests to the API with the access token returned.
The access token allows you to make requests to the API on a behalf of a user. The access token allows you to make requests to the API on a behalf of a user.
``` ```
GET https://localhost:3000/api/v3/user?access_token=OAUTH-TOKEN GET https://gitlab.example.com/api/v3/user?access_token=OAUTH-TOKEN
``` ```
Or you can put the token to the Authorization header: Or you can put the token to the Authorization header:
``` ```
curl --header "Authorization: Bearer OAUTH-TOKEN" https://localhost:3000/api/v3/user curl --header "Authorization: Bearer OAUTH-TOKEN" https://gitlab.example.com/api/v3/user
``` ```
## Resource Owner Password Credentials ## Resource Owner Password Credentials
......
...@@ -72,13 +72,10 @@ Parameters: ...@@ -72,13 +72,10 @@ Parameters:
"last_activity_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3, "creator_id": 3,
"namespace": { "namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
"id": 3, "id": 3,
"name": "Diaspora", "name": "Diaspora",
"owner_id": 1,
"path": "diaspora", "path": "diaspora",
"updated_at": "2013-09-30T13:46:02Z" "kind": "group"
}, },
"archived": false, "archived": false,
"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png", "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",
...@@ -125,13 +122,10 @@ Parameters: ...@@ -125,13 +122,10 @@ Parameters:
"last_activity_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3, "creator_id": 3,
"namespace": { "namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
"id": 4, "id": 4,
"name": "Brightbox", "name": "Brightbox",
"owner_id": 1,
"path": "brightbox", "path": "brightbox",
"updated_at": "2013-09-30T13:46:02Z" "kind": "group"
}, },
"permissions": { "permissions": {
"project_access": { "project_access": {
...@@ -210,13 +204,10 @@ Parameters: ...@@ -210,13 +204,10 @@ Parameters:
"last_activity_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3, "creator_id": 3,
"namespace": { "namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
"id": 3, "id": 3,
"name": "Diaspora", "name": "Diaspora",
"owner_id": 1,
"path": "diaspora", "path": "diaspora",
"updated_at": "2013-09-30T13:46:02Z" "kind": "group"
}, },
"archived": false, "archived": false,
"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png", "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",
...@@ -260,13 +251,10 @@ Parameters: ...@@ -260,13 +251,10 @@ Parameters:
"last_activity_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3, "creator_id": 3,
"namespace": { "namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
"id": 4, "id": 4,
"name": "Brightbox", "name": "Brightbox",
"owner_id": 1,
"path": "brightbox", "path": "brightbox",
"updated_at": "2013-09-30T13:46:02Z" "kind": "group"
}, },
"permissions": { "permissions": {
"project_access": { "project_access": {
...@@ -398,13 +386,10 @@ Parameters: ...@@ -398,13 +386,10 @@ Parameters:
"last_activity_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3, "creator_id": 3,
"namespace": { "namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
"id": 3, "id": 3,
"name": "Diaspora", "name": "Diaspora",
"owner_id": 1,
"path": "diaspora", "path": "diaspora",
"updated_at": "2013-09-30T13:46:02Z" "kind": "group"
}, },
"permissions": { "permissions": {
"project_access": { "project_access": {
...@@ -779,13 +764,10 @@ Example response: ...@@ -779,13 +764,10 @@ Example response:
"last_activity_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3, "creator_id": 3,
"namespace": { "namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
"id": 3, "id": 3,
"name": "Diaspora", "name": "Diaspora",
"owner_id": 1,
"path": "diaspora", "path": "diaspora",
"updated_at": "2013-09-30T13:46:02Z" "kind": "group"
}, },
"archived": true, "archived": true,
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
...@@ -847,13 +829,10 @@ Example response: ...@@ -847,13 +829,10 @@ Example response:
"last_activity_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3, "creator_id": 3,
"namespace": { "namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
"id": 3, "id": 3,
"name": "Diaspora", "name": "Diaspora",
"owner_id": 1,
"path": "diaspora", "path": "diaspora",
"updated_at": "2013-09-30T13:46:02Z" "kind": "group"
}, },
"archived": true, "archived": true,
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
...@@ -921,13 +900,10 @@ Example response: ...@@ -921,13 +900,10 @@ Example response:
"last_activity_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3, "creator_id": 3,
"namespace": { "namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
"id": 3, "id": 3,
"name": "Diaspora", "name": "Diaspora",
"owner_id": 1,
"path": "diaspora", "path": "diaspora",
"updated_at": "2013-09-30T13:46:02Z" "kind": "group"
}, },
"permissions": { "permissions": {
"project_access": { "project_access": {
...@@ -1006,13 +982,10 @@ Example response: ...@@ -1006,13 +982,10 @@ Example response:
"last_activity_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3, "creator_id": 3,
"namespace": { "namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
"id": 3, "id": 3,
"name": "Diaspora", "name": "Diaspora",
"owner_id": 1,
"path": "diaspora", "path": "diaspora",
"updated_at": "2013-09-30T13:46:02Z" "kind": "group"
}, },
"permissions": { "permissions": {
"project_access": { "project_access": {
......
@snippets
Feature: Snippets User
Background:
Given I sign in as a user
And I have public "Personal snippet one" snippet
And I have private "Personal snippet private" snippet
And I have internal "Personal snippet internal" snippet
Scenario: I should see all my snippets
Given I visit my snippets page
Then I should see "Personal snippet one" in snippets
And I should see "Personal snippet private" in snippets
And I should see "Personal snippet internal" in snippets
Scenario: I can see only my private snippets
Given I visit my snippets page
And I click "Private" filter
Then I should not see "Personal snippet one" in snippets
And I should not see "Personal snippet internal" in snippets
And I should see "Personal snippet private" in snippets
Scenario: I can see only my public snippets
Given I visit my snippets page
And I click "Public" filter
Then I should see "Personal snippet one" in snippets
And I should not see "Personal snippet private" in snippets
And I should not see "Personal snippet internal" in snippets
Scenario: I can see only my internal snippets
Given I visit my snippets page
And I click "Internal" filter
Then I should see "Personal snippet internal" in snippets
And I should not see "Personal snippet private" in snippets
And I should not see "Personal snippet one" in snippets
class Spinach::Features::SnippetsUser < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedSnippet
step 'I visit my snippets page' do
visit dashboard_snippets_path
end
step 'I should see "Personal snippet one" in snippets' do
expect(page).to have_content "Personal snippet one"
end
step 'I should see "Personal snippet private" in snippets' do
expect(page).to have_content "Personal snippet private"
end
step 'I should see "Personal snippet internal" in snippets' do
expect(page).to have_content "Personal snippet internal"
end
step 'I should not see "Personal snippet one" in snippets' do
expect(page).not_to have_content "Personal snippet one"
end
step 'I should not see "Personal snippet private" in snippets' do
expect(page).not_to have_content "Personal snippet private"
end
step 'I should not see "Personal snippet internal" in snippets' do
expect(page).not_to have_content "Personal snippet internal"
end
step 'I click "Internal" filter' do
page.within('.snippet-scope-menu') do
click_link "Internal"
end
end
step 'I click "Private" filter' do
page.within('.snippet-scope-menu') do
click_link "Private"
end
end
step 'I click "Public" filter' do
page.within('.snippet-scope-menu') do
click_link "Public"
end
end
def snippet
@snippet ||= PersonalSnippet.find_by!(title: "Personal snippet one")
end
end
...@@ -11,28 +11,27 @@ ...@@ -11,28 +11,27 @@
"webpack-prod": "NODE_ENV=production npm run webpack" "webpack-prod": "NODE_ENV=production npm run webpack"
}, },
"dependencies": { "dependencies": {
"babel": "^5.8.38", "babel-core": "^6.22.1",
"babel-core": "^5.8.38", "babel-loader": "^6.2.10",
"babel-loader": "^5.4.2", "babel-preset-es2015": "^6.22.0",
"babel-preset-stage-2": "^6.22.0",
"bootstrap-sass": "3.3.6", "bootstrap-sass": "3.3.6",
"compression-webpack-plugin": "^0.3.2", "compression-webpack-plugin": "^0.3.2",
"d3": "3.5.11", "d3": "3.5.11",
"dropzone": "4.2.0", "dropzone": "4.2.0",
"exports-loader": "^0.6.3",
"imports-loader": "^0.6.5", "imports-loader": "^0.6.5",
"jquery": "2.2.1", "jquery": "2.2.1",
"jquery-ui": "github:jquery/jquery-ui#1.11.4", "jquery-ui": "github:jquery/jquery-ui#1.11.4",
"jquery-ujs": "1.2.1", "jquery-ujs": "1.2.1",
"json-loader": "^0.5.4",
"mousetrap": "1.4.6", "mousetrap": "1.4.6",
"pikaday": "^1.5.1", "pikaday": "^1.5.1",
"select2": "3.5.2-browserify", "select2": "3.5.2-browserify",
"stats-webpack-plugin": "^0.4.2", "stats-webpack-plugin": "^0.4.3",
"underscore": "1.8.3", "underscore": "1.8.3",
"vue": "2.0.3", "vue": "2.0.3",
"vue-resource": "0.9.3", "vue-resource": "0.9.3",
"webpack": "^1.14.0", "webpack": "^2.2.1",
"webpack-dev-server": "^1.16.2" "webpack-dev-server": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^3.10.1", "eslint": "^3.10.1",
...@@ -43,10 +42,10 @@ ...@@ -43,10 +42,10 @@
"istanbul": "^0.4.5", "istanbul": "^0.4.5",
"jasmine-core": "^2.5.2", "jasmine-core": "^2.5.2",
"jasmine-jquery": "^2.1.1", "jasmine-jquery": "^2.1.1",
"karma": "^1.3.0", "karma": "^1.4.1",
"karma-jasmine": "^1.1.0", "karma-jasmine": "^1.1.0",
"karma-phantomjs-launcher": "^1.0.2", "karma-phantomjs-launcher": "^1.0.2",
"karma-sourcemap-loader": "^0.3.7", "karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^1.8.0" "karma-webpack": "^2.0.2"
} }
} }
module RuboCop module RuboCop
module Cop module Cop
# Cop that checks for all gems specified in the Gemfile, and will # This cop prevents usage of the `git` and `github` arguments to `gem` in a
# alert if any gem is to be fetched not from the RubyGems index. # `Gemfile` in order to avoid additional points of failure beyond
# This enforcement is done so as to minimize external build # rubygems.org.
# dependencies and build times.
class GemFetcher < RuboCop::Cop::Cop class GemFetcher < RuboCop::Cop::Cop
MSG = 'Do not use gems from git repositories, only use gems from RubyGems.' MSG = 'Do not use gems from git repositories, only use gems from RubyGems.'
GIT_KEYS = [:git, :github] GIT_KEYS = [:git, :github]
def on_send(node) def on_send(node)
file_path = node.location.expression.source_buffer.name return unless gemfile?(node)
return unless file_path.end_with?("Gemfile")
func_name = node.children[1] func_name = node.children[1]
return unless func_name == :gem return unless func_name == :gem
...@@ -19,10 +17,21 @@ module RuboCop ...@@ -19,10 +17,21 @@ module RuboCop
node.children.last.each_node(:pair) do |pair| node.children.last.each_node(:pair) do |pair|
key_name = pair.children[0].children[0].to_sym key_name = pair.children[0].children[0].to_sym
if GIT_KEYS.include?(key_name) if GIT_KEYS.include?(key_name)
add_offense(node, :selector) add_offense(node, pair.source_range, MSG)
end end
end end
end end
private
def gemfile?(node)
node
.location
.expression
.source_buffer
.name
.end_with?("Gemfile")
end
end end
end end
end end
require_relative 'cop/migration/add_index' require_relative 'cop/gem_fetcher'
require_relative 'cop/migration/add_column' require_relative 'cop/migration/add_column'
require_relative 'cop/migration/add_column_with_default' require_relative 'cop/migration/add_column_with_default'
require_relative 'cop/gem_fetcher' require_relative 'cop/migration/add_index'
...@@ -72,8 +72,8 @@ feature 'Expand and collapse diffs', js: true, feature: true do ...@@ -72,8 +72,8 @@ feature 'Expand and collapse diffs', js: true, feature: true do
it 'collapses large diffs for renamed files by default' do it 'collapses large diffs for renamed files by default' do
expect(large_diff_renamed).not_to have_selector('.code') expect(large_diff_renamed).not_to have_selector('.code')
expect(large_diff_renamed).to have_selector('.nothing-here-block') expect(large_diff_renamed).to have_selector('.nothing-here-block')
expect(large_diff_renamed).to have_selector('.file-title .deletion') expect(large_diff_renamed).to have_selector('.js-file-title .deletion')
expect(large_diff_renamed).to have_selector('.file-title .addition') expect(large_diff_renamed).to have_selector('.js-file-title .addition')
end end
it 'shows non-renderable diffs as such immediately, regardless of their size' do it 'shows non-renderable diffs as such immediately, regardless of their size' do
...@@ -115,9 +115,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do ...@@ -115,9 +115,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do
context 'expanding a large diff' do context 'expanding a large diff' do
before do before do
# Wait for diffs # Wait for diffs
find('.file-title', match: :first) find('.js-file-title', match: :first)
# Click `large_diff.md` title # Click `large_diff.md` title
all('.file-title')[1].click all('.diff-toggle-caret')[1].click
wait_for_ajax wait_for_ajax
end end
...@@ -159,9 +159,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do ...@@ -159,9 +159,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do
context 'expanding the diff' do context 'expanding the diff' do
before do before do
# Wait for diffs # Wait for diffs
find('.file-title', match: :first) find('.js-file-title', match: :first)
# Click `large_diff.md` title # Click `large_diff.md` title
all('.file-title')[1].click all('.diff-toggle-caret')[1].click
wait_for_ajax wait_for_ajax
end end
...@@ -181,9 +181,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do ...@@ -181,9 +181,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do
context 'collapsing an expanded diff' do context 'collapsing an expanded diff' do
before do before do
# Wait for diffs # Wait for diffs
find('.file-title', match: :first) find('.js-file-title', match: :first)
# Click `small_diff.md` title # Click `small_diff.md` title
all('.file-title')[3].click all('.diff-toggle-caret')[3].click
end end
it 'hides the diff content' do it 'hides the diff content' do
...@@ -194,9 +194,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do ...@@ -194,9 +194,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do
context 're-expanding the same diff' do context 're-expanding the same diff' do
before do before do
# Wait for diffs # Wait for diffs
find('.file-title', match: :first) find('.js-file-title', match: :first)
# Click `small_diff.md` title # Click `small_diff.md` title
all('.file-title')[3].click all('.diff-toggle-caret')[3].click
end end
it 'shows the diff content' do it 'shows the diff content' do
...@@ -290,9 +290,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do ...@@ -290,9 +290,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do
context 'collapsing an expanded diff' do context 'collapsing an expanded diff' do
before do before do
# Wait for diffs # Wait for diffs
find('.file-title', match: :first) find('.js-file-title', match: :first)
# Click `small_diff.md` title # Click `small_diff.md` title
all('.file-title')[3].click all('.diff-toggle-caret')[3].click
end end
it 'hides the diff content' do it 'hides the diff content' do
...@@ -303,9 +303,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do ...@@ -303,9 +303,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do
context 're-expanding the same diff' do context 're-expanding the same diff' do
before do before do
# Wait for diffs # Wait for diffs
find('.file-title', match: :first) find('.js-file-title', match: :first)
# Click `small_diff.md` title # Click `small_diff.md` title
all('.file-title')[3].click all('.diff-toggle-caret')[3].click
end end
it 'shows the diff content' do it 'shows the diff content' do
......
...@@ -22,7 +22,7 @@ feature 'Find file keyboard shortcuts', feature: true, js: true do ...@@ -22,7 +22,7 @@ feature 'Find file keyboard shortcuts', feature: true, js: true do
expect(page).to have_selector('.blob-content-holder') expect(page).to have_selector('.blob-content-holder')
page.within('.file-title') do page.within('.js-file-title') do
expect(page).to have_content('CHANGELOG') expect(page).to have_content('CHANGELOG')
end end
end end
...@@ -35,7 +35,7 @@ feature 'Find file keyboard shortcuts', feature: true, js: true do ...@@ -35,7 +35,7 @@ feature 'Find file keyboard shortcuts', feature: true, js: true do
expect(page).to have_selector('.blob-content-holder') expect(page).to have_selector('.blob-content-holder')
page.within('.file-title') do page.within('.js-file-title') do
expect(page).to have_content('application.js') expect(page).to have_content('application.js')
end end
end end
......
...@@ -26,7 +26,11 @@ RSpec.shared_examples "protected branches > access control > CE" do ...@@ -26,7 +26,11 @@ RSpec.shared_examples "protected branches > access control > CE" do
within(".protected-branches-list") do within(".protected-branches-list") do
find(".js-allowed-to-push").click find(".js-allowed-to-push").click
within('.js-allowed-to-push-container') { click_on access_type_name }
within('.js-allowed-to-push-container') do
expect(first("li")).to have_content("Roles")
click_on access_type_name
end
end end
wait_for_ajax wait_for_ajax
...@@ -61,7 +65,11 @@ RSpec.shared_examples "protected branches > access control > CE" do ...@@ -61,7 +65,11 @@ RSpec.shared_examples "protected branches > access control > CE" do
within(".protected-branches-list") do within(".protected-branches-list") do
find(".js-allowed-to-merge").click find(".js-allowed-to-merge").click
within('.js-allowed-to-merge-container') { click_on access_type_name }
within('.js-allowed-to-merge-container') do
expect(first("li")).to have_content("Roles")
click_on access_type_name
end
end end
wait_for_ajax wait_for_ajax
......
require 'rails_helper'
feature 'User Snippets', feature: true do
let(:author) { create(:user) }
let!(:public_snippet) { create(:personal_snippet, :public, author: author, title: "This is a public snippet") }
let!(:internal_snippet) { create(:personal_snippet, :internal, author: author, title: "This is an internal snippet") }
let!(:private_snippet) { create(:personal_snippet, :private, author: author, title: "This is a private snippet") }
background do
login_as author
visit dashboard_snippets_path
end
scenario 'View all of my snippets' do
expect(page).to have_content(public_snippet.title)
expect(page).to have_content(internal_snippet.title)
expect(page).to have_content(private_snippet.title)
end
scenario 'View my public snippets' do
page.within('.snippet-scope-menu') do
click_link "Public"
end
expect(page).to have_content(public_snippet.title)
expect(page).not_to have_content(internal_snippet.title)
expect(page).not_to have_content(private_snippet.title)
end
scenario 'View my internal snippets' do
page.within('.snippet-scope-menu') do
click_link "Internal"
end
expect(page).not_to have_content(public_snippet.title)
expect(page).to have_content(internal_snippet.title)
expect(page).not_to have_content(private_snippet.title)
end
scenario 'View my private snippets' do
page.within('.snippet-scope-menu') do
click_link "Private"
end
expect(page).not_to have_content(public_snippet.title)
expect(page).not_to have_content(internal_snippet.title)
expect(page).to have_content(private_snippet.title)
end
end
...@@ -9,7 +9,7 @@ require('~/filtered_search/dropdown_user'); ...@@ -9,7 +9,7 @@ require('~/filtered_search/dropdown_user');
let dropdownUser; let dropdownUser;
beforeEach(() => { beforeEach(() => {
spyOn(gl.FilteredSearchDropdown.prototype, 'constructor').and.callFake(() => {}); spyOn(gl.DropdownUser.prototype, 'bindEvents').and.callFake(() => {});
spyOn(gl.DropdownUser.prototype, 'getProjectId').and.callFake(() => {}); spyOn(gl.DropdownUser.prototype, 'getProjectId').and.callFake(() => {});
spyOn(gl.DropdownUtils, 'getSearchInput').and.callFake(() => {}); spyOn(gl.DropdownUtils, 'getSearchInput').and.callFake(() => {});
...@@ -39,7 +39,7 @@ require('~/filtered_search/dropdown_user'); ...@@ -39,7 +39,7 @@ require('~/filtered_search/dropdown_user');
describe('config droplabAjaxFilter\'s endpoint', () => { describe('config droplabAjaxFilter\'s endpoint', () => {
beforeEach(() => { beforeEach(() => {
spyOn(gl.FilteredSearchDropdown.prototype, 'constructor').and.callFake(() => {}); spyOn(gl.DropdownUser.prototype, 'bindEvents').and.callFake(() => {});
spyOn(gl.DropdownUser.prototype, 'getProjectId').and.callFake(() => {}); spyOn(gl.DropdownUser.prototype, 'getProjectId').and.callFake(() => {});
}); });
......
require 'spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
require_relative '../../../rubocop/cop/gem_fetcher'
describe RuboCop::Cop::GemFetcher do
include CopHelper
subject(:cop) { described_class.new }
context 'in Gemfile' do
before do
allow(cop).to receive(:gemfile?).and_return(true)
end
it 'registers an offense when a gem uses `git`' do
inspect_source(cop, 'gem "foo", git: "https://gitlab.com/foo/bar.git"')
aggregate_failures do
expect(cop.offenses.size).to eq(1)
expect(cop.offenses.map(&:line)).to eq([1])
expect(cop.highlights).to eq(['git: "https://gitlab.com/foo/bar.git"'])
end
end
it 'registers an offense when a gem uses `github`' do
inspect_source(cop, 'gem "foo", github: "foo/bar.git"')
aggregate_failures do
expect(cop.offenses.size).to eq(1)
expect(cop.offenses.map(&:line)).to eq([1])
expect(cop.highlights).to eq(['github: "foo/bar.git"'])
end
end
end
context 'outside of Gemfile' do
it 'registers no offense' do
inspect_source(cop, 'gem "foo", git: "https://gitlab.com/foo/bar.git"')
expect(cop.offenses.size).to eq(0)
end
end
end
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