Commit 50076ab9 authored by Kamil Trzcinski's avatar Kamil Trzcinski

Merge remote-tracking branch 'origin/master' into per-build-token

# Conflicts:
#	db/schema.rb
parents 11f87700 4768521a
*.erb *.erb
lib/gitlab/sanitizers/svg/whitelist.rb
...@@ -206,10 +206,15 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21 ...@@ -206,10 +206,15 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
- bundle exec $CI_BUILD_NAME - bundle exec $CI_BUILD_NAME
rubocop: *exec rubocop: *exec
rake haml_lint: *exec
rake scss_lint: *exec rake scss_lint: *exec
rake brakeman: *exec rake brakeman: *exec
rake flog: *exec rake flog:
rake flay: *exec <<: *exec
allow_failure: yes
rake flay:
<<: *exec
allow_failure: yes
license_finder: *exec license_finder: *exec
rake downtime_check: *exec rake downtime_check: *exec
......
# Whether to ignore frontmatter at the beginning of HAML documents for
# frameworks such as Jekyll/Middleman
skip_frontmatter: false
exclude:
- 'vendor/**/*'
- 'spec/**/*'
linters:
AltText:
enabled: false
ClassAttributeWithStaticValue:
enabled: false
ClassesBeforeIds:
enabled: false
ConsecutiveComments:
enabled: false
ConsecutiveSilentScripts:
enabled: false
max_consecutive: 2
EmptyObjectReference:
enabled: true
EmptyScript:
enabled: true
FinalNewline:
enabled: false
present: true
HtmlAttributes:
enabled: false
ImplicitDiv:
enabled: false
LeadingCommentSpace:
enabled: false
LineLength:
enabled: false
max: 80
MultilinePipe:
enabled: false
MultilineScript:
enabled: true
ObjectReferenceAttributes:
enabled: true
RuboCop:
enabled: false
# These cops are incredibly noisy when it comes to HAML templates, so we
# ignore them.
ignored_cops:
- Lint/BlockAlignment
- Lint/EndAlignment
- Lint/Void
- Metrics/LineLength
- Style/AlignParameters
- Style/BlockNesting
- Style/ElseAlignment
- Style/FileName
- Style/FinalNewline
- Style/FrozenStringLiteralComment
- Style/IfUnlessModifier
- Style/IndentationWidth
- Style/Next
- Style/TrailingBlankLines
- Style/TrailingWhitespace
- Style/WhileUntilModifier
RubyComments:
enabled: false
SpaceBeforeScript:
enabled: false
SpaceInsideHashAttributes:
enabled: false
style: space
Indentation:
enabled: true
character: space # or tab
TagName:
enabled: true
TrailingWhitespace:
enabled: false
UnnecessaryInterpolation:
enabled: false
UnnecessaryStringOutput:
enabled: false
This diff is collapsed.
...@@ -2,24 +2,29 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -2,24 +2,29 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.12.0 (unreleased) v 8.12.0 (unreleased)
- Update the rouge gem to 2.0.6, which adds highlighting support for JSX, Prometheus, and others. !6251 - Update the rouge gem to 2.0.6, which adds highlighting support for JSX, Prometheus, and others. !6251
- Only check :can_resolve permission if the note is resolvable
- Add ability to fork to a specific namespace using API. (ritave) - Add ability to fork to a specific namespace using API. (ritave)
- Cleanup misalignments in Issue list view !6206 - Cleanup misalignments in Issue list view !6206
- Prune events older than 12 months. (ritave) - Prune events older than 12 months. (ritave)
- Prepend blank line to `Closes` message on merge request linked to issue (lukehowell) - Prepend blank line to `Closes` message on merge request linked to issue (lukehowell)
- Filter tags by name !6121 - Filter tags by name !6121
- Update gitlab shell secret file also when it is empty. !3774 (glensc)
- Give project selection dropdowns responsive width, make non-wrapping. - Give project selection dropdowns responsive width, make non-wrapping.
- Make push events have equal vertical spacing. - Make push events have equal vertical spacing.
- Add two-factor recovery endpoint to internal API !5510 - Add two-factor recovery endpoint to internal API !5510
- Pass the "Remember me" value to the U2F authentication form - Pass the "Remember me" value to the U2F authentication form
- Remove vendor prefixes for linear-gradient CSS (ClemMakesApps) - Remove vendor prefixes for linear-gradient CSS (ClemMakesApps)
- Move pushes_since_gc from the database to Redis
- Add font color contrast to external label in admin area (ClemMakesApps) - Add font color contrast to external label in admin area (ClemMakesApps)
- Change logo animation to CSS (ClemMakesApps) - Change logo animation to CSS (ClemMakesApps)
- Instructions for enabling Git packfile bitmaps !6104 - Instructions for enabling Git packfile bitmaps !6104
- Use Search::GlobalService.new in the `GET /projects/search/:query` endpoint - Use Search::GlobalService.new in the `GET /projects/search/:query` endpoint
- Fix pagination on user snippets page - Fix pagination on user snippets page
- Fix sorting of issues in API - Fix sorting of issues in API
- Ensure specs on sorting of issues in API are deterministic on MySQL
- Escape search term before passing it to Regexp.new !6241 (winniehell) - Escape search term before passing it to Regexp.new !6241 (winniehell)
- Fix pinned sidebar behavior in smaller viewports !6169 - Fix pinned sidebar behavior in smaller viewports !6169
- Fix file permissions change when updating a file on the Gitlab UI !5979
- Change merge_error column from string to text type - Change merge_error column from string to text type
- Reduce contributions calendar data payload (ClemMakesApps) - Reduce contributions calendar data payload (ClemMakesApps)
- Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
...@@ -76,6 +81,7 @@ v 8.12.0 (unreleased) ...@@ -76,6 +81,7 @@ v 8.12.0 (unreleased)
- Remove inconsistent font weight for sidebar's labels (ClemMakesApps) - Remove inconsistent font weight for sidebar's labels (ClemMakesApps)
- Align add button on repository view (ClemMakesApps) - Align add button on repository view (ClemMakesApps)
- Fix contributions calendar month label truncation (ClemMakesApps) - Fix contributions calendar month label truncation (ClemMakesApps)
- Import release note descriptions from GitHub (EspadaV8)
- Added tests for diff notes - Added tests for diff notes
- Add pipeline events to Slack integration !5525 - Add pipeline events to Slack integration !5525
- Add a button to download latest successful artifacts for branches and tags !5142 - Add a button to download latest successful artifacts for branches and tags !5142
...@@ -87,12 +93,14 @@ v 8.12.0 (unreleased) ...@@ -87,12 +93,14 @@ v 8.12.0 (unreleased)
- Fix repo title alignment (ClemMakesApps) - Fix repo title alignment (ClemMakesApps)
- Change update interval of contacted_at - Change update interval of contacted_at
- Fix branch title trailing space on hover (ClemMakesApps) - Fix branch title trailing space on hover (ClemMakesApps)
- Don't include 'Created By' tag line when importing from GitHub if there is a linked GitLab account (EspadaV8)
- Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison) - Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison)
- Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison) - Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison)
- Order award emoji tooltips in order they were added (EspadaV8) - Order award emoji tooltips in order they were added (EspadaV8)
- Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps) - Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps)
- Update merge_requests.md with a simpler way to check out a merge request. !5944 - Update merge_requests.md with a simpler way to check out a merge request. !5944
- Fix button missing type (ClemMakesApps) - Fix button missing type (ClemMakesApps)
- Gitlab::Checks is now instrumented
- Move to project dropdown with infinite scroll for better performance - Move to project dropdown with infinite scroll for better performance
- Fix leaking of submit buttons outside the width of a main container !18731 (originally by @pavelloz) - Fix leaking of submit buttons outside the width of a main container !18731 (originally by @pavelloz)
- Load branches asynchronously in Cherry Pick and Revert dialogs. - Load branches asynchronously in Cherry Pick and Revert dialogs.
...@@ -111,6 +119,8 @@ v 8.12.0 (unreleased) ...@@ -111,6 +119,8 @@ v 8.12.0 (unreleased)
- Avoid conflict with admin labels when importing GitHub labels - Avoid conflict with admin labels when importing GitHub labels
- User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496 - User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496
- Fix repository page ui issues - Fix repository page ui issues
- Avoid protected branches checks when verifying access without branch name
- Add information about user and manual build start to runner as variables !6201 (Sergey Gnuskov)
- Fixed invisible scroll controls on build page on iPhone - Fixed invisible scroll controls on build page on iPhone
- Fix error on raw build trace download for old builds stored in database !4822 - Fix error on raw build trace download for old builds stored in database !4822
- Refactor the triggers page and documentation !6217 - Refactor the triggers page and documentation !6217
...@@ -119,8 +129,23 @@ v 8.12.0 (unreleased) ...@@ -119,8 +129,23 @@ v 8.12.0 (unreleased)
- API for Ci Lint !5953 (Katarzyna Kobierska Urszula Budziszewska) - API for Ci Lint !5953 (Katarzyna Kobierska Urszula Budziszewska)
- Allow bulk update merge requests from merge requests index page - Allow bulk update merge requests from merge requests index page
- Add notification_settings API calls !5632 (mahcsig) - Add notification_settings API calls !5632 (mahcsig)
- Remove duplication between project builds and admin builds view !5680 (Katarzyna Kobierska Ula Budziszewska)
v 8.11.6 (unreleased) - Fix URLs with anchors in wiki !6300 (houqp)
- Deleting source project with existing fork link will close all related merge requests !6177 (Katarzyna Kobierska Ula Budziszeska)
- Return 204 instead of 404 for /ci/api/v1/builds/register.json if no builds are scheduled for a runner !6225
- Fix Gitlab::Popen.popen thread-safety issue
- Add specs to removing project (Katarzyna Kobierska Ula Budziszewska)
- Clean environment variables when running git hooks
v 8.11.6
- Fix unnecessary horizontal scroll area in pipeline visualizations. !6005
- Make merge conflict file size limit 200 KB, to match the docs. !6052
- Fix an error where we were unable to create a CommitStatus for running state. !6107
- Optimize discussion notes resolving and unresolving. !6141
- Fix GitLab import button. !6167
- Restore SSH Key title auto-population behavior. !6186
- Fix DB schema to match latest migration. !6256
- Exclude some pending or inactivated rows in Member scopes.
v 8.11.5 v 8.11.5
- Optimize branch lookups and force a repository reload for Repository#find_branch. !6087 - Optimize branch lookups and force a repository reload for Repository#find_branch. !6087
...@@ -325,6 +350,13 @@ v 8.11.0 ...@@ -325,6 +350,13 @@ v 8.11.0
- Update gitlab_git gem to 10.4.7 - Update gitlab_git gem to 10.4.7
- Simplify SQL queries of marking a todo as done - Simplify SQL queries of marking a todo as done
v 8.10.9
- Exclude some pending or inactivated rows in Member scopes
v 8.10.8
- Fix information disclosure in issue boards.
- Fix privilege escalation in project import.
v 8.10.7 v 8.10.7
- Upgrade Hamlit to 2.6.1. !5873 - Upgrade Hamlit to 2.6.1. !5873
- Upgrade Doorkeeper to 4.2.0. !5881 - Upgrade Doorkeeper to 4.2.0. !5881
...@@ -550,6 +582,9 @@ v 8.10.0 ...@@ -550,6 +582,9 @@ v 8.10.0
- Fix migration corrupting import data for old version upgrades - Fix migration corrupting import data for old version upgrades
- Show tooltip on GitLab export link in new project page - Show tooltip on GitLab export link in new project page
v 8.9.9
- Exclude some pending or inactivated rows in Member scopes
v 8.9.8 v 8.9.8
- Upgrade Doorkeeper to 4.2.0. !5881 - Upgrade Doorkeeper to 4.2.0. !5881
......
...@@ -91,19 +91,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs]. ...@@ -91,19 +91,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
## Implement design & UI elements ## Implement design & UI elements
### Design reference Please see the [UI Guide for building GitLab].
The GitLab design reference can be found in the [gitlab-design] project.
The designs are made using Antetype (`.atype` files). You can use the
[free Antetype viewer (Mac OSX only)] or grab an exported PNG from the design
(the PNG is 1:1).
The current designs can be found in the [`gitlab8.atype` file].
### UI development kit
Implemented UI elements can also be found at https://gitlab.com/help/ui. Please
note that this page isn't comprehensive at this time.
## Issue tracker ## Issue tracker
...@@ -489,7 +477,5 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor ...@@ -489,7 +477,5 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide" [doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide" [scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide" [newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design [UI Guide for building GitLab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/ui_guide.md
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab8.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/current/
[license-finder-doc]: doc/development/licensing.md [license-finder-doc]: doc/development/licensing.md
...@@ -26,7 +26,7 @@ gem 'omniauth-auth0', '~> 1.4.1' ...@@ -26,7 +26,7 @@ gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6' gem 'omniauth-azure-oauth2', '~> 0.0.6'
gem 'omniauth-bitbucket', '~> 0.0.2' gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-cas3', '~> 1.1.2' gem 'omniauth-cas3', '~> 1.1.2'
gem 'omniauth-facebook', '~> 3.0.0' gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0' gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.4.1' gem 'omniauth-google-oauth2', '~> 0.4.1'
...@@ -53,7 +53,7 @@ gem 'browser', '~> 2.2' ...@@ -53,7 +53,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem 'gitlab_git', '~> 10.6.3' gem 'gitlab_git', '~> 10.6.6'
# LDAP Auth # LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes # GitLab fork with several improvements to original library. For full list of changes
...@@ -295,9 +295,10 @@ group :development, :test do ...@@ -295,9 +295,10 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.1.0' gem 'spring-commands-spinach', '~> 1.1.0'
gem 'spring-commands-teaspoon', '~> 0.0.2' gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.41.2', require: false gem 'rubocop', '~> 0.42.0', require: false
gem 'rubocop-rspec', '~> 1.5.0', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false gem 'scss_lint', '~> 0.47.0', require: false
gem 'haml_lint', '~> 0.18.2', require: false
gem 'simplecov', '0.12.0', require: false gem 'simplecov', '0.12.0', require: false
gem 'flog', '~> 4.3.2', require: false gem 'flog', '~> 4.3.2', require: false
gem 'flay', '~> 2.6.1', require: false gem 'flay', '~> 2.6.1', require: false
......
...@@ -279,7 +279,7 @@ GEM ...@@ -279,7 +279,7 @@ GEM
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab_git (10.6.3) gitlab_git (10.6.6)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.7.3) charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
...@@ -322,11 +322,18 @@ GEM ...@@ -322,11 +322,18 @@ GEM
grape-entity (0.4.8) grape-entity (0.4.8)
activesupport activesupport
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
haml (4.0.7)
tilt
haml_lint (0.18.2)
haml (~> 4.0)
rake (>= 10, < 12)
rubocop (>= 0.36.0)
sysexits (~> 1.1)
hamlit (2.6.1) hamlit (2.6.1)
temple (~> 0.7.6) temple (~> 0.7.6)
thor thor
tilt tilt
hashie (3.4.3) hashie (3.4.4)
health_check (2.1.0) health_check (2.1.0)
rails (>= 4.0) rails (>= 4.0)
hipchat (1.5.2) hipchat (1.5.2)
...@@ -394,7 +401,7 @@ GEM ...@@ -394,7 +401,7 @@ GEM
mime-types (>= 1.16, < 4) mime-types (>= 1.16, < 4)
mail_room (0.8.0) mail_room (0.8.0)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.99.2) mime-types (2.99.3)
mimemagic (0.3.0) mimemagic (0.3.0)
mini_portile2 (2.1.0) mini_portile2 (2.1.0)
minitest (5.7.0) minitest (5.7.0)
...@@ -437,7 +444,7 @@ GEM ...@@ -437,7 +444,7 @@ GEM
addressable (~> 2.3) addressable (~> 2.3)
nokogiri (~> 1.6.6) nokogiri (~> 1.6.6)
omniauth (~> 1.2) omniauth (~> 1.2)
omniauth-facebook (3.0.0) omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2) omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2) omniauth-github (1.1.2)
omniauth (~> 1.0) omniauth (~> 1.0)
...@@ -612,7 +619,7 @@ GEM ...@@ -612,7 +619,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)
rubocop (0.41.2) rubocop (0.42.0)
parser (>= 2.3.1.1, < 3.0) parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1) powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0) rainbow (>= 1.99.1, < 3.0)
...@@ -723,6 +730,7 @@ GEM ...@@ -723,6 +730,7 @@ GEM
stringex (2.5.2) stringex (2.5.2)
sys-filesystem (1.1.6) sys-filesystem (1.1.6)
ffi ffi
sysexits (1.2.0)
systemu (2.6.5) systemu (2.6.5)
task_list (1.0.2) task_list (1.0.2)
html-pipeline html-pipeline
...@@ -754,7 +762,7 @@ GEM ...@@ -754,7 +762,7 @@ GEM
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.2) unf_ext (0.0.7.2)
unicode-display_width (1.1.0) unicode-display_width (1.1.1)
unicorn (4.9.0) unicorn (4.9.0)
kgio (~> 2.6) kgio (~> 2.6)
rack rack
...@@ -858,7 +866,7 @@ DEPENDENCIES ...@@ -858,7 +866,7 @@ DEPENDENCIES
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
github-markup (~> 1.4) github-markup (~> 1.4)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_git (~> 10.6.3) gitlab_git (~> 10.6.6)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2) gollum-lib (~> 4.2)
...@@ -866,6 +874,7 @@ DEPENDENCIES ...@@ -866,6 +874,7 @@ DEPENDENCIES
gon (~> 6.1.0) gon (~> 6.1.0)
grape (~> 0.15.0) grape (~> 0.15.0)
grape-entity (~> 0.4.2) grape-entity (~> 0.4.2)
haml_lint (~> 0.18.2)
hamlit (~> 2.6.1) hamlit (~> 2.6.1)
health_check (~> 2.1.0) health_check (~> 2.1.0)
hipchat (~> 1.5.0) hipchat (~> 1.5.0)
...@@ -900,7 +909,7 @@ DEPENDENCIES ...@@ -900,7 +909,7 @@ DEPENDENCIES
omniauth-azure-oauth2 (~> 0.0.6) omniauth-azure-oauth2 (~> 0.0.6)
omniauth-bitbucket (~> 0.0.2) omniauth-bitbucket (~> 0.0.2)
omniauth-cas3 (~> 1.1.2) omniauth-cas3 (~> 1.1.2)
omniauth-facebook (~> 3.0.0) omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.1.1) omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0) omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.4.1) omniauth-google-oauth2 (~> 0.4.1)
...@@ -935,7 +944,7 @@ DEPENDENCIES ...@@ -935,7 +944,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)
rubocop (~> 0.41.2) rubocop (~> 0.42.0)
rubocop-rspec (~> 1.5.0) rubocop-rspec (~> 1.5.0)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.15.9) ruby-prof (~> 0.15.9)
......
...@@ -79,10 +79,6 @@ ...@@ -79,10 +79,6 @@
padding-left: 15px !important; padding-left: 15px !important;
} }
.issue-info, .merge-request-info {
display: none;
}
.nav-links, .nav-links { .nav-links, .nav-links {
li a { li a {
font-size: 14px; font-size: 14px;
......
...@@ -206,7 +206,7 @@ ...@@ -206,7 +206,7 @@
padding-top: 0; padding-top: 0;
.block { .block {
width: $sidebar_collapsed_width - 1px; width: $sidebar_collapsed_width - 2px;
margin-left: -19px; margin-left: -19px;
padding: 15px 0 0; padding: 15px 0 0;
border-bottom: none; border-bottom: none;
......
...@@ -37,6 +37,15 @@ form.edit-issue { ...@@ -37,6 +37,15 @@ form.edit-issue {
margin: 0; margin: 0;
} }
ul.related-merge-requests > li {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
.merge-request-id {
flex-shrink: 0;
}
}
.merge-requests-title, .related-branches-title { .merge-requests-title, .related-branches-title {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
......
...@@ -7,8 +7,7 @@ module CreatesCommit ...@@ -7,8 +7,7 @@ module CreatesCommit
commit_params = @commit_params.merge( commit_params = @commit_params.merge(
source_project: @project, source_project: @project,
source_branch: @ref, source_branch: @ref,
target_branch: @target_branch, target_branch: @target_branch
previous_path: @previous_path
) )
result = service.new(@tree_edit_project, current_user, commit_params).execute result = service.new(@tree_edit_project, current_user, commit_params).execute
......
...@@ -38,12 +38,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -38,12 +38,7 @@ class Projects::BlobController < Projects::ApplicationController
end end
def update def update
if params[:file_path].present? @path = params[:file_path] if params[:file_path].present?
@previous_path = @path
@path = params[:file_path]
@commit_params[:file_path] = @path
end
after_edit_path = after_edit_path =
if from_merge_request && @target_branch == @ref if from_merge_request && @target_branch == @ref
diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) + diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) +
...@@ -143,6 +138,8 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -143,6 +138,8 @@ class Projects::BlobController < Projects::ApplicationController
params[:file_name] = params[:file].original_filename params[:file_name] = params[:file].original_filename
end end
File.join(@path, params[:file_name]) File.join(@path, params[:file_name])
elsif params[:file_path].present?
params[:file_path]
else else
@path @path
end end
...@@ -155,6 +152,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -155,6 +152,7 @@ class Projects::BlobController < Projects::ApplicationController
@commit_params = { @commit_params = {
file_path: @file_path, file_path: @file_path,
commit_message: params[:commit_message], commit_message: params[:commit_message],
previous_path: @path,
file_content: params[:content], file_content: params[:content],
file_content_encoding: params[:encoding], file_content_encoding: params[:encoding],
last_commit_sha: params[:last_commit_sha] last_commit_sha: params[:last_commit_sha]
......
...@@ -428,17 +428,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -428,17 +428,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def validates_merge_request def validates_merge_request
# If source project was removed (Ex. mr from fork to origin)
return invalid_mr unless @merge_request.source_project
# Show git not found page # Show git not found page
# if there is no saved commits between source & target branch # if there is no saved commits between source & target branch
if @merge_request.commits.blank? if @merge_request.commits.blank?
# and if target branch doesn't exist # and if target branch doesn't exist
return invalid_mr unless @merge_request.target_branch_exists? return invalid_mr unless @merge_request.target_branch_exists?
# or if source branch doesn't exist
return invalid_mr unless @merge_request.source_branch_exists?
end end
end end
......
...@@ -30,6 +30,37 @@ module SearchHelper ...@@ -30,6 +30,37 @@ module SearchHelper
"Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\"" "Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\""
end end
def parse_search_result(result)
ref = nil
filename = nil
basename = nil
startline = 0
result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
startline = startline.to_i - index
extname = Regexp.escape(File.extname(filename))
basename = filename.sub(/#{extname}$/, '')
break
end
end
data = ""
result.each_line do |line|
data << line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
end
OpenStruct.new(
filename: filename,
basename: basename,
ref: ref,
startline: startline,
data: data
)
end
private private
# Autocomplete results for various settings pages # Autocomplete results for various settings pages
......
...@@ -22,6 +22,18 @@ class Blob < SimpleDelegator ...@@ -22,6 +22,18 @@ class Blob < SimpleDelegator
new(blob) new(blob)
end end
# Returns the data of the blob.
#
# If the blob is a text based blob the content is converted to UTF-8 and any
# invalid byte sequences are replaced.
def data
if binary?
super
else
@data ||= super.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
end
end
def no_highlighting? def no_highlighting?
size && size > 1.megabyte size && size > 1.megabyte
end end
......
...@@ -153,6 +153,7 @@ module Ci ...@@ -153,6 +153,7 @@ module Ci
variables += runner.predefined_variables if runner variables += runner.predefined_variables if runner
variables += project.container_registry_variables variables += project.container_registry_variables
variables += yaml_variables variables += yaml_variables
variables += user_variables
variables += project.secret_variables variables += project.secret_variables
variables += trigger_request.user_variables if trigger_request variables += trigger_request.user_variables if trigger_request
variables variables
...@@ -435,6 +436,15 @@ module Ci ...@@ -435,6 +436,15 @@ module Ci
read_attribute(:yaml_variables) || build_attributes_from_config[:yaml_variables] || [] read_attribute(:yaml_variables) || build_attributes_from_config[:yaml_variables] || []
end end
def user_variables
return [] if user.blank?
[
{ key: 'GITLAB_USER_ID', value: user.id.to_s, public: true },
{ key: 'GITLAB_USER_EMAIL', value: user.email, public: true }
]
end
private private
def update_artifacts_size def update_artifacts_size
...@@ -470,6 +480,7 @@ module Ci ...@@ -470,6 +480,7 @@ module Ci
] ]
variables << { key: 'CI_BUILD_TAG', value: ref, public: true } if tag? variables << { key: 'CI_BUILD_TAG', value: ref, public: true } if tag?
variables << { key: 'CI_BUILD_TRIGGERED', value: 'true', public: true } if trigger_request variables << { key: 'CI_BUILD_TRIGGERED', value: 'true', public: true } if trigger_request
variables << { key: 'CI_BUILD_MANUAL', value: 'true', public: true } if manual?
variables variables
end end
......
...@@ -28,17 +28,34 @@ class Member < ActiveRecord::Base ...@@ -28,17 +28,34 @@ class Member < ActiveRecord::Base
allow_nil: true allow_nil: true
} }
# This scope encapsulates (most of) the conditions a row in the member table
# must satisfy if it is a valid permission. Of particular note:
#
# * Access requests must be excluded
# * Blocked users must be excluded
# * Invitations take effect immediately
# * expires_at is not implemented. A background worker purges expired rows
scope :active, -> do
is_external_invite = arel_table[:user_id].eq(nil).and(arel_table[:invite_token].not_eq(nil))
user_is_active = User.arel_table[:state].eq(:active)
includes(:user).references(:users)
.where(is_external_invite.or(user_is_active))
.where(requested_at: nil)
end
scope :invite, -> { where.not(invite_token: nil) } scope :invite, -> { where.not(invite_token: nil) }
scope :non_invite, -> { where(invite_token: nil) } scope :non_invite, -> { where(invite_token: nil) }
scope :request, -> { where.not(requested_at: nil) } scope :request, -> { where.not(requested_at: nil) }
scope :has_access, -> { where('access_level > 0') }
scope :has_access, -> { active.where('access_level > 0') }
scope :guests, -> { where(access_level: GUEST) }
scope :reporters, -> { where(access_level: REPORTER) } scope :guests, -> { active.where(access_level: GUEST) }
scope :developers, -> { where(access_level: DEVELOPER) } scope :reporters, -> { active.where(access_level: REPORTER) }
scope :masters, -> { where(access_level: MASTER) } scope :developers, -> { active.where(access_level: DEVELOPER) }
scope :owners, -> { where(access_level: OWNER) } scope :masters, -> { active.where(access_level: MASTER) }
scope :owners_and_masters, -> { where(access_level: [OWNER, MASTER]) } scope :owners, -> { active.where(access_level: OWNER) }
scope :owners_and_masters, -> { active.where(access_level: [OWNER, MASTER]) }
before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? } before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? }
......
...@@ -316,6 +316,10 @@ class MergeRequest < ActiveRecord::Base ...@@ -316,6 +316,10 @@ class MergeRequest < ActiveRecord::Base
closed? && forked_source_project_missing? closed? && forked_source_project_missing?
end end
def closed_without_source_project?
closed? && !source_project
end
def forked_source_project_missing? def forked_source_project_missing?
return false unless for_fork? return false unless for_fork?
return true unless source_project return true unless source_project
...@@ -323,6 +327,12 @@ class MergeRequest < ActiveRecord::Base ...@@ -323,6 +327,12 @@ class MergeRequest < ActiveRecord::Base
!source_project.forked_from?(target_project) !source_project.forked_from?(target_project)
end end
def reopenable?
return false if closed_without_fork? || closed_without_source_project? || merged?
closed?
end
def ensure_merge_request_diff def ensure_merge_request_diff
merge_request_diff || create_merge_request_diff merge_request_diff || create_merge_request_diff
end end
......
...@@ -58,7 +58,7 @@ class Project < ActiveRecord::Base ...@@ -58,7 +58,7 @@ class Project < ActiveRecord::Base
# Relations # Relations
belongs_to :creator, foreign_key: 'creator_id', class_name: 'User' belongs_to :creator, foreign_key: 'creator_id', class_name: 'User'
belongs_to :group, -> { where(type: Group) }, foreign_key: 'namespace_id' belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id'
belongs_to :namespace belongs_to :namespace
has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event', foreign_key: 'project_id' has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event', foreign_key: 'project_id'
...@@ -1282,8 +1282,24 @@ class Project < ActiveRecord::Base ...@@ -1282,8 +1282,24 @@ class Project < ActiveRecord::Base
end end
end end
def pushes_since_gc
Gitlab::Redis.with { |redis| redis.get(pushes_since_gc_redis_key).to_i }
end
def increment_pushes_since_gc
Gitlab::Redis.with { |redis| redis.incr(pushes_since_gc_redis_key) }
end
def reset_pushes_since_gc
Gitlab::Redis.with { |redis| redis.del(pushes_since_gc_redis_key) }
end
private private
def pushes_since_gc_redis_key
"projects/#{id}/pushes_since_gc"
end
# Prevents the creation of project_feature record for every project # Prevents the creation of project_feature record for every project
def setup_project_feature def setup_project_feature
build_project_feature unless project_feature build_project_feature unless project_feature
......
...@@ -813,7 +813,7 @@ class Repository ...@@ -813,7 +813,7 @@ class Repository
update: true update: true
} }
if previous_path if previous_path && previous_path != path
options[:file][:previous_path] = previous_path options[:file][:previous_path] = previous_path
Gitlab::Git::Blob.rename(raw_repository, options) Gitlab::Git::Blob.rename(raw_repository, options)
else else
...@@ -990,37 +990,6 @@ class Repository ...@@ -990,37 +990,6 @@ class Repository
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/) Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end end
def parse_search_result(result)
ref = nil
filename = nil
basename = nil
startline = 0
result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
startline = startline.to_i - index
extname = Regexp.escape(File.extname(filename))
basename = filename.sub(/#{extname}$/, '')
break
end
end
data = ""
result.each_line do |line|
data << line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
end
OpenStruct.new(
filename: filename,
basename: basename,
ref: ref,
startline: startline,
data: data
)
end
def fetch_ref(source_path, source_ref, target_ref) def fetch_ref(source_path, source_ref, target_ref)
args = %W(#{Gitlab.config.git.bin_path} fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref}) args = %W(#{Gitlab.config.git.bin_path} fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo) Gitlab::Popen.popen(args, path_to_repo)
...@@ -1048,7 +1017,7 @@ class Repository ...@@ -1048,7 +1017,7 @@ class Repository
GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do
update_ref!(ref, newrev, oldrev) update_ref!(ref, newrev, oldrev)
if was_empty || !target_branch if was_empty || !target_branch
# If repo was empty expire cache # If repo was empty expire cache
after_create if was_empty after_create if was_empty
......
...@@ -31,13 +31,13 @@ module Ci ...@@ -31,13 +31,13 @@ module Ci
current_status = status_for_prior_stages(index) current_status = status_for_prior_stages(index)
created_builds_in_stage(index).select do |build| created_builds_in_stage(index).select do |build|
process_build(build, current_status) if HasStatus::COMPLETED_STATUSES.include?(current_status)
process_build(build, current_status)
end
end end
end end
def process_build(build, current_status) def process_build(build, current_status)
return false unless HasStatus::COMPLETED_STATUSES.include?(current_status)
if valid_statuses_for_when(build.when).include?(current_status) if valid_statuses_for_when(build.when).include?(current_status)
build.enqueue build.enqueue
true true
......
...@@ -27,6 +27,8 @@ module Projects ...@@ -27,6 +27,8 @@ module Projects
# Git data (e.g. a list of branch names). # Git data (e.g. a list of branch names).
flush_caches(project, wiki_path) flush_caches(project, wiki_path)
Projects::UnlinkForkService.new(project, current_user).execute
Project.transaction do Project.transaction do
project.destroy! project.destroy!
......
...@@ -30,10 +30,8 @@ module Projects ...@@ -30,10 +30,8 @@ module Projects
end end
def increment! def increment!
if Gitlab::ExclusiveLease.new("project_housekeeping:increment!:#{@project.id}", timeout: 60).try_obtain Gitlab::Metrics.measure(:increment_pushes_since_gc) do
Gitlab::Metrics.measure(:increment_pushes_since_gc) do @project.increment_pushes_since_gc
update_pushes_since_gc(@project.pushes_since_gc + 1)
end
end end
end end
...@@ -43,14 +41,10 @@ module Projects ...@@ -43,14 +41,10 @@ module Projects
GitGarbageCollectWorker.perform_async(@project.id) GitGarbageCollectWorker.perform_async(@project.id)
ensure ensure
Gitlab::Metrics.measure(:reset_pushes_since_gc) do Gitlab::Metrics.measure(:reset_pushes_since_gc) do
update_pushes_since_gc(0) @project.reset_pushes_since_gc
end end
end end
def update_pushes_since_gc(new_value)
@project.update_column(:pushes_since_gc, new_value)
end
def try_obtain_lease def try_obtain_lease
Gitlab::Metrics.measure(:obtain_housekeeping_lease) do Gitlab::Metrics.measure(:obtain_housekeeping_lease) do
lease = ::Gitlab::ExclusiveLease.new("project_housekeeping:#{@project.id}", timeout: LEASE_TIMEOUT) lease = ::Gitlab::ExclusiveLease.new("project_housekeeping:#{@project.id}", timeout: LEASE_TIMEOUT)
......
- project = build.project
%tr.build.commit
%td.status
= ci_status_with_icon(build.status)
%td
.branch-commit
- if can?(current_user, :read_build, build.project)
= link_to namespace_project_build_url(build.project.namespace, build.project, build) do
%span.build-link ##{build.id}
- else
%span.build-link ##{build.id}
- if build.ref
.icon-container
= build.tag? ? icon('tag') : icon('code-fork')
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name"
- else
.light none
.icon-container
= custom_icon("icon_commit")
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace commit-id"
- if build.stuck?
%i.fa.fa-warning.text-warning
.label-container
- if build.tags.any?
- build.tags.each do |tag|
%span.label.label-primary
= tag
- if build.try(:trigger_request)
%span.label.label-info triggered
- if build.try(:allow_failure)
%span.label.label-danger allowed to fail
%td
- if project
= link_to project.name_with_namespace, admin_namespace_project_path(project.namespace, project)
%td
- if build.try(:runner)
= runner_link(build.runner)
- else
.light none
%td
#{build.stage} / #{build.name}
%td
- if build.duration
%p.duration
= custom_icon("icon_timer")
= duration_in_numbers(build.duration)
- if build.finished_at
%p.finished-at
= icon("calendar")
%span #{time_ago_with_tooltip(build.finished_at)}
- if defined?(coverage) && coverage
%td.coverage
- if build.try(:coverage)
#{build.coverage}%
%td
.pull-right
- if can?(current_user, :read_build, project) && build.artifacts?
= link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts', class: 'btn btn-build' do
%i.fa.fa-download
- if can?(current_user, :update_build, build.project)
- if build.active?
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && build.retryable?
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
%i.fa.fa-refresh
...@@ -4,26 +4,8 @@ ...@@ -4,26 +4,8 @@
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
%ul.nav-links - build_path_proc = ->(scope) { admin_builds_path(scope: scope) }
%li{class: ('active' if @scope.nil?)} = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
= link_to admin_builds_path do
All
%span.badge.js-totalbuilds-count= @all_builds.count(:id)
%li{class: ('active' if @scope == 'pending')}
= link_to admin_builds_path(scope: :pending) do
Pending
%span.badge= number_with_delimiter(@all_builds.pending.count(:id))
%li{class: ('active' if @scope == 'running')}
= link_to admin_builds_path(scope: :running) do
Running
%span.badge= number_with_delimiter(@all_builds.running.count(:id))
%li{class: ('active' if @scope == 'finished')}
= link_to admin_builds_path(scope: :finished) do
Finished
%span.badge= number_with_delimiter(@all_builds.finished.count(:id))
.nav-controls .nav-controls
- if @all_builds.running_or_pending.any? - if @all_builds.running_or_pending.any?
...@@ -33,23 +15,4 @@ ...@@ -33,23 +15,4 @@
#{(@scope || 'all').capitalize} builds #{(@scope || 'all').capitalize} builds
%ul.content-list.builds-content-list %ul.content-list.builds-content-list
- if @builds.blank? = render "projects/builds/table", builds: @builds, admin: true
%li
.nothing-here-block No builds to show
- else
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Commit
%th Project
%th Runner
%th Name
%th
%th
- @builds.each do |build|
= render "admin/builds/build", build: build
= paginate @builds, theme: 'gitlab'
- page_title "SSH Keys" - page_title "SSH Keys"
= render 'profiles/head'
.row.prepend-top-default .row.prepend-top-default
.col-lg-3.profile-settings-sidebar .col-lg-3.profile-settings-sidebar
......
- admin = local_assigns.fetch(:admin, false)
- if builds.blank?
%li
.nothing-here-block No builds to show
- else
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Commit
- if admin
%th Project
%th Runner
%th Stage
%th Name
%th
%th Coverage
%th
= render partial: "projects/ci/builds/build", collection: builds, as: :build, locals: { commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: admin || project.build_coverage_enabled?, admin: admin }
= paginate builds, theme: 'gitlab'
...@@ -4,30 +4,8 @@ ...@@ -4,30 +4,8 @@
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
%ul.nav-links - build_path_proc = ->(scope) { project_builds_path(@project, scope: scope) }
%li{class: ('active' if @scope.nil?)} = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
= link_to project_builds_path(@project) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(@all_builds.count(:id))
%li{class: ('active' if @scope == 'pending')}
= link_to project_builds_path(@project, scope: :pending) do
Pending
%span.badge
= number_with_delimiter(@all_builds.pending.count(:id))
%li{class: ('active' if @scope == 'running')}
= link_to project_builds_path(@project, scope: :running) do
Running
%span.badge
= number_with_delimiter(@all_builds.running.count(:id))
%li{class: ('active' if @scope == 'finished')}
= link_to project_builds_path(@project, scope: :finished) do
Finished
%span.badge
= number_with_delimiter(@all_builds.finished.count(:id))
.nav-controls .nav-controls
- if can?(current_user, :update_build, @project) - if can?(current_user, :update_build, @project)
...@@ -42,23 +20,4 @@ ...@@ -42,23 +20,4 @@
%span CI Lint %span CI Lint
%ul.content-list.builds-content-list %ul.content-list.builds-content-list
- if @builds.blank? = render "table", builds: @builds, project: @project
%li
.nothing-here-block No builds to show
- else
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Commit
%th Stage
%th Name
%th
- if @project.build_coverage_enabled?
%th Coverage
%th
= render @builds, commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: @project.build_coverage_enabled?
= paginate @builds, theme: 'gitlab'
- admin = local_assigns.fetch(:admin, false)
- ref = local_assigns.fetch(:ref, nil)
- commit_sha = local_assigns.fetch(:commit_sha, nil)
- retried = local_assigns.fetch(:retried, false)
- stage = local_assigns.fetch(:stage, false)
- coverage = local_assigns.fetch(:coverage, false)
- allow_retry = local_assigns.fetch(:allow_retry, false)
%tr.build.commit %tr.build.commit
%td.status %td.status
- if can?(current_user, :read_build, build) - if can?(current_user, :read_build, build)
...@@ -9,11 +17,11 @@ ...@@ -9,11 +17,11 @@
.branch-commit .branch-commit
- if can?(current_user, :read_build, build) - if can?(current_user, :read_build, build)
= link_to namespace_project_build_url(build.project.namespace, build.project, build) do = link_to namespace_project_build_url(build.project.namespace, build.project, build) do
%span ##{build.id} %span.build-link ##{build.id}
- else - else
%span ##{build.id} %span.build-link ##{build.id}
- if defined?(ref) && ref - if ref
- if build.ref - if build.ref
.icon-container .icon-container
= build.tag? ? icon('tag') : icon('code-fork') = build.tag? ? icon('tag') : icon('code-fork')
...@@ -23,12 +31,12 @@ ...@@ -23,12 +31,12 @@
.icon-container .icon-container
= custom_icon("icon_commit") = custom_icon("icon_commit")
- if defined?(commit_sha) && commit_sha - if commit_sha
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace" = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace"
- if build.stuck? - if build.stuck?
= icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.') = icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.')
- if defined?(retried) && retried - if retried
= icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.') = icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.')
.label-container .label-container
...@@ -40,19 +48,24 @@ ...@@ -40,19 +48,24 @@
%span.label.label-info triggered %span.label.label-info triggered
- if build.try(:allow_failure) - if build.try(:allow_failure)
%span.label.label-danger allowed to fail %span.label.label-danger allowed to fail
- if defined?(retried) && retried - if retried
%span.label.label-warning retried %span.label.label-warning retried
- if build.manual? - if build.manual?
%span.label.label-info manual %span.label.label-info manual
- if defined?(runner) && runner - if admin
%td
- if build.project
= link_to build.project.name_with_namespace, admin_namespace_project_path(build.project.namespace, build.project)
- if admin
%td %td
- if build.try(:runner) - if build.try(:runner)
= runner_link(build.runner) = runner_link(build.runner)
- else - else
.light none .light none
- if defined?(stage) && stage - if stage
%td %td
= build.stage = build.stage
...@@ -64,13 +77,14 @@ ...@@ -64,13 +77,14 @@
%p.duration %p.duration
= custom_icon("icon_timer") = custom_icon("icon_timer")
= duration_in_numbers(build.duration) = duration_in_numbers(build.duration)
- if build.finished_at - if build.finished_at
%p.finished-at %p.finished-at
= icon("calendar") = icon("calendar")
%span #{time_ago_with_tooltip(build.finished_at)} %span #{time_ago_with_tooltip(build.finished_at)}
- if defined?(coverage) && coverage %td.coverage
%td.coverage - if coverage
- if build.try(:coverage) - if build.try(:coverage)
#{build.coverage}% #{build.coverage}%
...@@ -83,10 +97,10 @@ ...@@ -83,10 +97,10 @@
- if build.active? - if build.active?
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do = link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
= icon('remove', class: 'cred') = icon('remove', class: 'cred')
- elsif defined?(allow_retry) && allow_retry - elsif allow_retry
- if build.retryable? - if build.retryable?
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do = link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
= icon('repeat') = icon('repeat')
- elsif build.playable? - elsif build.playable? && !admin
= link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do = link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do
= custom_icon('icon_play') = custom_icon('icon_play')
- if @merge_requests.any? - if @merge_requests.any?
%h2.merge-requests-title %h2.merge-requests-title
= pluralize(@merge_requests.count, 'Related Merge Request') = pluralize(@merge_requests.count, 'Related Merge Request')
%ul.unstyled-list %ul.unstyled-list.related-merge-requests
- has_any_ci = @merge_requests.any?(&:pipeline) - has_any_ci = @merge_requests.any?(&:pipeline)
- @merge_requests.each do |merge_request| - @merge_requests.each do |merge_request|
%li %li
......
- if @related_branches.any? - if @related_branches.any?
%h2.related-branches-title %h2.related-branches-title
= pluralize(@related_branches.count, 'Related Branch') = pluralize(@related_branches.count, 'Related Branch')
%ul.unstyled-list %ul.unstyled-list.related-merge-requests
- @related_branches.each do |branch| - @related_branches.each do |branch|
%li %li
- target = @project.repository.find_branch(branch).target - target = @project.repository.find_branch(branch).target
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- if can?(current_user, :update_merge_request, @merge_request) - if can?(current_user, :update_merge_request, @merge_request)
- if @merge_request.open? - if @merge_request.open?
= link_to 'Close merge request', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-comment btn-close close-mr-link js-note-target-close", title: "Close merge request", data: {original_text: "Close merge request", alternative_text: "Comment & close merge request"} = link_to 'Close merge request', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-comment btn-close close-mr-link js-note-target-close", title: "Close merge request", data: {original_text: "Close merge request", alternative_text: "Comment & close merge request"}
- if @merge_request.closed? - if @merge_request.reopenable?
= link_to 'Reopen merge request', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request", data: {original_text: "Reopen merge request", alternative_text: "Comment & reopen merge request"} = link_to 'Reopen merge request', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request", data: {original_text: "Reopen merge request", alternative_text: "Comment & reopen merge request"}
%comment-and-resolve-btn{ "inline-template" => true, ":discussion-id" => "" } %comment-and-resolve-btn{ "inline-template" => true, ":discussion-id" => "" }
%button.btn.btn-nr.btn-default.append-right-10.js-comment-resolve-button{ "v-if" => "showButton", type: "submit", data: { namespace_path: "#{@merge_request.project.namespace.path}", project_path: "#{@merge_request.project.path}" } } %button.btn.btn-nr.btn-default.append-right-10.js-comment-resolve-button{ "v-if" => "showButton", type: "submit", data: { namespace_path: "#{@merge_request.project.namespace.path}", project_path: "#{@merge_request.project.path}" } }
......
...@@ -29,17 +29,19 @@ ...@@ -29,17 +29,19 @@
%ul.dropdown-menu.dropdown-menu-align-right %ul.dropdown-menu.dropdown-menu-align-right
%li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch) %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
%li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff) %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
.normal - unless @merge_request.closed_without_fork?
%span Request to merge .normal
%span.label-branch= source_branch_with_namespace(@merge_request) %span Request to merge
%span into %span.label-branch= source_branch_with_namespace(@merge_request)
%span.label-branch %span into
= link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch) %span.label-branch
- if @merge_request.open? && @merge_request.diverged_from_target_branch? = link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch)
%span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind) - if @merge_request.open? && @merge_request.diverged_from_target_branch?
%span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind)
= render "projects/merge_requests/show/how_to_merge" - unless @merge_request.closed_without_source_project?
= render "projects/merge_requests/widget/show.html.haml" = render "projects/merge_requests/show/how_to_merge"
= render "projects/merge_requests/widget/show.html.haml"
- if @merge_request.source_branch_exists? && @merge_request.mergeable? && @merge_request.can_be_merged_by?(current_user) - if @merge_request.source_branch_exists? && @merge_request.mergeable? && @merge_request.can_be_merged_by?(current_user)
.light.prepend-top-default.append-bottom-default .light.prepend-top-default.append-bottom-default
...@@ -53,10 +55,11 @@ ...@@ -53,10 +55,11 @@
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do
Discussion Discussion
%span.badge= @merge_request.mr_and_commit_notes.user.count %span.badge= @merge_request.mr_and_commit_notes.user.count
%li.commits-tab - unless @merge_request.closed_without_source_project?
= link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do %li.commits-tab
Commits = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do
%span.badge= @commits_count Commits
%span.badge= @commits_count
- if @pipeline - if @pipeline
%li.pipelines-tab %li.pipelines-tab
= link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do = link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do
......
- return unless note.author - return unless note.author
- return if note.cross_reference_not_visible_for?(current_user) - return if note.cross_reference_not_visible_for?(current_user)
- can_resolve = can?(current_user, :resolve_note, note)
- note_editable = note_editable?(note) - note_editable = note_editable?(note)
%li.timeline-entry{ id: dom_id(note), class: ["note", "note-row-#{note.id}", ('system-note' if note.system)], data: {author_id: note.author.id, editable: note_editable} } %li.timeline-entry{ id: dom_id(note), class: ["note", "note-row-#{note.id}", ('system-note' if note.system)], data: {author_id: note.author.id, editable: note_editable} }
...@@ -24,6 +23,8 @@ ...@@ -24,6 +23,8 @@
%span.note-role.hidden-xs= access %span.note-role.hidden-xs= access
- if note.resolvable? - if note.resolvable?
- can_resolve = can?(current_user, :resolve_note, note)
%resolve-btn{ ":namespace-path" => "'#{note.project.namespace.path}'", %resolve-btn{ ":namespace-path" => "'#{note.project.namespace.path}'",
":project-path" => "'#{note.project.path}'", ":project-path" => "'#{note.project.path}'",
":discussion-id" => "'#{note.discussion_id}'", ":discussion-id" => "'#{note.discussion_id}'",
......
- blob = @project.repository.parse_search_result(blob) - blob = parse_search_result(blob)
.blob-result .blob-result
.file-holder .file-holder
.file-title .file-title
......
- wiki_blob = @project.repository.parse_search_result(wiki_blob) - wiki_blob = parse_search_result(wiki_blob)
.blob-result .blob-result
.file-holder .file-holder
.file-title .file-title
......
%ul.nav-links
%li{ class: ('active' if scope.nil?) }
= link_to build_path_proc.call(nil) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(all_builds.count(:id))
%li{ class: ('active' if scope == 'pending') }
= link_to build_path_proc.call('pending') do
Pending
%span.badge
= number_with_delimiter(all_builds.pending.count(:id))
%li{ class: ('active' if scope == 'running') }
= link_to build_path_proc.call('running') do
Running
%span.badge
= number_with_delimiter(all_builds.running.count(:id))
%li{ class: ('active' if scope == 'finished') }
= link_to build_path_proc.call('finished') do
Finished
%span.badge
= number_with_delimiter(all_builds.finished.count(:id))
...@@ -68,7 +68,8 @@ if Gitlab::Metrics.enabled? ...@@ -68,7 +68,8 @@ if Gitlab::Metrics.enabled?
['app', 'mailers', 'emails'] => ['app', 'mailers'], ['app', 'mailers', 'emails'] => ['app', 'mailers'],
['app', 'services', '**'] => ['app', 'services'], ['app', 'services', '**'] => ['app', 'services'],
['lib', 'gitlab', 'diff'] => ['lib'], ['lib', 'gitlab', 'diff'] => ['lib'],
['lib', 'gitlab', 'email', 'message'] => ['lib'] ['lib', 'gitlab', 'email', 'message'] => ['lib'],
['lib', 'gitlab', 'checks'] => ['lib']
} }
paths_to_instrument.each do |(path, prefix)| paths_to_instrument.each do |(path, prefix)|
......
...@@ -13,9 +13,5 @@ Mime::Type.register "video/mp4", :mp4, [], [:m4v, :mov] ...@@ -13,9 +13,5 @@ Mime::Type.register "video/mp4", :mp4, [], [:m4v, :mov]
Mime::Type.register "video/webm", :webm Mime::Type.register "video/webm", :webm
Mime::Type.register "video/ogg", :ogv Mime::Type.register "video/ogg", :ogv
middlewares = Gitlab::Application.config.middleware Mime::Type.unregister :json
middlewares.swap(ActionDispatch::ParamsParser, ActionDispatch::ParamsParser, { Mime::Type.register 'application/json', :json, %w(application/vnd.git-lfs+json application/json)
Mime::Type.lookup('application/vnd.git-lfs+json') => lambda do |body|
ActiveSupport::JSON.decode(body)
end
})
...@@ -8,14 +8,28 @@ class MergeRequestDiffRemoveUniq < ActiveRecord::Migration ...@@ -8,14 +8,28 @@ class MergeRequestDiffRemoveUniq < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
def up def up
if index_exists?(:merge_request_diffs, :merge_request_id) constraint_name = 'merge_request_diffs_merge_request_id_key'
remove_index :merge_request_diffs, :merge_request_id
transaction do
if index_exists?(:merge_request_diffs, :merge_request_id)
remove_index(:merge_request_diffs, :merge_request_id)
end
# In some bizarre cases PostgreSQL might have a separate unique constraint
# that we'll need to drop.
if constraint_exists?(constraint_name) && Gitlab::Database.postgresql?
execute("ALTER TABLE merge_request_diffs DROP CONSTRAINT IF EXISTS #{constraint_name};")
end
end end
end end
def down def down
unless index_exists?(:merge_request_diffs, :merge_request_id) unless index_exists?(:merge_request_diffs, :merge_request_id)
add_concurrent_index :merge_request_diffs, :merge_request_id, unique: true add_concurrent_index(:merge_request_diffs, :merge_request_id, unique: true)
end end
end end
def constraint_exists?(name)
indexes(:merge_request_diffs).map(&:name).include?(name)
end
end end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveProjectsPushesSinceGc < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = true
DOWNTIME_REASON = 'This migration removes an existing column'
disable_ddl_transaction!
def up
remove_column :projects, :pushes_since_gc
end
def down
add_column_with_default! :projects, :pushes_since_gc, :integer, default: 0
end
end
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160907131111) do
ActiveRecord::Schema.define(version: 20160913162434) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -826,7 +827,6 @@ ActiveRecord::Schema.define(version: 20160907131111) do ...@@ -826,7 +827,6 @@ ActiveRecord::Schema.define(version: 20160907131111) do
t.integer "build_timeout", default: 3600, null: false t.integer "build_timeout", default: 3600, null: false
t.boolean "pending_delete", default: false t.boolean "pending_delete", default: false
t.boolean "public_builds", default: true, null: false t.boolean "public_builds", default: true, null: false
t.integer "pushes_since_gc", default: 0
t.boolean "last_repository_check_failed" t.boolean "last_repository_check_failed"
t.datetime "last_repository_check_at" t.datetime "last_repository_check_at"
t.boolean "container_registry_enabled" t.boolean "container_registry_enabled"
......
...@@ -406,7 +406,8 @@ To configure the storage driver in Omnibus: ...@@ -406,7 +406,8 @@ To configure the storage driver in Omnibus:
's3' => { 's3' => {
'accesskey' => 's3-access-key', 'accesskey' => 's3-access-key',
'secretkey' => 's3-secret-key-for-access-key', 'secretkey' => 's3-secret-key-for-access-key',
'bucket' => 'your-s3-bucket' 'bucket' => 'your-s3-bucket',
'region' => 'your-s3-region'
} }
} }
``` ```
...@@ -428,6 +429,7 @@ storage: ...@@ -428,6 +429,7 @@ storage:
accesskey: 'AKIAKIAKI' accesskey: 'AKIAKIAKI'
secretkey: 'secret123' secretkey: 'secret123'
bucket: 'gitlab-registry-bucket-AKIAKIAKI' bucket: 'gitlab-registry-bucket-AKIAKIAKI'
region: 'your-s3-region'
cache: cache:
blobdescriptor: inmemory blobdescriptor: inmemory
delete: delete:
......
...@@ -38,6 +38,15 @@ POST /ci/api/v1/builds/register ...@@ -38,6 +38,15 @@ POST /ci/api/v1/builds/register
curl --request POST "https://gitlab.example.com/ci/api/v1/builds/register" --form "token=t0k3n" curl --request POST "https://gitlab.example.com/ci/api/v1/builds/register" --form "token=t0k3n"
``` ```
**Responses:**
| Status | Data |Description |
|--------|------|---------------------------------------------------------------------------|
| `201` | yes | When a build is scheduled for a runner |
| `204` | no | When no builds are scheduled for a runner (for GitLab Runner >= `v1.3.0`) |
| `403` | no | When invalid token is used or no token is sent |
| `404` | no | When no builds are scheduled for a runner (for GitLab Runner < `v1.3.0`) **or** when the runner is set to `paused` in GitLab runner's configuration page |
### Update details of an existing build ### Update details of an existing build
``` ```
......
...@@ -34,6 +34,7 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`. ...@@ -34,6 +34,7 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`.
| **CI_BUILD_REF_NAME** | all | all | The branch or tag name for which project is built | | **CI_BUILD_REF_NAME** | all | all | The branch or tag name for which project is built |
| **CI_BUILD_REPO** | all | all | The URL to clone the Git repository | | **CI_BUILD_REPO** | all | all | The URL to clone the Git repository |
| **CI_BUILD_TRIGGERED** | all | 0.5 | The flag to indicate that build was [triggered] | | **CI_BUILD_TRIGGERED** | all | 0.5 | The flag to indicate that build was [triggered] |
| **CI_BUILD_MANUAL** | 8.12 | all | The flag to indicate that build was manually started |
| **CI_BUILD_TOKEN** | all | 1.2 | Token used for authenticating with the GitLab Container Registry | | **CI_BUILD_TOKEN** | all | 1.2 | Token used for authenticating with the GitLab Container Registry |
| **CI_PIPELINE_ID** | 8.10 | 0.5 | The unique id of the current pipeline that GitLab CI uses internally | | **CI_PIPELINE_ID** | 8.10 | 0.5 | The unique id of the current pipeline that GitLab CI uses internally |
| **CI_PROJECT_ID** | all | all | The unique id of the current project that GitLab CI uses internally | | **CI_PROJECT_ID** | all | all | The unique id of the current project that GitLab CI uses internally |
...@@ -47,6 +48,8 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`. ...@@ -47,6 +48,8 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`.
| **CI_RUNNER_ID** | 8.10 | 0.5 | The unique id of runner being used | | **CI_RUNNER_ID** | 8.10 | 0.5 | The unique id of runner being used |
| **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab | | **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab |
| **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags | | **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags |
| **GITLAB_USER_ID** | 8.12 | all | The id of the user who started the build |
| **GITLAB_USER_EMAIL** | 8.12 | all | The email of the user who started the build |
**Some of the variables are only available when using runner with at least defined version.** **Some of the variables are only available when using runner with at least defined version.**
...@@ -60,6 +63,7 @@ export CI_BUILD_REPO="https://gitab-ci-token:abcde-1234ABCD5678ef@gitlab.com/git ...@@ -60,6 +63,7 @@ export CI_BUILD_REPO="https://gitab-ci-token:abcde-1234ABCD5678ef@gitlab.com/git
export CI_BUILD_TAG="1.0.0" export CI_BUILD_TAG="1.0.0"
export CI_BUILD_NAME="spec:other" export CI_BUILD_NAME="spec:other"
export CI_BUILD_STAGE="test" export CI_BUILD_STAGE="test"
export CI_BUILD_MANUAL="true"
export CI_BUILD_TRIGGERED="true" export CI_BUILD_TRIGGERED="true"
export CI_BUILD_TOKEN="abcde-1234ABCD5678ef" export CI_BUILD_TOKEN="abcde-1234ABCD5678ef"
export CI_PIPELINE_ID="1000" export CI_PIPELINE_ID="1000"
...@@ -78,6 +82,8 @@ export CI_SERVER="yes" ...@@ -78,6 +82,8 @@ export CI_SERVER="yes"
export CI_SERVER_NAME="GitLab" export CI_SERVER_NAME="GitLab"
export CI_SERVER_REVISION="70606bf" export CI_SERVER_REVISION="70606bf"
export CI_SERVER_VERSION="8.9.0" export CI_SERVER_VERSION="8.9.0"
export GITLAB_USER_ID="42"
export GITLAB_USER_EMAIL="alexzander@sporer.com"
``` ```
### YAML-defined variables ### YAML-defined variables
......
...@@ -137,3 +137,18 @@ end ...@@ -137,3 +137,18 @@ end
``` ```
Here the final value of `sleep_real_time` will be `3`, _not_ `1`. Here the final value of `sleep_real_time` will be `3`, _not_ `1`.
## Tracking Custom Events
Besides instrumenting code GitLab Performance Monitoring also supports tracking
of custom events. This is primarily intended to be used for tracking business
metrics such as the number of Git pushes, repository imports, and so on.
To track a custom event simply call `Gitlab::Metrics.add_event` passing it an
event name and a custom set of (optional) tags. For example:
```ruby
Gitlab::Metrics.add_event(:user_login, email: current_user.email)
```
Event names should be verbs such as `push_repository` and `remove_branch`.
...@@ -70,7 +70,7 @@ sudo -u git -H git checkout 8-12-stable-ee ...@@ -70,7 +70,7 @@ sudo -u git -H git checkout 8-12-stable-ee
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags sudo -u git -H git fetch --all --tags
sudo -u git -H git checkout v3.4.0 sudo -u git -H git checkout v3.5.0
``` ```
### 6. Update gitlab-workhorse ### 6. Update gitlab-workhorse
......
...@@ -93,6 +93,9 @@ A merge request contains all the history from a repository, plus the additional ...@@ -93,6 +93,9 @@ A merge request contains all the history from a repository, plus the additional
commits added to the branch associated with the merge request. Here's a few commits added to the branch associated with the merge request. Here's a few
tricks to checkout a merge request locally. tricks to checkout a merge request locally.
Please note that you can checkout a merge request locally even if the source
project is a fork (even a private fork) of the target project.
#### Checkout locally by adding a git alias #### Checkout locally by adding a git alias
Add the following alias to your `~/.gitconfig`: Add the following alias to your `~/.gitconfig`:
......
...@@ -15,6 +15,7 @@ At its current state, GitHub importer can import: ...@@ -15,6 +15,7 @@ At its current state, GitHub importer can import:
- the wiki pages (introduced in GitLab 8.4) - the wiki pages (introduced in GitLab 8.4)
- the milestones (introduced in GitLab 8.7) - the milestones (introduced in GitLab 8.7)
- the labels (introduced in GitLab 8.7) - the labels (introduced in GitLab 8.7)
- the release note descriptions (introduced in GitLab 8.12)
With GitLab 8.7+, references to pull requests and issues are preserved. With GitLab 8.7+, references to pull requests and issues are preserved.
......
...@@ -37,7 +37,7 @@ module API ...@@ -37,7 +37,7 @@ module API
# id (required) - The ID of a project # id (required) - The ID of a project
# sha (required) - The commit hash # sha (required) - The commit hash
# ref (optional) - The ref # ref (optional) - The ref
# state (required) - The state of the status. Can be: pending, running, success, error or failure # state (required) - The state of the status. Can be: pending, running, success, failed or canceled
# target_url (optional) - The target URL to associate with this status # target_url (optional) - The target URL to associate with this status
# description (optional) - A short description of the status # description (optional) - A short description of the status
# name or context (optional) - A string label to differentiate this status from the status of other systems. Default: "default" # name or context (optional) - A string label to differentiate this status from the status of other systems. Default: "default"
...@@ -46,7 +46,7 @@ module API ...@@ -46,7 +46,7 @@ module API
post ':id/statuses/:sha' do post ':id/statuses/:sha' do
authorize! :create_commit_status, user_project authorize! :create_commit_status, user_project
required_attributes! [:state] required_attributes! [:state]
attrs = attributes_for_keys [:ref, :target_url, :description, :context, :name] attrs = attributes_for_keys [:target_url, :description]
commit = @project.commit(params[:sha]) commit = @project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
...@@ -58,36 +58,38 @@ module API ...@@ -58,36 +58,38 @@ module API
# the first found branch on that commit # the first found branch on that commit
ref = params[:ref] ref = params[:ref]
unless ref ref ||= @project.repository.branch_names_contains(commit.sha).first
branches = @project.repository.branch_names_contains(commit.sha) not_found! 'References for commit' unless ref
not_found! 'References for commit' if branches.none?
ref = branches.first name = params[:name] || params[:context] || 'default'
end
pipeline = @project.ensure_pipeline(ref, commit.sha, current_user) pipeline = @project.ensure_pipeline(ref, commit.sha, current_user)
name = params[:name] || params[:context] status = GenericCommitStatus.running_or_pending.find_or_initialize_by(
status = GenericCommitStatus.running_or_pending.find_by(pipeline: pipeline, name: name, ref: params[:ref]) project: @project, pipeline: pipeline,
status ||= GenericCommitStatus.new(project: @project, pipeline: pipeline, user: current_user) user: current_user, name: name, ref: ref)
status.update(attrs) status.attributes = attrs
case params[:state].to_s begin
when 'running' case params[:state].to_s
status.run when 'pending'
when 'success' status.enqueue!
status.success when 'running'
when 'failed' status.enqueue
status.drop status.run!
when 'canceled' when 'success'
status.cancel status.success!
else when 'failed'
status.status = params[:state].to_s status.drop!
end when 'canceled'
status.cancel!
else
render_api_error!('invalid state', 400)
end
if status.save
present status, with: Entities::CommitStatus present status, with: Entities::CommitStatus
else rescue StateMachines::InvalidTransition => e
render_validation_error!(status) render_api_error!(e.message, 400)
end end
end end
end end
......
...@@ -269,6 +269,10 @@ module API ...@@ -269,6 +269,10 @@ module API
render_api_error!('304 Not Modified', 304) render_api_error!('304 Not Modified', 304)
end end
def no_content!
render_api_error!('204 No Content', 204)
end
def render_validation_error!(model) def render_validation_error!(model)
if model.errors.any? if model.errors.any?
render_api_error!(model.errors.messages || '400 Bad Request', 400) render_api_error!(model.errors.messages || '400 Bad Request', 400)
......
...@@ -31,6 +31,7 @@ module Banzai ...@@ -31,6 +31,7 @@ module Banzai
def apply_relative_link_rules! def apply_relative_link_rules!
if @uri.relative? && @uri.path.present? if @uri.relative? && @uri.path.present?
link = ::File.join(@wiki_base_path, @uri.path) link = ::File.join(@wiki_base_path, @uri.path)
link = "#{link}##{@uri.fragment}" if @uri.fragment
@uri = Addressable::URI.parse(link) @uri = Addressable::URI.parse(link)
end end
end end
......
...@@ -27,7 +27,7 @@ module Ci ...@@ -27,7 +27,7 @@ module Ci
else else
Gitlab::Metrics.add_event(:build_not_found) Gitlab::Metrics.add_event(:build_not_found)
not_found! build_not_found!
end end
end end
......
...@@ -40,6 +40,14 @@ module Ci ...@@ -40,6 +40,14 @@ module Ci
end end
end end
def build_not_found!
if headers['User-Agent'].match(/gitlab-ci-multi-runner \d+\.\d+\.\d+(~beta\.\d+\.g[0-9a-f]+)? /)
no_content!
else
not_found!
end
end
def current_runner def current_runner
@runner ||= Runner.find_by_token(params[:token].to_s) @runner ||= Runner.find_by_token(params[:token].to_s)
end end
......
...@@ -195,7 +195,7 @@ module Gitlab ...@@ -195,7 +195,7 @@ module Gitlab
# Create (if necessary) and link the secret token file # Create (if necessary) and link the secret token file
def generate_and_link_secret_token def generate_and_link_secret_token
secret_file = Gitlab.config.gitlab_shell.secret_file secret_file = Gitlab.config.gitlab_shell.secret_file
unless File.exist? secret_file unless File.size?(secret_file)
# Generate a new token of 16 random hexadecimal characters and store it in secret_file. # Generate a new token of 16 random hexadecimal characters and store it in secret_file.
token = SecureRandom.hex(16) token = SecureRandom.hex(16)
File.write(secret_file, token) File.write(secret_file, token)
......
...@@ -23,6 +23,7 @@ module Gitlab ...@@ -23,6 +23,7 @@ module Gitlab
protected protected
def protected_branch_checks def protected_branch_checks
return unless @branch_name
return unless project.protected_branch?(@branch_name) return unless project.protected_branch?(@branch_name)
if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches) if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches)
......
...@@ -17,11 +17,13 @@ module Gitlab ...@@ -17,11 +17,13 @@ module Gitlab
def trigger(gl_id, oldrev, newrev, ref) def trigger(gl_id, oldrev, newrev, ref)
return [true, nil] unless exists? return [true, nil] unless exists?
case name Bundler.with_clean_env do
when "pre-receive", "post-receive" case name
call_receive_hook(gl_id, oldrev, newrev, ref) when "pre-receive", "post-receive"
when "update" call_receive_hook(gl_id, oldrev, newrev, ref)
call_update_hook(gl_id, oldrev, newrev, ref) when "update"
call_update_hook(gl_id, oldrev, newrev, ref)
end
end end
end end
......
...@@ -20,6 +20,11 @@ module Gitlab ...@@ -20,6 +20,11 @@ module Gitlab
find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s). find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s).
try(:id) try(:id)
end end
def gitlab_author_id
return @gitlab_author_id if defined?(@gitlab_author_id)
@gitlab_author_id = gitlab_user_id(raw_data.user.id)
end
end end
end end
end end
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
end end
def author_id def author_id
gitlab_user_id(raw_data.user.id) || project.creator_id gitlab_author_id || project.creator_id
end end
def body def body
...@@ -52,7 +52,11 @@ module Gitlab ...@@ -52,7 +52,11 @@ module Gitlab
end end
def note def note
formatter.author_line(author) + body if gitlab_author_id
body
else
formatter.author_line(author) + body
end
end end
def type def type
......
...@@ -24,6 +24,7 @@ module Gitlab ...@@ -24,6 +24,7 @@ module Gitlab
import_issues import_issues
import_pull_requests import_pull_requests
import_wiki import_wiki
import_releases
handle_errors handle_errors
true true
...@@ -177,6 +178,18 @@ module Gitlab ...@@ -177,6 +178,18 @@ module Gitlab
errors << { type: :wiki, errors: e.message } errors << { type: :wiki, errors: e.message }
end end
end end
def import_releases
releases = client.releases(repo, per_page: 100)
releases.each do |raw|
begin
gh_release = ReleaseFormatter.new(project, raw)
gh_release.create! if gh_release.valid?
rescue => e
errors << { type: :release, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
end
end
end
end end
end end
end end
...@@ -49,7 +49,7 @@ module Gitlab ...@@ -49,7 +49,7 @@ module Gitlab
end end
def author_id def author_id
gitlab_user_id(raw_data.user.id) || project.creator_id gitlab_author_id || project.creator_id
end end
def body def body
...@@ -57,7 +57,11 @@ module Gitlab ...@@ -57,7 +57,11 @@ module Gitlab
end end
def description def description
@formatter.author_line(author) + body if gitlab_author_id
body
else
formatter.author_line(author) + body
end
end end
def milestone def milestone
......
...@@ -77,7 +77,7 @@ module Gitlab ...@@ -77,7 +77,7 @@ module Gitlab
end end
def author_id def author_id
gitlab_user_id(raw_data.user.id) || project.creator_id gitlab_author_id || project.creator_id
end end
def body def body
...@@ -85,7 +85,11 @@ module Gitlab ...@@ -85,7 +85,11 @@ module Gitlab
end end
def description def description
formatter.author_line(author) + body if gitlab_author_id
body
else
formatter.author_line(author) + body
end
end end
def milestone def milestone
......
module Gitlab
module GithubImport
class ReleaseFormatter < BaseFormatter
def attributes
{
project: project,
tag: raw_data.tag_name,
description: raw_data.body,
created_at: raw_data.created_at,
updated_at: raw_data.created_at
}
end
def klass
Release
end
def valid?
!raw_data.draft
end
end
end
end
...@@ -18,18 +18,18 @@ module Gitlab ...@@ -18,18 +18,18 @@ module Gitlab
FileUtils.mkdir_p(path) FileUtils.mkdir_p(path)
end end
@cmd_output = "" cmd_output = ""
@cmd_status = 0 cmd_status = 0
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
yield(stdin) if block_given? yield(stdin) if block_given?
stdin.close stdin.close
@cmd_output << stdout.read cmd_output << stdout.read
@cmd_output << stderr.read cmd_output << stderr.read
@cmd_status = wait_thr.value.exitstatus cmd_status = wait_thr.value.exitstatus
end end
[@cmd_output, @cmd_status] [cmd_output, cmd_status]
end end
end end
end end
...@@ -102,7 +102,7 @@ module Gitlab ...@@ -102,7 +102,7 @@ module Gitlab
def secret def secret
@secret ||= begin @secret ||= begin
bytes = Base64.strict_decode64(File.read(secret_path)) bytes = Base64.strict_decode64(File.read(secret_path).chomp)
raise "#{secret_path} does not contain #{SECRET_LENGTH} bytes" if bytes.length != SECRET_LENGTH raise "#{secret_path} does not contain #{SECRET_LENGTH} bytes" if bytes.length != SECRET_LENGTH
bytes bytes
end end
......
unless Rails.env.production?
require 'haml_lint/rake_task'
HamlLint::RakeTask.new
end
...@@ -181,6 +181,25 @@ describe ProjectsController do ...@@ -181,6 +181,25 @@ describe ProjectsController do
expect(response).to have_http_status(302) expect(response).to have_http_status(302)
expect(response).to redirect_to(dashboard_projects_path) expect(response).to redirect_to(dashboard_projects_path)
end end
context "when the project is forked" do
let(:project) { create(:project) }
let(:fork_project) { create(:project, forked_from_project: project) }
let(:merge_request) do
create(:merge_request,
source_project: fork_project,
target_project: project)
end
it "closes all related merge requests" do
project.merge_requests << merge_request
sign_in(admin)
delete :destroy, namespace_id: fork_project.namespace.path, id: fork_project.path
expect(merge_request.reload.state).to eq('closed')
end
end
end end
describe "POST #toggle_star" do describe "POST #toggle_star" do
......
...@@ -30,5 +30,9 @@ FactoryGirl.define do ...@@ -30,5 +30,9 @@ FactoryGirl.define do
trait :shared do trait :shared do
is_shared true is_shared true
end end
trait :inactive do
active false
end
end end
end end
FactoryGirl.define do FactoryGirl.define do
sequence :issue_created_at do |n|
4.hours.ago + ( 2 * n ).seconds
end
factory :issue do factory :issue do
title title
author author
......
require 'rails_helper'
describe 'Profile > SSH Keys', feature: true do
let(:user) { create(:user) }
before do
login_as(user)
visit profile_keys_path
end
describe 'User adds an SSH key' do
it 'auto-populates the title', js: true do
fill_in('Key', with: attributes_for(:key).fetch(:key))
expect(find_field('Title').value).to eq 'dummy@gitlab.com'
end
end
end
...@@ -57,7 +57,7 @@ feature 'Project', feature: true do ...@@ -57,7 +57,7 @@ feature 'Project', feature: true do
describe 'removal', js: true do describe 'removal', js: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) } let(:project) { create(:project, namespace: user.namespace, name: 'project1') }
before do before do
login_with(user) login_with(user)
...@@ -65,8 +65,12 @@ feature 'Project', feature: true do ...@@ -65,8 +65,12 @@ feature 'Project', feature: true do
visit edit_namespace_project_path(project.namespace, project) visit edit_namespace_project_path(project.namespace, project)
end end
it 'removes project' do it 'removes a project' do
expect { remove_with_confirm('Remove project', project.path) }.to change {Project.count}.by(-1) expect { remove_with_confirm('Remove project', project.path) }.to change {Project.count}.by(-1)
expect(page).to have_content "Project 'project1' will be deleted."
expect(Project.all.count).to be_zero
expect(project.issues).to be_empty
expect(project.merge_requests).to be_empty
end end
end end
......
...@@ -6,6 +6,38 @@ describe SearchHelper do ...@@ -6,6 +6,38 @@ describe SearchHelper do
str str
end end
describe 'parsing result' do
let(:project) { create(:project) }
let(:repository) { project.repository }
let(:results) { repository.search_files('feature', 'master') }
let(:search_result) { results.first }
subject { helper.parse_search_result(search_result) }
it "returns a valid OpenStruct object" do
is_expected.to be_an OpenStruct
expect(subject.filename).to eq('CHANGELOG')
expect(subject.basename).to eq('CHANGELOG')
expect(subject.ref).to eq('master')
expect(subject.startline).to eq(186)
expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n")
end
context "when filename has extension" do
let(:search_result) { "master:CONTRIBUTE.md:5:- [Contribute to GitLab](#contribute-to-gitlab)\n" }
it { expect(subject.filename).to eq('CONTRIBUTE.md') }
it { expect(subject.basename).to eq('CONTRIBUTE') }
end
context "when file under directory" do
let(:search_result) { "master:a/b/c.md:5:a b c\n" }
it { expect(subject.filename).to eq('a/b/c.md') }
it { expect(subject.basename).to eq('a/b/c') }
end
end
describe 'search_autocomplete_source' do describe 'search_autocomplete_source' do
context "with no current user" do context "with no current user" do
before do before do
......
...@@ -127,6 +127,13 @@ describe Banzai::Pipeline::WikiPipeline do ...@@ -127,6 +127,13 @@ describe Banzai::Pipeline::WikiPipeline do
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"") expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
end end
it 'rewrites links with anchor' do
markdown = '[Link to Header](start-page#title)'
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/start-page#title\"")
end
end end
describe "when creating root links" do describe "when creating root links" do
......
...@@ -73,6 +73,12 @@ describe Gitlab::GithubImport::CommentFormatter, lib: true do ...@@ -73,6 +73,12 @@ describe Gitlab::GithubImport::CommentFormatter, lib: true do
gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(comment.attributes.fetch(:author_id)).to eq gl_user.id expect(comment.attributes.fetch(:author_id)).to eq gl_user.id
end end
it 'returns note without created at tag line' do
create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(comment.attributes.fetch(:note)).to eq("I'm having a problem with this.")
end
end end
end end
end end
...@@ -98,6 +98,30 @@ describe Gitlab::GithubImport::Importer, lib: true do ...@@ -98,6 +98,30 @@ describe Gitlab::GithubImport::Importer, lib: true do
) )
end end
let(:release1) do
double(
tag_name: 'v1.0.0',
name: 'First release',
body: 'Release v1.0.0',
draft: false,
created_at: created_at,
updated_at: updated_at,
url: 'https://api.github.com/repos/octocat/Hello-World/releases/1'
)
end
let(:release2) do
double(
tag_name: 'v2.0.0',
name: 'Second release',
body: nil,
draft: false,
created_at: created_at,
updated_at: updated_at,
url: 'https://api.github.com/repos/octocat/Hello-World/releases/2'
)
end
before do before do
allow(project).to receive(:import_data).and_return(double.as_null_object) allow(project).to receive(:import_data).and_return(double.as_null_object)
allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound) allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound)
...@@ -106,6 +130,7 @@ describe Gitlab::GithubImport::Importer, lib: true do ...@@ -106,6 +130,7 @@ describe Gitlab::GithubImport::Importer, lib: true do
allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2]) allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2])
allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request]) allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request])
allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil })) allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil }))
allow_any_instance_of(Octokit::Client).to receive(:releases).and_return([release1, release2])
allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error) allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error)
end end
...@@ -127,8 +152,9 @@ describe Gitlab::GithubImport::Importer, lib: true do ...@@ -127,8 +152,9 @@ describe Gitlab::GithubImport::Importer, lib: true do
{ type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank, Title is too short (minimum is 0 characters)" }, { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank, Title is too short (minimum is 0 characters)" },
{ type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Invalid Repository. Use user/repo format." }, { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Invalid Repository. Use user/repo format." },
{ type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Validation failed: Validate branches Cannot Create: This merge request already exists: [\"New feature\"]" }, { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Validation failed: Validate branches Cannot Create: This merge request already exists: [\"New feature\"]" },
{ type: :wiki, errors: "Gitlab::Shell::Error" } { type: :wiki, errors: "Gitlab::Shell::Error" },
] { type: :release, url: 'https://api.github.com/repos/octocat/Hello-World/releases/2', errors: "Validation failed: Description can't be blank" }
]
} }
described_class.new(project).execute described_class.new(project).execute
......
...@@ -109,6 +109,12 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do ...@@ -109,6 +109,12 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
expect(issue.attributes.fetch(:author_id)).to eq gl_user.id expect(issue.attributes.fetch(:author_id)).to eq gl_user.id
end end
it 'returns description without created at tag line' do
create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(issue.attributes.fetch(:description)).to eq("I'm having a problem with this.")
end
end end
end end
......
...@@ -140,6 +140,12 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do ...@@ -140,6 +140,12 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id
end end
it 'returns description without created at tag line' do
create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(pull_request.attributes.fetch(:description)).to eq('Please pull these awesome changes')
end
end end
context 'when it has a milestone' do context 'when it has a milestone' do
......
require 'spec_helper'
describe Gitlab::GithubImport::ReleaseFormatter, lib: true do
let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) }
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:base_data) do
{
tag_name: 'v1.0.0',
name: 'First release',
draft: false,
created_at: created_at,
published_at: created_at,
body: 'Release v1.0.0'
}
end
subject(:release) { described_class.new(project, raw_data) }
describe '#attributes' do
let(:raw_data) { double(base_data) }
it 'returns formatted attributes' do
expected = {
project: project,
tag: 'v1.0.0',
description: 'Release v1.0.0',
created_at: created_at,
updated_at: created_at
}
expect(release.attributes).to eq(expected)
end
end
describe '#valid' do
context 'when release is not a draft' do
let(:raw_data) { double(base_data) }
it 'returns true' do
expect(release.valid?).to eq true
end
end
context 'when release is draft' do
let(:raw_data) { double(base_data.merge(draft: true)) }
it 'returns false' do
expect(release.valid?).to eq false
end
end
end
end
...@@ -30,6 +30,11 @@ describe Gitlab::Workhorse, lib: true do ...@@ -30,6 +30,11 @@ describe Gitlab::Workhorse, lib: true do
expect(subject.encoding).to eq(Encoding::ASCII_8BIT) expect(subject.encoding).to eq(Encoding::ASCII_8BIT)
end end
it 'accepts a trailing newline' do
open(described_class.secret_path, 'a') { |f| f.write "\n" }
expect(subject.length).to eq(32)
end
it 'raises an exception if the secret file cannot be read' do it 'raises an exception if the secret file cannot be read' do
File.delete(described_class.secret_path) File.delete(described_class.secret_path)
expect { subject }.to raise_exception(Errno::ENOENT) expect { subject }.to raise_exception(Errno::ENOENT)
......
# encoding: utf-8
require 'rails_helper' require 'rails_helper'
describe Blob do describe Blob do
...@@ -7,6 +8,25 @@ describe Blob do ...@@ -7,6 +8,25 @@ describe Blob do
end end
end end
describe '#data' do
context 'using a binary blob' do
it 'returns the data as-is' do
data = "\n\xFF\xB9\xC3"
blob = described_class.new(double(binary?: true, data: data))
expect(blob.data).to eq(data)
end
end
context 'using a text blob' do
it 'converts the data to UTF-8' do
blob = described_class.new(double(binary?: false, data: "\n\xFF\xB9\xC3"))
expect(blob.data).to eq("\n���")
end
end
end
describe '#svg?' do describe '#svg?' do
it 'is falsey when not text' do it 'is falsey when not text' do
git_blob = double(text?: false) git_blob = double(text?: false)
......
...@@ -231,6 +231,34 @@ describe Ci::Build, models: true do ...@@ -231,6 +231,34 @@ describe Ci::Build, models: true do
it { is_expected.to eq(predefined_variables) } it { is_expected.to eq(predefined_variables) }
end end
context 'when build has user' do
let(:user) { create(:user, username: 'starter') }
let(:user_variables) do
[
{ key: 'GITLAB_USER_ID', value: user.id.to_s, public: true },
{ key: 'GITLAB_USER_EMAIL', value: user.email, public: true }
]
end
before do
build.update_attributes(user: user)
end
it { user_variables.each { |v| is_expected.to include(v) } }
end
context 'when build started manually' do
before do
build.update_attributes(when: :manual)
end
let(:manual_variable) do
{ key: 'CI_BUILD_MANUAL', value: 'true', public: true }
end
it { is_expected.to include(manual_variable) }
end
context 'when build is for tag' do context 'when build is for tag' do
let(:tag_variable) do let(:tag_variable) do
{ key: 'CI_BUILD_TAG', value: 'master', public: true } { key: 'CI_BUILD_TAG', value: 'master', public: true }
......
...@@ -57,7 +57,7 @@ describe Member, models: true do ...@@ -57,7 +57,7 @@ describe Member, models: true do
describe 'Scopes & finders' do describe 'Scopes & finders' do
before do before do
project = create(:project) project = create(:empty_project)
group = create(:group) group = create(:group)
@owner_user = create(:user).tap { |u| group.add_owner(u) } @owner_user = create(:user).tap { |u| group.add_owner(u) }
@owner = group.members.find_by(user_id: @owner_user.id) @owner = group.members.find_by(user_id: @owner_user.id)
...@@ -65,6 +65,15 @@ describe Member, models: true do ...@@ -65,6 +65,15 @@ describe Member, models: true do
@master_user = create(:user).tap { |u| project.team << [u, :master] } @master_user = create(:user).tap { |u| project.team << [u, :master] }
@master = project.members.find_by(user_id: @master_user.id) @master = project.members.find_by(user_id: @master_user.id)
@blocked_user = create(:user).tap do |u|
project.team << [u, :master]
project.team << [u, :developer]
u.block!
end
@blocked_master = project.members.find_by(user_id: @blocked_user.id, access_level: Gitlab::Access::MASTER)
@blocked_developer = project.members.find_by(user_id: @blocked_user.id, access_level: Gitlab::Access::DEVELOPER)
Member.add_user( Member.add_user(
project.members, project.members,
'toto1@example.com', 'toto1@example.com',
...@@ -73,7 +82,7 @@ describe Member, models: true do ...@@ -73,7 +82,7 @@ describe Member, models: true do
) )
@invited_member = project.members.invite.find_by_invite_email('toto1@example.com') @invited_member = project.members.invite.find_by_invite_email('toto1@example.com')
accepted_invite_user = build(:user) accepted_invite_user = build(:user, state: :active)
Member.add_user( Member.add_user(
project.members, project.members,
'toto2@example.com', 'toto2@example.com',
...@@ -91,7 +100,7 @@ describe Member, models: true do ...@@ -91,7 +100,7 @@ describe Member, models: true do
describe '.access_for_user_ids' do describe '.access_for_user_ids' do
it 'returns the right access levels' do it 'returns the right access levels' do
users = [@owner_user.id, @master_user.id] users = [@owner_user.id, @master_user.id, @blocked_user.id]
expected = { expected = {
@owner_user.id => Gitlab::Access::OWNER, @owner_user.id => Gitlab::Access::OWNER,
@master_user.id => Gitlab::Access::MASTER @master_user.id => Gitlab::Access::MASTER
...@@ -125,6 +134,19 @@ describe Member, models: true do ...@@ -125,6 +134,19 @@ describe Member, models: true do
it { expect(described_class.request).not_to include @accepted_request_member } it { expect(described_class.request).not_to include @accepted_request_member }
end end
describe '.developers' do
subject { described_class.developers.to_a }
it { is_expected.not_to include @owner }
it { is_expected.not_to include @master }
it { is_expected.to include @invited_member }
it { is_expected.to include @accepted_invite_member }
it { is_expected.not_to include @requested_member }
it { is_expected.to include @accepted_request_member }
it { is_expected.not_to include @blocked_master }
it { is_expected.not_to include @blocked_developer }
end
describe '.owners_and_masters' do describe '.owners_and_masters' do
it { expect(described_class.owners_and_masters).to include @owner } it { expect(described_class.owners_and_masters).to include @owner }
it { expect(described_class.owners_and_masters).to include @master } it { expect(described_class.owners_and_masters).to include @master }
...@@ -132,6 +154,20 @@ describe Member, models: true do ...@@ -132,6 +154,20 @@ describe Member, models: true do
it { expect(described_class.owners_and_masters).not_to include @accepted_invite_member } it { expect(described_class.owners_and_masters).not_to include @accepted_invite_member }
it { expect(described_class.owners_and_masters).not_to include @requested_member } it { expect(described_class.owners_and_masters).not_to include @requested_member }
it { expect(described_class.owners_and_masters).not_to include @accepted_request_member } it { expect(described_class.owners_and_masters).not_to include @accepted_request_member }
it { expect(described_class.owners_and_masters).not_to include @blocked_master }
end
describe '.has_access' do
subject { described_class.has_access.to_a }
it { is_expected.to include @owner }
it { is_expected.to include @master }
it { is_expected.to include @invited_member }
it { is_expected.to include @accepted_invite_member }
it { is_expected.not_to include @requested_member }
it { is_expected.to include @accepted_request_member }
it { is_expected.not_to include @blocked_master }
it { is_expected.not_to include @blocked_developer }
end end
end end
......
...@@ -1038,4 +1038,81 @@ describe MergeRequest, models: true do ...@@ -1038,4 +1038,81 @@ describe MergeRequest, models: true do
end end
end end
end end
describe '#closed_without_source_project?' do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:fork_project) { create(:project, forked_from_project: project, namespace: user.namespace) }
let(:destroy_service) { Projects::DestroyService.new(fork_project, user) }
context 'when the merge request is closed' do
let(:closed_merge_request) do
create(:closed_merge_request,
source_project: fork_project,
target_project: project)
end
it 'returns false if the source project exists' do
expect(closed_merge_request.closed_without_source_project?).to be_falsey
end
it 'returns true if the source project does not exist' do
destroy_service.execute
closed_merge_request.reload
expect(closed_merge_request.closed_without_source_project?).to be_truthy
end
end
context 'when the merge request is open' do
it 'returns false' do
expect(subject.closed_without_source_project?).to be_falsey
end
end
end
describe '#reopenable?' do
context 'when the merge request is closed' do
it 'returns true' do
subject.close
expect(subject.reopenable?).to be_truthy
end
context 'forked project' do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:fork_project) { create(:project, forked_from_project: project, namespace: user.namespace) }
let(:merge_request) do
create(:closed_merge_request,
source_project: fork_project,
target_project: project)
end
it 'returns false if unforked' do
Projects::UnlinkForkService.new(fork_project, user).execute
expect(merge_request.reload.reopenable?).to be_falsey
end
it 'returns false if the source project is deleted' do
Projects::DestroyService.new(fork_project, user).execute
expect(merge_request.reload.reopenable?).to be_falsey
end
it 'returns false if the merge request is merged' do
merge_request.update_attributes(state: 'merged')
expect(merge_request.reload.reopenable?).to be_falsey
end
end
end
context 'when the merge request is opened' do
it 'returns false' do
expect(subject.reopenable?).to be_falsey
end
end
end
end end
...@@ -6,6 +6,7 @@ describe Project, models: true do ...@@ -6,6 +6,7 @@ describe Project, models: true do
it { is_expected.to belong_to(:namespace) } it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:creator).class_name('User') } it { is_expected.to belong_to(:creator).class_name('User') }
it { is_expected.to have_many(:users) } it { is_expected.to have_many(:users) }
it { is_expected.to have_many(:services) }
it { is_expected.to have_many(:events).dependent(:destroy) } it { is_expected.to have_many(:events).dependent(:destroy) }
it { is_expected.to have_many(:merge_requests).dependent(:destroy) } it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
it { is_expected.to have_many(:issues).dependent(:destroy) } it { is_expected.to have_many(:issues).dependent(:destroy) }
...@@ -24,6 +25,30 @@ describe Project, models: true do ...@@ -24,6 +25,30 @@ describe Project, models: true do
it { is_expected.to have_one(:pushover_service).dependent(:destroy) } it { is_expected.to have_one(:pushover_service).dependent(:destroy) }
it { is_expected.to have_one(:asana_service).dependent(:destroy) } it { is_expected.to have_one(:asana_service).dependent(:destroy) }
it { is_expected.to have_one(:board).dependent(:destroy) } it { is_expected.to have_one(:board).dependent(:destroy) }
it { is_expected.to have_one(:campfire_service).dependent(:destroy) }
it { is_expected.to have_one(:drone_ci_service).dependent(:destroy) }
it { is_expected.to have_one(:emails_on_push_service).dependent(:destroy) }
it { is_expected.to have_one(:builds_email_service).dependent(:destroy) }
it { is_expected.to have_one(:emails_on_push_service).dependent(:destroy) }
it { is_expected.to have_one(:irker_service).dependent(:destroy) }
it { is_expected.to have_one(:pivotaltracker_service).dependent(:destroy) }
it { is_expected.to have_one(:hipchat_service).dependent(:destroy) }
it { is_expected.to have_one(:flowdock_service).dependent(:destroy) }
it { is_expected.to have_one(:assembla_service).dependent(:destroy) }
it { is_expected.to have_one(:gemnasium_service).dependent(:destroy) }
it { is_expected.to have_one(:buildkite_service).dependent(:destroy) }
it { is_expected.to have_one(:bamboo_service).dependent(:destroy) }
it { is_expected.to have_one(:teamcity_service).dependent(:destroy) }
it { is_expected.to have_one(:jira_service).dependent(:destroy) }
it { is_expected.to have_one(:redmine_service).dependent(:destroy) }
it { is_expected.to have_one(:custom_issue_tracker_service).dependent(:destroy) }
it { is_expected.to have_one(:bugzilla_service).dependent(:destroy) }
it { is_expected.to have_one(:gitlab_issue_tracker_service).dependent(:destroy) }
it { is_expected.to have_one(:external_wiki_service).dependent(:destroy) }
it { is_expected.to have_one(:project_feature).dependent(:destroy) }
it { is_expected.to have_one(:import_data).class_name('ProjectImportData').dependent(:destroy) }
it { is_expected.to have_one(:last_event).class_name('Event') }
it { is_expected.to have_one(:forked_from_project).through(:forked_project_link) }
it { is_expected.to have_many(:commit_statuses) } it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:pipelines) } it { is_expected.to have_many(:pipelines) }
it { is_expected.to have_many(:builds) } it { is_expected.to have_many(:builds) }
...@@ -31,9 +56,16 @@ describe Project, models: true do ...@@ -31,9 +56,16 @@ describe Project, models: true do
it { is_expected.to have_many(:runners) } it { is_expected.to have_many(:runners) }
it { is_expected.to have_many(:variables) } it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) } it { is_expected.to have_many(:triggers) }
it { is_expected.to have_many(:labels).dependent(:destroy) }
it { is_expected.to have_many(:users_star_projects).dependent(:destroy) }
it { is_expected.to have_many(:environments).dependent(:destroy) } it { is_expected.to have_many(:environments).dependent(:destroy) }
it { is_expected.to have_many(:deployments).dependent(:destroy) } it { is_expected.to have_many(:deployments).dependent(:destroy) }
it { is_expected.to have_many(:todos).dependent(:destroy) } it { is_expected.to have_many(:todos).dependent(:destroy) }
it { is_expected.to have_many(:releases).dependent(:destroy) }
it { is_expected.to have_many(:lfs_objects_projects).dependent(:destroy) }
it { is_expected.to have_many(:project_group_links).dependent(:destroy) }
it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
it { is_expected.to have_many(:forks).through(:forked_project_links) }
describe '#members & #requesters' do describe '#members & #requesters' do
let(:project) { create(:project) } let(:project) { create(:project) }
...@@ -178,7 +210,7 @@ describe Project, models: true do ...@@ -178,7 +210,7 @@ describe Project, models: true do
expect(project.runners_token).not_to eq('') expect(project.runners_token).not_to eq('')
end end
it 'does not set an random toke if one provided' do it 'does not set an random token if one provided' do
project = FactoryGirl.create :empty_project, runners_token: 'my-token' project = FactoryGirl.create :empty_project, runners_token: 'my-token'
expect(project.runners_token).to eq('my-token') expect(project.runners_token).to eq('my-token')
end end
...@@ -1497,4 +1529,56 @@ describe Project, models: true do ...@@ -1497,4 +1529,56 @@ describe Project, models: true do
project.change_head(project.default_branch) project.change_head(project.default_branch)
end end
end end
describe '#pushes_since_gc' do
let(:project) { create(:project) }
after do
project.reset_pushes_since_gc
end
context 'without any pushes' do
it 'returns 0' do
expect(project.pushes_since_gc).to eq(0)
end
end
context 'with a number of pushes' do
it 'returns the number of pushes' do
3.times { project.increment_pushes_since_gc }
expect(project.pushes_since_gc).to eq(3)
end
end
end
describe '#increment_pushes_since_gc' do
let(:project) { create(:project) }
after do
project.reset_pushes_since_gc
end
it 'increments the number of pushes since the last GC' do
3.times { project.increment_pushes_since_gc }
expect(project.pushes_since_gc).to eq(3)
end
end
describe '#reset_pushes_since_gc' do
let(:project) { create(:project) }
after do
project.reset_pushes_since_gc
end
it 'resets the number of pushes since the last GC' do
3.times { project.increment_pushes_since_gc }
project.reset_pushes_since_gc
expect(project.pushes_since_gc).to eq(0)
end
end
end end
...@@ -186,32 +186,6 @@ describe Repository, models: true do ...@@ -186,32 +186,6 @@ describe Repository, models: true do
it { is_expected.to be_an String } it { is_expected.to be_an String }
it { expect(subject.lines[2]).to eq("master:CHANGELOG:188: - Feature: Replace teams with group membership\n") } it { expect(subject.lines[2]).to eq("master:CHANGELOG:188: - Feature: Replace teams with group membership\n") }
end end
describe 'parsing result' do
subject { repository.parse_search_result(search_result) }
let(:search_result) { results.first }
it { is_expected.to be_an OpenStruct }
it { expect(subject.filename).to eq('CHANGELOG') }
it { expect(subject.basename).to eq('CHANGELOG') }
it { expect(subject.ref).to eq('master') }
it { expect(subject.startline).to eq(186) }
it { expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") }
context "when filename has extension" do
let(:search_result) { "master:CONTRIBUTE.md:5:- [Contribute to GitLab](#contribute-to-gitlab)\n" }
it { expect(subject.filename).to eq('CONTRIBUTE.md') }
it { expect(subject.basename).to eq('CONTRIBUTE') }
end
context "when file under directory" do
let(:search_result) { "master:a/b/c.md:5:a b c\n" }
it { expect(subject.filename).to eq('a/b/c.md') }
it { expect(subject.basename).to eq('a/b/c') }
end
end
end end
describe "#changelog" do describe "#changelog" do
......
...@@ -117,17 +117,36 @@ describe API::CommitStatuses, api: true do ...@@ -117,17 +117,36 @@ describe API::CommitStatuses, api: true do
let(:post_url) { "/projects/#{project.id}/statuses/#{sha}" } let(:post_url) { "/projects/#{project.id}/statuses/#{sha}" }
context 'developer user' do context 'developer user' do
context 'only required parameters' do %w[pending running success failed canceled].each do |status|
before { post api(post_url, developer), state: 'success' } context "for #{status}" do
context 'uses only required parameters' do
it 'creates commit status' do
post api(post_url, developer), state: status
expect(response).to have_http_status(201)
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq(status)
expect(json_response['name']).to eq('default')
expect(json_response['ref']).not_to be_empty
expect(json_response['target_url']).to be_nil
expect(json_response['description']).to be_nil
end
end
end
end
it 'creates commit status' do context 'transitions status from pending' do
expect(response).to have_http_status(201) before do
expect(json_response['sha']).to eq(commit.id) post api(post_url, developer), state: 'pending'
expect(json_response['status']).to eq('success') end
expect(json_response['name']).to eq('default')
expect(json_response['ref']).to be_nil %w[running success failed canceled].each do |status|
expect(json_response['target_url']).to be_nil it "to #{status}" do
expect(json_response['description']).to be_nil expect { post api(post_url, developer), state: status }.not_to change { CommitStatus.count }
expect(response).to have_http_status(201)
expect(json_response['status']).to eq(status)
end
end end
end end
......
...@@ -18,6 +18,7 @@ describe API::API, api: true do ...@@ -18,6 +18,7 @@ describe API::API, api: true do
project: project, project: project,
state: :closed, state: :closed,
milestone: milestone, milestone: milestone,
created_at: generate(:issue_created_at),
updated_at: 3.hours.ago updated_at: 3.hours.ago
end end
let!(:confidential_issue) do let!(:confidential_issue) do
...@@ -26,6 +27,7 @@ describe API::API, api: true do ...@@ -26,6 +27,7 @@ describe API::API, api: true do
project: project, project: project,
author: author, author: author,
assignee: assignee, assignee: assignee,
created_at: generate(:issue_created_at),
updated_at: 2.hours.ago updated_at: 2.hours.ago
end end
let!(:issue) do let!(:issue) do
...@@ -34,6 +36,7 @@ describe API::API, api: true do ...@@ -34,6 +36,7 @@ describe API::API, api: true do
assignee: user, assignee: user,
project: project, project: project,
milestone: milestone, milestone: milestone,
created_at: generate(:issue_created_at),
updated_at: 1.hour.ago updated_at: 1.hour.ago
end end
let!(:label) do let!(:label) do
......
...@@ -15,6 +15,25 @@ describe Ci::API::API do ...@@ -15,6 +15,25 @@ describe Ci::API::API do
describe "POST /builds/register" do describe "POST /builds/register" do
let!(:build) { create(:ci_build, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) } let!(:build) { create(:ci_build, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
let(:user_agent) { 'gitlab-ci-multi-runner 1.5.2 (1-5-stable; go1.6.3; linux/amd64)' }
shared_examples 'no builds available' do
context 'when runner sends version in User-Agent' do
context 'for stable version' do
it { expect(response).to have_http_status(204) }
end
context 'for beta version' do
let(:user_agent) { 'gitlab-ci-multi-runner 1.6.0~beta.167.g2b2bacc (1-5-stable; go1.6.3; linux/amd64)' }
it { expect(response).to have_http_status(204) }
end
end
context "when runner doesn't send version in User-Agent" do
let(:user_agent) { 'Go-http-client/1.1' }
it { expect(response).to have_http_status(404) }
end
end
it "starts a build" do it "starts a build" do
register_builds info: { platform: :darwin } register_builds info: { platform: :darwin }
...@@ -33,36 +52,30 @@ describe Ci::API::API do ...@@ -33,36 +52,30 @@ describe Ci::API::API do
context 'when builds are finished' do context 'when builds are finished' do
before do before do
build.success build.success
end
it "returns 404 error if no builds for specific runner" do
register_builds register_builds
expect(response).to have_http_status(404)
end end
it_behaves_like 'no builds available'
end end
context 'for other project with builds' do context 'for other project with builds' do
before do before do
build.success build.success
create(:ci_build, :pending) create(:ci_build, :pending)
end
it "returns 404 error if no builds for shared runner" do
register_builds register_builds
expect(response).to have_http_status(404)
end end
it_behaves_like 'no builds available'
end end
context 'for shared runner' do context 'for shared runner' do
let(:shared_runner) { create(:ci_runner, token: "SharedRunner") } let(:shared_runner) { create(:ci_runner, token: "SharedRunner") }
it "should return 404 error if no builds for shared runner" do before do
register_builds shared_runner.token register_builds shared_runner.token
expect(response).to have_http_status(404)
end end
it_behaves_like 'no builds available'
end end
context 'for triggered build' do context 'for triggered build' do
...@@ -136,18 +149,27 @@ describe Ci::API::API do ...@@ -136,18 +149,27 @@ describe Ci::API::API do
end end
context 'when runner is not allowed to pick untagged builds' do context 'when runner is not allowed to pick untagged builds' do
before { runner.update_column(:run_untagged, false) } before do
runner.update_column(:run_untagged, false)
it 'does not pick build' do
register_builds register_builds
expect(response).to have_http_status 404
end end
it_behaves_like 'no builds available'
end end
end end
context 'when runner is paused' do
let(:inactive_runner) { create(:ci_runner, :inactive, token: "InactiveRunner") }
before do
register_builds inactive_runner.token
end
it { expect(response).to have_http_status 404 }
end
def register_builds(token = runner.token, **params) def register_builds(token = runner.token, **params)
post ci_api("/builds/register"), params.merge(token: token) post ci_api("/builds/register"), params.merge(token: token), { 'User-Agent' => user_agent }
end end
end end
......
...@@ -4,12 +4,11 @@ describe Projects::HousekeepingService do ...@@ -4,12 +4,11 @@ describe Projects::HousekeepingService do
subject { Projects::HousekeepingService.new(project) } subject { Projects::HousekeepingService.new(project) }
let(:project) { create :project } let(:project) { create :project }
describe 'execute' do after do
before do project.reset_pushes_since_gc
project.pushes_since_gc = 3 end
project.save!
end
describe '#execute' do
it 'enqueues a sidekiq job' do it 'enqueues a sidekiq job' do
expect(subject).to receive(:try_obtain_lease).and_return(true) expect(subject).to receive(:try_obtain_lease).and_return(true)
expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id) expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id)
...@@ -32,12 +31,12 @@ describe Projects::HousekeepingService do ...@@ -32,12 +31,12 @@ describe Projects::HousekeepingService do
it 'does not reset pushes_since_gc' do it 'does not reset pushes_since_gc' do
expect do expect do
expect { subject.execute }.to raise_error(Projects::HousekeepingService::LeaseTaken) expect { subject.execute }.to raise_error(Projects::HousekeepingService::LeaseTaken)
end.not_to change { project.pushes_since_gc }.from(3) end.not_to change { project.pushes_since_gc }
end end
end end
end end
describe 'needed?' do describe '#needed?' do
it 'when the count is low enough' do it 'when the count is low enough' do
expect(subject.needed?).to eq(false) expect(subject.needed?).to eq(false)
end end
...@@ -48,25 +47,11 @@ describe Projects::HousekeepingService do ...@@ -48,25 +47,11 @@ describe Projects::HousekeepingService do
end end
end end
describe 'increment!' do describe '#increment!' do
let(:lease_key) { "project_housekeeping:increment!:#{project.id}" }
it 'increments the pushes_since_gc counter' do it 'increments the pushes_since_gc counter' do
lease = double(:lease, try_obtain: true)
expect(Gitlab::ExclusiveLease).to receive(:new).with(lease_key, anything).and_return(lease)
expect do expect do
subject.increment! subject.increment!
end.to change { project.pushes_since_gc }.from(0).to(1) end.to change { project.pushes_since_gc }.from(0).to(1)
end end
it 'does not increment when no lease can be obtained' do
lease = double(:lease, try_obtain: false)
expect(Gitlab::ExclusiveLease).to receive(:new).with(lease_key, anything).and_return(lease)
expect do
subject.increment!
end.not_to change { project.pushes_since_gc }
end
end end
end end
...@@ -3,5 +3,4 @@ build/ ...@@ -3,5 +3,4 @@ build/
nbbuild/ nbbuild/
dist/ dist/
nbdist/ nbdist/
nbactions.xml
.nb-gradle/ .nb-gradle/
...@@ -9,6 +9,7 @@ gtags.files ...@@ -9,6 +9,7 @@ gtags.files
GTAGS GTAGS
GRTAGS GRTAGS
GPATH GPATH
GSYMS
cscope.files cscope.files
cscope.out cscope.out
cscope.in.out cscope.in.out
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
.LSOverride .LSOverride
# Icon must end with two \r # Icon must end with two \r
Icon Icon
# Thumbnails # Thumbnails
._* ._*
......
...@@ -17,3 +17,4 @@ cabal.sandbox.config ...@@ -17,3 +17,4 @@ cabal.sandbox.config
*.eventlog *.eventlog
.stack-work/ .stack-work/
cabal.project.local cabal.project.local
.HTF/
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
/administrator/language/en-GB/en-GB.plg_content_contact.sys.ini /administrator/language/en-GB/en-GB.plg_content_contact.sys.ini
/administrator/language/en-GB/en-GB.plg_content_finder.ini /administrator/language/en-GB/en-GB.plg_content_finder.ini
/administrator/language/en-GB/en-GB.plg_content_finder.sys.ini /administrator/language/en-GB/en-GB.plg_content_finder.sys.ini
/administrator/language/en-GB/en-GB.plg_editors-xtd_module*
/administrator/language/en-GB/en-GB.plg_finder_categories.ini /administrator/language/en-GB/en-GB.plg_finder_categories.ini
/administrator/language/en-GB/en-GB.plg_finder_categories.sys.ini /administrator/language/en-GB/en-GB.plg_finder_categories.sys.ini
/administrator/language/en-GB/en-GB.plg_finder_contacts.ini /administrator/language/en-GB/en-GB.plg_finder_contacts.ini
...@@ -64,6 +65,10 @@ ...@@ -64,6 +65,10 @@
/administrator/language/en-GB/en-GB.plg_finder_tags.sys.ini /administrator/language/en-GB/en-GB.plg_finder_tags.sys.ini
/administrator/language/en-GB/en-GB.plg_finder_weblinks.ini /administrator/language/en-GB/en-GB.plg_finder_weblinks.ini
/administrator/language/en-GB/en-GB.plg_finder_weblinks.sys.ini /administrator/language/en-GB/en-GB.plg_finder_weblinks.sys.ini
/administrator/language/en-GB/en-GB.plg_installer_folderinstaller*
/administrator/language/en-GB/en-GB.plg_installer_packageinstaller*
/administrator/language/en-GB/en-GB.plg_installer_packageinstaller
/administrator/language/en-GB/en-GB.plg_installer_urlinstaller*
/administrator/language/en-GB/en-GB.plg_installer_webinstaller.ini /administrator/language/en-GB/en-GB.plg_installer_webinstaller.ini
/administrator/language/en-GB/en-GB.plg_installer_webinstaller.sys.ini /administrator/language/en-GB/en-GB.plg_installer_webinstaller.sys.ini
/administrator/language/en-GB/en-GB.plg_quickicon_joomlaupdate.ini /administrator/language/en-GB/en-GB.plg_quickicon_joomlaupdate.ini
...@@ -72,6 +77,8 @@ ...@@ -72,6 +77,8 @@
/administrator/language/en-GB/en-GB.plg_search_tags.sys.ini /administrator/language/en-GB/en-GB.plg_search_tags.sys.ini
/administrator/language/en-GB/en-GB.plg_system_languagecode.ini /administrator/language/en-GB/en-GB.plg_system_languagecode.ini
/administrator/language/en-GB/en-GB.plg_system_languagecode.sys.ini /administrator/language/en-GB/en-GB.plg_system_languagecode.sys.ini
/administrator/language/en-GB/en-GB.plg_system_stats*
/administrator/language/en-GB/en-GB.plg_system_updatenotification*
/administrator/language/en-GB/en-GB.plg_twofactorauth_totp.ini /administrator/language/en-GB/en-GB.plg_twofactorauth_totp.ini
/administrator/language/en-GB/en-GB.plg_twofactorauth_totp.sys.ini /administrator/language/en-GB/en-GB.plg_twofactorauth_totp.sys.ini
/administrator/language/en-GB/en-GB.plg_twofactorauth_yubikey.ini /administrator/language/en-GB/en-GB.plg_twofactorauth_yubikey.ini
...@@ -249,8 +256,10 @@ ...@@ -249,8 +256,10 @@
/administrator/language/en-GB/en-GB.tpl_hathor.sys.ini /administrator/language/en-GB/en-GB.tpl_hathor.sys.ini
/administrator/language/en-GB/en-GB.xml /administrator/language/en-GB/en-GB.xml
/administrator/language/en-GB/index.html /administrator/language/en-GB/index.html
/administrator/language/ru-RU/index.html
/administrator/language/overrides/* /administrator/language/overrides/*
/administrator/language/index.html /administrator/language/index.html
/administrator/logs/index.html
/administrator/manifests/* /administrator/manifests/*
/administrator/modules/mod_custom/* /administrator/modules/mod_custom/*
/administrator/modules/mod_feed/* /administrator/modules/mod_feed/*
...@@ -289,6 +298,7 @@ ...@@ -289,6 +298,7 @@
/components/com_finder/* /components/com_finder/*
/components/com_mailto/* /components/com_mailto/*
/components/com_media/* /components/com_media/*
/components/com_modules/*
/components/com_newsfeeds/* /components/com_newsfeeds/*
/components/com_search/* /components/com_search/*
/components/com_users/* /components/com_users/*
...@@ -407,6 +417,7 @@ ...@@ -407,6 +417,7 @@
/libraries/idna_convert/* /libraries/idna_convert/*
/libraries/joomla/* /libraries/joomla/*
/libraries/legacy/* /libraries/legacy/*
/libraries/php-encryption/*
/libraries/phpass/* /libraries/phpass/*
/libraries/phpmailer/* /libraries/phpmailer/*
/libraries/phputf8/* /libraries/phputf8/*
...@@ -431,9 +442,11 @@ ...@@ -431,9 +442,11 @@
/media/media/* /media/media/*
/media/mod_languages/* /media/mod_languages/*
/media/overrider/* /media/overrider/*
/media/plg_captcha_recaptcha/*
/media/plg_quickicon_extensionupdate/* /media/plg_quickicon_extensionupdate/*
/media/plg_quickicon_joomlaupdate/* /media/plg_quickicon_joomlaupdate/*
/media/plg_system_highlight/* /media/plg_system_highlight/*
/media/plg_system_stats/*
/media/system/* /media/system/*
/media/index.html /media/index.html
/modules/mod_articles_archive/* /modules/mod_articles_archive/*
...@@ -486,6 +499,7 @@ ...@@ -486,6 +499,7 @@
/plugins/editors/none/* /plugins/editors/none/*
/plugins/editors/tinymce/* /plugins/editors/tinymce/*
/plugins/editors/index.html /plugins/editors/index.html
/plugins/editors-xtd/module/*
/plugins/editors-xtd/article/* /plugins/editors-xtd/article/*
/plugins/editors-xtd/image/* /plugins/editors-xtd/image/*
/plugins/editors-xtd/pagebreak/* /plugins/editors-xtd/pagebreak/*
...@@ -523,6 +537,8 @@ ...@@ -523,6 +537,8 @@
/plugins/system/redirect/* /plugins/system/redirect/*
/plugins/system/remember/* /plugins/system/remember/*
/plugins/system/sef/* /plugins/system/sef/*
/plugins/system/stats/*
/plugins/system/updatenotification/*
/plugins/system/index.html /plugins/system/index.html
/plugins/twofactorauth/* /plugins/twofactorauth/*
/plugins/user/contactcreator/* /plugins/user/contactcreator/*
......
...@@ -34,5 +34,8 @@ jspm_packages ...@@ -34,5 +34,8 @@ jspm_packages
# Optional npm cache directory # Optional npm cache directory
.npm .npm
# Optional eslint cache
.eslintcache
# Optional REPL history # Optional REPL history
.node_repl_history .node_repl_history
...@@ -50,7 +50,9 @@ Carthage/Build ...@@ -50,7 +50,9 @@ Carthage/Build
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
fastlane/report.xml fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots fastlane/screenshots
fastlane/test_output
# Code Injection # Code Injection
# #
......
...@@ -79,6 +79,7 @@ celerybeat-schedule ...@@ -79,6 +79,7 @@ celerybeat-schedule
.env .env
# virtualenv # virtualenv
.venv/
venv/ venv/
ENV/ ENV/
......
...@@ -12,9 +12,11 @@ capybara-*.html ...@@ -12,9 +12,11 @@ capybara-*.html
rerun.txt rerun.txt
pickle-email-*.html pickle-email-*.html
# TODO Comment out these rules if you are OK with secrets being uploaded to the repo # TODO Comment out this rule if you are OK with secrets being uploaded to the repo
config/initializers/secret_token.rb config/initializers/secret_token.rb
config/secrets.yml
# Only include if you have production secrets in this file, which is no longer a Rails default
# config/secrets.yml
# dotenv # dotenv
# TODO Comment out this rule if environment variables can be committed # TODO Comment out this rule if environment variables can be committed
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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