Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
fd5fdb2c
Commit
fd5fdb2c
authored
May 17, 2018
by
Clement Ho
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into bootstrap4
parents
42189e91
ec7163ae
Changes
53
Show whitespace changes
Inline
Side-by-side
Showing
53 changed files
with
613 additions
and
252 deletions
+613
-252
.gitlab-ci.yml
.gitlab-ci.yml
+3
-3
app/assets/javascripts/notes/components/note_header.vue
app/assets/javascripts/notes/components/note_header.vue
+4
-1
app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js
...ges/projects/graphs/show/stat_graph_contributors_graph.js
+36
-18
app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
...ts/javascripts/vue_shared/components/time_ago_tooltip.vue
+2
-2
app/assets/stylesheets/pages/boards.scss
app/assets/stylesheets/pages/boards.scss
+0
-2
app/assets/stylesheets/pages/issues.scss
app/assets/stylesheets/pages/issues.scss
+0
-2
app/assets/stylesheets/pages/notes.scss
app/assets/stylesheets/pages/notes.scss
+4
-0
app/controllers/admin/dashboard_controller.rb
app/controllers/admin/dashboard_controller.rb
+2
-0
app/controllers/concerns/accepts_pending_invitations.rb
app/controllers/concerns/accepts_pending_invitations.rb
+15
-0
app/controllers/confirmations_controller.rb
app/controllers/confirmations_controller.rb
+4
-0
app/controllers/projects/commit_controller.rb
app/controllers/projects/commit_controller.rb
+6
-2
app/controllers/projects/settings/ci_cd_controller.rb
app/controllers/projects/settings/ci_cd_controller.rb
+1
-1
app/controllers/registrations_controller.rb
app/controllers/registrations_controller.rb
+3
-1
app/helpers/count_helper.rb
app/helpers/count_helper.rb
+5
-0
app/models/appearance.rb
app/models/appearance.rb
+1
-2
app/models/ci/runner.rb
app/models/ci/runner.rb
+1
-1
app/models/concerns/with_uploads.rb
app/models/concerns/with_uploads.rb
+39
-0
app/models/group.rb
app/models/group.rb
+1
-2
app/models/project.rb
app/models/project.rb
+1
-2
app/models/user.rb
app/models/user.rb
+27
-5
app/policies/ci/runner_policy.rb
app/policies/ci/runner_policy.rb
+9
-6
app/views/admin/dashboard/index.html.haml
app/views/admin/dashboard/index.html.haml
+10
-10
app/views/notify/member_invited_email.html.haml
app/views/notify/member_invited_email.html.haml
+1
-1
app/views/shared/notes/_note.html.haml
app/views/shared/notes/_note.html.haml
+3
-2
changelogs/unreleased/22647-width-contributors-graphs.yml
changelogs/unreleased/22647-width-contributors-graphs.yml
+5
-0
changelogs/unreleased/42531-open-invite-404.yml
changelogs/unreleased/42531-open-invite-404.yml
+5
-0
changelogs/unreleased/jivl-add-dot-system-notes.yml
changelogs/unreleased/jivl-add-dot-system-notes.yml
+5
-0
changelogs/unreleased/jprovazn-remote-upload-destroy.yml
changelogs/unreleased/jprovazn-remote-upload-destroy.yml
+5
-0
changelogs/unreleased/zj-workhorse-commit-patch-diff.yml
changelogs/unreleased/zj-workhorse-commit-patch-diff.yml
+5
-0
lib/api/groups.rb
lib/api/groups.rb
+1
-0
lib/api/runners.rb
lib/api/runners.rb
+9
-14
lib/api/v3/groups.rb
lib/api/v3/groups.rb
+1
-0
lib/api/v3/runners.rb
lib/api/v3/runners.rb
+1
-1
lib/gitlab/database/count.rb
lib/gitlab/database/count.rb
+48
-0
lib/gitlab/git/commit.rb
lib/gitlab/git/commit.rb
+0
-25
scripts/create_mysql_user.sh
scripts/create_mysql_user.sh
+0
-1
scripts/create_postgres_user.sh
scripts/create_postgres_user.sh
+1
-3
scripts/prepare_build.sh
scripts/prepare_build.sh
+3
-15
scripts/utils.sh
scripts/utils.sh
+18
-0
spec/controllers/projects/commit_controller_spec.rb
spec/controllers/projects/commit_controller_spec.rb
+5
-28
spec/controllers/projects/settings/ci_cd_controller_spec.rb
spec/controllers/projects/settings/ci_cd_controller_spec.rb
+3
-3
spec/features/invites_spec.rb
spec/features/invites_spec.rb
+100
-12
spec/lib/gitlab/database/count_spec.rb
spec/lib/gitlab/database/count_spec.rb
+62
-0
spec/lib/gitlab/git/commit_spec.rb
spec/lib/gitlab/git/commit_spec.rb
+0
-14
spec/mailers/notify_spec.rb
spec/mailers/notify_spec.rb
+1
-1
spec/models/appearance_spec.rb
spec/models/appearance_spec.rb
+9
-1
spec/models/ci/runner_spec.rb
spec/models/ci/runner_spec.rb
+13
-49
spec/models/commit_spec.rb
spec/models/commit_spec.rb
+0
-1
spec/models/group_spec.rb
spec/models/group_spec.rb
+9
-1
spec/models/project_spec.rb
spec/models/project_spec.rb
+9
-1
spec/models/user_spec.rb
spec/models/user_spec.rb
+83
-17
spec/requests/api/runners_spec.rb
spec/requests/api/runners_spec.rb
+11
-2
spec/support/shared_examples/models/with_uploads_shared_examples.rb
...rt/shared_examples/models/with_uploads_shared_examples.rb
+23
-0
No files found.
.gitlab-ci.yml
View file @
fd5fdb2c
...
@@ -189,7 +189,7 @@ stages:
...
@@ -189,7 +189,7 @@ stages:
<<
:
*dedicated-no-docs-and-no-qa-pull-cache-job
<<
:
*dedicated-no-docs-and-no-qa-pull-cache-job
<<
:
*use-pg
<<
:
*use-pg
variables
:
variables
:
CREATE_DB_USER
:
"
tru
e"
SETUP_DB
:
"
fals
e"
script
:
script
:
# Manually clone gitlab-test and only seed this project in
# Manually clone gitlab-test and only seed this project in
# db/fixtures/development/04_project.rb thanks to SIZE=1 below
# db/fixtures/development/04_project.rb thanks to SIZE=1 below
...
@@ -233,7 +233,7 @@ stages:
...
@@ -233,7 +233,7 @@ stages:
.migration-paths
:
&migration-paths
.migration-paths
:
&migration-paths
<<
:
*dedicated-no-docs-and-no-qa-pull-cache-job
<<
:
*dedicated-no-docs-and-no-qa-pull-cache-job
variables
:
variables
:
CREATE_DB_USER
:
"
tru
e"
SETUP_DB
:
"
fals
e"
script
:
script
:
-
git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v9.3.0
-
git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v9.3.0
-
git checkout -f FETCH_HEAD
-
git checkout -f FETCH_HEAD
...
@@ -242,7 +242,7 @@ stages:
...
@@ -242,7 +242,7 @@ stages:
-
cp config/gitlab.yml.example config/gitlab.yml
-
cp config/gitlab.yml.example config/gitlab.yml
-
bundle exec rake db:drop db:create db:schema:load db:seed_fu
-
bundle exec rake db:drop db:create db:schema:load db:seed_fu
-
date
-
date
-
git checkout $CI_COMMIT_SHA
-
git checkout
-f
$CI_COMMIT_SHA
-
bundle install $BUNDLE_INSTALL_FLAGS
-
bundle install $BUNDLE_INSTALL_FLAGS
-
date
-
date
-
. scripts/prepare_build.sh
-
. scripts/prepare_build.sh
...
...
app/assets/javascripts/notes/components/note_header.vue
View file @
fd5fdb2c
...
@@ -93,10 +93,13 @@ export default {
...
@@ -93,10 +93,13 @@ export default {
v-html=
"actionTextHtml"
v-html=
"actionTextHtml"
class=
"system-note-message"
>
class=
"system-note-message"
>
</span>
</span>
<span
class=
"system-note-separator"
>
·
</span>
<a
<a
:href=
"noteTimestampLink"
:href=
"noteTimestampLink"
@
click=
"updateTargetNoteHash"
@
click=
"updateTargetNoteHash"
class=
"note-timestamp"
>
class=
"note-timestamp
system-note-separator
"
>
<time-ago-tooltip
<time-ago-tooltip
:time=
"createdAt"
:time=
"createdAt"
tooltip-placement=
"bottom"
tooltip-placement=
"bottom"
...
...
app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js
View file @
fd5fdb2c
/* eslint-disable func-names, space-before-function-paren,
no-var,
prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return, no-shadow */
/* eslint-disable func-names, space-before-function-paren, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return, no-shadow */
import
$
from
'
jquery
'
;
import
$
from
'
jquery
'
;
import
_
from
'
underscore
'
;
import
_
from
'
underscore
'
;
...
@@ -13,17 +13,17 @@ import { dateTickFormat } from '~/lib/utils/tick_formats';
...
@@ -13,17 +13,17 @@ import { dateTickFormat } from '~/lib/utils/tick_formats';
const
d3
=
{
extent
,
max
,
select
,
scaleTime
,
scaleLinear
,
axisLeft
,
axisBottom
,
area
,
brushX
,
timeParse
};
const
d3
=
{
extent
,
max
,
select
,
scaleTime
,
scaleLinear
,
axisLeft
,
axisBottom
,
area
,
brushX
,
timeParse
};
const
extend
=
function
(
child
,
parent
)
{
for
(
var
key
in
parent
)
{
if
(
hasProp
.
call
(
parent
,
key
))
child
[
key
]
=
parent
[
key
];
}
function
ctor
()
{
this
.
constructor
=
child
;
}
ctor
.
prototype
=
parent
.
prototype
;
child
.
prototype
=
new
ctor
();
child
.
__super__
=
parent
.
prototype
;
return
child
;
};
const
hasProp
=
{}.
hasOwnProperty
;
const
hasProp
=
{}.
hasOwnProperty
;
const
extend
=
function
(
child
,
parent
)
{
for
(
const
key
in
parent
)
{
if
(
hasProp
.
call
(
parent
,
key
))
child
[
key
]
=
parent
[
key
];
}
function
ctor
()
{
this
.
constructor
=
child
;
}
ctor
.
prototype
=
parent
.
prototype
;
child
.
prototype
=
new
ctor
();
child
.
__super__
=
parent
.
prototype
;
return
child
;
};
export
const
ContributorsGraph
=
(
function
()
{
export
const
ContributorsGraph
=
(
function
()
{
function
ContributorsGraph
()
{}
function
ContributorsGraph
()
{}
ContributorsGraph
.
prototype
.
MARGIN
=
{
ContributorsGraph
.
prototype
.
MARGIN
=
{
top
:
20
,
top
:
20
,
right
:
2
0
,
right
:
1
0
,
bottom
:
30
,
bottom
:
30
,
left
:
5
0
left
:
4
0
};
};
ContributorsGraph
.
prototype
.
x_domain
=
null
;
ContributorsGraph
.
prototype
.
x_domain
=
null
;
...
@@ -32,6 +32,12 @@ export const ContributorsGraph = (function() {
...
@@ -32,6 +32,12 @@ export const ContributorsGraph = (function() {
ContributorsGraph
.
prototype
.
dates
=
[];
ContributorsGraph
.
prototype
.
dates
=
[];
ContributorsGraph
.
prototype
.
determine_width
=
function
(
baseWidth
,
$parentElement
)
{
const
parentPaddingWidth
=
parseFloat
(
$parentElement
.
css
(
'
padding-left
'
))
+
parseFloat
(
$parentElement
.
css
(
'
padding-right
'
));
const
marginWidth
=
this
.
MARGIN
.
left
+
this
.
MARGIN
.
right
;
return
baseWidth
-
parentPaddingWidth
-
marginWidth
;
};
ContributorsGraph
.
set_x_domain
=
function
(
data
)
{
ContributorsGraph
.
set_x_domain
=
function
(
data
)
{
return
ContributorsGraph
.
prototype
.
x_domain
=
data
;
return
ContributorsGraph
.
prototype
.
x_domain
=
data
;
};
};
...
@@ -105,11 +111,10 @@ export const ContributorsMasterGraph = (function(superClass) {
...
@@ -105,11 +111,10 @@ export const ContributorsMasterGraph = (function(superClass) {
function
ContributorsMasterGraph
(
data1
)
{
function
ContributorsMasterGraph
(
data1
)
{
const
$parentElement
=
$
(
'
#contributors-master
'
);
const
$parentElement
=
$
(
'
#contributors-master
'
);
const
parentPadding
=
parseFloat
(
$parentElement
.
css
(
'
padding-left
'
))
+
parseFloat
(
$parentElement
.
css
(
'
padding-right
'
));
this
.
data
=
data1
;
this
.
data
=
data1
;
this
.
update_content
=
this
.
update_content
.
bind
(
this
);
this
.
update_content
=
this
.
update_content
.
bind
(
this
);
this
.
width
=
$
(
'
.content
'
).
width
()
-
parentPadding
-
(
this
.
MARGIN
.
left
+
this
.
MARGIN
.
righ
t
);
this
.
width
=
this
.
determine_width
(
$
(
'
.js-graphs-show
'
).
width
(),
$parentElemen
t
);
this
.
height
=
200
;
this
.
height
=
200
;
this
.
x
=
null
;
this
.
x
=
null
;
this
.
y
=
null
;
this
.
y
=
null
;
...
@@ -122,8 +127,7 @@ export const ContributorsMasterGraph = (function(superClass) {
...
@@ -122,8 +127,7 @@ export const ContributorsMasterGraph = (function(superClass) {
}
}
ContributorsMasterGraph
.
prototype
.
process_dates
=
function
(
data
)
{
ContributorsMasterGraph
.
prototype
.
process_dates
=
function
(
data
)
{
var
dates
;
const
dates
=
this
.
get_dates
(
data
);
dates
=
this
.
get_dates
(
data
);
this
.
parse_dates
(
data
);
this
.
parse_dates
(
data
);
return
ContributorsGraph
.
set_dates
(
dates
);
return
ContributorsGraph
.
set_dates
(
dates
);
};
};
...
@@ -133,8 +137,7 @@ export const ContributorsMasterGraph = (function(superClass) {
...
@@ -133,8 +137,7 @@ export const ContributorsMasterGraph = (function(superClass) {
};
};
ContributorsMasterGraph
.
prototype
.
parse_dates
=
function
(
data
)
{
ContributorsMasterGraph
.
prototype
.
parse_dates
=
function
(
data
)
{
var
parseDate
;
const
parseDate
=
d3
.
timeParse
(
"
%Y-%m-%d
"
);
parseDate
=
d3
.
timeParse
(
"
%Y-%m-%d
"
);
return
data
.
forEach
(
function
(
d
)
{
return
data
.
forEach
(
function
(
d
)
{
return
d
.
date
=
parseDate
(
d
.
date
);
return
d
.
date
=
parseDate
(
d
.
date
);
});
});
...
@@ -152,7 +155,14 @@ export const ContributorsMasterGraph = (function(superClass) {
...
@@ -152,7 +155,14 @@ export const ContributorsMasterGraph = (function(superClass) {
};
};
ContributorsMasterGraph
.
prototype
.
create_svg
=
function
()
{
ContributorsMasterGraph
.
prototype
.
create_svg
=
function
()
{
return
this
.
svg
=
d3
.
select
(
"
#contributors-master
"
).
append
(
"
svg
"
).
attr
(
"
width
"
,
this
.
width
+
this
.
MARGIN
.
left
+
this
.
MARGIN
.
right
).
attr
(
"
height
"
,
this
.
height
+
this
.
MARGIN
.
top
+
this
.
MARGIN
.
bottom
).
attr
(
"
class
"
,
"
tint-box
"
).
append
(
"
g
"
).
attr
(
"
transform
"
,
"
translate(
"
+
this
.
MARGIN
.
left
+
"
,
"
+
this
.
MARGIN
.
top
+
"
)
"
);
this
.
svg
=
d3
.
select
(
"
#contributors-master
"
)
.
append
(
"
svg
"
)
.
attr
(
"
width
"
,
this
.
width
+
this
.
MARGIN
.
left
+
this
.
MARGIN
.
right
)
.
attr
(
"
height
"
,
this
.
height
+
this
.
MARGIN
.
top
+
this
.
MARGIN
.
bottom
)
.
attr
(
"
class
"
,
"
tint-box
"
)
.
append
(
"
g
"
)
.
attr
(
"
transform
"
,
"
translate(
"
+
this
.
MARGIN
.
left
+
"
,
"
+
this
.
MARGIN
.
top
+
"
)
"
);
return
this
.
svg
;
};
};
ContributorsMasterGraph
.
prototype
.
create_area
=
function
(
x
,
y
)
{
ContributorsMasterGraph
.
prototype
.
create_area
=
function
(
x
,
y
)
{
...
@@ -218,12 +228,14 @@ export const ContributorsAuthorGraph = (function(superClass) {
...
@@ -218,12 +228,14 @@ export const ContributorsAuthorGraph = (function(superClass) {
extend
(
ContributorsAuthorGraph
,
superClass
);
extend
(
ContributorsAuthorGraph
,
superClass
);
function
ContributorsAuthorGraph
(
data1
)
{
function
ContributorsAuthorGraph
(
data1
)
{
const
$parentElements
=
$
(
'
.person
'
);
this
.
data
=
data1
;
this
.
data
=
data1
;
// Don't split graph size in half for mobile devices.
// Don't split graph size in half for mobile devices.
if
(
$
(
window
).
width
()
<
7
68
)
{
if
(
$
(
window
).
width
()
<
7
90
)
{
this
.
width
=
$
(
'
.content
'
).
width
()
-
80
;
this
.
width
=
this
.
determine_width
(
$
(
'
.js-graphs-show
'
).
width
(),
$parentElements
)
;
}
else
{
}
else
{
this
.
width
=
(
$
(
'
.content
'
).
width
()
/
2
)
-
100
;
this
.
width
=
this
.
determine_width
(
$
(
'
.js-graphs-show
'
).
width
()
/
2
,
$parentElements
)
;
}
}
this
.
height
=
200
;
this
.
height
=
200
;
this
.
x
=
null
;
this
.
x
=
null
;
...
@@ -249,8 +261,7 @@ export const ContributorsAuthorGraph = (function(superClass) {
...
@@ -249,8 +261,7 @@ export const ContributorsAuthorGraph = (function(superClass) {
ContributorsAuthorGraph
.
prototype
.
create_area
=
function
(
x
,
y
)
{
ContributorsAuthorGraph
.
prototype
.
create_area
=
function
(
x
,
y
)
{
return
this
.
area
=
d3
.
area
().
x
(
function
(
d
)
{
return
this
.
area
=
d3
.
area
().
x
(
function
(
d
)
{
var
parseDate
;
const
parseDate
=
d3
.
timeParse
(
"
%Y-%m-%d
"
);
parseDate
=
d3
.
timeParse
(
"
%Y-%m-%d
"
);
return
x
(
parseDate
(
d
));
return
x
(
parseDate
(
d
));
}).
y0
(
this
.
height
).
y1
((
function
(
_this
)
{
}).
y0
(
this
.
height
).
y1
((
function
(
_this
)
{
return
function
(
d
)
{
return
function
(
d
)
{
...
@@ -264,9 +275,16 @@ export const ContributorsAuthorGraph = (function(superClass) {
...
@@ -264,9 +275,16 @@ export const ContributorsAuthorGraph = (function(superClass) {
};
};
ContributorsAuthorGraph
.
prototype
.
create_svg
=
function
()
{
ContributorsAuthorGraph
.
prototype
.
create_svg
=
function
()
{
var
persons
=
document
.
querySelectorAll
(
'
.person
'
);
const
persons
=
document
.
querySelectorAll
(
'
.person
'
);
this
.
list_item
=
persons
[
persons
.
length
-
1
];
this
.
list_item
=
persons
[
persons
.
length
-
1
];
return
this
.
svg
=
d3
.
select
(
this
.
list_item
).
append
(
"
svg
"
).
attr
(
"
width
"
,
this
.
width
+
this
.
MARGIN
.
left
+
this
.
MARGIN
.
right
).
attr
(
"
height
"
,
this
.
height
+
this
.
MARGIN
.
top
+
this
.
MARGIN
.
bottom
).
attr
(
"
class
"
,
"
spark
"
).
append
(
"
g
"
).
attr
(
"
transform
"
,
"
translate(
"
+
this
.
MARGIN
.
left
+
"
,
"
+
this
.
MARGIN
.
top
+
"
)
"
);
this
.
svg
=
d3
.
select
(
this
.
list_item
)
.
append
(
"
svg
"
)
.
attr
(
"
width
"
,
this
.
width
+
this
.
MARGIN
.
left
+
this
.
MARGIN
.
right
)
.
attr
(
"
height
"
,
this
.
height
+
this
.
MARGIN
.
top
+
this
.
MARGIN
.
bottom
)
.
attr
(
"
class
"
,
"
spark
"
)
.
append
(
"
g
"
)
.
attr
(
"
transform
"
,
"
translate(
"
+
this
.
MARGIN
.
left
+
"
,
"
+
this
.
MARGIN
.
top
+
"
)
"
);
return
this
.
svg
;
};
};
ContributorsAuthorGraph
.
prototype
.
draw_path
=
function
(
data
)
{
ContributorsAuthorGraph
.
prototype
.
draw_path
=
function
(
data
)
{
...
...
app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
View file @
fd5fdb2c
...
@@ -40,7 +40,7 @@ export default {
...
@@ -40,7 +40,7 @@ export default {
:class=
"cssClass"
:class=
"cssClass"
:title=
"tooltipTitle(time)"
:title=
"tooltipTitle(time)"
:data-placement=
"tooltipPlacement"
:data-placement=
"tooltipPlacement"
data-container=
"body"
>
data-container=
"body"
{{
timeFormated
(
time
)
}}
v-text=
"timeFormated(time)"
>
</time>
</time>
</
template
>
</
template
>
app/assets/stylesheets/pages/boards.scss
View file @
fd5fdb2c
@import
'./issues/issue_count_badge'
;
[
v-cloak
]
{
[
v-cloak
]
{
display
:
none
;
display
:
none
;
}
}
...
...
app/assets/stylesheets/pages/issues.scss
View file @
fd5fdb2c
@import
"./issues/issue_count_badge"
;
.issues-list
{
.issues-list
{
.issue
{
.issue
{
padding
:
10px
0
10px
$gl-padding
;
padding
:
10px
0
10px
$gl-padding
;
...
...
app/assets/stylesheets/pages/notes.scss
View file @
fd5fdb2c
...
@@ -455,6 +455,10 @@ ul.notes {
...
@@ -455,6 +455,10 @@ ul.notes {
white-space
:
normal
;
white-space
:
normal
;
}
}
.system-note-separator
{
color
:
$gl-text-color-disabled
;
}
a
:hover
{
a
:hover
{
text-decoration
:
underline
;
text-decoration
:
underline
;
}
}
...
...
app/controllers/admin/dashboard_controller.rb
View file @
fd5fdb2c
class
Admin::DashboardController
<
Admin
::
ApplicationController
class
Admin::DashboardController
<
Admin
::
ApplicationController
include
CountHelper
def
index
def
index
@projects
=
Project
.
order_id_desc
.
without_deleted
.
with_route
.
limit
(
10
)
@projects
=
Project
.
order_id_desc
.
without_deleted
.
with_route
.
limit
(
10
)
@users
=
User
.
order_id_desc
.
limit
(
10
)
@users
=
User
.
order_id_desc
.
limit
(
10
)
...
...
app/controllers/concerns/accepts_pending_invitations.rb
0 → 100644
View file @
fd5fdb2c
module
AcceptsPendingInvitations
extend
ActiveSupport
::
Concern
def
accept_pending_invitations
return
unless
resource
.
active_for_authentication?
clear_stored_location_for_resource
if
resource
.
accept_pending_invitations!
.
any?
end
def
clear_stored_location_for_resource
session_key
=
stored_location_key_for
(
resource
)
session
.
delete
(
session_key
)
end
end
app/controllers/confirmations_controller.rb
View file @
fd5fdb2c
class
ConfirmationsController
<
Devise
::
ConfirmationsController
class
ConfirmationsController
<
Devise
::
ConfirmationsController
include
AcceptsPendingInvitations
def
almost_there
def
almost_there
flash
[
:notice
]
=
nil
flash
[
:notice
]
=
nil
render
layout:
"devise_empty"
render
layout:
"devise_empty"
...
@@ -11,6 +13,8 @@ class ConfirmationsController < Devise::ConfirmationsController
...
@@ -11,6 +13,8 @@ class ConfirmationsController < Devise::ConfirmationsController
end
end
def
after_confirmation_path_for
(
resource_name
,
resource
)
def
after_confirmation_path_for
(
resource_name
,
resource
)
accept_pending_invitations
# incoming resource can either be a :user or an :email
# incoming resource can either be a :user or an :email
if
signed_in?
(
:user
)
if
signed_in?
(
:user
)
after_sign_in
(
resource
)
after_sign_in
(
resource
)
...
...
app/controllers/projects/commit_controller.rb
View file @
fd5fdb2c
...
@@ -23,8 +23,12 @@ class Projects::CommitController < Projects::ApplicationController
...
@@ -23,8 +23,12 @@ class Projects::CommitController < Projects::ApplicationController
respond_to
do
|
format
|
respond_to
do
|
format
|
format
.
html
{
render
}
format
.
html
{
render
}
format
.
diff
{
render
text:
@commit
.
to_diff
}
format
.
diff
do
format
.
patch
{
render
text:
@commit
.
to_patch
}
send_git_diff
(
@project
.
repository
,
@commit
.
diff_refs
)
end
format
.
patch
do
send_git_patch
(
@project
.
repository
,
@commit
.
diff_refs
)
end
end
end
end
end
...
...
app/controllers/projects/settings/ci_cd_controller.rb
View file @
fd5fdb2c
...
@@ -69,7 +69,7 @@ module Projects
...
@@ -69,7 +69,7 @@ module Projects
@project_runners
=
@project
.
runners
.
ordered
@project_runners
=
@project
.
runners
.
ordered
@assignable_runners
=
current_user
@assignable_runners
=
current_user
.
ci_
authoriz
ed_runners
.
ci_
own
ed_runners
.
assignable_for
(
project
)
.
assignable_for
(
project
)
.
ordered
.
ordered
.
page
(
params
[
:page
]).
per
(
20
)
.
page
(
params
[
:page
]).
per
(
20
)
...
...
app/controllers/registrations_controller.rb
View file @
fd5fdb2c
class
RegistrationsController
<
Devise
::
RegistrationsController
class
RegistrationsController
<
Devise
::
RegistrationsController
include
Recaptcha
::
Verify
include
Recaptcha
::
Verify
include
AcceptsPendingInvitations
before_action
:whitelist_query_limiting
,
only:
[
:destroy
]
before_action
:whitelist_query_limiting
,
only:
[
:destroy
]
...
@@ -16,6 +17,7 @@ class RegistrationsController < Devise::RegistrationsController
...
@@ -16,6 +17,7 @@ class RegistrationsController < Devise::RegistrationsController
end
end
if
!
Gitlab
::
Recaptcha
.
load_configurations!
||
verify_recaptcha
if
!
Gitlab
::
Recaptcha
.
load_configurations!
||
verify_recaptcha
accept_pending_invitations
super
super
else
else
flash
[
:alert
]
=
'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
flash
[
:alert
]
=
'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
...
@@ -60,7 +62,7 @@ class RegistrationsController < Devise::RegistrationsController
...
@@ -60,7 +62,7 @@ class RegistrationsController < Devise::RegistrationsController
def
after_sign_up_path_for
(
user
)
def
after_sign_up_path_for
(
user
)
Gitlab
::
AppLogger
.
info
(
"User Created: username=
#{
user
.
username
}
email=
#{
user
.
email
}
ip=
#{
request
.
remote_ip
}
confirmed:
#{
user
.
confirmed?
}
"
)
Gitlab
::
AppLogger
.
info
(
"User Created: username=
#{
user
.
username
}
email=
#{
user
.
email
}
ip=
#{
request
.
remote_ip
}
confirmed:
#{
user
.
confirmed?
}
"
)
user
.
confirmed?
?
dashboard_projects_path
:
users_almost_there_path
user
.
confirmed?
?
stored_location_for
(
user
)
||
dashboard_projects_path
:
users_almost_there_path
end
end
def
after_inactive_sign_up_path_for
(
resource
)
def
after_inactive_sign_up_path_for
(
resource
)
...
...
app/helpers/count_helper.rb
0 → 100644
View file @
fd5fdb2c
module
CountHelper
def
approximate_count_with_delimiters
(
model
)
number_with_delimiter
(
Gitlab
::
Database
::
Count
.
approximate_count
(
model
))
end
end
app/models/appearance.rb
View file @
fd5fdb2c
...
@@ -2,6 +2,7 @@ class Appearance < ActiveRecord::Base
...
@@ -2,6 +2,7 @@ class Appearance < ActiveRecord::Base
include
CacheMarkdownField
include
CacheMarkdownField
include
AfterCommitQueue
include
AfterCommitQueue
include
ObjectStorage
::
BackgroundMove
include
ObjectStorage
::
BackgroundMove
include
WithUploads
cache_markdown_field
:description
cache_markdown_field
:description
cache_markdown_field
:new_project_guidelines
cache_markdown_field
:new_project_guidelines
...
@@ -14,8 +15,6 @@ class Appearance < ActiveRecord::Base
...
@@ -14,8 +15,6 @@ class Appearance < ActiveRecord::Base
mount_uploader
:logo
,
AttachmentUploader
mount_uploader
:logo
,
AttachmentUploader
mount_uploader
:header_logo
,
AttachmentUploader
mount_uploader
:header_logo
,
AttachmentUploader
has_many
:uploads
,
as: :model
,
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
CACHE_KEY
=
"current_appearance:
#{
Gitlab
::
VERSION
}
"
.
freeze
CACHE_KEY
=
"current_appearance:
#{
Gitlab
::
VERSION
}
"
.
freeze
after_commit
:flush_redis_cache
after_commit
:flush_redis_cache
...
...
app/models/ci/runner.rb
View file @
fd5fdb2c
...
@@ -52,7 +52,7 @@ module Ci
...
@@ -52,7 +52,7 @@ module Ci
# Without that, placeholders would miss one and couldn't match.
# Without that, placeholders would miss one and couldn't match.
where
(
locked:
false
)
where
(
locked:
false
)
.
where
.
not
(
"ci_runners.id IN (
#{
project
.
runners
.
select
(
:id
).
to_sql
}
)"
)
.
where
.
not
(
"ci_runners.id IN (
#{
project
.
runners
.
select
(
:id
).
to_sql
}
)"
)
.
specific
.
project_type
end
end
validate
:tag_constraints
validate
:tag_constraints
...
...
app/models/concerns/with_uploads.rb
0 → 100644
View file @
fd5fdb2c
# Mounted uploaders are destroyed by carrierwave's after_commit
# hook. This hook fetches upload location (local vs remote) from
# Upload model. So it's neccessary to make sure that during that
# after_commit hook model's associated uploads are not deleted yet.
# IOW we can not use dependent: :destroy :
# has_many :uploads, as: :model, dependent: :destroy
#
# And because not-mounted uploads require presence of upload's
# object model when destroying them (FileUploader's `build_upload` method
# references `model` on delete), we can not use after_commit hook for these
# uploads.
#
# Instead FileUploads are destroyed in before_destroy hook and remaining uploads
# are destroyed by the carrierwave's after_commit hook.
module
WithUploads
extend
ActiveSupport
::
Concern
# Currently there is no simple way how to select only not-mounted
# uploads, it should be all FileUploaders so we select them by
# `uploader` class
FILE_UPLOADERS
=
%w(PersonalFileUploader NamespaceFileUploader FileUploader)
.
freeze
included
do
has_many
:uploads
,
as: :model
before_destroy
:destroy_file_uploads
end
# mounted uploads are deleted in carrierwave's after_commit hook,
# but FileUploaders which are not mounted must be deleted explicitly and
# it can not be done in after_commit because FileUploader requires loads
# associated model on destroy (which is already deleted in after_commit)
def
destroy_file_uploads
self
.
uploads
.
where
(
uploader:
FILE_UPLOADERS
).
find_each
do
|
upload
|
upload
.
destroy
end
end
end
app/models/group.rb
View file @
fd5fdb2c
...
@@ -10,6 +10,7 @@ class Group < Namespace
...
@@ -10,6 +10,7 @@ class Group < Namespace
include
LoadedInGroupList
include
LoadedInGroupList
include
GroupDescendant
include
GroupDescendant
include
TokenAuthenticatable
include
TokenAuthenticatable
include
WithUploads
has_many
:group_members
,
->
{
where
(
requested_at:
nil
)
},
dependent: :destroy
,
as: :source
# rubocop:disable Cop/ActiveRecordDependent
has_many
:group_members
,
->
{
where
(
requested_at:
nil
)
},
dependent: :destroy
,
as: :source
# rubocop:disable Cop/ActiveRecordDependent
alias_method
:members
,
:group_members
alias_method
:members
,
:group_members
...
@@ -30,8 +31,6 @@ class Group < Namespace
...
@@ -30,8 +31,6 @@ class Group < Namespace
has_many
:variables
,
class_name:
'Ci::GroupVariable'
has_many
:variables
,
class_name:
'Ci::GroupVariable'
has_many
:custom_attributes
,
class_name:
'GroupCustomAttribute'
has_many
:custom_attributes
,
class_name:
'GroupCustomAttribute'
has_many
:uploads
,
as: :model
,
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
has_many
:boards
has_many
:boards
has_many
:badges
,
class_name:
'GroupBadge'
has_many
:badges
,
class_name:
'GroupBadge'
...
...
app/models/project.rb
View file @
fd5fdb2c
...
@@ -23,6 +23,7 @@ class Project < ActiveRecord::Base
...
@@ -23,6 +23,7 @@ class Project < ActiveRecord::Base
include
::
Gitlab
::
Utils
::
StrongMemoize
include
::
Gitlab
::
Utils
::
StrongMemoize
include
ChronicDurationAttribute
include
ChronicDurationAttribute
include
FastDestroyAll
::
Helpers
include
FastDestroyAll
::
Helpers
include
WithUploads
extend
Gitlab
::
ConfigHelper
extend
Gitlab
::
ConfigHelper
...
@@ -301,8 +302,6 @@ class Project < ActiveRecord::Base
...
@@ -301,8 +302,6 @@ class Project < ActiveRecord::Base
inclusion:
{
in:
->
(
_object
)
{
Gitlab
.
config
.
repositories
.
storages
.
keys
}
}
inclusion:
{
in:
->
(
_object
)
{
Gitlab
.
config
.
repositories
.
storages
.
keys
}
}
validates
:variables
,
variable_duplicates:
{
scope: :environment_scope
}
validates
:variables
,
variable_duplicates:
{
scope: :environment_scope
}
has_many
:uploads
,
as: :model
,
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
# Scopes
# Scopes
scope
:pending_delete
,
->
{
where
(
pending_delete:
true
)
}
scope
:pending_delete
,
->
{
where
(
pending_delete:
true
)
}
scope
:without_deleted
,
->
{
where
(
pending_delete:
false
)
}
scope
:without_deleted
,
->
{
where
(
pending_delete:
false
)
}
...
...
app/models/user.rb
View file @
fd5fdb2c
...
@@ -17,6 +17,7 @@ class User < ActiveRecord::Base
...
@@ -17,6 +17,7 @@ class User < ActiveRecord::Base
include
IgnorableColumn
include
IgnorableColumn
include
BulkMemberAccessLoad
include
BulkMemberAccessLoad
include
BlocksJsonSerialization
include
BlocksJsonSerialization
include
WithUploads
DEFAULT_NOTIFICATION_LEVEL
=
:participating
DEFAULT_NOTIFICATION_LEVEL
=
:participating
...
@@ -137,7 +138,6 @@ class User < ActiveRecord::Base
...
@@ -137,7 +138,6 @@ class User < ActiveRecord::Base
has_many
:custom_attributes
,
class_name:
'UserCustomAttribute'
has_many
:custom_attributes
,
class_name:
'UserCustomAttribute'
has_many
:callouts
,
class_name:
'UserCallout'
has_many
:callouts
,
class_name:
'UserCallout'
has_many
:uploads
,
as: :model
,
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
has_many
:term_agreements
has_many
:term_agreements
belongs_to
:accepted_term
,
class_name:
'ApplicationSetting::Term'
belongs_to
:accepted_term
,
class_name:
'ApplicationSetting::Term'
...
@@ -860,6 +860,16 @@ class User < ActiveRecord::Base
...
@@ -860,6 +860,16 @@ class User < ActiveRecord::Base
confirmed?
&&
!
temp_oauth_email?
confirmed?
&&
!
temp_oauth_email?
end
end
def
accept_pending_invitations!
pending_invitations
.
select
do
|
member
|
member
.
accept_invite!
(
self
)
end
end
def
pending_invitations
Member
.
where
(
invite_email:
verified_emails
).
invite
end
def
all_emails
def
all_emails
all_emails
=
[]
all_emails
=
[]
all_emails
<<
email
unless
temp_oauth_email?
all_emails
<<
email
unless
temp_oauth_email?
...
@@ -999,12 +1009,19 @@ class User < ActiveRecord::Base
...
@@ -999,12 +1009,19 @@ class User < ActiveRecord::Base
!
solo_owned_groups
.
present?
!
solo_owned_groups
.
present?
end
end
def
ci_
authoriz
ed_runners
def
ci_
own
ed_runners
@ci_
authoriz
ed_runners
||=
begin
@ci_
own
ed_runners
||=
begin
runner_ids
=
Ci
::
RunnerProject
project_
runner_ids
=
Ci
::
RunnerProject
.
where
(
project:
authorized_projects
(
Gitlab
::
Access
::
MASTER
))
.
where
(
project:
authorized_projects
(
Gitlab
::
Access
::
MASTER
))
.
select
(
:runner_id
)
.
select
(
:runner_id
)
Ci
::
Runner
.
specific
.
where
(
id:
runner_ids
)
group_runner_ids
=
Ci
::
RunnerNamespace
.
where
(
namespace_id:
owned_or_masters_groups
.
select
(
:id
))
.
select
(
:runner_id
)
union
=
Gitlab
::
SQL
::
Union
.
new
([
project_runner_ids
,
group_runner_ids
])
Ci
::
Runner
.
specific
.
where
(
"ci_runners.id IN (
#{
union
.
to_sql
}
)"
)
# rubocop:disable GitlabSecurity/SqlInjection
end
end
end
end
...
@@ -1205,6 +1222,11 @@ class User < ActiveRecord::Base
...
@@ -1205,6 +1222,11 @@ class User < ActiveRecord::Base
!
terms_accepted?
!
terms_accepted?
end
end
def
owned_or_masters_groups
union
=
Gitlab
::
SQL
::
Union
.
new
([
owned_groups
,
masters_groups
])
Group
.
from
(
"(
#{
union
.
to_sql
}
) namespaces"
)
end
protected
protected
# override, from Devise::Validatable
# override, from Devise::Validatable
...
...
app/policies/ci/runner_policy.rb
View file @
fd5fdb2c
module
Ci
module
Ci
class
RunnerPolicy
<
BasePolicy
class
RunnerPolicy
<
BasePolicy
with_options
scope: :subject
,
score:
0
condition
(
:shared
)
{
@subject
.
is_shared?
}
with_options
scope: :subject
,
score:
0
with_options
scope: :subject
,
score:
0
condition
(
:locked
,
scope: :subject
)
{
@subject
.
locked?
}
condition
(
:locked
,
scope: :subject
)
{
@subject
.
locked?
}
condition
(
:
authorized_runner
)
{
@user
.
ci_authorized_runners
.
include?
(
@subject
)
}
condition
(
:
owned_runner
)
{
@user
.
ci_owned_runners
.
exists?
(
@subject
.
id
)
}
rule
{
anonymous
}.
prevent_all
rule
{
anonymous
}.
prevent_all
rule
{
admin
|
authorized_runner
}.
enable
:assign_runner
rule
{
~
admin
&
shared
}.
prevent
:assign_runner
rule
{
admin
|
owned_runner
}.
policy
do
enable
:assign_runner
enable
:read_runner
enable
:update_runner
enable
:delete_runner
end
rule
{
~
admin
&
locked
}.
prevent
:assign_runner
rule
{
~
admin
&
locked
}.
prevent
:assign_runner
end
end
end
end
app/views/admin/dashboard/index.html.haml
View file @
fd5fdb2c
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
=
link_to
admin_projects_path
do
=
link_to
admin_projects_path
do
%h3
.text-center
%h3
.text-center
Projects:
Projects:
=
number_with_delimiter
(
Project
.
cached_coun
t
)
=
approximate_count_with_delimiters
(
Projec
t
)
%hr
%hr
=
link_to
(
'New project'
,
new_project_path
,
class:
"btn btn-new"
)
=
link_to
(
'New project'
,
new_project_path
,
class:
"btn btn-new"
)
.col-sm-4
.col-sm-4
...
@@ -19,7 +19,7 @@
...
@@ -19,7 +19,7 @@
=
link_to
admin_users_path
do
=
link_to
admin_users_path
do
%h3
.text-center
%h3
.text-center
Users:
Users:
=
number_with_delimiter
(
User
.
count
)
=
approximate_count_with_delimiters
(
User
)
%hr
%hr
=
link_to
'New user'
,
new_admin_user_path
,
class:
"btn btn-new"
=
link_to
'New user'
,
new_admin_user_path
,
class:
"btn btn-new"
.col-sm-4
.col-sm-4
...
@@ -28,7 +28,7 @@
...
@@ -28,7 +28,7 @@
=
link_to
admin_groups_path
do
=
link_to
admin_groups_path
do
%h3
.text-center
%h3
.text-center
Groups:
Groups:
=
number_with_delimiter
(
Group
.
count
)
=
approximate_count_with_delimiters
(
Group
)
%hr
%hr
=
link_to
'New group'
,
new_admin_group_path
,
class:
"btn btn-new"
=
link_to
'New group'
,
new_admin_group_path
,
class:
"btn btn-new"
.row
.row
...
@@ -39,31 +39,31 @@
...
@@ -39,31 +39,31 @@
%p
%p
Forks
Forks
%span
.light.float-right
%span
.light.float-right
=
number_with_delimiter
(
ForkedProjectLink
.
count
)
=
approximate_count_with_delimiters
(
ForkedProjectLink
)
%p
%p
Issues
Issues
%span
.light.float-right
%span
.light.float-right
=
number_with_delimiter
(
Issue
.
count
)
=
approximate_count_with_delimiters
(
Issue
)
%p
%p
Merge Requests
Merge Requests
%span
.light.float-right
%span
.light.float-right
=
number_with_delimiter
(
MergeRequest
.
coun
t
)
=
approximate_count_with_delimiters
(
MergeReques
t
)
%p
%p
Notes
Notes
%span
.light.float-right
%span
.light.float-right
=
number_with_delimiter
(
Note
.
count
)
=
approximate_count_with_delimiters
(
Note
)
%p
%p
Snippets
Snippets
%span
.light.float-right
%span
.light.float-right
=
number_with_delimiter
(
Snippet
.
coun
t
)
=
approximate_count_with_delimiters
(
Snippe
t
)
%p
%p
SSH Keys
SSH Keys
%span
.light.float-right
%span
.light.float-right
=
number_with_delimiter
(
Key
.
count
)
=
approximate_count_with_delimiters
(
Key
)
%p
%p
Milestones
Milestones
%span
.light.float-right
%span
.light.float-right
=
number_with_delimiter
(
Milestone
.
count
)
=
approximate_count_with_delimiters
(
Milestone
)
%p
%p
Active Users
Active Users
%span
.light.float-right
%span
.light.float-right
...
...
app/views/notify/member_invited_email.html.haml
View file @
fd5fdb2c
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
by
by
=
link_to
member
.
created_by
.
name
,
user_url
(
member
.
created_by
)
=
link_to
member
.
created_by
.
name
,
user_url
(
member
.
created_by
)
to join the
to join the
=
link_to
member_source
.
human_name
,
member_source
.
web_url
=
link_to
member_source
.
human_name
,
member_source
.
public?
?
member_source
.
web_url
:
invite_url
(
@token
)
#{
member_source
.
model_name
.
singular
}
as
#{
member
.
human_access
}
.
#{
member_source
.
model_name
.
singular
}
as
#{
member
.
human_access
}
.
%p
%p
...
...
app/views/shared/notes/_note.html.haml
View file @
fd5fdb2c
...
@@ -41,8 +41,9 @@
...
@@ -41,8 +41,9 @@
-
if
note
.
system
-
if
note
.
system
%span
.system-note-message
%span
.system-note-message
=
markdown_field
(
note
,
:note
)
=
markdown_field
(
note
,
:note
)
%a
{
href:
"##{dom_id(note)}"
}
%span
.system-note-separator
=
time_ago_with_tooltip
(
note
.
created_at
,
placement:
'bottom'
,
html_class:
'note-created-ago'
)
·
%a
.system-note-separator
{
href:
"##{dom_id(note)}"
}=
time_ago_with_tooltip
(
note
.
created_at
,
placement:
'bottom'
,
html_class:
'note-created-ago'
)
-
unless
note
.
system?
-
unless
note
.
system?
.note-actions
.note-actions
-
if
note
.
for_personal_snippet?
-
if
note
.
for_personal_snippet?
...
...
changelogs/unreleased/22647-width-contributors-graphs.yml
0 → 100644
View file @
fd5fdb2c
---
title
:
Fix width of contributors graphs
merge_request
:
18639
author
:
Paul Vorbach
type
:
fixed
changelogs/unreleased/42531-open-invite-404.yml
0 → 100644
View file @
fd5fdb2c
---
title
:
Automatically accepts project/group invite by email after user signup
merge_request
:
17634
author
:
Jacopo Beschi @jacopo-beschi
type
:
changed
changelogs/unreleased/jivl-add-dot-system-notes.yml
0 → 100644
View file @
fd5fdb2c
---
title
:
Add dot to separate system notes content
merge_request
:
18864
author
:
type
:
changed
changelogs/unreleased/jprovazn-remote-upload-destroy.yml
0 → 100644
View file @
fd5fdb2c
---
title
:
Fix deletion of Object Store uploads
merge_request
:
author
:
type
:
fixed
changelogs/unreleased/zj-workhorse-commit-patch-diff.yml
0 → 100644
View file @
fd5fdb2c
---
title
:
Workhorse to send raw diff and patch for commits
merge_request
:
author
:
type
:
other
lib/api/groups.rb
View file @
fd5fdb2c
...
@@ -165,6 +165,7 @@ module API
...
@@ -165,6 +165,7 @@ module API
group
=
find_group!
(
params
[
:id
])
group
=
find_group!
(
params
[
:id
])
authorize!
:admin_group
,
group
authorize!
:admin_group
,
group
Gitlab
::
QueryLimiting
.
whitelist
(
'https://gitlab.com/gitlab-org/gitlab-ce/issues/46285'
)
destroy_conditionally!
(
group
)
do
|
group
|
destroy_conditionally!
(
group
)
do
|
group
|
::
Groups
::
DestroyService
.
new
(
group
,
current_user
).
execute
::
Groups
::
DestroyService
.
new
(
group
,
current_user
).
execute
end
end
...
...
lib/api/runners.rb
View file @
fd5fdb2c
...
@@ -14,7 +14,7 @@ module API
...
@@ -14,7 +14,7 @@ module API
use
:pagination
use
:pagination
end
end
get
do
get
do
runners
=
filter_runners
(
current_user
.
ci_
authoriz
ed_runners
,
params
[
:scope
],
without:
%w(specific shared)
)
runners
=
filter_runners
(
current_user
.
ci_
own
ed_runners
,
params
[
:scope
],
without:
%w(specific shared)
)
present
paginate
(
runners
),
with:
Entities
::
Runner
present
paginate
(
runners
),
with:
Entities
::
Runner
end
end
...
@@ -184,40 +184,35 @@ module API
...
@@ -184,40 +184,35 @@ module API
def
authenticate_show_runner!
(
runner
)
def
authenticate_show_runner!
(
runner
)
return
if
runner
.
is_shared
||
current_user
.
admin?
return
if
runner
.
is_shared
||
current_user
.
admin?
forbidden!
(
"No access granted"
)
unless
user_can_access_runner?
(
runner
)
forbidden!
(
"No access granted"
)
unless
can?
(
current_user
,
:read_runner
,
runner
)
end
end
def
authenticate_update_runner!
(
runner
)
def
authenticate_update_runner!
(
runner
)
return
if
current_user
.
admin?
return
if
current_user
.
admin?
forbidden!
(
"Runner is shared"
)
if
runner
.
is_shared?
forbidden!
(
"No access granted"
)
unless
can?
(
current_user
,
:update_runner
,
runner
)
forbidden!
(
"No access granted"
)
unless
user_can_access_runner?
(
runner
)
end
end
def
authenticate_delete_runner!
(
runner
)
def
authenticate_delete_runner!
(
runner
)
return
if
current_user
.
admin?
return
if
current_user
.
admin?
forbidden!
(
"Runner is shared"
)
if
runner
.
is_shared?
forbidden!
(
"Runner associated with more than one project"
)
if
runner
.
projects
.
count
>
1
forbidden!
(
"Runner associated with more than one project"
)
if
runner
.
projects
.
count
>
1
forbidden!
(
"No access granted"
)
unless
user_can_access_runner?
(
runner
)
forbidden!
(
"No access granted"
)
unless
can?
(
current_user
,
:delete_runner
,
runner
)
end
end
def
authenticate_enable_runner!
(
runner
)
def
authenticate_enable_runner!
(
runner
)
forbidden!
(
"Runner is
shared"
)
if
runner
.
is_shared
?
forbidden!
(
"Runner is
a group runner"
)
if
runner
.
group_type
?
forbidden!
(
"Runner is locked"
)
if
runner
.
locked?
return
if
current_user
.
admin?
return
if
current_user
.
admin?
forbidden!
(
"No access granted"
)
unless
user_can_access_runner?
(
runner
)
forbidden!
(
"Runner is locked"
)
if
runner
.
locked?
forbidden!
(
"No access granted"
)
unless
can?
(
current_user
,
:assign_runner
,
runner
)
end
end
def
authenticate_list_runners_jobs!
(
runner
)
def
authenticate_list_runners_jobs!
(
runner
)
return
if
current_user
.
admin?
return
if
current_user
.
admin?
forbidden!
(
"No access granted"
)
unless
user_can_access_runner?
(
runner
)
forbidden!
(
"No access granted"
)
unless
can?
(
current_user
,
:read_runner
,
runner
)
end
def
user_can_access_runner?
(
runner
)
current_user
.
ci_authorized_runners
.
exists?
(
runner
.
id
)
end
end
end
end
end
end
...
...
lib/api/v3/groups.rb
View file @
fd5fdb2c
...
@@ -131,6 +131,7 @@ module API
...
@@ -131,6 +131,7 @@ module API
delete
":id"
do
delete
":id"
do
group
=
find_group!
(
params
[
:id
])
group
=
find_group!
(
params
[
:id
])
authorize!
:admin_group
,
group
authorize!
:admin_group
,
group
Gitlab
::
QueryLimiting
.
whitelist
(
'https://gitlab.com/gitlab-org/gitlab-ce/issues/46285'
)
present
::
Groups
::
DestroyService
.
new
(
group
,
current_user
).
execute
,
with:
Entities
::
GroupDetail
,
current_user:
current_user
present
::
Groups
::
DestroyService
.
new
(
group
,
current_user
).
execute
,
with:
Entities
::
GroupDetail
,
current_user:
current_user
end
end
...
...
lib/api/v3/runners.rb
View file @
fd5fdb2c
...
@@ -58,7 +58,7 @@ module API
...
@@ -58,7 +58,7 @@ module API
end
end
def
user_can_access_runner?
(
runner
)
def
user_can_access_runner?
(
runner
)
current_user
.
ci_
authoriz
ed_runners
.
exists?
(
runner
.
id
)
current_user
.
ci_
own
ed_runners
.
exists?
(
runner
.
id
)
end
end
end
end
end
end
...
...
lib/gitlab/database/count.rb
0 → 100644
View file @
fd5fdb2c
# For large tables, PostgreSQL can take a long time to count rows due to MVCC.
# We can optimize this by using the reltuples count as described in https://wiki.postgresql.org/wiki/Slow_Counting.
module
Gitlab
module
Database
module
Count
CONNECTION_ERRORS
=
if
defined?
(
PG
)
[
ActionView
::
Template
::
Error
,
ActiveRecord
::
StatementInvalid
,
PG
::
Error
].
freeze
else
[
ActionView
::
Template
::
Error
,
ActiveRecord
::
StatementInvalid
].
freeze
end
def
self
.
approximate_count
(
model
)
return
model
.
count
unless
Gitlab
::
Database
.
postgresql?
execute_estimate_if_updated_recently
(
model
)
||
model
.
count
end
def
self
.
execute_estimate_if_updated_recently
(
model
)
ActiveRecord
::
Base
.
connection
.
select_value
(
postgresql_estimate_query
(
model
)).
to_i
if
reltuples_updated_recently?
(
model
)
rescue
*
CONNECTION_ERRORS
end
def
self
.
reltuples_updated_recently?
(
model
)
time
=
"to_timestamp(
#{
1
.
hour
.
ago
.
to_i
}
)"
query
=
<<~
SQL
SELECT 1 FROM pg_stat_user_tables WHERE relname = '
#{
model
.
table_name
}
' AND
(last_vacuum >
#{
time
}
OR last_autovacuum >
#{
time
}
OR last_analyze >
#{
time
}
OR last_autoanalyze >
#{
time
}
)
SQL
ActiveRecord
::
Base
.
connection
.
select_all
(
query
).
count
>
0
rescue
*
CONNECTION_ERRORS
false
end
def
self
.
postgresql_estimate_query
(
model
)
"SELECT reltuples::bigint AS estimate FROM pg_class where relname = '
#{
model
.
table_name
}
'"
end
end
end
end
lib/gitlab/git/commit.rb
View file @
fd5fdb2c
...
@@ -342,21 +342,6 @@ module Gitlab
...
@@ -342,21 +342,6 @@ module Gitlab
parent_ids
.
first
parent_ids
.
first
end
end
# Shows the diff between the commit's parent and the commit.
#
# Cuts out the header and stats from #to_patch and returns only the diff.
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/324
def
to_diff
Gitlab
::
GitalyClient
.
migrate
(
:commit_patch
,
status:
Gitlab
::
GitalyClient
::
MigrationStatus
::
OPT_OUT
)
do
|
is_enabled
|
if
is_enabled
@repository
.
gitaly_commit_client
.
patch
(
id
)
else
rugged_diff_from_parent
.
patch
end
end
end
# Returns a diff object for the changes from this commit's first parent.
# Returns a diff object for the changes from this commit's first parent.
# If there is no parent, then the diff is between this commit and an
# If there is no parent, then the diff is between this commit and an
# empty repo. See Repository#diff for keys allowed in the +options+
# empty repo. See Repository#diff for keys allowed in the +options+
...
@@ -432,16 +417,6 @@ module Gitlab
...
@@ -432,16 +417,6 @@ module Gitlab
Gitlab
::
Git
::
CommitStats
.
new
(
@repository
,
self
)
Gitlab
::
Git
::
CommitStats
.
new
(
@repository
,
self
)
end
end
def
to_patch
(
options
=
{})
begin
rugged_commit
.
to_mbox
(
options
)
rescue
Rugged
::
InvalidError
=>
ex
if
ex
.
message
=~
/commit \w+ is a merge commit/i
'Patch format is not currently supported for merge commits.'
end
end
end
# Get ref names collection
# Get ref names collection
#
#
# Ex.
# Ex.
...
...
scripts/create_mysql_user.sh
View file @
fd5fdb2c
#!/bin/bash
#!/bin/bash
mysql
--user
=
root
--host
=
mysql
<<
EOF
mysql
--user
=
root
--host
=
mysql
<<
EOF
CREATE DATABASE IF NOT EXISTS gitlabhq_test DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER IF NOT EXISTS 'gitlab'@'%';
CREATE USER IF NOT EXISTS 'gitlab'@'%';
GRANT ALL PRIVILEGES ON gitlabhq_test.* TO 'gitlab'@'%';
GRANT ALL PRIVILEGES ON gitlabhq_test.* TO 'gitlab'@'%';
FLUSH PRIVILEGES;
FLUSH PRIVILEGES;
...
...
scripts/create_postgres_user.sh
View file @
fd5fdb2c
#!/bin/bash
#!/bin/bash
psql
-h
postgres
-U
postgres postgres
<<
EOF
psql
-h
postgres
-U
postgres postgres
<<
EOF
DROP DATABASE IF EXISTS gitlabhq_test;
CREATE DATABASE gitlabhq_test;
CREATE USER gitlab;
CREATE USER gitlab;
GRANT ALL PRIVILEGES ON
DATABASE gitlabhq_test
TO gitlab;
GRANT ALL PRIVILEGES ON
ALL TABLES IN SCHEMA public
TO gitlab;
EOF
EOF
scripts/prepare_build.sh
View file @
fd5fdb2c
...
@@ -49,20 +49,8 @@ sed -i 's/localhost/redis/g' config/redis.queues.yml
...
@@ -49,20 +49,8 @@ sed -i 's/localhost/redis/g' config/redis.queues.yml
cp
config/redis.shared_state.yml.example config/redis.shared_state.yml
cp
config/redis.shared_state.yml.example config/redis.shared_state.yml
sed
-i
's/localhost/redis/g'
config/redis.shared_state.yml
sed
-i
's/localhost/redis/g'
config/redis.shared_state.yml
# Some tasks (e.g. db:seed_fu) need to have a properly-configured database
# user but not necessarily a full schema loaded
if
[
"
$CREATE_DB_USER
"
!=
"false"
]
;
then
if
[
"
$GITLAB_DATABASE
"
=
'postgresql'
]
;
then
.
scripts/create_postgres_user.sh
else
.
scripts/create_mysql_user.sh
fi
fi
if
[
"
$SETUP_DB
"
!=
"false"
]
;
then
if
[
"
$SETUP_DB
"
!=
"false"
]
;
then
bundle
exec
rake db:drop db:create db:schema:load db:migrate
setup_db
elif
getent hosts postgres
||
getent hosts mysql
;
then
if
[
"
$GITLAB_DATABASE
"
=
"mysql"
]
;
then
setup_db_user_only
bundle
exec
rake add_limits_mysql
fi
fi
fi
scripts/utils.sh
View file @
fd5fdb2c
...
@@ -12,3 +12,21 @@ retry() {
...
@@ -12,3 +12,21 @@ retry() {
done
done
return
1
return
1
}
}
setup_db_user_only
()
{
if
[
"
$GITLAB_DATABASE
"
=
"postgresql"
]
;
then
.
scripts/create_postgres_user.sh
else
.
scripts/create_mysql_user.sh
fi
}
setup_db
()
{
setup_db_user_only
bundle
exec
rake db:drop db:create db:schema:load db:migrate
if
[
"
$GITLAB_DATABASE
"
=
"mysql"
]
;
then
bundle
exec
rake add_limits_mysql
fi
}
spec/controllers/projects/commit_controller_spec.rb
View file @
fd5fdb2c
...
@@ -79,41 +79,18 @@ describe Projects::CommitController do
...
@@ -79,41 +79,18 @@ describe Projects::CommitController do
end
end
describe
"as diff"
do
describe
"as diff"
do
i
nclude_examples
"export as"
,
:diff
i
t
"triggers workhorse to serve the request"
do
let
(
:format
)
{
:diff
}
go
(
id:
commit
.
id
,
format: :diff
)
it
"should really only be a git diff"
do
expect
(
response
.
headers
[
Gitlab
::
Workhorse
::
SEND_DATA_HEADER
]).
to
start_with
(
"git-diff:"
)
go
(
id:
'66eceea0db202bb39c4e445e8ca28689645366c5'
,
format:
format
)
expect
(
response
.
body
).
to
start_with
(
"diff --git"
)
end
it
"is only be a git diff without whitespace changes"
do
go
(
id:
'66eceea0db202bb39c4e445e8ca28689645366c5'
,
format:
format
,
w:
1
)
expect
(
response
.
body
).
to
start_with
(
"diff --git"
)
# without whitespace option, there are more than 2 diff_splits for other formats
diff_splits
=
assigns
(
:diffs
).
diff_files
.
first
.
diff
.
diff
.
split
(
"
\n
"
)
expect
(
diff_splits
.
length
).
to
be
<=
2
end
end
end
end
describe
"as patch"
do
describe
"as patch"
do
include_examples
"export as"
,
:patch
let
(
:format
)
{
:patch
}
let
(
:commit2
)
{
project
.
commit
(
'498214de67004b1da3d820901307bed2a68a8ef6'
)
}
it
"is a git email patch"
do
go
(
id:
commit2
.
id
,
format:
format
)
expect
(
response
.
body
).
to
start_with
(
"From
#{
commit2
.
id
}
"
)
end
it
"contains a git diff"
do
it
"contains a git diff"
do
go
(
id:
commit
2
.
id
,
format:
format
)
go
(
id:
commit
.
id
,
format: :patch
)
expect
(
response
.
body
).
to
match
(
/^diff --git/
)
expect
(
response
.
headers
[
Gitlab
::
Workhorse
::
SEND_DATA_HEADER
]).
to
start_with
(
"git-format-patch:"
)
end
end
end
end
...
...
spec/controllers/projects/settings/ci_cd_controller_spec.rb
View file @
fd5fdb2c
...
@@ -19,11 +19,11 @@ describe Projects::Settings::CiCdController do
...
@@ -19,11 +19,11 @@ describe Projects::Settings::CiCdController do
end
end
context
'with group runners'
do
context
'with group runners'
do
let
(
:group_runner
)
{
create
(
:ci_runner
)
}
let
(
:group_runner
)
{
create
(
:ci_runner
,
runner_type: :group_type
)
}
let
(
:parent_group
)
{
create
(
:group
)
}
let
(
:parent_group
)
{
create
(
:group
)
}
let
(
:group
)
{
create
(
:group
,
runners:
[
group_runner
],
parent:
parent_group
)
}
let
(
:group
)
{
create
(
:group
,
runners:
[
group_runner
],
parent:
parent_group
)
}
let
(
:other_project
)
{
create
(
:project
,
group:
group
)
}
let
(
:other_project
)
{
create
(
:project
,
group:
group
)
}
let!
(
:project_runner
)
{
create
(
:ci_runner
,
projects:
[
other_project
])
}
let!
(
:project_runner
)
{
create
(
:ci_runner
,
projects:
[
other_project
]
,
runner_type: :project_type
)
}
let!
(
:shared_runner
)
{
create
(
:ci_runner
,
:shared
)
}
let!
(
:shared_runner
)
{
create
(
:ci_runner
,
:shared
)
}
it
'sets assignable project runners only'
do
it
'sets assignable project runners only'
do
...
@@ -31,7 +31,7 @@ describe Projects::Settings::CiCdController do
...
@@ -31,7 +31,7 @@ describe Projects::Settings::CiCdController do
get
:show
,
namespace_id:
project
.
namespace
,
project_id:
project
get
:show
,
namespace_id:
project
.
namespace
,
project_id:
project
expect
(
assigns
(
:assignable_runners
)).
to
eq
[
project_runner
]
expect
(
assigns
(
:assignable_runners
)).
to
contain_exactly
(
project_runner
)
end
end
end
end
end
end
...
...
spec/features/invites_spec.rb
View file @
fd5fdb2c
...
@@ -5,18 +5,41 @@ describe 'Invites' do
...
@@ -5,18 +5,41 @@ describe 'Invites' do
let
(
:owner
)
{
create
(
:user
,
name:
'John Doe'
)
}
let
(
:owner
)
{
create
(
:user
,
name:
'John Doe'
)
}
let
(
:group
)
{
create
(
:group
,
name:
'Owned'
)
}
let
(
:group
)
{
create
(
:group
,
name:
'Owned'
)
}
let
(
:project
)
{
create
(
:project
,
:repository
,
namespace:
group
)
}
let
(
:project
)
{
create
(
:project
,
:repository
,
namespace:
group
)
}
let
(
:invite
)
{
group
.
group_members
.
invite
.
last
}
let
(
:
group_
invite
)
{
group
.
group_members
.
invite
.
last
}
before
do
before
do
project
.
add_master
(
owner
)
project
.
add_master
(
owner
)
group
.
add_user
(
owner
,
Gitlab
::
Access
::
OWNER
)
group
.
add_user
(
owner
,
Gitlab
::
Access
::
OWNER
)
group
.
add_developer
(
'user@example.com'
,
owner
)
group
.
add_developer
(
'user@example.com'
,
owner
)
invite
.
generate_invite_token!
group_invite
.
generate_invite_token!
end
def
confirm_email_and_sign_in
(
new_user
)
new_user_token
=
User
.
find_by_email
(
new_user
.
email
).
confirmation_token
visit
user_confirmation_path
(
confirmation_token:
new_user_token
)
fill_in_sign_in_form
(
new_user
)
end
def
fill_in_sign_up_form
(
new_user
)
fill_in
'new_user_name'
,
with:
new_user
.
name
fill_in
'new_user_username'
,
with:
new_user
.
username
fill_in
'new_user_email'
,
with:
new_user
.
email
fill_in
'new_user_email_confirmation'
,
with:
new_user
.
email
fill_in
'new_user_password'
,
with:
new_user
.
password
click_button
"Register"
end
def
fill_in_sign_in_form
(
user
)
fill_in
'user_login'
,
with:
user
.
email
fill_in
'user_password'
,
with:
user
.
password
check
'user_remember_me'
click_button
'Sign in'
end
end
context
'when signed out'
do
context
'when signed out'
do
before
do
before
do
visit
invite_path
(
invite
.
raw_invite_token
)
visit
invite_path
(
group_
invite
.
raw_invite_token
)
end
end
it
'renders sign in page with sign in notice'
do
it
'renders sign in page with sign in notice'
do
...
@@ -25,12 +48,9 @@ describe 'Invites' do
...
@@ -25,12 +48,9 @@ describe 'Invites' do
end
end
it
'sign in and redirects to invitation page'
do
it
'sign in and redirects to invitation page'
do
fill_in
'user_login'
,
with:
user
.
email
fill_in_sign_in_form
(
user
)
fill_in
'user_password'
,
with:
user
.
password
check
'user_remember_me'
click_button
'Sign in'
expect
(
current_path
).
to
eq
(
invite_path
(
invite
.
raw_invite_token
))
expect
(
current_path
).
to
eq
(
invite_path
(
group_
invite
.
raw_invite_token
))
expect
(
page
).
to
have_content
(
expect
(
page
).
to
have_content
(
'You have been invited by John Doe to join group Owned as Developer.'
'You have been invited by John Doe to join group Owned as Developer.'
)
)
...
@@ -45,7 +65,7 @@ describe 'Invites' do
...
@@ -45,7 +65,7 @@ describe 'Invites' do
end
end
it
'shows message user already a member'
do
it
'shows message user already a member'
do
visit
invite_path
(
invite
.
raw_invite_token
)
visit
invite_path
(
group_
invite
.
raw_invite_token
)
expect
(
page
).
to
have_content
(
'However, you are already a member of this group.'
)
expect
(
page
).
to
have_content
(
'However, you are already a member of this group.'
)
end
end
end
end
...
@@ -53,7 +73,7 @@ describe 'Invites' do
...
@@ -53,7 +73,7 @@ describe 'Invites' do
describe
'accepting the invitation'
do
describe
'accepting the invitation'
do
before
do
before
do
sign_in
(
user
)
sign_in
(
user
)
visit
invite_path
(
invite
.
raw_invite_token
)
visit
invite_path
(
group_
invite
.
raw_invite_token
)
end
end
it
'grants access and redirects to group page'
do
it
'grants access and redirects to group page'
do
...
@@ -69,7 +89,7 @@ describe 'Invites' do
...
@@ -69,7 +89,7 @@ describe 'Invites' do
context
'when signed in'
do
context
'when signed in'
do
before
do
before
do
sign_in
(
user
)
sign_in
(
user
)
visit
invite_path
(
invite
.
raw_invite_token
)
visit
invite_path
(
group_
invite
.
raw_invite_token
)
end
end
it
'declines application and redirects to dashboard'
do
it
'declines application and redirects to dashboard'
do
...
@@ -83,7 +103,7 @@ describe 'Invites' do
...
@@ -83,7 +103,7 @@ describe 'Invites' do
context
'when signed out'
do
context
'when signed out'
do
before
do
before
do
visit
decline_invite_path
(
invite
.
raw_invite_token
)
visit
decline_invite_path
(
group_
invite
.
raw_invite_token
)
end
end
it
'declines application and redirects to sign in page'
do
it
'declines application and redirects to sign in page'
do
...
@@ -94,4 +114,72 @@ describe 'Invites' do
...
@@ -94,4 +114,72 @@ describe 'Invites' do
end
end
end
end
end
end
describe
'invite an user using their email address'
do
let
(
:new_user
)
{
build_stubbed
(
:user
)
}
let
(
:invite_email
)
{
new_user
.
email
}
let
(
:group_invite
)
{
create
(
:group_member
,
:invited
,
group:
group
,
invite_email:
invite_email
)
}
let!
(
:project_invite
)
{
create
(
:project_member
,
:invited
,
project:
project
,
invite_email:
invite_email
)
}
before
do
stub_application_setting
(
send_user_confirmation_email:
send_email_confirmation
)
visit
invite_path
(
group_invite
.
raw_invite_token
)
end
context
'email confirmation disabled'
do
let
(
:send_email_confirmation
)
{
false
}
it
'signs up and redirects to the dashboard page with all the projects/groups invitations automatically accepted'
do
fill_in_sign_up_form
(
new_user
)
expect
(
current_path
).
to
eq
(
dashboard_projects_path
)
expect
(
page
).
to
have_content
(
project
.
full_name
)
visit
group_path
(
group
)
expect
(
page
).
to
have_content
(
group
.
full_name
)
end
context
'the user sign-up using a different email address'
do
let
(
:invite_email
)
{
build_stubbed
(
:user
).
email
}
it
'signs up and redirects to the invitation page'
do
fill_in_sign_up_form
(
new_user
)
expect
(
current_path
).
to
eq
(
invite_path
(
group_invite
.
raw_invite_token
))
end
end
end
context
'email confirmation enabled'
do
let
(
:send_email_confirmation
)
{
true
}
it
'signs up and redirects to root page with all the project/groups invitation automatically accepted'
do
fill_in_sign_up_form
(
new_user
)
confirm_email_and_sign_in
(
new_user
)
expect
(
current_path
).
to
eq
(
root_path
)
expect
(
page
).
to
have_content
(
project
.
full_name
)
visit
group_path
(
group
)
expect
(
page
).
to
have_content
(
group
.
full_name
)
end
it
"doesn't accept invitations until the user confirm his email"
do
fill_in_sign_up_form
(
new_user
)
sign_in
(
owner
)
visit
project_project_members_path
(
project
)
expect
(
page
).
to
have_content
'Invited'
end
context
'the user sign-up using a different email address'
do
let
(
:invite_email
)
{
build_stubbed
(
:user
).
email
}
it
'signs up and redirects to the invitation page'
do
fill_in_sign_up_form
(
new_user
)
confirm_email_and_sign_in
(
new_user
)
expect
(
current_path
).
to
eq
(
invite_path
(
group_invite
.
raw_invite_token
))
end
end
end
end
end
end
spec/lib/gitlab/database/count_spec.rb
0 → 100644
View file @
fd5fdb2c
require
'spec_helper'
describe
Gitlab
::
Database
::
Count
do
before
do
create_list
(
:project
,
3
)
end
describe
'.execute_estimate_if_updated_recently'
,
:postgresql
do
context
'when reltuples have not been updated'
do
before
do
expect
(
described_class
).
to
receive
(
:reltuples_updated_recently?
).
and_return
(
false
)
end
it
'returns nil'
do
expect
(
described_class
.
execute_estimate_if_updated_recently
(
Project
)).
to
be
nil
end
end
context
'when reltuples have been updated'
do
before
do
ActiveRecord
::
Base
.
connection
.
execute
(
'ANALYZE projects'
)
end
it
'calls postgresql_estimate_query'
do
expect
(
described_class
).
to
receive
(
:postgresql_estimate_query
).
with
(
Project
).
and_call_original
expect
(
described_class
.
execute_estimate_if_updated_recently
(
Project
)).
to
eq
(
3
)
end
end
end
describe
'.approximate_count'
do
context
'when reltuples have not been updated'
do
it
'counts all projects the normal way'
do
allow
(
described_class
).
to
receive
(
:reltuples_updated_recently?
).
and_return
(
false
)
expect
(
Project
).
to
receive
(
:count
).
and_call_original
expect
(
described_class
.
approximate_count
(
Project
)).
to
eq
(
3
)
end
end
context
'no permission'
do
it
'falls back to standard query'
do
allow
(
described_class
).
to
receive
(
:reltuples_updated_recently?
).
and_raise
(
PG
::
InsufficientPrivilege
)
expect
(
Project
).
to
receive
(
:count
).
and_call_original
expect
(
described_class
.
approximate_count
(
Project
)).
to
eq
(
3
)
end
end
describe
'when reltuples have been updated'
,
:postgresql
do
before
do
ActiveRecord
::
Base
.
connection
.
execute
(
'ANALYZE projects'
)
end
it
'counts all projects in the fast way'
do
expect
(
described_class
).
to
receive
(
:postgresql_estimate_query
).
with
(
Project
).
and_call_original
expect
(
described_class
.
approximate_count
(
Project
)).
to
eq
(
3
)
end
end
end
end
spec/lib/gitlab/git/commit_spec.rb
View file @
fd5fdb2c
...
@@ -554,24 +554,10 @@ describe Gitlab::Git::Commit, seed_helper: true do
...
@@ -554,24 +554,10 @@ describe Gitlab::Git::Commit, seed_helper: true do
it_should_behave_like
'#stats'
it_should_behave_like
'#stats'
end
end
describe
'#to_diff'
do
subject
{
commit
.
to_diff
}
it
{
is_expected
.
not_to
include
"From
#{
SeedRepo
::
Commit
::
ID
}
"
}
it
{
is_expected
.
to
include
'diff --git a/files/ruby/popen.rb b/files/ruby/popen.rb'
}
end
describe
'#has_zero_stats?'
do
describe
'#has_zero_stats?'
do
it
{
expect
(
commit
.
has_zero_stats?
).
to
eq
(
false
)
}
it
{
expect
(
commit
.
has_zero_stats?
).
to
eq
(
false
)
}
end
end
describe
'#to_patch'
do
subject
{
commit
.
to_patch
}
it
{
is_expected
.
to
include
"From
#{
SeedRepo
::
Commit
::
ID
}
"
}
it
{
is_expected
.
to
include
'diff --git a/files/ruby/popen.rb b/files/ruby/popen.rb'
}
end
describe
'#to_hash'
do
describe
'#to_hash'
do
let
(
:hash
)
{
commit
.
to_hash
}
let
(
:hash
)
{
commit
.
to_hash
}
subject
{
hash
}
subject
{
hash
}
...
...
spec/mailers/notify_spec.rb
View file @
fd5fdb2c
...
@@ -594,7 +594,7 @@ describe Notify do
...
@@ -594,7 +594,7 @@ describe Notify do
it
'contains all the useful information'
do
it
'contains all the useful information'
do
is_expected
.
to
have_subject
"Invitation to join the
#{
project
.
full_name
}
project"
is_expected
.
to
have_subject
"Invitation to join the
#{
project
.
full_name
}
project"
is_expected
.
to
have_html_escaped_body_text
project
.
full_name
is_expected
.
to
have_html_escaped_body_text
project
.
full_name
is_expected
.
to
have_body_text
project
.
web_url
is_expected
.
to
have_body_text
project
.
full_name
is_expected
.
to
have_body_text
project_member
.
human_access
is_expected
.
to
have_body_text
project_member
.
human_access
is_expected
.
to
have_body_text
project_member
.
invite_token
is_expected
.
to
have_body_text
project_member
.
invite_token
end
end
...
...
spec/models/appearance_spec.rb
View file @
fd5fdb2c
...
@@ -5,7 +5,7 @@ describe Appearance do
...
@@ -5,7 +5,7 @@ describe Appearance do
it
{
is_expected
.
to
be_valid
}
it
{
is_expected
.
to
be_valid
}
it
{
is_expected
.
to
have_many
(
:uploads
)
.
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
(
:uploads
)
}
describe
'.current'
,
:use_clean_rails_memory_store_caching
do
describe
'.current'
,
:use_clean_rails_memory_store_caching
do
let!
(
:appearance
)
{
create
(
:appearance
)
}
let!
(
:appearance
)
{
create
(
:appearance
)
}
...
@@ -41,4 +41,12 @@ describe Appearance do
...
@@ -41,4 +41,12 @@ describe Appearance do
expect
(
new_row
.
valid?
).
to
eq
(
false
)
expect
(
new_row
.
valid?
).
to
eq
(
false
)
end
end
end
end
context
'with uploads'
do
it_behaves_like
'model with mounted uploader'
,
false
do
let
(
:model_object
)
{
create
(
:appearance
,
:with_logo
)
}
let
(
:upload_attribute
)
{
:logo
}
let
(
:uploader_class
)
{
AttachmentUploader
}
end
end
end
end
spec/models/ci/runner_spec.rb
View file @
fd5fdb2c
...
@@ -626,62 +626,26 @@ describe Ci::Runner do
...
@@ -626,62 +626,26 @@ describe Ci::Runner do
end
end
describe
'.assignable_for'
do
describe
'.assignable_for'
do
let
(
:runner
)
{
create
(
:ci_runner
)
}
let!
(
:unlocked_project_runner
)
{
create
(
:ci_runner
,
runner_type: :project_type
,
projects:
[
project
])
}
let!
(
:locked_project_runner
)
{
create
(
:ci_runner
,
runner_type: :project_type
,
locked:
true
,
projects:
[
project
])
}
let!
(
:group_runner
)
{
create
(
:ci_runner
,
runner_type: :group_type
)
}
let!
(
:instance_runner
)
{
create
(
:ci_runner
,
:shared
)
}
let
(
:project
)
{
create
(
:project
)
}
let
(
:project
)
{
create
(
:project
)
}
let
(
:another_project
)
{
create
(
:project
)
}
let
(
:another_project
)
{
create
(
:project
)
}
before
do
context
'with already assigned project'
do
project
.
runners
<<
runner
end
context
'with shared runners'
do
before
do
runner
.
update
(
is_shared:
true
)
end
context
'does not give owned runner'
do
subject
{
described_class
.
assignable_for
(
project
)
}
it
{
is_expected
.
to
be_empty
}
end
context
'does not give shared runner'
do
subject
{
described_class
.
assignable_for
(
another_project
)
}
it
{
is_expected
.
to
be_empty
}
end
end
context
'with unlocked runner'
do
context
'does not give owned runner'
do
subject
{
described_class
.
assignable_for
(
project
)
}
subject
{
described_class
.
assignable_for
(
project
)
}
it
{
is_expected
.
to
be_empty
}
it
{
is_expected
.
to
be_empty
}
end
end
context
'does give a specific runner
'
do
context
'with a different project
'
do
subject
{
described_class
.
assignable_for
(
another_project
)
}
subject
{
described_class
.
assignable_for
(
another_project
)
}
it
{
is_expected
.
to
contain_exactly
(
runner
)
}
it
{
is_expected
.
to
include
(
unlocked_project_runner
)
}
end
it
{
is_expected
.
not_to
include
(
group_runner
)
}
end
it
{
is_expected
.
not_to
include
(
locked_project_runner
)
}
it
{
is_expected
.
not_to
include
(
instance_runner
)
}
context
'with locked runner'
do
before
do
runner
.
update
(
locked:
true
)
end
context
'does not give owned runner'
do
subject
{
described_class
.
assignable_for
(
project
)
}
it
{
is_expected
.
to
be_empty
}
end
context
'does not give a locked runner'
do
subject
{
described_class
.
assignable_for
(
another_project
)
}
it
{
is_expected
.
to
be_empty
}
end
end
end
end
end
...
...
spec/models/commit_spec.rb
View file @
fd5fdb2c
...
@@ -182,7 +182,6 @@ eos
...
@@ -182,7 +182,6 @@ eos
it
{
is_expected
.
to
respond_to
(
:date
)
}
it
{
is_expected
.
to
respond_to
(
:date
)
}
it
{
is_expected
.
to
respond_to
(
:diffs
)
}
it
{
is_expected
.
to
respond_to
(
:diffs
)
}
it
{
is_expected
.
to
respond_to
(
:id
)
}
it
{
is_expected
.
to
respond_to
(
:id
)
}
it
{
is_expected
.
to
respond_to
(
:to_patch
)
}
end
end
describe
'#closes_issues'
do
describe
'#closes_issues'
do
...
...
spec/models/group_spec.rb
View file @
fd5fdb2c
...
@@ -15,7 +15,7 @@ describe Group do
...
@@ -15,7 +15,7 @@ describe Group do
it
{
is_expected
.
to
have_many
(
:notification_settings
).
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
(
:notification_settings
).
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
(
:labels
).
class_name
(
'GroupLabel'
)
}
it
{
is_expected
.
to
have_many
(
:labels
).
class_name
(
'GroupLabel'
)
}
it
{
is_expected
.
to
have_many
(
:variables
).
class_name
(
'Ci::GroupVariable'
)
}
it
{
is_expected
.
to
have_many
(
:variables
).
class_name
(
'Ci::GroupVariable'
)
}
it
{
is_expected
.
to
have_many
(
:uploads
)
.
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
(
:uploads
)
}
it
{
is_expected
.
to
have_one
(
:chat_team
)
}
it
{
is_expected
.
to
have_one
(
:chat_team
)
}
it
{
is_expected
.
to
have_many
(
:custom_attributes
).
class_name
(
'GroupCustomAttribute'
)
}
it
{
is_expected
.
to
have_many
(
:custom_attributes
).
class_name
(
'GroupCustomAttribute'
)
}
it
{
is_expected
.
to
have_many
(
:badges
).
class_name
(
'GroupBadge'
)
}
it
{
is_expected
.
to
have_many
(
:badges
).
class_name
(
'GroupBadge'
)
}
...
@@ -691,4 +691,12 @@ describe Group do
...
@@ -691,4 +691,12 @@ describe Group do
end
end
end
end
end
end
context
'with uploads'
do
it_behaves_like
'model with mounted uploader'
,
true
do
let
(
:model_object
)
{
create
(
:group
,
:with_avatar
)
}
let
(
:upload_attribute
)
{
:avatar
}
let
(
:uploader_class
)
{
AttachmentUploader
}
end
end
end
end
spec/models/project_spec.rb
View file @
fd5fdb2c
...
@@ -76,7 +76,7 @@ describe Project do
...
@@ -76,7 +76,7 @@ describe Project do
it
{
is_expected
.
to
have_many
(
:project_group_links
)
}
it
{
is_expected
.
to
have_many
(
:project_group_links
)
}
it
{
is_expected
.
to
have_many
(
:notification_settings
).
dependent
(
:delete_all
)
}
it
{
is_expected
.
to
have_many
(
:notification_settings
).
dependent
(
:delete_all
)
}
it
{
is_expected
.
to
have_many
(
:forks
).
through
(
:forked_project_links
)
}
it
{
is_expected
.
to
have_many
(
:forks
).
through
(
:forked_project_links
)
}
it
{
is_expected
.
to
have_many
(
:uploads
)
.
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
(
:uploads
)
}
it
{
is_expected
.
to
have_many
(
:pipeline_schedules
)
}
it
{
is_expected
.
to
have_many
(
:pipeline_schedules
)
}
it
{
is_expected
.
to
have_many
(
:members_and_requesters
)
}
it
{
is_expected
.
to
have_many
(
:members_and_requesters
)
}
it
{
is_expected
.
to
have_many
(
:clusters
)
}
it
{
is_expected
.
to
have_many
(
:clusters
)
}
...
@@ -3739,4 +3739,12 @@ describe Project do
...
@@ -3739,4 +3739,12 @@ describe Project do
it
{
is_expected
.
to
be_nil
}
it
{
is_expected
.
to
be_nil
}
end
end
end
end
context
'with uploads'
do
it_behaves_like
'model with mounted uploader'
,
true
do
let
(
:model_object
)
{
create
(
:project
,
:with_avatar
)
}
let
(
:upload_attribute
)
{
:avatar
}
let
(
:uploader_class
)
{
AttachmentUploader
}
end
end
end
end
spec/models/user_spec.rb
View file @
fd5fdb2c
...
@@ -39,7 +39,7 @@ describe User do
...
@@ -39,7 +39,7 @@ describe User do
it
{
is_expected
.
to
have_many
(
:builds
).
dependent
(
:nullify
)
}
it
{
is_expected
.
to
have_many
(
:builds
).
dependent
(
:nullify
)
}
it
{
is_expected
.
to
have_many
(
:pipelines
).
dependent
(
:nullify
)
}
it
{
is_expected
.
to
have_many
(
:pipelines
).
dependent
(
:nullify
)
}
it
{
is_expected
.
to
have_many
(
:chat_names
).
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
(
:chat_names
).
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
(
:uploads
)
.
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
(
:uploads
)
}
it
{
is_expected
.
to
have_many
(
:reported_abuse_reports
).
dependent
(
:destroy
).
class_name
(
'AbuseReport'
)
}
it
{
is_expected
.
to
have_many
(
:reported_abuse_reports
).
dependent
(
:destroy
).
class_name
(
'AbuseReport'
)
}
it
{
is_expected
.
to
have_many
(
:custom_attributes
).
class_name
(
'UserCustomAttribute'
)
}
it
{
is_expected
.
to
have_many
(
:custom_attributes
).
class_name
(
'UserCustomAttribute'
)
}
...
@@ -1223,6 +1223,24 @@ describe User do
...
@@ -1223,6 +1223,24 @@ describe User do
end
end
end
end
describe
'#accept_pending_invitations!'
do
let
(
:user
)
{
create
(
:user
,
email:
'user@email.com'
)
}
let!
(
:project_member_invite
)
{
create
(
:project_member
,
:invited
,
invite_email:
user
.
email
)
}
let!
(
:group_member_invite
)
{
create
(
:group_member
,
:invited
,
invite_email:
user
.
email
)
}
let!
(
:external_project_member_invite
)
{
create
(
:project_member
,
:invited
,
invite_email:
'external@email.com'
)
}
let!
(
:external_group_member_invite
)
{
create
(
:group_member
,
:invited
,
invite_email:
'external@email.com'
)
}
it
'accepts all the user members pending invitations and returns the accepted_members'
do
accepted_members
=
user
.
accept_pending_invitations!
expect
(
accepted_members
).
to
match_array
([
project_member_invite
,
group_member_invite
])
expect
(
group_member_invite
.
reload
).
not_to
be_invite
expect
(
project_member_invite
.
reload
).
not_to
be_invite
expect
(
external_project_member_invite
.
reload
).
to
be_invite
expect
(
external_group_member_invite
.
reload
).
to
be_invite
end
end
describe
'#all_emails'
do
describe
'#all_emails'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:user
)
{
create
(
:user
)
}
...
@@ -1786,28 +1804,54 @@ describe User do
...
@@ -1786,28 +1804,54 @@ describe User do
end
end
end
end
describe
'#ci_
authoriz
ed_runners'
do
describe
'#ci_
own
ed_runners'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:runner
)
{
create
(
:ci_runner
)
}
let
(
:runner_1
)
{
create
(
:ci_runner
)
}
let
(
:runner_2
)
{
create
(
:ci_runner
)
}
before
do
context
'without any projects nor groups'
do
project
.
runners
<<
runner
let!
(
:project
)
{
create
(
:project
,
runners:
[
runner_1
])
}
end
let!
(
:group
)
{
create
(
:group
)
}
context
'without any projects'
do
let
(
:project
)
{
create
(
:project
)
}
it
'does not load'
do
it
'does not load'
do
expect
(
user
.
ci_
authoriz
ed_runners
).
to
be_empty
expect
(
user
.
ci_
own
ed_runners
).
to
be_empty
end
end
end
end
context
'with personal projects runners'
do
context
'with personal projects runners'
do
let
(
:namespace
)
{
create
(
:namespace
,
owner:
user
)
}
let
(
:namespace
)
{
create
(
:namespace
,
owner:
user
)
}
let
(
:project
)
{
create
(
:project
,
namespace:
namespace
)
}
let!
(
:project
)
{
create
(
:project
,
namespace:
namespace
,
runners:
[
runner_1
])
}
it
'loads'
do
expect
(
user
.
ci_owned_runners
).
to
contain_exactly
(
runner_1
)
end
end
context
'with personal group runner'
do
let!
(
:project
)
{
create
(
:project
,
runners:
[
runner_1
])
}
let!
(
:group
)
do
create
(
:group
,
runners:
[
runner_2
]).
tap
do
|
group
|
group
.
add_owner
(
user
)
end
end
it
'loads'
do
expect
(
user
.
ci_owned_runners
).
to
contain_exactly
(
runner_2
)
end
end
context
'with personal project and group runner'
do
let
(
:namespace
)
{
create
(
:namespace
,
owner:
user
)
}
let!
(
:project
)
{
create
(
:project
,
namespace:
namespace
,
runners:
[
runner_1
])
}
let!
(
:group
)
do
create
(
:group
,
runners:
[
runner_2
]).
tap
do
|
group
|
group
.
add_owner
(
user
)
end
end
it
'loads'
do
it
'loads'
do
expect
(
user
.
ci_
authorized_runners
).
to
contain_exactly
(
runner
)
expect
(
user
.
ci_
owned_runners
).
to
contain_exactly
(
runner_1
,
runner_2
)
end
end
end
end
...
@@ -1818,7 +1862,7 @@ describe User do
...
@@ -1818,7 +1862,7 @@ describe User do
end
end
it
'loads'
do
it
'loads'
do
expect
(
user
.
ci_
authorized_runners
).
to
contain_exactly
(
runner
)
expect
(
user
.
ci_
owned_runners
).
to
contain_exactly
(
runner_1
)
end
end
end
end
...
@@ -1828,14 +1872,28 @@ describe User do
...
@@ -1828,14 +1872,28 @@ describe User do
end
end
it
'does not load'
do
it
'does not load'
do
expect
(
user
.
ci_
authoriz
ed_runners
).
to
be_empty
expect
(
user
.
ci_
own
ed_runners
).
to
be_empty
end
end
end
end
end
end
context
'with groups projects runners'
do
context
'with groups projects runners'
do
let
(
:group
)
{
create
(
:group
)
}
let
(
:group
)
{
create
(
:group
)
}
let
(
:project
)
{
create
(
:project
,
group:
group
)
}
let!
(
:project
)
{
create
(
:project
,
group:
group
,
runners:
[
runner_1
])
}
def
add_user
(
access
)
group
.
add_user
(
user
,
access
)
end
it_behaves_like
:member
end
context
'with groups runners'
do
let!
(
:group
)
do
create
(
:group
,
runners:
[
runner_1
]).
tap
do
|
group
|
group
.
add_owner
(
user
)
end
end
def
add_user
(
access
)
def
add_user
(
access
)
group
.
add_user
(
user
,
access
)
group
.
add_user
(
user
,
access
)
...
@@ -1845,7 +1903,7 @@ describe User do
...
@@ -1845,7 +1903,7 @@ describe User do
end
end
context
'with other projects runners'
do
context
'with other projects runners'
do
let
(
:project
)
{
create
(
:project
)
}
let
!
(
:project
)
{
create
(
:project
,
runners:
[
runner_1
]
)
}
def
add_user
(
access
)
def
add_user
(
access
)
project
.
add_role
(
user
,
access
)
project
.
add_role
(
user
,
access
)
...
@@ -1858,7 +1916,7 @@ describe User do
...
@@ -1858,7 +1916,7 @@ describe User do
let
(
:group
)
{
create
(
:group
)
}
let
(
:group
)
{
create
(
:group
)
}
let
(
:another_user
)
{
create
(
:user
)
}
let
(
:another_user
)
{
create
(
:user
)
}
let
(
:subgroup
)
{
create
(
:group
,
parent:
group
)
}
let
(
:subgroup
)
{
create
(
:group
,
parent:
group
)
}
let
(
:project
)
{
create
(
:project
,
group:
subgroup
)
}
let
!
(
:project
)
{
create
(
:project
,
group:
subgroup
,
runners:
[
runner_1
]
)
}
def
add_user
(
access
)
def
add_user
(
access
)
group
.
add_user
(
user
,
access
)
group
.
add_user
(
user
,
access
)
...
@@ -2769,4 +2827,12 @@ describe User do
...
@@ -2769,4 +2827,12 @@ describe User do
expect
{
user
.
increment_failed_attempts!
}.
not_to
change
(
user
,
:failed_attempts
)
expect
{
user
.
increment_failed_attempts!
}.
not_to
change
(
user
,
:failed_attempts
)
end
end
end
end
context
'with uploads'
do
it_behaves_like
'model with mounted uploader'
,
false
do
let
(
:model_object
)
{
create
(
:user
,
:with_avatar
)
}
let
(
:upload_attribute
)
{
:avatar
}
let
(
:uploader_class
)
{
AttachmentUploader
}
end
end
end
end
spec/requests/api/runners_spec.rb
View file @
fd5fdb2c
...
@@ -27,7 +27,7 @@ describe API::Runners do
...
@@ -27,7 +27,7 @@ describe API::Runners do
end
end
end
end
let!
(
:group_runner
)
{
create
(
:ci_runner
,
description:
'Group runner'
,
groups:
[
group
])
}
let!
(
:group_runner
)
{
create
(
:ci_runner
,
description:
'Group runner'
,
groups:
[
group
]
,
runner_type: :group_type
)
}
before
do
before
do
# Set project access for users
# Set project access for users
...
@@ -48,7 +48,7 @@ describe API::Runners do
...
@@ -48,7 +48,7 @@ describe API::Runners do
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
[
0
]).
to
have_key
(
'ip_address'
)
expect
(
json_response
[
0
]).
to
have_key
(
'ip_address'
)
expect
(
descriptions
).
to
contain_exactly
(
expect
(
descriptions
).
to
contain_exactly
(
'Project runner'
,
'Two projects runner'
'Project runner'
,
'Two projects runner'
,
'Group runner'
)
)
expect
(
shared
).
to
be_falsey
expect
(
shared
).
to
be_falsey
end
end
...
@@ -592,6 +592,15 @@ describe API::Runners do
...
@@ -592,6 +592,15 @@ describe API::Runners do
end
.
to
change
{
project
.
runners
.
count
}.
by
(
+
1
)
end
.
to
change
{
project
.
runners
.
count
}.
by
(
+
1
)
expect
(
response
).
to
have_gitlab_http_status
(
201
)
expect
(
response
).
to
have_gitlab_http_status
(
201
)
end
end
it
'enables a shared runner'
do
expect
do
post
api
(
"/projects/
#{
project
.
id
}
/runners"
,
admin
),
runner_id:
shared_runner
.
id
end
.
to
change
{
project
.
runners
.
count
}.
by
(
1
)
expect
(
shared_runner
.
reload
).
not_to
be_shared
expect
(
response
).
to
have_gitlab_http_status
(
201
)
end
end
end
context
'user is not admin'
do
context
'user is not admin'
do
...
...
spec/support/shared_examples/models/with_uploads_shared_examples.rb
0 → 100644
View file @
fd5fdb2c
require
'spec_helper'
shared_examples_for
'model with mounted uploader'
do
|
supports_fileuploads
|
describe
'.destroy'
do
before
do
stub_uploads_object_storage
(
uploader_class
)
model_object
.
public_send
(
upload_attribute
).
migrate!
(
ObjectStorage
::
Store
::
REMOTE
)
end
it
'deletes remote uploads'
do
expect_any_instance_of
(
CarrierWave
::
Storage
::
Fog
::
File
).
to
receive
(
:delete
).
and_call_original
expect
{
model_object
.
destroy
}.
to
change
{
Upload
.
count
}.
by
(
-
1
)
end
it
'deletes any FileUploader uploads which are not mounted'
,
skip:
!
supports_fileuploads
do
create
(
:upload
,
uploader:
FileUploader
,
model:
model_object
)
expect
{
model_object
.
destroy
}.
to
change
{
Upload
.
count
}.
by
(
-
2
)
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment