Commit d20d8f8e authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'ce-to-ee' into 'master'

CE to EE following update of `db/schema.rb` with `activerecord_sane_schema_dumper`

Resolved conflicts:

```
UU app/controllers/projects/merge_requests_controller.rb
UU app/helpers/merge_requests_helper.rb
UU app/views/projects/merge_requests/widget/_open.html.haml
UU db/schema.rb
UU doc/README.md
UU spec/lib/extracts_path_spec.rb
UU spec/services/merge_requests/refresh_service_spec.rb
```

See merge request !800
parents 67e6d54e 06c90e57
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.13.0 (unreleased) v 8.13.0 (unreleased)
- Respond with 404 Not Found for non-existent tags (Linus Thiel)
- Truncate long labels with ellipsis in labels page - Truncate long labels with ellipsis in labels page
- Update runner version only when updating contacted_at - Update runner version only when updating contacted_at
- Add link from system note to compare with previous version - Add link from system note to compare with previous version
- Improve issue load time performance by avoiding ORDER BY in find_by call
- Use gitlab-shell v3.6.2 (GIT TRACE logging) - Use gitlab-shell v3.6.2 (GIT TRACE logging)
- Add `/projects/visible` API endpoint (Ben Boeckel) - Add `/projects/visible` API endpoint (Ben Boeckel)
- Fix centering of custom header logos (Ashley Dumaine) - Fix centering of custom header logos (Ashley Dumaine)
- ExpireBuildArtifactsWorker query builds table without ordering enqueuing one job per build to cleanup - ExpireBuildArtifactsWorker query builds table without ordering enqueuing one job per build to cleanup
- Add an example for testing a phoenix application with Gitlab CI in the docs (Manthan Mallikarjun)
- Updating verbiage on git basics to be more intuitive
- Clarify documentation for Runners API (Gennady Trafimenkov)
- Change user & group landing page routing from /u/:username to /:username
- Prevent running GfmAutocomplete setup for each diff note !6569
- Added documentation for .gitattributes files
- AbstractReferenceFilter caches project_refs on RequestStore when active - AbstractReferenceFilter caches project_refs on RequestStore when active
- Replaced the check sign to arrow in the show build view. !6501 - Replaced the check sign to arrow in the show build view. !6501
- Add a /wip slash command to toggle the Work In Progress status of a merge request. !6259 (tbalthazar) - Add a /wip slash command to toggle the Work In Progress status of a merge request. !6259 (tbalthazar)
- Fix Error 500 when viewing old merge requests with bad diff data
- Speed-up group milestones show page - Speed-up group milestones show page
- Fix inconsistent options dropdown caret on mobile viewports (ClemMakesApps)
- Don't include archived projects when creating group milestones. !4940 (Jeroen Jacobs) - Don't include archived projects when creating group milestones. !4940 (Jeroen Jacobs)
- Add tag shortcut from the Commit page. !6543 - Add tag shortcut from the Commit page. !6543
- Keep refs for each deployment - Keep refs for each deployment
- Allow browsing branches that end with '.atom'
- Log LDAP lookup errors and don't swallow unrelated exceptions. !6103 (Markus Koller) - Log LDAP lookup errors and don't swallow unrelated exceptions. !6103 (Markus Koller)
- Add more tests for calendar contribution (ClemMakesApps) - Add more tests for calendar contribution (ClemMakesApps)
- Update Gitlab Shell to fix some problems with moving projects between storages - Update Gitlab Shell to fix some problems with moving projects between storages
...@@ -27,6 +36,7 @@ v 8.13.0 (unreleased) ...@@ -27,6 +36,7 @@ v 8.13.0 (unreleased)
- Revert "Label list shows all issues (opened or closed) with that label" - Revert "Label list shows all issues (opened or closed) with that label"
- Expose expires_at field when sharing project on API - Expose expires_at field when sharing project on API
- Fix VueJS template tags being rendered in code comments - Fix VueJS template tags being rendered in code comments
- Added copy file path button to merge request diff files
- Fix issue with page scrolling to top when closing or pinning sidebar (lukehowell) - Fix issue with page scrolling to top when closing or pinning sidebar (lukehowell)
- Add Issue Board API support (andrebsguedes) - Add Issue Board API support (andrebsguedes)
- Allow the Koding integration to be configured through the API - Allow the Koding integration to be configured through the API
...@@ -36,6 +46,8 @@ v 8.13.0 (unreleased) ...@@ -36,6 +46,8 @@ v 8.13.0 (unreleased)
- Add word-wrap to issue title on issue and milestone boards (ClemMakesApps) - Add word-wrap to issue title on issue and milestone boards (ClemMakesApps)
- Fix todos page mobile viewport layout (ClemMakesApps) - Fix todos page mobile viewport layout (ClemMakesApps)
- Fix inconsistent highlighting of already selected activity nav-links (ClemMakesApps) - Fix inconsistent highlighting of already selected activity nav-links (ClemMakesApps)
- Remove redundant mixins (ClemMakesApps)
- Added 'Download' button to the Snippets page (Justin DiPierro)
- Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison) - Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison)
- Close open merge request without source project (Katarzyna Kobierska Ula Budziszewska) - Close open merge request without source project (Katarzyna Kobierska Ula Budziszewska)
- Fix that manual jobs would no longer block jobs in the next stage. !6604 - Fix that manual jobs would no longer block jobs in the next stage. !6604
...@@ -59,8 +71,10 @@ v 8.13.0 (unreleased) ...@@ -59,8 +71,10 @@ v 8.13.0 (unreleased)
- Fix Long commit messages overflow viewport in file tree - Fix Long commit messages overflow viewport in file tree
- Revert avoid touching file system on Build#artifacts? - Revert avoid touching file system on Build#artifacts?
- Stop using a Redis lease when updating the project activity timestamp whenever a new event is created - Stop using a Redis lease when updating the project activity timestamp whenever a new event is created
- Add disabled delete button to protected branches (ClemMakesApps)
- Add broadcast messages and alerts below sub-nav - Add broadcast messages and alerts below sub-nav
- Better empty state for Groups view - Better empty state for Groups view
- API: New /users/:id/events endpoint
- Update ruby-prof to 0.16.2. !6026 (Elan Ruusamäe) - Update ruby-prof to 0.16.2. !6026 (Elan Ruusamäe)
- Replace bootstrap caret with fontawesome caret (ClemMakesApps) - Replace bootstrap caret with fontawesome caret (ClemMakesApps)
- Fix unnecessary escaping of reserved HTML characters in milestone title. !6533 - Fix unnecessary escaping of reserved HTML characters in milestone title. !6533
...@@ -78,14 +92,28 @@ v 8.13.0 (unreleased) ...@@ -78,14 +92,28 @@ v 8.13.0 (unreleased)
- Fix broken repository 500 errors in project list - Fix broken repository 500 errors in project list
- Fix Pipeline list commit column width should be adjusted - Fix Pipeline list commit column width should be adjusted
- Close todos when accepting merge requests via the API !6486 (tonygambone) - Close todos when accepting merge requests via the API !6486 (tonygambone)
- Ability to batch assign issues relating to a merge request to the author. !5725 (jamedjo)
- Changed Slack service user referencing from full name to username (Sebastian Poxhofer) - Changed Slack service user referencing from full name to username (Sebastian Poxhofer)
- Retouch environments list and deployments list - Retouch environments list and deployments list
- Add multiple command support for all label related slash commands !6780 (barthc)
- Add Container Registry on/off status to Admin Area !6638 (the-undefined) - Add Container Registry on/off status to Admin Area !6638 (the-undefined)
- Allow empty merge requests !6384 (Artem Sidorenko)
- Grouped pipeline dropdown is a scrollable container - Grouped pipeline dropdown is a scrollable container
- Cleanup Ci::ApplicationController. !6757 (Takuya Noguchi) - Cleanup Ci::ApplicationController. !6757 (Takuya Noguchi)
- Fix a typo in doc/api/labels.md - Fix a typo in doc/api/labels.md
- API: all unknown routing will be handled with 404 Not Found
- Make guests unable to view MRs on private projects
v 8.12.6
- Update mailroom to 0.8.1 in Gemfile.lock !6814
v 8.12.5 (unreleased) v 8.12.5
- Switch from request to env in ::API::Helpers. !6615
- Update the mail_room gem to 0.8.1 to fix a race condition with the mailbox watching thread. !6714
- Improve issue load time performance by avoiding ORDER BY in find_by call. !6724
- Add a new gitlab:users:clear_all_authentication_tokens task. !6745
- Don't send Private-Token (API authentication) headers to Sentry
- Share projects via the API only with groups the authenticated user can access
v 8.12.4 v 8.12.4
- Fix "Copy to clipboard" tooltip to say "Copied!" when clipboard button is clicked. !6294 (lukehowell) - Fix "Copy to clipboard" tooltip to say "Copied!" when clipboard button is clicked. !6294 (lukehowell)
...@@ -100,7 +128,6 @@ v 8.12.4 ...@@ -100,7 +128,6 @@ v 8.12.4
- Fix failed project deletion when feature visibility set to private. !6688 - Fix failed project deletion when feature visibility set to private. !6688
- Prevent claiming associated model IDs via import. - Prevent claiming associated model IDs via import.
- Set GitLab project exported file permissions to owner only - Set GitLab project exported file permissions to owner only
- Change user & group landing page routing from /u/:username to /:username
v 8.12.3 v 8.12.3
- Update Gitlab Shell to support low IO priority for storage moves - Update Gitlab Shell to support low IO priority for storage moves
...@@ -121,13 +148,13 @@ v 8.12.2 ...@@ -121,13 +148,13 @@ v 8.12.2
- Fix bug where 'Search results' repeated many times when a search in the emoji search form is cleared (Xavier Bick) (@zeiv) - Fix bug where 'Search results' repeated many times when a search in the emoji search form is cleared (Xavier Bick) (@zeiv)
- Fix resolve discussion buttons endpoint path - Fix resolve discussion buttons endpoint path
- Refactor remnants of CoffeeScript destructured opts and super !6261 - Refactor remnants of CoffeeScript destructured opts and super !6261
- Prevent running GfmAutocomplete setup for each diff note !6569
v 8.12.1 v 8.12.1
- Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST - Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST
- Fix issue with search filter labels not displaying - Fix issue with search filter labels not displaying
v 8.12.0 v 8.12.0
- Removes inconsistency regarding tagging immediatelly as merged once you create a new branch. !6408
- 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 - Only check :can_resolve permission if the note is resolvable
- Bump fog-aws to v0.11.0 to support ap-south-1 region - Bump fog-aws to v0.11.0 to support ap-south-1 region
...@@ -315,6 +342,10 @@ v 8.12.0 ...@@ -315,6 +342,10 @@ v 8.12.0
- Fix non-master branch readme display in tree view - Fix non-master branch readme display in tree view
- Add UX improvements for merge request version diffs - Add UX improvements for merge request version diffs
v 8.11.9
- Don't send Private-Token (API authentication) headers to Sentry
- Share projects via the API only with groups the authenticated user can access
v 8.11.8 v 8.11.8
- Respect the fork_project permission when forking projects - Respect the fork_project permission when forking projects
- Set a restrictive CORS policy on the API for credentialed requests - Set a restrictive CORS policy on the API for credentialed requests
...@@ -325,7 +356,6 @@ v 8.11.7 ...@@ -325,7 +356,6 @@ v 8.11.7
- Avoid conflict with admin labels when importing GitHub labels. !6158 - Avoid conflict with admin labels when importing GitHub labels. !6158
- Restores `fieldName` to allow only string values in `gl_dropdown.js`. !6234 - Restores `fieldName` to allow only string values in `gl_dropdown.js`. !6234
- Allow the Rails cookie to be used for API authentication. - Allow the Rails cookie to be used for API authentication.
- Updating verbiage on git basics to be more intuitive
v 8.11.6 v 8.11.6
- Fix unnecessary horizontal scroll area in pipeline visualizations. !6005 - Fix unnecessary horizontal scroll area in pipeline visualizations. !6005
...@@ -486,7 +516,6 @@ v 8.11.0 ...@@ -486,7 +516,6 @@ v 8.11.0
- Add pipeline events hook - Add pipeline events hook
- Bump gitlab_git to speedup DiffCollection iterations - Bump gitlab_git to speedup DiffCollection iterations
- Rewrite description of a blocked user in admin settings. (Elias Werberich) - Rewrite description of a blocked user in admin settings. (Elias Werberich)
- Clarify documentation for Runners API (Gennady Trafimenkov)
- Make branches sortable without push permission !5462 (winniehell) - Make branches sortable without push permission !5462 (winniehell)
- Check for Ci::Build artifacts at database level on pipeline partial - Check for Ci::Build artifacts at database level on pipeline partial
- Convert image diff background image to CSS (ClemMakesApps) - Convert image diff background image to CSS (ClemMakesApps)
...@@ -542,6 +571,10 @@ v 8.11.0 ...@@ -542,6 +571,10 @@ 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.12
- Don't send Private-Token (API authentication) headers to Sentry
- Share projects via the API only with groups the authenticated user can access
v 8.10.11 v 8.10.11
- Respect the fork_project permission when forking projects - Respect the fork_project permission when forking projects
- Set a restrictive CORS policy on the API for credentialed requests - Set a restrictive CORS policy on the API for credentialed requests
......
...@@ -337,7 +337,7 @@ gem 'newrelic_rpm', '~> 3.16' ...@@ -337,7 +337,7 @@ gem 'newrelic_rpm', '~> 3.16'
gem 'octokit', '~> 4.3.0' gem 'octokit', '~> 4.3.0'
gem 'mail_room', '~> 0.8' gem 'mail_room', '~> 0.8.1'
gem 'email_reply_parser', '~> 0.5.8' gem 'email_reply_parser', '~> 0.5.8'
......
...@@ -425,7 +425,7 @@ GEM ...@@ -425,7 +425,7 @@ GEM
systemu (~> 2.6.2) systemu (~> 2.6.2)
mail (2.6.4) mail (2.6.4)
mime-types (>= 1.16, < 4) mime-types (>= 1.16, < 4)
mail_room (0.8.0) mail_room (0.8.1)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.99.3) mime-types (2.99.3)
mimemagic (0.3.0) mimemagic (0.3.0)
...@@ -924,7 +924,7 @@ DEPENDENCIES ...@@ -924,7 +924,7 @@ DEPENDENCIES
license_finder (~> 2.1.0) license_finder (~> 2.1.0)
licensee (~> 8.0.0) licensee (~> 8.0.0)
loofah (~> 2.0.3) loofah (~> 2.0.3)
mail_room (~> 0.8) mail_room (~> 0.8.1)
method_source (~> 0.8) method_source (~> 0.8)
minitest (~> 5.7.0) minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6) mousetrap-rails (~> 1.4.6)
......
...@@ -126,6 +126,9 @@ ...@@ -126,6 +126,9 @@
new TreeView(); new TreeView();
} }
break; break;
case 'projects:pipelines:show':
new gl.Pipelines();
break;
case 'groups:activity': case 'groups:activity':
new Activities(); new Activities();
break; break;
......
(function() { ((global) => {
function toggleGraph() {
class Pipelines {
constructor() {
$(document).off('click', '.toggle-pipeline-btn').on('click', '.toggle-pipeline-btn', this.toggleGraph);
this.addMarginToBuildColumns();
}
toggleGraph() {
const $pipelineBtn = $(this).closest('.toggle-pipeline-btn'); const $pipelineBtn = $(this).closest('.toggle-pipeline-btn');
const $pipelineGraph = $(this).closest('.row-content-block').next('.pipeline-graph'); const $pipelineGraph = $(this).closest('.row-content-block').next('.pipeline-graph');
const $btnText = $(this).find('.toggle-btn-text'); const $btnText = $(this).find('.toggle-btn-text');
const $icon = $(this).find('.fa'); const graphCollapsed = $pipelineGraph.hasClass('graph-collapsed');
$($pipelineBtn).add($pipelineGraph).toggleClass('graph-collapsed'); $($pipelineBtn).add($pipelineGraph).toggleClass('graph-collapsed');
const graphCollapsed = $pipelineGraph.hasClass('graph-collapsed');
const expandIcon = 'fa-caret-down'; graphCollapsed ? $btnText.text('Expand') : $btnText.text('Hide')
const hideIcon = 'fa-caret-up'; }
if(graphCollapsed) { addMarginToBuildColumns() {
$btnText.text('Expand'); const $secondChildBuildNode = $('.build:nth-child(2)');
$icon.removeClass(hideIcon).addClass(expandIcon); if ($secondChildBuildNode.length) {
} else { const $firstChildBuildNode = $secondChildBuildNode.prev('.build');
$btnText.text('Hide'); const $multiBuildColumn = $secondChildBuildNode.closest('.stage-column');
$icon.removeClass(expandIcon).addClass(hideIcon); const $previousColumn = $multiBuildColumn.prev('.stage-column');
$multiBuildColumn.addClass('left-margin');
$firstChildBuildNode.addClass('left-connector');
$previousColumn.each(function() {
$this = $(this);
if ($('.build', $this).length === 1) $this.addClass('no-margin');
});
} }
$('.pipeline-graph').removeClass('hidden');
} }
}
global.Pipelines = Pipelines;
$(document).on('click', '.toggle-pipeline-btn', toggleGraph); })(window.gl || (window.gl = {}));
})();
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
width: 40px; width: 40px;
height: 40px; height: 40px;
padding: 0; padding: 0;
@include border-radius($avatar_radius); border-radius: $avatar_radius;
border: 1px solid rgba(0, 0, 0, .1); border: 1px solid rgba(0, 0, 0, .1);
&.avatar-inline { &.avatar-inline {
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
} }
&.avatar-tile { &.avatar-tile {
@include border-radius(0); border-radius: 0;
border: none; border: none;
} }
......
...@@ -133,7 +133,7 @@ ...@@ -133,7 +133,7 @@
} }
.identicon { .identicon {
@include border-radius(50%); border-radius: 50%;
} }
} }
......
@mixin btn-default { @mixin btn-default {
@include border-radius(3px); border-radius: 3px;
font-size: $gl-font-size; font-size: $gl-font-size;
font-weight: 500; font-weight: 500;
padding: $gl-vert-padding $gl-btn-padding; padding: $gl-vert-padding $gl-btn-padding;
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
&:active { &:active {
outline: none; outline: none;
background-color: $btn-active-gray; background-color: $btn-active-gray;
@include box-shadow($gl-btn-active-background); box-shadow: $gl-btn-active-background;
} }
} }
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
&:active, &:active,
&.active { &.active {
@include box-shadow ($gl-btn-active-background); box-shadow: $gl-btn-active-background;
background-color: $dark; background-color: $dark;
border-color: $border-dark; border-color: $border-dark;
...@@ -279,7 +279,7 @@ ...@@ -279,7 +279,7 @@
} }
.active { .active {
@include box-shadow($gl-btn-active-background); box-shadow: $gl-btn-active-background;
border: 1px solid #c6cacf !important; border: 1px solid #c6cacf !important;
background-color: #e4e7ed !important; background-color: #e4e7ed !important;
......
...@@ -73,7 +73,7 @@ label { ...@@ -73,7 +73,7 @@ label {
} }
.form-control { .form-control {
@include box-shadow(none); box-shadow: none;
border-radius: 3px; border-radius: 3px;
padding: $gl-vert-padding $gl-input-padding; padding: $gl-vert-padding $gl-input-padding;
} }
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
margin-top: 5px; margin-top: 5px;
} }
@include border-radius(3px); border-radius: 3px;
display: block; display: block;
float: left; float: left;
margin-right: 10px; margin-right: 10px;
......
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
} }
.markdown-area { .markdown-area {
@include border-radius(0); border-radius: 0;
background: #fff; background: #fff;
border: 1px solid #ddd; border: 1px solid #ddd;
min-height: 140px; min-height: 140px;
......
/**
* Generic mixins
*/
@mixin box-shadow($shadow) {
box-shadow: $shadow;
}
@mixin border-radius($radius) {
border-radius: $radius;
}
/** /**
* Prefilled mixins * Prefilled mixins
* Mixins with fixed values * Mixins with fixed values
......
...@@ -133,5 +133,5 @@ ...@@ -133,5 +133,5 @@
font-size: 20px; font-size: 20px;
color: #777; color: #777;
z-index: 100; z-index: 100;
@include box-shadow(0 1px 2px #ddd); box-shadow: 0 1px 2px #ddd;
} }
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
} }
.select2-drop { .select2-drop {
@include box-shadow(rgba(76, 86, 103, 0.247059) 0 0 1px 0, rgba(31, 37, 50, 0.317647) 0 2px 18px 0); box-shadow: rgba(76, 86, 103, 0.247059) 0 0 1px 0, rgba(31, 37, 50, 0.317647) 0 2px 18px 0;
@include border-radius ($border-radius-default); border-radius: $border-radius-default;
border: none; border: none;
min-width: 175px; min-width: 175px;
} }
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
.select2-container-active { .select2-container-active {
.select2-choice, .select2-choices { .select2-choice, .select2-choices {
@include box-shadow(none); box-shadow: none;
} }
} }
...@@ -82,13 +82,13 @@ ...@@ -82,13 +82,13 @@
outline: 0; outline: 0;
background-image: none; background-image: none;
background-color: $white-dark; background-color: $white-dark;
@include box-shadow($gl-btn-active-gradient); box-shadow: $gl-btn-active-gradient;
} }
} }
.select2-container-multi { .select2-container-multi {
.select2-choices { .select2-choices {
@include border-radius($border-radius-default); border-radius: $border-radius-default;
border-color: $input-border; border-color: $input-border;
background: none; background: none;
...@@ -123,7 +123,7 @@ ...@@ -123,7 +123,7 @@
&.select2-container-active .select2-choices, &.select2-container-active .select2-choices,
&.select2-dropdown-open .select2-choices { &.select2-dropdown-open .select2-choices {
border-color: $border-white-normal; border-color: $border-white-normal;
@include box-shadow($gl-btn-active-gradient); box-shadow: $gl-btn-active-gradient;
} }
} }
...@@ -157,7 +157,7 @@ ...@@ -157,7 +157,7 @@
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right 0 bottom 6px; background-position: right 0 bottom 6px;
border: 1px solid $input-border; border: 1px solid $input-border;
@include border-radius($border-radius-default); border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
&:focus { &:focus {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
&.page-sidebar-pinned { &.page-sidebar-pinned {
.sidebar-wrapper { .sidebar-wrapper {
@include box-shadow(none); box-shadow: none;
} }
} }
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
width: 0; width: 0;
overflow: hidden; overflow: hidden;
transition: width $sidebar-transition-duration; transition: width $sidebar-transition-duration;
@include box-shadow(2px 0 16px 0 $black-transparent); box-shadow: 2px 0 16px 0 $black-transparent;
} }
} }
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
.count { .count {
float: right; float: right;
padding: 0 8px; padding: 0 8px;
@include border-radius(6px); border-radius: 6px;
} }
} }
......
...@@ -116,7 +116,7 @@ ...@@ -116,7 +116,7 @@
font-size: 13px; font-size: 13px;
line-height: 1.6em; line-height: 1.6em;
overflow-x: auto; overflow-x: auto;
@include border-radius(2px); border-radius: 2px;
} }
p > code { p > code {
......
...@@ -17,8 +17,10 @@ $white-normal: #ededed; ...@@ -17,8 +17,10 @@ $white-normal: #ededed;
$white-dark: #ececec; $white-dark: #ececec;
$gray-light: #fafafa; $gray-light: #fafafa;
$gray-lighter: #f9f9f9;
$gray-normal: #f5f5f5; $gray-normal: #f5f5f5;
$gray-dark: #ededed; $gray-dark: #ededed;
$gray-darker: #eee;
$gray-darkest: #c9c9c9; $gray-darkest: #c9c9c9;
$green-light: #38ae67; $green-light: #38ae67;
...@@ -33,6 +35,8 @@ $blue-medium-light: #3498cb; ...@@ -33,6 +35,8 @@ $blue-medium-light: #3498cb;
$blue-medium: #2f8ebf; $blue-medium: #2f8ebf;
$blue-medium-dark: #2d86b4; $blue-medium-dark: #2d86b4;
$blue-light-transparent: rgba(44, 159, 216, 0.05);
$orange-light: #fc8a51; $orange-light: #fc8a51;
$orange-normal: #e75e40; $orange-normal: #e75e40;
$orange-dark: #ce5237; $orange-dark: #ce5237;
...@@ -91,6 +95,7 @@ $table-text-gray: #8f8f8f; ...@@ -91,6 +95,7 @@ $table-text-gray: #8f8f8f;
$gl-font-size: 15px; $gl-font-size: 15px;
$gl-title-color: #333; $gl-title-color: #333;
$gl-text-color: #5c5c5c; $gl-text-color: #5c5c5c;
$gl-text-color-light: #8c8c8c;
$gl-text-green: #4a2; $gl-text-green: #4a2;
$gl-text-red: #d12f19; $gl-text-red: #d12f19;
$gl-text-orange: #d90; $gl-text-orange: #d90;
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
.bordered-box { .bordered-box {
border: 1px solid $border-color; border: 1px solid $border-color;
@include border-radius($border-radius-default); border-radius: $border-radius-default;
} }
......
.file-editor { .file-editor {
#editor { #editor {
border: none; border: none;
@include border-radius(0); border-radius: 0;
height: 500px; height: 500px;
margin: 0; margin: 0;
padding: 0; padding: 0;
......
...@@ -91,7 +91,7 @@ ...@@ -91,7 +91,7 @@
float: right; float: right;
border: 1px solid #eee; border: 1px solid #eee;
padding: 5px; padding: 5px;
@include border-radius(5px); border-radius: 5px;
background: $gray-light; background: $gray-light;
margin-left: 10px; margin-left: 10px;
top: -6px; top: -6px;
......
.suggest-colors { .suggest-colors {
margin-top: 5px; margin-top: 5px;
a { a {
@include border-radius(4px); border-radius: 4px;
width: 30px; width: 30px;
height: 30px; height: 30px;
display: inline-block; display: inline-block;
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
overflow: hidden; overflow: hidden;
a { a {
@include border-radius(0); border-radius: 0;
width: (100% / 7); width: (100% / 7);
margin-right: 0; margin-right: 0;
margin-bottom: -5px; margin-bottom: -5px;
......
...@@ -73,12 +73,12 @@ ...@@ -73,12 +73,12 @@
height: auto; height: auto;
&.top { &.top {
@include border-radius(5px 5px 0 0); border-radius: 5px 5px 0 0;
margin-bottom: 0; margin-bottom: 0;
} }
&.bottom { &.bottom {
@include border-radius(0 0 5px 5px); border-radius: 0 0 5px 5px;
border-top: 0; border-top: 0;
margin-bottom: 20px; margin-bottom: 20px;
} }
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
&.middle { &.middle {
border-top: 0; border-top: 0;
margin-bottom: 0; margin-bottom: 0;
@include border-radius(0); border-radius: 0;
} }
&:active, &:focus { &:active, &:focus {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
background: $background-color; background: $background-color;
color: $gl-gray; color: $gl-gray;
border: 1px solid $border-color; border: 1px solid $border-color;
@include border-radius(2px); border-radius: 2px;
form { form {
margin-bottom: 0; margin-bottom: 0;
...@@ -204,6 +204,18 @@ ...@@ -204,6 +204,18 @@
word-break: break-all; word-break: break-all;
} }
.commits-empty {
text-align: center;
h4 {
padding-top: 20px;
padding-bottom: 10px;
}
svg {
width: 230px;
}
}
.mr-list { .mr-list {
.merge-request { .merge-request {
padding: 10px 15px; padding: 10px 15px;
......
...@@ -334,7 +334,7 @@ ul.notes { ...@@ -334,7 +334,7 @@ ul.notes {
.add-diff-note { .add-diff-note {
margin-top: -4px; margin-top: -4px;
@include border-radius(40px); border-radius: 40px;
background: #fff; background: #fff;
padding: 4px; padding: 4px;
font-size: 16px; font-size: 16px;
......
...@@ -303,16 +303,41 @@ ...@@ -303,16 +303,41 @@
.stage-column { .stage-column {
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
margin-right: 65px;
&:not(:last-child) {
margin-right: 44px;
}
&.left-margin {
&:not(:first-child) {
margin-left: 44px;
.left-connector {
&::before {
content: '';
position: absolute;
top: 48%;
left: -48px;
border-top: 2px solid $border-color;
width: 48px;
height: 1px;
}
}
}
}
&.no-margin {
margin: 0;
}
li { li {
list-style: none; list-style: none;
} }
.stage-name { .stage-name {
margin-bottom: 15px; margin: 0 0 15px 10px;
font-weight: bold; font-weight: bold;
width: 150px; width: 176px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
...@@ -321,17 +346,23 @@ ...@@ -321,17 +346,23 @@
.build { .build {
border: 1px solid $border-color; border: 1px solid $border-color;
position: relative; position: relative;
padding: 6px 10px; padding: 7px 10px 8px;
border-radius: 30px; border-radius: 30px;
width: 150px; width: 186px;
margin-bottom: 10px; margin-bottom: 10px;
&:hover {
background-color: $gray-lighter;
.dropdown-menu-toggle {
background-color: transparent;
}
}
&.playable { &.playable {
background-color: $gray-light;
svg { svg {
height: 12px; height: 13px;
width: 12px; width: 20px;
position: relative; position: relative;
top: 1px; top: 1px;
...@@ -342,10 +373,20 @@ ...@@ -342,10 +373,20 @@
} }
.build-content { .build-content {
width: 130px; display: -ms-flexbox;
display: -webkit-flex;
display: flex;
width: 164px;
.ci-status-icon {
svg {
height: 20px;
width: 20px;
}
}
.ci-status-text { .ci-status-text {
width: 110px; width: 135px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
...@@ -356,44 +397,53 @@ ...@@ -356,44 +397,53 @@
} }
a { a {
color: $layout-link-gray; color: $gl-text-color-light;
text-decoration: none; text-decoration: none;
&:hover {
.ci-status-text {
text-decoration: underline;
}
}
} }
.dropdown-menu-toggle { .dropdown-menu-toggle {
border: none; border: none;
width: auto; width: auto;
padding: 0; padding: 0;
color: $layout-link-gray; color: $gl-text-color-light;
flex-grow: 1;
.ci-status-text { .ci-status-text {
width: 80px; max-width: 112px;
width: auto;
} }
} }
.grouped-pipeline-dropdown { .grouped-pipeline-dropdown {
padding: 8px 0; padding: 8px 0;
width: 200px; width: 186px;
left: auto; left: auto;
right: -214px; right: -197px;
top: -9px; top: -9px;
max-height: 245px; max-height: 245px;
overflow-y: scroll; overflow-y: scroll;
a:hover { a {
color: $gl-text-color;
padding: 7px 8px 8px;
&:hover {
background-color: $blue-light-transparent;
border-radius: 3px;
.ci-status-text { .ci-status-text {
text-decoration: none; text-decoration: none;
} }
} }
}
svg {
width: 14px;
height: 14px;
}
.ci-status-text { .ci-status-text {
width: 145px; width: 112px;
} }
.arrow { .arrow {
...@@ -426,9 +476,10 @@ ...@@ -426,9 +476,10 @@
} }
.badge { .badge {
background-color: $gray-dark; background-color: $gray-darker;
color: $layout-link-gray; color: $gl-text-color-light;
font-weight: normal; font-weight: normal;
margin-left: $btn-xs-side-margin;
} }
} }
...@@ -442,10 +493,10 @@ ...@@ -442,10 +493,10 @@
&::after { &::after {
content: ''; content: '';
position: absolute; position: absolute;
top: 50%; top: 48%;
right: -69px; right: -48px;
border-top: 2px solid $border-color; border-top: 2px solid $border-color;
width: 69px; width: 48px;
height: 1px; height: 1px;
} }
} }
...@@ -454,25 +505,25 @@ ...@@ -454,25 +505,25 @@
&:not(:first-child) { &:not(:first-child) {
&::after, &::before { &::after, &::before {
content: ''; content: '';
top: -47px; top: -49px;
position: absolute; position: absolute;
border-bottom: 2px solid $border-color; border-bottom: 2px solid $border-color;
width: 20px; width: 25px;
height: 65px; height: 69px;
} }
// Right connecting curves // Right connecting curves
&::after { &::after {
right: -20px; right: -25px;
border-right: 2px solid $border-color; border-right: 2px solid $border-color;
border-radius: 0 0 15px; border-radius: 0 0 20px;
} }
// Left connecting curves // Left connecting curves
&::before { &::before {
left: -20px; left: -25px;
border-left: 2px solid $border-color; border-left: 2px solid $border-color;
border-radius: 0 0 0 15px; border-radius: 0 0 0 20px;
} }
} }
...@@ -480,7 +531,7 @@ ...@@ -480,7 +531,7 @@
&:nth-child(2) { &:nth-child(2) {
&::after, &::before { &::after, &::before {
height: 29px; height: 29px;
top: -10px; top: -9px;
} }
.curve { .curve {
display: block; display: block;
...@@ -538,20 +589,20 @@ ...@@ -538,20 +589,20 @@
width: 21px; width: 21px;
height: 25px; height: 25px;
position: absolute; position: absolute;
top: -29px; top: -32px;
border-top: 2px solid $border-color; border-top: 2px solid $border-color;
} }
&::after { &::after {
left: -39px; left: -44px;
border-right: 2px solid $border-color; border-right: 2px solid $border-color;
border-radius: 0 15px; border-radius: 0 20px;
} }
&::before { &::before {
right: -39px; right: -44px;
border-left: 2px solid $border-color; border-left: 2px solid $border-color;
border-radius: 15px 0 0; border-radius: 20px 0 0;
} }
} }
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
text-align: center; text-align: center;
.preview { .preview {
@include border-radius(4px); border-radius: 4px;
height: 80px; height: 80px;
margin-bottom: 10px; margin-bottom: 10px;
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
width: 160px; width: 160px;
img { img {
@include border-radius(4px); border-radius: 4px;
max-width: 100%; max-width: 100%;
} }
......
...@@ -354,7 +354,7 @@ a.deploy-project-label { ...@@ -354,7 +354,7 @@ a.deploy-project-label {
justify-content: flex-start; justify-content: flex-start;
.fork-thumbnail { .fork-thumbnail {
@include border-radius($border-radius-base); border-radius: $border-radius-base;
background-color: $white-light; background-color: $white-light;
border: 1px solid $border-white-light; border: 1px solid $border-white-light;
height: 202px; height: 202px;
...@@ -371,7 +371,7 @@ a.deploy-project-label { ...@@ -371,7 +371,7 @@ a.deploy-project-label {
background-color: $gray-light; background-color: $gray-light;
border: 1px solid $gray-dark; border: 1px solid $gray-dark;
margin: 0 auto; margin: 0 auto;
@include border-radius(50%); border-radius: 50%;
i { i {
font-size: 100px; font-size: 100px;
color: $gray-dark; color: $gray-dark;
...@@ -390,7 +390,7 @@ a.deploy-project-label { ...@@ -390,7 +390,7 @@ a.deploy-project-label {
} }
img { img {
@include border-radius(50%); border-radius: 50%;
max-width: 100px; max-width: 100px;
} }
} }
...@@ -496,7 +496,7 @@ pre.light-well { ...@@ -496,7 +496,7 @@ pre.light-well {
} }
.light-well { .light-well {
@include border-radius (2px); border-radius: 2px;
color: #5b6169; color: #5b6169;
font-size: 13px; font-size: 13px;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
margin-right: 10px; margin-right: 10px;
border: 1px solid #eee; border: 1px solid #eee;
white-space: nowrap; white-space: nowrap;
@include border-radius(4px); border-radius: 4px;
&:hover { &:hover {
text-decoration: none; text-decoration: none;
......
...@@ -21,8 +21,7 @@ class Explore::ProjectsController < Explore::ApplicationController ...@@ -21,8 +21,7 @@ class Explore::ProjectsController < Explore::ApplicationController
end end
def trending def trending
@projects = TrendingProjectsFinder.new.execute @projects = filter_projects(Project.trending)
@projects = filter_projects(@projects)
@projects = @projects.page(params[:page]) @projects = @projects.page(params[:page])
respond_to do |format| respond_to do |format|
......
class NamespacesController < ApplicationController
skip_before_action :authenticate_user!
def show
namespace = Namespace.find_by(path: params[:id])
if namespace
if namespace.is_a?(Group)
group = namespace
else
user = namespace.owner
end
end
if user
redirect_to user_path(user)
elsif group && can?(current_user, :read_group, group)
redirect_to group_path(group)
elsif current_user.nil?
authenticate_user!
else
render_404
end
end
end
...@@ -10,7 +10,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -10,7 +10,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_action :module_enabled before_action :module_enabled
before_action :merge_request, only: [ before_action :merge_request, only: [
:edit, :update, :show, :diffs, :commits, :conflicts, :builds, :pipelines, :merge, :merge_check, :edit, :update, :show, :diffs, :commits, :conflicts, :builds, :pipelines, :merge, :merge_check,
:ci_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip, :resolve_conflicts, :ci_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues,
:approve, :rebase :approve, :rebase
] ]
before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds, :pipelines] before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds, :pipelines]
...@@ -32,6 +32,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -32,6 +32,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
# Allow modify merge_request # Allow modify merge_request
before_action :authorize_update_merge_request!, only: [:close, :edit, :update, :remove_wip, :sort] before_action :authorize_update_merge_request!, only: [:close, :edit, :update, :remove_wip, :sort]
before_action :authenticate_user!, only: [:assign_related_issues]
before_action :authorize_can_resolve_conflicts!, only: [:conflicts, :resolve_conflicts] before_action :authorize_can_resolve_conflicts!, only: [:conflicts, :resolve_conflicts]
def index def index
...@@ -381,6 +383,25 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -381,6 +383,25 @@ class Projects::MergeRequestsController < Projects::ApplicationController
render layout: false render layout: false
end end
def assign_related_issues
result = MergeRequests::AssignIssuesService.new(project, current_user, merge_request: @merge_request).execute
respond_to do |format|
format.html do
case result[:count]
when 0
flash[:error] = "Failed to assign you issues related to the merge request"
when 1
flash[:notice] = "1 issue has been assigned to you"
else
flash[:notice] = "#{result[:count]} issues have been assigned to you"
end
redirect_to(merge_request_path(@merge_request))
end
end
end
def ci_status def ci_status
pipeline = @merge_request.pipeline pipeline = @merge_request.pipeline
if pipeline if pipeline
......
...@@ -20,6 +20,8 @@ class Projects::TagsController < Projects::ApplicationController ...@@ -20,6 +20,8 @@ class Projects::TagsController < Projects::ApplicationController
def show def show
@tag = @repository.find_tag(params[:id]) @tag = @repository.find_tag(params[:id])
return render_404 unless @tag
@release = @project.releases.find_or_initialize_by(tag: @tag.name) @release = @project.releases.find_or_initialize_by(tag: @tag.name)
@commit = @repository.commit(@tag.target) @commit = @repository.commit(@tag.target)
end end
......
class SnippetsController < ApplicationController class SnippetsController < ApplicationController
include ToggleAwardEmoji include ToggleAwardEmoji
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw] before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :download]
# Allow read snippet # Allow read snippet
before_action :authorize_read_snippet!, only: [:show, :raw] before_action :authorize_read_snippet!, only: [:show, :raw, :download]
# Allow modify snippet # Allow modify snippet
before_action :authorize_update_snippet!, only: [:edit, :update] before_action :authorize_update_snippet!, only: [:edit, :update]
...@@ -12,7 +12,7 @@ class SnippetsController < ApplicationController ...@@ -12,7 +12,7 @@ class SnippetsController < ApplicationController
# Allow destroy snippet # Allow destroy snippet
before_action :authorize_admin_snippet!, only: [:destroy] before_action :authorize_admin_snippet!, only: [:destroy]
skip_before_action :authenticate_user!, only: [:index, :show, :raw] skip_before_action :authenticate_user!, only: [:index, :show, :raw, :download]
layout 'snippets' layout 'snippets'
respond_to :html respond_to :html
...@@ -75,6 +75,14 @@ class SnippetsController < ApplicationController ...@@ -75,6 +75,14 @@ class SnippetsController < ApplicationController
) )
end end
def download
send_data(
@snippet.content,
type: 'text/plain; charset=utf-8',
filename: @snippet.sanitized_file_name
)
end
protected protected
def snippet def snippet
......
# Finder for retrieving public trending projects in a given time range.
class TrendingProjectsFinder
# current_user - The currently logged in User, if any.
# last_months - The number of months to limit the trending data to.
def execute(months_limit = 1)
Rails.cache.fetch(cache_key_for(months_limit), expires_in: 1.day) do
Project.public_only.trending(months_limit.months.ago)
end
end
private
def cache_key_for(months)
"trending_projects/#{months}"
end
end
...@@ -15,10 +15,11 @@ module ButtonHelper ...@@ -15,10 +15,11 @@ module ButtonHelper
# #
# See http://clipboardjs.com/#usage # See http://clipboardjs.com/#usage
def clipboard_button(data = {}) def clipboard_button(data = {})
css_class = data[:class] || 'btn-clipboard'
data = { toggle: 'tooltip', placement: 'bottom', container: 'body' }.merge(data) data = { toggle: 'tooltip', placement: 'bottom', container: 'body' }.merge(data)
content_tag :button, content_tag :button,
icon('clipboard'), icon('clipboard'),
class: "btn btn-clipboard", class: "btn #{css_class}",
data: data, data: data,
type: :button, type: :button,
title: "Copy to Clipboard" title: "Copy to Clipboard"
......
...@@ -109,6 +109,19 @@ module MergeRequestsHelper ...@@ -109,6 +109,19 @@ module MergeRequestsHelper
str str
end end
def mr_assign_issues_link
issues = MergeRequests::AssignIssuesService.new(@project,
current_user,
merge_request: @merge_request,
closes_issues: mr_closes_issues
).assignable_issues
path = assign_related_issues_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
if issues.present?
pluralize_this_issue = issues.count > 1 ? "these issues" : "this issue"
link_to "Assign yourself to #{pluralize_this_issue}", path, method: :post
end
end
def source_branch_with_namespace(merge_request) def source_branch_with_namespace(merge_request)
branch = link_to(merge_request.source_branch, namespace_project_commits_path(merge_request.source_project.namespace, merge_request.source_project, merge_request.source_branch)) branch = link_to(merge_request.source_branch, namespace_project_commits_path(merge_request.source_project.namespace, merge_request.source_project, merge_request.source_branch))
......
...@@ -73,8 +73,10 @@ class Event < ActiveRecord::Base ...@@ -73,8 +73,10 @@ class Event < ActiveRecord::Base
true true
elsif issue? || issue_note? elsif issue? || issue_note?
Ability.allowed?(user, :read_issue, note? ? note_target : target) Ability.allowed?(user, :read_issue, note? ? note_target : target)
elsif merge_request? || merge_request_note?
Ability.allowed?(user, :read_merge_request, note? ? note_target : target)
else else
((merge_request? || note?) && target.present?) || milestone? milestone?
end end
end end
...@@ -285,6 +287,10 @@ class Event < ActiveRecord::Base ...@@ -285,6 +287,10 @@ class Event < ActiveRecord::Base
note? && target && target.for_issue? note? && target && target.for_issue?
end end
def merge_request_note?
note? && target && target.for_merge_request?
end
def project_snippet_note? def project_snippet_note?
target.for_snippet? target.for_snippet?
end end
......
...@@ -6,6 +6,9 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -6,6 +6,9 @@ class MergeRequestDiff < ActiveRecord::Base
# Prevent store of diff if commits amount more then 500 # Prevent store of diff if commits amount more then 500
COMMITS_SAFE_SIZE = 100 COMMITS_SAFE_SIZE = 100
# Valid types of serialized diffs allowed by Gitlab::Git::Diff
VALID_CLASSES = [Hash, Rugged::Patch, Rugged::Diff::Delta]
belongs_to :merge_request belongs_to :merge_request
state_machine :state, initial: :empty do state_machine :state, initial: :empty do
...@@ -170,6 +173,15 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -170,6 +173,15 @@ class MergeRequestDiff < ActiveRecord::Base
private private
# Old GitLab implementations may have generated diffs as ["--broken-diff"].
# Avoid an error 500 by ignoring bad elements. See:
# https://gitlab.com/gitlab-org/gitlab-ce/issues/20776
def valid_raw_diff?(raw)
return false unless raw.respond_to?(:each)
raw.any? { |element| VALID_CLASSES.include?(element.class) }
end
def dump_commits(commits) def dump_commits(commits)
commits.map(&:to_hash) commits.map(&:to_hash)
end end
...@@ -200,7 +212,7 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -200,7 +212,7 @@ class MergeRequestDiff < ActiveRecord::Base
end end
def load_diffs(raw, options) def load_diffs(raw, options)
if raw.respond_to?(:each) if valid_raw_diff?(raw)
if paths = options[:paths] if paths = options[:paths]
raw = raw.select do |diff| raw = raw.select do |diff|
paths.include?(diff[:old_path]) || paths.include?(diff[:new_path]) paths.include?(diff[:old_path]) || paths.include?(diff[:new_path])
......
...@@ -409,19 +409,9 @@ class Project < ActiveRecord::Base ...@@ -409,19 +409,9 @@ class Project < ActiveRecord::Base
%r{(?<project>#{name_pattern}/#{name_pattern})} %r{(?<project>#{name_pattern}/#{name_pattern})}
end end
def trending(since = 1.month.ago) def trending
# By counting in the JOIN we don't expose the GROUP BY to the outer query. joins('INNER JOIN trending_projects ON projects.id = trending_projects.project_id').
# This means that calls such as "any?" and "count" just return a number of reorder('trending_projects.id ASC')
# the total count, instead of the counts grouped per project as a Hash.
join_body = "INNER JOIN (
SELECT project_id, COUNT(*) AS amount
FROM notes
WHERE created_at >= #{sanitize(since)}
AND system IS FALSE
GROUP BY project_id
) join_note_counts ON projects.id = join_note_counts.project_id"
joins(join_body).reorder('join_note_counts.amount DESC')
end end
def cached_count def cached_count
......
...@@ -10,7 +10,7 @@ class ProjectGroupLink < ActiveRecord::Base ...@@ -10,7 +10,7 @@ class ProjectGroupLink < ActiveRecord::Base
belongs_to :group belongs_to :group
validates :project_id, presence: true validates :project_id, presence: true
validates :group_id, presence: true validates :group, presence: true
validates :group_id, uniqueness: { scope: [:project_id], message: "already shared with this group" } validates :group_id, uniqueness: { scope: [:project_id], message: "already shared with this group" }
validates :group_access, presence: true validates :group_access, presence: true
validates :group_access, inclusion: { in: Gitlab::Access.values }, presence: true validates :group_access, inclusion: { in: Gitlab::Access.values }, presence: true
......
...@@ -1118,7 +1118,8 @@ class Repository ...@@ -1118,7 +1118,8 @@ class Repository
root_ref_commit = commit(root_ref) root_ref_commit = commit(root_ref)
if branch_commit if branch_commit
is_ancestor?(branch_commit.id, root_ref_commit.id) same_head = branch_commit.id == root_ref_commit.id
!same_head && is_ancestor?(branch_commit.id, root_ref_commit.id)
else else
nil nil
end end
......
class TrendingProject < ActiveRecord::Base
belongs_to :project
# The number of months to include in the trending calculation.
MONTHS_TO_INCLUDE = 1
# The maximum number of projects to include in the trending set.
PROJECTS_LIMIT = 100
# Populates the trending projects table with the current list of trending
# projects.
def self.refresh!
# The calculation **must** run in a transaction. If the removal of data and
# insertion of new data were to run separately a user might end up with an
# empty list of trending projects for a short period of time.
transaction do
delete_all
timestamp = connection.quote(MONTHS_TO_INCLUDE.months.ago)
connection.execute <<-EOF.strip_heredoc
INSERT INTO #{table_name} (project_id)
SELECT project_id
FROM notes
INNER JOIN projects ON projects.id = notes.project_id
WHERE notes.created_at >= #{timestamp}
AND notes.system IS FALSE
AND projects.visibility_level = #{Gitlab::VisibilityLevel::PUBLIC}
GROUP BY project_id
ORDER BY count(*) DESC
LIMIT #{PROJECTS_LIMIT};
EOF
end
end
end
...@@ -626,6 +626,11 @@ class User < ActiveRecord::Base ...@@ -626,6 +626,11 @@ class User < ActiveRecord::Base
end end
def set_projects_limit def set_projects_limit
# `User.select(:id)` raises
# `ActiveModel::MissingAttributeError: missing attribute: projects_limit`
# without this safeguard!
return unless self.has_attribute?(:projects_limit)
connection_default_value_defined = new_record? && !projects_limit_changed? connection_default_value_defined = new_record? && !projects_limit_changed?
return unless self.projects_limit.nil? || connection_default_value_defined return unless self.projects_limit.nil? || connection_default_value_defined
......
...@@ -43,7 +43,6 @@ class ProjectPolicy < BasePolicy ...@@ -43,7 +43,6 @@ class ProjectPolicy < BasePolicy
can! :read_milestone can! :read_milestone
can! :read_project_snippet can! :read_project_snippet
can! :read_project_member can! :read_project_member
can! :read_merge_request
can! :read_note can! :read_note
can! :create_project can! :create_project
can! :create_issue can! :create_issue
...@@ -66,6 +65,7 @@ class ProjectPolicy < BasePolicy ...@@ -66,6 +65,7 @@ class ProjectPolicy < BasePolicy
can! :read_pipeline can! :read_pipeline
can! :read_environment can! :read_environment
can! :read_deployment can! :read_deployment
can! :read_merge_request
end end
# Permissions given when an user is team member of a project # Permissions given when an user is team member of a project
...@@ -126,6 +126,7 @@ class ProjectPolicy < BasePolicy ...@@ -126,6 +126,7 @@ class ProjectPolicy < BasePolicy
can! :read_container_image can! :read_container_image
can! :build_download_code can! :build_download_code
can! :build_read_container_image can! :build_read_container_image
can! :read_merge_request
end end
def owner_access! def owner_access!
......
module MergeRequests
class AssignIssuesService < BaseService
def assignable_issues
@assignable_issues ||= begin
if current_user == merge_request.author
closes_issues.select do |issue|
!issue.assignee_id? && can?(current_user, :admin_issue, issue)
end
else
[]
end
end
end
def execute
assignable_issues.each do |issue|
Issues::UpdateService.new(issue.project, current_user, assignee_id: current_user.id).execute(issue)
end
{
count: assignable_issues.count
}
end
private
def merge_request
params[:merge_request]
end
def closes_issues
@closes_issues ||= params[:closes_issues] || merge_request.closes_issues(current_user)
end
end
end
...@@ -4,7 +4,7 @@ module MergeRequests ...@@ -4,7 +4,7 @@ module MergeRequests
merge_request = MergeRequest.new(params) merge_request = MergeRequest.new(params)
# Set MR attributes # Set MR attributes
merge_request.can_be_created = false merge_request.can_be_created = true
merge_request.compare_commits = [] merge_request.compare_commits = []
merge_request.source_project = project unless merge_request.source_project merge_request.source_project = project unless merge_request.source_project
...@@ -22,6 +22,12 @@ module MergeRequests ...@@ -22,6 +22,12 @@ module MergeRequests
return build_failed(merge_request, message) return build_failed(merge_request, message)
end end
if merge_request.source_project == merge_request.target_project &&
merge_request.target_branch == merge_request.source_branch
return build_failed(merge_request, 'You must select different branches')
end
compare = CompareService.new.execute( compare = CompareService.new.execute(
merge_request.source_project, merge_request.source_project,
merge_request.source_branch, merge_request.source_branch,
...@@ -29,17 +35,8 @@ module MergeRequests ...@@ -29,17 +35,8 @@ module MergeRequests
merge_request.target_branch, merge_request.target_branch,
) )
commits = compare.commits merge_request.compare_commits = compare.commits
# At this point we decide if merge request can be created
# If we have at least one commit to merge -> creation allowed
if commits.present?
merge_request.compare_commits = commits
merge_request.can_be_created = true
merge_request.compare = compare merge_request.compare = compare
else
merge_request.can_be_created = false
end
set_title_and_description(merge_request) set_title_and_description(merge_request)
end end
...@@ -94,6 +91,8 @@ module MergeRequests ...@@ -94,6 +91,8 @@ module MergeRequests
end end
end end
merge_request.title = merge_request.wip_title if commits.empty?
merge_request merge_request
end end
......
...@@ -488,10 +488,12 @@ class NotificationService ...@@ -488,10 +488,12 @@ class NotificationService
end end
def reject_users_without_access(recipients, target) def reject_users_without_access(recipients, target)
return recipients unless target.is_a?(Issue) return recipients unless target.is_a?(Issuable)
ability = :"read_#{target.to_ability_name}"
recipients.select do |user| recipients.select do |user|
user.can?(:read_issue, target) user.can?(ability, target)
end end
end end
......
...@@ -122,7 +122,12 @@ module SlashCommands ...@@ -122,7 +122,12 @@ module SlashCommands
command :label do |labels_param| command :label do |labels_param|
label_ids = find_label_ids(labels_param) label_ids = find_label_ids(labels_param)
@updates[:add_label_ids] = label_ids unless label_ids.empty? if label_ids.any?
@updates[:add_label_ids] ||= []
@updates[:add_label_ids] += label_ids
@updates[:add_label_ids].uniq!
end
end end
desc 'Remove all or specific label(s)' desc 'Remove all or specific label(s)'
...@@ -136,7 +141,12 @@ module SlashCommands ...@@ -136,7 +141,12 @@ module SlashCommands
if labels_param.present? if labels_param.present?
label_ids = find_label_ids(labels_param) label_ids = find_label_ids(labels_param)
@updates[:remove_label_ids] = label_ids unless label_ids.empty? if label_ids.any?
@updates[:remove_label_ids] ||= []
@updates[:remove_label_ids] += label_ids
@updates[:remove_label_ids].uniq!
end
else else
@updates[:label_ids] = [] @updates[:label_ids] = []
end end
...@@ -152,7 +162,12 @@ module SlashCommands ...@@ -152,7 +162,12 @@ module SlashCommands
command :relabel do |labels_param| command :relabel do |labels_param|
label_ids = find_label_ids(labels_param) label_ids = find_label_ids(labels_param)
@updates[:label_ids] = label_ids unless label_ids.empty? if label_ids.any?
@updates[:label_ids] ||= []
@updates[:label_ids] += label_ids
@updates[:label_ids].uniq!
end
end end
desc 'Add a todo' desc 'Add a todo'
......
...@@ -291,12 +291,12 @@ class TodoService ...@@ -291,12 +291,12 @@ class TodoService
end end
def reject_users_without_access(users, project, target) def reject_users_without_access(users, project, target)
if target.is_a?(Note) && target.for_issue? if target.is_a?(Note) && (target.for_issue? || target.for_merge_request?)
target = target.noteable target = target.noteable
end end
if target.is_a?(Issue) if target.is_a?(Issuable)
select_users(users, :read_issue, target) select_users(users, :"read_#{target.to_ability_name}", target)
else else
select_users(users, :read_project, project) select_users(users, :read_project, project)
end end
......
...@@ -24,6 +24,7 @@ class NamespaceValidator < ActiveModel::EachValidator ...@@ -24,6 +24,7 @@ class NamespaceValidator < ActiveModel::EachValidator
projects projects
public public
repository repository
robots.txt
s s
search search
services services
......
...@@ -36,8 +36,8 @@ ...@@ -36,8 +36,8 @@
= render 'projects/buttons/download', project: @project, ref: branch.name = render 'projects/buttons/download', project: @project, ref: branch.name
- if can_remove_branch?(@project, branch.name) - if can?(current_user, :push_code, @project)
= link_to namespace_project_branch_path(@project.namespace, @project, branch.name), class: 'btn btn-remove remove-row has-tooltip', title: "Delete branch", method: :delete, data: { confirm: "Deleting the '#{branch.name}' branch cannot be undone. Are you sure?", container: 'body' }, remote: true do = link_to namespace_project_branch_path(@project.namespace, @project, branch.name), class: "btn btn-remove remove-row has-tooltip #{can_remove_branch?(@project, branch.name) ? '' : 'disabled'}", title: "Delete branch", method: :delete, data: { confirm: "Deleting the '#{branch.name}' branch cannot be undone. Are you sure?", container: 'body' }, remote: true do
= icon("trash-o") = icon("trash-o")
- if branch.name != @repository.root_ref - if branch.name != @repository.root_ref
......
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
.ci-status-text= subject.name .ci-status-text= subject.name
- elsif can?(current_user, :read_build, @project) - elsif can?(current_user, :read_build, @project)
= link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do = link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do
%span.ci-status-icon
= render_status_with_link('build', subject.status) = render_status_with_link('build', subject.status)
.ci-status-text= subject.name .ci-status-text= subject.name
- else - else
%span.ci-status-icon
= render_status_with_link('build', subject.status) = render_status_with_link('build', subject.status)
= ci_icon_for_status(subject.status) = ci_icon_for_status(subject.status)
.row-content-block.build-content.middle-block.pipeline-actions .pipeline-graph-container
.row-content-block.build-content.middle-block.pipeline-actions
.pull-right .pull-right
.btn.btn-grouped.btn-white.toggle-pipeline-btn .btn.btn-grouped.btn-white.toggle-pipeline-btn
%span.toggle-btn-text Hide %span.toggle-btn-text Hide
%span pipeline graph %span pipeline graph
= icon('caret-up') %span.caret
- if can?(current_user, :update_pipeline, pipeline.project) - if can?(current_user, :update_pipeline, pipeline.project)
- if pipeline.builds.latest.failed.any?(&:retryable?) - if pipeline.builds.latest.failed.any?(&:retryable?)
= link_to "Retry failed", retry_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: 'btn btn-grouped btn-primary', method: :post = link_to "Retry failed", retry_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: 'btn btn-grouped btn-primary', method: :post
...@@ -27,7 +28,7 @@ ...@@ -27,7 +28,7 @@
in in
= time_interval_in_words pipeline.duration = time_interval_in_words pipeline.duration
.row-content-block.build-content.middle-block.pipeline-graph .row-content-block.build-content.middle-block.pipeline-graph.hidden
.pipeline-visualization .pipeline-visualization
%ul.stage-column-list %ul.stage-column-list
- stages = pipeline.stages_with_latest_statuses - stages = pipeline.stages_with_latest_statuses
......
...@@ -10,5 +10,5 @@ ...@@ -10,5 +10,5 @@
- else - else
%li.build %li.build
.curve .curve
.build-content .dropdown.inline.build-content
= render "projects/commit/pipeline_status_group", name: group_name, subject: grouped_statuses = render "projects/commit/pipeline_status_group", name: group_name, subject: grouped_statuses
- group_status = CommitStatus.where(id: subject).status - group_status = CommitStatus.where(id: subject).status
= render_status_with_link('build', group_status) %button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown' } }
.dropdown.inline %span.ci-status-icon
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown' } } = render_status_with_link('build', group_status)
%span.ci-status-text %span.ci-status-text
= name = name
%span.badge= subject.size %span.badge= subject.size
%ul.dropdown-menu.grouped-pipeline-dropdown %ul.dropdown-menu.grouped-pipeline-dropdown
.arrow %li.arrow
- subject.each do |status| - subject.each do |status|
%li
= render "projects/#{status.to_partial_path}_pipeline", subject: status = render "projects/#{status.to_partial_path}_pipeline", subject: status
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
%div{ class: container_class } %div{ class: container_class }
.sub-header-block .sub-header-block
Compare branches, tags or commit ranges. Compare Git revisions.
%br %br
Fill input field with commit id like Fill input field with commit id like
%code.label-branch 4eedf23 %code.label-branch 4eedf23
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
= link_to '#', class: 'js-toggle-diff-comments btn active has-tooltip btn-file-option', title: "Toggle comments for this file", disabled: @diff_notes_disabled do = link_to '#', class: 'js-toggle-diff-comments btn active has-tooltip btn-file-option', title: "Toggle comments for this file", disabled: @diff_notes_disabled do
= icon('comment') = icon('comment')
\ \
= clipboard_button(clipboard_text: diff_file.new_path, class: 'btn-file-option')
- if editable_diff?(diff_file) - if editable_diff?(diff_file)
- link_opts = @merge_request.id ? { from_merge_request_id: @merge_request.id } : {} - link_opts = @merge_request.id ? { from_merge_request_id: @merge_request.id } : {}
= edit_blob_link(@merge_request.source_project, @merge_request.source_branch, diff_file.new_path, = edit_blob_link(@merge_request.source_project, @merge_request.source_branch, diff_file.new_path,
......
...@@ -99,7 +99,7 @@ ...@@ -99,7 +99,7 @@
Git Large File Storage Git Large File Storage
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
.col-md-3 .col-md-3
= f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control' = f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control', data: { field: 'lfs_enabled' }
- if Gitlab.config.registry.enabled - if Gitlab.config.registry.enabled
.form-group .form-group
......
...@@ -62,5 +62,3 @@ ...@@ -62,5 +62,3 @@
%td.coverage %td.coverage
- if generic_commit_status.try(:coverage) - if generic_commit_status.try(:coverage)
#{generic_commit_status.coverage}% #{generic_commit_status.coverage}%
%td
- if subject.target_url - if subject.target_url
= link_to subject.target_url do = link_to subject.target_url do
%span.ci-status-icon
= render_status_with_link('commit status', subject.status) = render_status_with_link('commit status', subject.status)
%span.ci-status-text= subject.name %span.ci-status-text= subject.name
- else - else
%span.ci-status-icon
= render_status_with_link('commit status', subject.status) = render_status_with_link('commit status', subject.status)
%span.ci-status-text= subject.name %span.ci-status-text= subject.name
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
.issuable-actions .issuable-actions
.clearfix.issue-btn-group.dropdown .clearfix.issue-btn-group.dropdown
%button.btn.btn-default.pull-left.hidden-md.hidden-lg{ type: "button", data: { toggle: "dropdown" } } %button.btn.btn-default.pull-left.hidden-md.hidden-lg{ type: "button", data: { toggle: "dropdown" } }
= icon('caret-down')
Options Options
= icon('caret-down')
.dropdown-menu.dropdown-menu-align-right.hidden-lg .dropdown-menu.dropdown-menu-align-right.hidden-lg
%ul %ul
- if can?(current_user, :create_issue, @project) - if can?(current_user, :create_issue, @project)
......
...@@ -65,19 +65,6 @@ ...@@ -65,19 +65,6 @@
- if @merge_request.errors.any? - if @merge_request.errors.any?
= form_errors(@merge_request) = form_errors(@merge_request)
- elsif @merge_request.source_branch.present? && @merge_request.target_branch.present?
.light-well.append-bottom-default
.center
%h4
There isn't anything to merge.
%p.slead
- if @merge_request.source_branch == @merge_request.target_branch
You'll need to use different branch names to get a valid comparison.
- else
%span.label-branch #{@merge_request.source_branch}
and
%span.label-branch #{@merge_request.target_branch}
are the same.
= f.submit 'Compare branches and continue', class: "btn btn-new mr-compare-btn" = f.submit 'Compare branches and continue', class: "btn btn-new mr-compare-btn"
:javascript :javascript
......
...@@ -18,6 +18,12 @@ ...@@ -18,6 +18,12 @@
= f.hidden_field :target_branch = f.hidden_field :target_branch
.mr-compare.merge-request .mr-compare.merge-request
- if @commits.empty?
.commits-empty
%h4
There are no commits yet.
= custom_icon ('illustration_no_commits')
- else
%ul.merge-request-tabs.nav-links.no-top.no-bottom %ul.merge-request-tabs.nav-links.no-top.no-bottom
%li.commits-tab.active %li.commits-tab.active
= link_to url_for(params), data: {target: 'div#commits', action: 'new', toggle: 'tab'} do = link_to url_for(params), data: {target: 'div#commits', action: 'new', toggle: 'tab'} do
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
.issuable-actions .issuable-actions
.clearfix.issue-btn-group.dropdown .clearfix.issue-btn-group.dropdown
%button.btn.btn-default.pull-left.hidden-md.hidden-lg{ type: "button", data: { toggle: "dropdown" } } %button.btn.btn-default.pull-left.hidden-md.hidden-lg{ type: "button", data: { toggle: "dropdown" } }
= icon('caret-down')
Options Options
= icon('caret-down')
.dropdown-menu.dropdown-menu-align-right.hidden-lg .dropdown-menu.dropdown-menu-align-right.hidden-lg
%ul %ul
%li{ class: merge_request_button_visibility(@merge_request, true) } %li{ class: merge_request_button_visibility(@merge_request, true) }
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
Accepting this merge request will close #{"issue".pluralize(mr_closes_issues.size)} Accepting this merge request will close #{"issue".pluralize(mr_closes_issues.size)}
= succeed '.' do = succeed '.' do
!= markdown issues_sentence(mr_closes_issues), pipeline: :gfm, author: @merge_request.author != markdown issues_sentence(mr_closes_issues), pipeline: :gfm, author: @merge_request.author
= mr_assign_issues_link
- if @merge_request.approvals.any? - if @merge_request.approvals.any?
.mr-widget-footer.approved-by-users .mr-widget-footer.approved-by-users
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
.project-network .project-network
.controls .controls
= form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f| = form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f|
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: "Input an extended SHA1 syntax", class: 'search-input form-control input-mx-250 search-sha' = text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: "Git revision", class: 'search-input form-control input-mx-250 search-sha'
= button_tag class: 'btn btn-success' do = button_tag class: 'btn btn-success' do
= icon('search') = icon('search')
.inline.prepend-left-20 .inline.prepend-left-20
......
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 168 107" xmlns:xlink="http://www.w3.org/1999/xlink"><g fill="#eee" fill-rule="evenodd"><path d="m4.01 2h1.102c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-1.102c-2.218 0-4.01 1.788-4.01 4 0 .552.448 1 1 1 .552 0 1-.448 1-1 0-1.108.892-2 2.01-2m12.702 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m8.088 0c.822 0 1.554.503 1.86 1.254.208.512.791.758 1.303.55.512-.208.758-.791.55-1.303-.609-1.497-2.069-2.5-3.712-2.5h-2.188c-.552 0-1 .448-1 1 0 .552.448 1 1 1h2.188m2.01 12.518c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7m0 11.6c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7m0 11.6c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7m0 6.282c0 1.108-.892 2-2.01 2h-.72c-.552 0-1 .448-1 1 0 .552.448 1 1 1h.72c2.218 0 4.01-1.788 4.01-4v-.382c0-.552-.448-1-1-1-.552 0-1 .448-1 1v.382m-14.325 2c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-8.47 0c-.755 0-1.438-.424-1.782-1.085-.255-.49-.859-.681-1.349-.426-.49.255-.681.859-.426 1.349.684 1.316 2.046 2.162 3.556 2.162h2.57c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-2.57m-2.01-12.136c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7m0-11.6c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7m0-11.6c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7m0-6.664c0-.552-.448-1-1-1-.552 0-1 .448-1 1v.764c0 .552.448 1 1 1 .552 0 1-.448 1-1v-.764" id="0"/><circle cx="21" cy="24" r="10"/><rect width="33" height="3" x="37" y="18" rx="1.5" id="1"/><rect width="53" height="3" x="37" y="27" rx="1.5" id="2"/><path d="m131 29c0 .552.447.999.996.999h22.01c.545 0 .996-.451.996-.999v-9c0-.552-.447-.999-.996-.999h-22.01c-.545 0-.996.451-.996.999v9m.996-12h22.01c1.655 0 2.996 1.344 2.996 2.999v9c0 1.657-1.35 2.999-2.996 2.999h-22.01c-1.655 0-2.996-1.344-2.996-2.999v-9c0-1.657 1.35-2.999 2.996-2.999" id="3"/><g transform="translate(0 59)"><use xlink:href="#0"/><circle cx="21" cy="24" r="10"/><use xlink:href="#1"/><use xlink:href="#2"/><use xlink:href="#3"/></g></g></svg>
\ No newline at end of file
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
.file-actions .file-actions
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']") = clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
= link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank" = link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
= link_to 'Download', download_snippet_path(@snippet), class: "btn btn-sm"
= render 'shared/snippets/blob' = render 'shared/snippets/blob'
= render 'award_emoji/awards_block', awardable: @snippet, inline: true = render 'award_emoji/awards_block', awardable: @snippet, inline: true
\ No newline at end of file
class TrendingProjectsWorker
include Sidekiq::Worker
sidekiq_options queue: :trending_projects
def perform
Rails.logger.info('Refreshing trending projects')
TrendingProject.refresh!
end
end
...@@ -395,6 +395,10 @@ Settings.cron_jobs['prune_old_events_worker'] ||= Settingslogic.new({}) ...@@ -395,6 +395,10 @@ Settings.cron_jobs['prune_old_events_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['prune_old_events_worker']['cron'] ||= '* */6 * * *' Settings.cron_jobs['prune_old_events_worker']['cron'] ||= '* */6 * * *'
Settings.cron_jobs['prune_old_events_worker']['job_class'] = 'PruneOldEventsWorker' Settings.cron_jobs['prune_old_events_worker']['job_class'] = 'PruneOldEventsWorker'
Settings.cron_jobs['trending_projects_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['trending_projects_worker']['cron'] = '0 1 * * *'
Settings.cron_jobs['trending_projects_worker']['job_class'] = 'TrendingProjectsWorker'
# #
# GitLab Shell # GitLab Shell
# #
......
...@@ -95,7 +95,5 @@ Rails.application.routes.draw do ...@@ -95,7 +95,5 @@ Rails.application.routes.draw do
# Get all keys of user # Get all keys of user
get ':username.keys' => 'profiles/keys#get_keys', constraints: { username: /.*/ } get ':username.keys' => 'profiles/keys#get_keys', constraints: { username: /.*/ }
get ':id' => 'namespaces#show', constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
root to: "root#index" root to: "root#index"
end end
...@@ -159,7 +159,7 @@ resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: ...@@ -159,7 +159,7 @@ resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only:
get( get(
'/commits/*id', '/commits/*id',
to: 'commits#show', to: 'commits#show',
constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }, constraints: { id: /.+/, format: false },
as: :commits as: :commits
) )
end end
...@@ -289,6 +289,7 @@ resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: ...@@ -289,6 +289,7 @@ resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only:
post :remove_wip post :remove_wip
get :diff_for_path get :diff_for_path
post :resolve_conflicts post :resolve_conflicts
post :assign_related_issues
end end
collection do collection do
......
resources :snippets, concerns: :awardable do resources :snippets, concerns: :awardable do
member do member do
get 'raw' get 'raw'
get 'download'
end 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 PrecalculateTrendingProjects < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
create_table :trending_projects do |t|
t.references :project, index: true, foreign_key: { on_delete: :cascade }, null: false
end
timestamp = connection.quote(1.month.ago)
# We're hardcoding the visibility level (public) here so that if it ever
# changes this query doesn't suddenly use the new value (which may break
# later migrations).
visibility = 20
execute <<-EOF.strip_heredoc
INSERT INTO trending_projects (project_id)
SELECT project_id
FROM notes
INNER JOIN projects ON projects.id = notes.project_id
WHERE notes.created_at >= #{timestamp}
AND notes.system IS FALSE
AND projects.visibility_level = #{visibility}
GROUP BY project_id
ORDER BY count(*) DESC
LIMIT 100;
EOF
end
def down
drop_table :trending_projects
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# 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: 20160926145521) do ActiveRecord::Schema.define(version: 20161007133303) 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"
...@@ -1033,7 +1033,7 @@ ActiveRecord::Schema.define(version: 20160926145521) do ...@@ -1033,7 +1033,7 @@ ActiveRecord::Schema.define(version: 20160926145521) do
create_table "protected_branch_merge_access_levels", force: :cascade do |t| create_table "protected_branch_merge_access_levels", force: :cascade do |t|
t.integer "protected_branch_id", null: false t.integer "protected_branch_id", null: false
t.integer "access_level", default: 40 t.integer "access_level", default: 40, null: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.integer "user_id" t.integer "user_id"
...@@ -1044,7 +1044,7 @@ ActiveRecord::Schema.define(version: 20160926145521) do ...@@ -1044,7 +1044,7 @@ ActiveRecord::Schema.define(version: 20160926145521) do
create_table "protected_branch_push_access_levels", force: :cascade do |t| create_table "protected_branch_push_access_levels", force: :cascade do |t|
t.integer "protected_branch_id", null: false t.integer "protected_branch_id", null: false
t.integer "access_level", default: 40 t.integer "access_level", default: 40, null: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.integer "user_id" t.integer "user_id"
...@@ -1234,6 +1234,12 @@ ActiveRecord::Schema.define(version: 20160926145521) do ...@@ -1234,6 +1234,12 @@ ActiveRecord::Schema.define(version: 20160926145521) do
add_index "todos", ["target_type", "target_id"], name: "index_todos_on_target_type_and_target_id", using: :btree add_index "todos", ["target_type", "target_id"], name: "index_todos_on_target_type_and_target_id", using: :btree
add_index "todos", ["user_id"], name: "index_todos_on_user_id", using: :btree add_index "todos", ["user_id"], name: "index_todos_on_user_id", using: :btree
create_table "trending_projects", force: :cascade do |t|
t.integer "project_id", null: false
end
add_index "trending_projects", ["project_id"], name: "index_trending_projects_on_project_id", using: :btree
create_table "u2f_registrations", force: :cascade do |t| create_table "u2f_registrations", force: :cascade do |t|
t.text "certificate" t.text "certificate"
t.string "key_handle" t.string "key_handle"
...@@ -1384,5 +1390,6 @@ ActiveRecord::Schema.define(version: 20160926145521) do ...@@ -1384,5 +1390,6 @@ ActiveRecord::Schema.define(version: 20160926145521) do
add_foreign_key "protected_branch_push_access_levels", "protected_branches" add_foreign_key "protected_branch_push_access_levels", "protected_branches"
add_foreign_key "protected_branch_push_access_levels", "users" add_foreign_key "protected_branch_push_access_levels", "users"
add_foreign_key "remote_mirrors", "projects" add_foreign_key "remote_mirrors", "projects"
add_foreign_key "trending_projects", "projects", on_delete: :cascade
add_foreign_key "u2f_registrations", "users" add_foreign_key "u2f_registrations", "users"
end end
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
- [Webhooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project. - [Webhooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
- [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN. - [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN.
- [University](university/README.md) Learn Git and GitLab through videos and courses. - [University](university/README.md) Learn Git and GitLab through videos and courses.
- [Git Attributes](user/project/git_attributes.md) Managing Git attributes using a `.gitattributes` file.
## Administrator documentation ## Administrator documentation
......
...@@ -356,6 +356,19 @@ follows: ...@@ -356,6 +356,19 @@ follows:
} }
``` ```
## Unknown route
When you try to access an API URL that does not exist you will receive 404 Not Found.
```
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "404 Not Found"
}
```
## Clients ## Clients
There are many unofficial GitLab API Clients for most of the popular There are many unofficial GitLab API Clients for most of the popular
......
...@@ -437,7 +437,7 @@ Parameters: ...@@ -437,7 +437,7 @@ Parameters:
### Get project events ### Get project events
Get the events for the specified project. Get the events for the specified project.
Sorted from newest to latest Sorted from newest to oldest
``` ```
GET /projects/:id/events GET /projects/:id/events
......
...@@ -629,3 +629,149 @@ Parameters: ...@@ -629,3 +629,149 @@ Parameters:
Will return `200 OK` on success, `404 User Not Found` is user cannot be found or Will return `200 OK` on success, `404 User Not Found` is user cannot be found or
`403 Forbidden` when trying to unblock a user blocked by LDAP synchronization. `403 Forbidden` when trying to unblock a user blocked by LDAP synchronization.
### Get user contribution events
Get the contribution events for the specified user, sorted from newest to oldest.
```
GET /users/:id/events
```
Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of the user |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/user/:id/events
```
Example response:
```json
[
{
"title": null,
"project_id": 15,
"action_name": "closed",
"target_id": 830,
"target_type": "Issue",
"author_id": 1,
"data": null,
"target_title": "Public project search field",
"author": {
"name": "Dmitriy Zaporozhets",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png",
"web_url": "http://localhost:3000/u/root"
},
"author_username": "root"
},
{
"title": null,
"project_id": 15,
"action_name": "opened",
"target_id": null,
"target_type": null,
"author_id": 1,
"author": {
"name": "Dmitriy Zaporozhets",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png",
"web_url": "http://localhost:3000/u/root"
},
"author_username": "john",
"data": {
"before": "50d4420237a9de7be1304607147aec22e4a14af7",
"after": "c5feabde2d8cd023215af4d2ceeb7a64839fc428",
"ref": "refs/heads/master",
"user_id": 1,
"user_name": "Dmitriy Zaporozhets",
"repository": {
"name": "gitlabhq",
"url": "git@dev.gitlab.org:gitlab/gitlabhq.git",
"description": "GitLab: self hosted Git management software. \r\nDistributed under the MIT License.",
"homepage": "https://dev.gitlab.org/gitlab/gitlabhq"
},
"commits": [
{
"id": "c5feabde2d8cd023215af4d2ceeb7a64839fc428",
"message": "Add simple search to projects in public area",
"timestamp": "2013-05-13T18:18:08+00:00",
"url": "https://dev.gitlab.org/gitlab/gitlabhq/commit/c5feabde2d8cd023215af4d2ceeb7a64839fc428",
"author": {
"name": "Dmitriy Zaporozhets",
"email": "dmitriy.zaporozhets@gmail.com"
}
}
],
"total_commits_count": 1
},
"target_title": null
},
{
"title": null,
"project_id": 15,
"action_name": "closed",
"target_id": 840,
"target_type": "Issue",
"author_id": 1,
"data": null,
"target_title": "Finish & merge Code search PR",
"author": {
"name": "Dmitriy Zaporozhets",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png",
"web_url": "http://localhost:3000/u/root"
},
"author_username": "root"
},
{
"title": null,
"project_id": 15,
"action_name": "commented on",
"target_id": 1312,
"target_type": "Note",
"author_id": 1,
"data": null,
"target_title": null,
"created_at": "2015-12-04T10:33:58.089Z",
"note": {
"id": 1312,
"body": "What an awesome day!",
"attachment": null,
"author": {
"name": "Dmitriy Zaporozhets",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png",
"web_url": "http://localhost:3000/u/root"
},
"created_at": "2015-12-04T10:33:56.698Z",
"system": false,
"upvote": false,
"downvote": false,
"noteable_id": 377,
"noteable_type": "Issue"
},
"author": {
"name": "Dmitriy Zaporozhets",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png",
"web_url": "http://localhost:3000/u/root"
},
"author_username": "root"
}
]
```
...@@ -11,6 +11,7 @@ Apart from those, here is an collection of tutorials and guides on setting up yo ...@@ -11,6 +11,7 @@ Apart from those, here is an collection of tutorials and guides on setting up yo
- [Test and deploy a Python application to Heroku](test-and-deploy-python-application-to-heroku.md) - [Test and deploy a Python application to Heroku](test-and-deploy-python-application-to-heroku.md)
- [Test a Clojure application](test-clojure-application.md) - [Test a Clojure application](test-clojure-application.md)
- [Test a Scala application](test-scala-application.md) - [Test a Scala application](test-scala-application.md)
- [Test a Phoenix application](test-phoenix-application.md)
- [Using `dpl` as deployment tool](deployment/README.md) - [Using `dpl` as deployment tool](deployment/README.md)
- [Blog post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) - [Blog post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/)
- [Repositories with examples for various languages](https://gitlab.com/groups/gitlab-examples) - [Repositories with examples for various languages](https://gitlab.com/groups/gitlab-examples)
......
## Test a Phoenix application
This example demonstrates the integration of Gitlab CI with Phoenix, Elixir and
Postgres.
### Add `.gitlab-ci.yml` file to project
The following `.gitlab-ci.yml` should be added in the root of your
repository to trigger CI:
```yaml
image: elixir:1.3
services:
- postgres:9.6
variables:
MIX_ENV: "test"
before_script:
# Setup phoenix dependencies
- apt-get update
- apt-get install -y postgresql-client
- mix local.hex --force
- mix deps.get --only test
- mix ecto.reset
test:
script:
- mix test
```
The variables will set the Mix environment to "test". The
`before_script` will install `psql`, some Phoenix dependencies, and will also
run your migrations.
Finally, the test `script` will run your tests.
### Update the Config Settings
In `config/test.exs`, update the database hostname:
```elixir
config :my_app, MyApp.Repo,
hostname: if(System.get_env("CI"), do: "postgres", else: "localhost"),
```
### Add the Migrations Folder
If you do not have any migrations yet, you will need to create an empty
`.gitkeep` file in `priv/repo/migrations`.
### Sources
- https://medium.com/@nahtnam/using-phoenix-on-gitlab-ci-5a51eec81142
- https://davejlong.com/ci-with-phoenix-and-gitlab/
...@@ -31,6 +31,8 @@ project. ...@@ -31,6 +31,8 @@ project.
## Seeing build status ## Seeing build status
Clicking on a pipeline will show the builds that were run for that pipeline. Clicking on a pipeline will show the builds that were run for that pipeline.
Clicking on an individual build will show you its build trace, and allow you to
cancel the build, retry it, or erase the build trace.
## Badges ## Badges
......
...@@ -48,6 +48,7 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`. ...@@ -48,6 +48,7 @@ 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 |
| **CI_DEBUG_TRACE** | all | 1.7 | Whether [debug tracing](#debug-tracing) is enabled |
| **GITLAB_USER_ID** | 8.12 | all | The id of the user who started the build | | **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 | | **GITLAB_USER_EMAIL** | 8.12 | all | The email of the user who started the build |
...@@ -105,6 +106,39 @@ Variables can be defined at a global level, but also at a job level. ...@@ -105,6 +106,39 @@ Variables can be defined at a global level, but also at a job level.
More information about Docker integration can be found in [Using Docker Images](../docker/using_docker_images.md). More information about Docker integration can be found in [Using Docker Images](../docker/using_docker_images.md).
#### Debug tracing
> **WARNING:** Enabling debug tracing can have severe security implications. The
output **will** contain the content of all your secure variables and any other
secrets! The output **will** be uploaded to the GitLab server and made visible
in build traces!
By default, GitLab Runner hides most of the details of what it is doing when
processing a job. This behaviour keeps build traces short, and prevents secrets
from being leaked into the trace unless your script writes them to the screen.
If a job isn't working as expected, this can make the problem difficult to
investigate; in these cases, you can enable debug tracing in `.gitlab-ci.yml`.
Available on GitLab Runner v1.7+, this feature enables the shell's execution
trace, resulting in a verbose build trace listing all commands that were run,
variables that were set, etc.
Before enabling this, you should ensure builds are visible to
[team members only](../../../user/permissions.md#project-features). You should
also [erase](../pipelines.md#seeing-build-traces) all generated build traces
before making them visible again.
To enable debug traces, set the `CI_DEBUG_TRACE` variable to `true`:
```yaml
job1:
variables:
CI_DEBUG_TRACE: "true"
```
The [example project](https://gitlab.com/gitlab-examples/ci-debug-trace)
demonstrates a working configuration, including build trace examples.
### User-defined variables (Secure Variables) ### User-defined variables (Secure Variables)
**This feature requires GitLab Runner 0.4.0 or higher** **This feature requires GitLab Runner 0.4.0 or higher**
......
...@@ -314,6 +314,29 @@ In this case: ...@@ -314,6 +314,29 @@ In this case:
- different highlighting languages are used for each config in the code block - different highlighting languages are used for each config in the code block
- the [references](#references) guide is used for reconfigure/restart - the [references](#references) guide is used for reconfigure/restart
## Fake tokens
There may be times where a token is needed to demonstrate an API call using
cURL or a secret variable used in CI. It is strongly advised not to use real
tokens in documentation even if the probability of a token being exploited is
low.
You can use the following fake tokens as examples.
| **Token type** | **Token value** |
| --------------------- | --------------------------------- |
| Private user token | `9koXpg98eAheJpvBs5tK` |
| Personal access token | `n671WNGecHugsdEDPsyo` |
| Application ID | `2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6` |
| Application secret | `04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df` |
| Secret CI variable | `Li8j-mLUVA3eZYjPfd_H` |
| Specific Runner token | `yrnZW46BrtBFqM7xDzE7dddd` |
| Shared Runner token | `6Vk7ZsosqQyfreAxXTZr` |
| Trigger token | `be20d8dcc028677c931e04f3871a9b` |
| Webhook secret token | `6XhDroRcYPM5by_h-HLY` |
| Health check token | `Tu7BgjR9qeZTEyRzGG2P` |
| Request profile token | `7VgpS4Ax5utVD2esNstz` |
## API ## API
Here is a list of must-have items. Use them in the exact order that appears Here is a list of must-have items. Use them in the exact order that appears
......
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
Step-by-step guides on the basics of working with Git and GitLab. Step-by-step guides on the basics of working with Git and GitLab.
- [Command line basics](command-line-commands.md)
- [Start using Git on the command line](start-using-git.md) - [Start using Git on the command line](start-using-git.md)
- [Create and add your SSH Keys](create-your-ssh-keys.md) - [Create and add your SSH Keys](create-your-ssh-keys.md)
- [Command Line basics](command-line-commands.md)
- [Create a project](create-project.md) - [Create a project](create-project.md)
- [Create a group](create-group.md) - [Create a group](create-group.md)
- [Create a branch](create-branch.md) - [Create a branch](create-branch.md)
- [Fork a project](fork-project.md) - [Fork a project](fork-project.md)
- [Add a file](add-file.md) - [Add a file](add-file.md)
- [Add an image](add-image.md) - [Add an image](add-image.md)
- [Create a Merge Request](add-merge-request.md) - [Create an issue](create-issue.md)
- [Create an Issue](create-issue.md) - [Create a merge request](add-merge-request.md)
# How to add a file # How to add a file
You can create a file in your [shell](command-line-commands.md) or in GitLab. You can create a file in your [terminal](command-line-commands.md) and push
to GitLab or you can use the
To create a file in GitLab, sign in to GitLab. [web interface](../user/project/repository/web_editor.md#create-a-file).
Select a project on the right side of your screen:
![Select a project](basicsimages/select_project.png)
It's a good idea to [create a branch](create-branch.md), but it's not necessary.
Go to the directory where you'd like to add the file and click on the "+" sign next to the name of the project and directory:
![Create a file](basicsimages/create_file.png)
Name your file (you can't add spaces, so you can use hyphens or underscores). Don't forget to include the markup language you'd like to use :
![File name](basicsimages/file_name.png)
Add all the information that you'd like to include in your file:
![Add information](basicsimages/white_space.png)
Add a commit message based on what you just added and then click on "commit changes":
![Commit changes](basicsimages/commit_changes.png)
# How to create a merge request # How to create a merge request
Merge Requests are useful to integrate separate changes that you've made to a project, on different branches. Merge requests are useful to integrate separate changes that you've made to a
project, on different branches. This is a brief guide on how to create a merge
request. For more information, check the
[merge requests documentation](../user/project/merge_requests.md).
To create a new Merge Request, sign in to GitLab. ---
Go to the project where you'd like to merge your changes: 1. Before you start, you should have already [created a branch](create-branch.md)
and [pushed your changes](basic-git-commands.md) to GitLab.
![Select a project](basicsimages/select_project.png) 1. You can then go to the project where you'd like to merge your changes and
click on the **Merge requests** tab.
Click on "Merge Requests" on the left side of your screen: ![Merge requests](img/project_navbar.png)
![Merge requests](basicsimages/merge_requests.png) 1. Click on **New merge request** on the right side of the screen.
Click on "+ new Merge Request" on the right side of the screen: ![New Merge Request](img/merge_request_new.png)
![New Merge Request](basicsimages/new_merge_request.png) 1. Select a source branch and click on the **Compare branches and continue** button.
Select a source branch or branch: ![Select a branch](img/merge_request_select_branch.png)
![Select a branch](basicsimages/select_branch.png) 1. At a minimum, add a title and a description to your merge request. Optionally,
select a user to review your merge request and to accept or close it. You may
also select a milestone and labels.
Click on the "compare branches" button: ![New merge request page](img/merge_request_page.png)
![Compare branches](basicsimages/compare_branches.png) 1. When ready, click on the **Submit merge request** button. Your merge request
will be ready to be approved and published.
Add a title and a description to your Merge Request:
![Add a title and description](basicsimages/title_description_mr.png)
Select a user to review your Merge Request and to accept or close it. You may also select milestones and labels (they are optional). Then click on the "submit new Merge Request" button:
![Add a new merge request](basicsimages/add_new_merge_request.png)
Your Merge Request will be ready to be approved and published.
### Note
After you created a new branch, you'll immediately find a "create a Merge Request" button at the top of your screen.
You may automatically create a Merge Request from your recently created branch when clicking on this button:
![Automatic MR button](basicsimages/button-create-mr.png)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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