Commit 7e5ac711 authored by Mike Greiling's avatar Mike Greiling

Merge branch 'master' into '36133-project-overview-page-doesn-t-load-commit-metadata-for-repo-view'

# Conflicts:
#   app/assets/javascripts/dispatcher.js
parents 3d08e472 2925850c
...@@ -514,8 +514,11 @@ codeclimate: ...@@ -514,8 +514,11 @@ codeclimate:
services: services:
- docker:dind - docker:dind
script: script:
- cp .rubocop.yml .rubocop.yml.bak
- grep -v "rubocop-gitlab-security" .rubocop.yml.bak > .rubocop.yml
- docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > raw_codeclimate.json - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > raw_codeclimate.json
- cat raw_codeclimate.json | docker run -i stedolan/jq -c 'map({check_name,fingerprint,location})' > codeclimate.json - cat raw_codeclimate.json | docker run -i stedolan/jq -c 'map({check_name,fingerprint,location})' > codeclimate.json
- mv .rubocop.yml.bak .rubocop.yml
artifacts: artifacts:
paths: [codeclimate.json] paths: [codeclimate.json]
......
require: require:
- rubocop-rspec - rubocop-rspec
- rubocop-gitlab-security
- ./rubocop/rubocop - ./rubocop/rubocop
inherit_from: .rubocop_todo.yml inherit_from: .rubocop_todo.yml
...@@ -206,6 +207,13 @@ Layout/SpaceAroundKeyword: ...@@ -206,6 +207,13 @@ Layout/SpaceAroundKeyword:
Layout/SpaceAroundOperators: Layout/SpaceAroundOperators:
Enabled: true Enabled: true
# Checks that block braces have or don't have a space before the opening
# brace depending on configuration.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: space, no_space
Layout/SpaceBeforeBlockBraces:
Enabled: true
# No spaces before commas. # No spaces before commas.
Layout/SpaceBeforeComma: Layout/SpaceBeforeComma:
Enabled: true Enabled: true
...@@ -1156,3 +1164,35 @@ RSpec/SubjectStub: ...@@ -1156,3 +1164,35 @@ RSpec/SubjectStub:
# Prefer using verifying doubles over normal doubles. # Prefer using verifying doubles over normal doubles.
RSpec/VerifiedDoubles: RSpec/VerifiedDoubles:
Enabled: false Enabled: false
# GitlabSecurity ##############################################################
GitlabSecurity/DeepMunge:
Enabled: true
Exclude:
- 'spec/**/*'
- 'lib/**/*.rake'
GitlabSecurity/PublicSend:
Enabled: true
Exclude:
- 'spec/**/*'
- 'lib/**/*.rake'
GitlabSecurity/RedirectToParamsUpdate:
Enabled: true
Exclude:
- 'spec/**/*'
- 'lib/**/*.rake'
GitlabSecurity/SqlInjection:
Enabled: true
Exclude:
- 'spec/**/*'
- 'lib/**/*.rake'
GitlabSecurity/SystemCommandInjection:
Enabled: true
Exclude:
- 'spec/**/*'
- 'lib/**/*.rake'
...@@ -26,13 +26,6 @@ Layout/IndentArray: ...@@ -26,13 +26,6 @@ Layout/IndentArray:
Layout/IndentHash: Layout/IndentHash:
Enabled: false Enabled: false
# Offense count: 174
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: space, no_space
Layout/SpaceBeforeBlockBraces:
Enabled: false
# Offense count: 8 # Offense count: 8
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment. # Configuration parameters: AllowForAlignment.
......
...@@ -341,6 +341,7 @@ group :development, :test do ...@@ -341,6 +341,7 @@ group :development, :test do
gem 'rubocop', '~> 0.49.1', require: false gem 'rubocop', '~> 0.49.1', require: false
gem 'rubocop-rspec', '~> 1.15.1', require: false gem 'rubocop-rspec', '~> 1.15.1', require: false
gem 'rubocop-gitlab-security', '~> 0.0.6', require: false
gem 'scss_lint', '~> 0.54.0', require: false gem 'scss_lint', '~> 0.54.0', require: false
gem 'haml_lint', '~> 0.26.0', require: false gem 'haml_lint', '~> 0.26.0', require: false
gem 'simplecov', '~> 0.14.0', require: false gem 'simplecov', '~> 0.14.0', require: false
...@@ -354,7 +355,7 @@ group :development, :test do ...@@ -354,7 +355,7 @@ group :development, :test do
gem 'activerecord_sane_schema_dumper', '0.2' gem 'activerecord_sane_schema_dumper', '0.2'
gem 'stackprof', '~> 0.2.10' gem 'stackprof', '~> 0.2.10', require: false
end end
group :test do group :test do
......
...@@ -548,7 +548,7 @@ GEM ...@@ -548,7 +548,7 @@ GEM
rubypants (~> 0.2) rubypants (~> 0.2)
orm_adapter (0.5.0) orm_adapter (0.5.0)
os (0.9.6) os (0.9.6)
parallel (1.11.2) parallel (1.12.0)
paranoia (2.3.1) paranoia (2.3.1)
activerecord (>= 4.0, < 5.2) activerecord (>= 4.0, < 5.2)
parser (2.4.0.0) parser (2.4.0.0)
...@@ -741,8 +741,9 @@ GEM ...@@ -741,8 +741,9 @@ GEM
rainbow (>= 1.99.1, < 3.0) rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1) unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-gitlab-security (0.0.6)
rubocop (>= 0.47.1)
rubocop-rspec (1.15.1) rubocop-rspec (1.15.1)
rubocop (>= 0.42.0)
ruby-fogbugz (0.2.1) ruby-fogbugz (0.2.1)
crack (~> 0.4) crack (~> 0.4)
ruby-prof (0.16.2) ruby-prof (0.16.2)
...@@ -1088,6 +1089,7 @@ DEPENDENCIES ...@@ -1088,6 +1089,7 @@ DEPENDENCIES
rspec-set (~> 0.1.3) rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5) rspec_profiling (~> 0.0.5)
rubocop (~> 0.49.1) rubocop (~> 0.49.1)
rubocop-gitlab-security (~> 0.0.6)
rubocop-rspec (~> 1.15.1) rubocop-rspec (~> 1.15.1)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.16.2) ruby-prof (~> 0.16.2)
......
...@@ -119,6 +119,12 @@ only be left until after the freeze if: ...@@ -119,6 +119,12 @@ only be left until after the freeze if:
are aware of it. are aware of it.
* It is in the correct milestone, with the ~Deliverable label. * It is in the correct milestone, with the ~Deliverable label.
If a merge request is not ready, but the developers and Product Manager
responsible for the feature think it is essential that it is in the release,
they can [ask for an exception](#asking-for-an-exception) in advance. This is
preferable to merging something that we are not confident in, but should still
be a rare case: most features can be allowed to slip a release.
All Community Edition merge requests from GitLab team members merged on the All Community Edition merge requests from GitLab team members merged on the
freeze date (the 7th) should have a corresponding Enterprise Edition merge freeze date (the 7th) should have a corresponding Enterprise Edition merge
request, even if there are no conflicts. This is to reduce the size of the request, even if there are no conflicts. This is to reduce the size of the
...@@ -128,11 +134,26 @@ information, see ...@@ -128,11 +134,26 @@ information, see
### After the 7th ### After the 7th
Once the stable branch is frozen, only fixes for [regressions](#regressions) Once the stable branch is frozen, the only MRs that can be cherry-picked into
and security issues will be cherry-picked into the stable branch. the stable branch are:
Any merge requests cherry-picked into the stable branch for a previous release will also be picked into the latest stable branch.
These fixes will be shipped in the next RC for that release if it is before the 22nd. * Fixes for [regressions](#regressions)
If the fixes are are completed on or after the 22nd, they will be shipped in a patch for that release. * Fixes for security issues
* New or updated translations (as long as they do not touch application code)
Any merge requests cherry-picked into the stable branch for a previous release
will also be picked into the latest stable branch. These fixes will be shipped
in the next RC for that release if it is before the 22nd. If the fixes are are
completed on or after the 22nd, they will be shipped in a patch for that
release.
During the feature freeze all merge requests that are meant to go into the upcoming
release should have the correct milestone assigned _and_ have the label
~"Pick into Stable" set, so that release managers can find and pick them.
Merge requests without a milestone and this label will
not be merged into any stable branches.
### Asking for an exception
If you think a merge request should go into an RC or patch even though it does not meet these requirements, If you think a merge request should go into an RC or patch even though it does not meet these requirements,
you can ask for an exception to be made. Exceptions require sign-off from 3 people besides the developer: you can ask for an exception to be made. Exceptions require sign-off from 3 people besides the developer:
...@@ -152,11 +173,7 @@ When in doubt, we err on the side of _not_ cherry-picking. ...@@ -152,11 +173,7 @@ When in doubt, we err on the side of _not_ cherry-picking.
For example, it is likely that an exception will be made for a trivial 1-5 line performance improvement For example, it is likely that an exception will be made for a trivial 1-5 line performance improvement
(e.g. adding a database index or adding `includes` to a query), but not for a new feature, no matter how relatively small or thoroughly tested. (e.g. adding a database index or adding `includes` to a query), but not for a new feature, no matter how relatively small or thoroughly tested.
During the feature freeze all merge requests that are meant to go into the upcoming All MRs which have had exceptions granted must be merged by the 15th.
release should have the correct milestone assigned _and_ have the label
~"Pick into Stable" set, so that release managers can find and pick them.
Merge requests without a milestone and this label will
not be merged into any stable branches.
### Regressions ### Regressions
......
/* eslint-disable func-names, object-shorthand, prefer-arrow-callback */ /* eslint-disable func-names, object-shorthand, prefer-arrow-callback */
/* global Dropzone */ /* global Dropzone */
import '../lib/utils/url_utility';
import { HIDDEN_CLASS } from '../lib/utils/constants';
function toggleLoading($el, $icon, loading) {
if (loading) {
$el.disable();
$icon.removeClass(HIDDEN_CLASS);
} else {
$el.enable();
$icon.addClass(HIDDEN_CLASS);
}
}
export default class BlobFileDropzone { export default class BlobFileDropzone {
constructor(form, method) { constructor(form, method) {
const formDropzone = form.find('.dropzone'); const formDropzone = form.find('.dropzone');
const submitButton = form.find('#submit-all');
const submitButtonLoadingIcon = submitButton.find('.js-loading-icon');
const dropzoneMessage = form.find('.dz-message');
Dropzone.autoDiscover = false; Dropzone.autoDiscover = false;
const dropzone = formDropzone.dropzone({ const dropzone = formDropzone.dropzone({
...@@ -26,12 +41,20 @@ export default class BlobFileDropzone { ...@@ -26,12 +41,20 @@ export default class BlobFileDropzone {
}, },
init: function () { init: function () {
this.on('addedfile', function () { this.on('addedfile', function () {
toggleLoading(submitButton, submitButtonLoadingIcon, false);
dropzoneMessage.addClass(HIDDEN_CLASS);
$('.dropzone-alerts').html('').hide(); $('.dropzone-alerts').html('').hide();
}); });
this.on('removedfile', function () {
toggleLoading(submitButton, submitButtonLoadingIcon, false);
dropzoneMessage.removeClass(HIDDEN_CLASS);
});
this.on('success', function (header, response) { this.on('success', function (header, response) {
window.location.href = response.filePath; $('#modal-upload-blob').modal('hide');
window.gl.utils.visitUrl(response.filePath);
}); });
this.on('maxfilesexceeded', function (file) { this.on('maxfilesexceeded', function (file) {
dropzoneMessage.addClass(HIDDEN_CLASS);
this.removeFile(file); this.removeFile(file);
}); });
this.on('sending', function (file, xhr, formData) { this.on('sending', function (file, xhr, formData) {
...@@ -48,14 +71,15 @@ export default class BlobFileDropzone { ...@@ -48,14 +71,15 @@ export default class BlobFileDropzone {
}, },
}); });
const submitButton = form.find('#submit-all')[0]; submitButton.on('click', (e) => {
submitButton.addEventListener('click', function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
if (dropzone[0].dropzone.getQueuedFiles().length === 0) { if (dropzone[0].dropzone.getQueuedFiles().length === 0) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
alert('Please select a file'); alert('Please select a file');
return false;
} }
toggleLoading(submitButton, submitButtonLoadingIcon, true);
dropzone[0].dropzone.processQueue(); dropzone[0].dropzone.processQueue();
return false; return false;
}); });
......
...@@ -343,6 +343,7 @@ import UserFeatureHelper from './helpers/user_feature_helper'; ...@@ -343,6 +343,7 @@ import UserFeatureHelper from './helpers/user_feature_helper';
if ($('#tree-slider').length) new TreeView(); if ($('#tree-slider').length) new TreeView();
if ($('.blob-viewer').length) new BlobViewer(); if ($('.blob-viewer').length) new BlobViewer();
if ($('.project-show-activity').length) new gl.Activities();
$('#tree-slider').waitForImages(function() { $('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath); gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
}); });
......
/* eslint-disable wrap-iife, func-names, space-before-function-paren, comma-dangle, prefer-template, consistent-return, class-methods-use-this, arrow-body-style, no-unused-vars, no-underscore-dangle, no-new, max-len, no-sequences, no-unused-expressions, no-param-reassign */ /* eslint-disable wrap-iife, func-names, space-before-function-paren, comma-dangle, prefer-template, consistent-return, class-methods-use-this, arrow-body-style, no-unused-vars, no-underscore-dangle, no-new, max-len, no-sequences, no-unused-expressions, no-param-reassign */
/* global dateFormat */ /* global dateFormat */
/* global Pikaday */
import Pikaday from 'pikaday';
import DateFix from './lib/utils/datefix'; import DateFix from './lib/utils/datefix';
class DueDateSelect { class DueDateSelect {
......
/* global bp */ /* global bp */
import Cookies from 'js-cookie';
import './breakpoints'; import './breakpoints';
export const canShowSubItems = () => bp.getBreakpointSize() === 'md' || bp.getBreakpointSize() === 'lg'; export const canShowActiveSubItems = (el) => {
const isHiddenByMedia = bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md';
if (el.classList.contains('active') && !isHiddenByMedia) {
return Cookies.get('sidebar_collapsed') === 'true';
}
return true;
};
export const canShowSubItems = () => bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md' || bp.getBreakpointSize() === 'lg';
export const calculateTop = (boundingRect, outerHeight) => { export const calculateTop = (boundingRect, outerHeight) => {
const windowHeight = window.innerHeight; const windowHeight = window.innerHeight;
...@@ -14,9 +24,10 @@ export const calculateTop = (boundingRect, outerHeight) => { ...@@ -14,9 +24,10 @@ export const calculateTop = (boundingRect, outerHeight) => {
export const showSubLevelItems = (el) => { export const showSubLevelItems = (el) => {
const subItems = el.querySelector('.sidebar-sub-level-items'); const subItems = el.querySelector('.sidebar-sub-level-items');
if (!subItems || !canShowSubItems()) return; if (!subItems || !canShowSubItems() || !canShowActiveSubItems(el)) return;
subItems.style.display = 'block'; subItems.style.display = 'block';
el.classList.add('is-showing-fly-out');
el.classList.add('is-over'); el.classList.add('is-over');
const boundingRect = el.getBoundingClientRect(); const boundingRect = el.getBoundingClientRect();
...@@ -34,15 +45,16 @@ export const showSubLevelItems = (el) => { ...@@ -34,15 +45,16 @@ export const showSubLevelItems = (el) => {
export const hideSubLevelItems = (el) => { export const hideSubLevelItems = (el) => {
const subItems = el.querySelector('.sidebar-sub-level-items'); const subItems = el.querySelector('.sidebar-sub-level-items');
if (!subItems || !canShowSubItems()) return; if (!subItems || !canShowSubItems() || !canShowActiveSubItems(el)) return;
el.classList.remove('is-showing-fly-out');
el.classList.remove('is-over'); el.classList.remove('is-over');
subItems.style.display = 'none'; subItems.style.display = 'none';
subItems.classList.remove('is-above'); subItems.classList.remove('is-above');
}; };
export default () => { export default () => {
const items = [...document.querySelectorAll('.sidebar-top-level-items > li:not(.active)')] const items = [...document.querySelectorAll('.sidebar-top-level-items > li')]
.filter(el => el.querySelector('.sidebar-sub-level-items')); .filter(el => el.querySelector('.sidebar-sub-level-items'));
items.forEach((el) => { items.forEach((el) => {
......
import Chart from 'vendor/Chart'; import Chart from 'vendor/Chart';
import _ from 'underscore';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const projectChartData = JSON.parse(document.getElementById('projectChartData').innerHTML); const projectChartData = JSON.parse(document.getElementById('projectChartData').innerHTML);
...@@ -27,28 +28,25 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -27,28 +28,25 @@ document.addEventListener('DOMContentLoaded', () => {
return generateChart(); return generateChart();
}; };
const chartData = (keys, values) => { const chartData = data => ({
const data = { labels: Object.keys(data),
labels: keys, datasets: [{
datasets: [{ fillColor: 'rgba(220,220,220,0.5)',
fillColor: 'rgba(220,220,220,0.5)', strokeColor: 'rgba(220,220,220,1)',
strokeColor: 'rgba(220,220,220,1)', barStrokeWidth: 1,
barStrokeWidth: 1, barValueSpacing: 1,
barValueSpacing: 1, barDatasetSpacing: 1,
barDatasetSpacing: 1, data: _.values(data),
data: values, }],
}], });
};
return data; const hourData = chartData(projectChartData.hour);
};
const hourData = chartData(projectChartData.hour.keys, projectChartData.hour.values);
responsiveChart($('#hour-chart'), hourData); responsiveChart($('#hour-chart'), hourData);
const dayData = chartData(projectChartData.weekDays.keys, projectChartData.weekDays.values); const dayData = chartData(projectChartData.weekDays);
responsiveChart($('#weekday-chart'), dayData); responsiveChart($('#weekday-chart'), dayData);
const monthData = chartData(projectChartData.month.keys, projectChartData.month.values); const monthData = chartData(projectChartData.month);
responsiveChart($('#month-chart'), monthData); responsiveChart($('#month-chart'), monthData);
const data = projectChartData.languages; const data = projectChartData.languages;
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
/* global GitLab */ /* global GitLab */
/* global Autosave */ /* global Autosave */
/* global dateFormat */ /* global dateFormat */
/* global Pikaday */
import Pikaday from 'pikaday';
import UsersSelect from './users_select'; import UsersSelect from './users_select';
import GfmAutoComplete from './gfm_auto_complete'; import GfmAutoComplete from './gfm_auto_complete';
import ZenMode from './zen_mode'; import ZenMode from './zen_mode';
......
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
export const BYTES_IN_KIB = 1024; export const BYTES_IN_KIB = 1024;
export const HIDDEN_CLASS = 'hidden';
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
import jQuery from 'jquery'; import jQuery from 'jquery';
import _ from 'underscore'; import _ from 'underscore';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import Pikaday from 'pikaday';
import Dropzone from 'dropzone'; import Dropzone from 'dropzone';
import Sortable from 'vendor/Sortable'; import Sortable from 'vendor/Sortable';
...@@ -20,7 +19,6 @@ import 'vendor/fuzzaldrin-plus'; ...@@ -20,7 +19,6 @@ import 'vendor/fuzzaldrin-plus';
window.jQuery = jQuery; window.jQuery = jQuery;
window.$ = jQuery; window.$ = jQuery;
window._ = _; window._ = _;
window.Pikaday = Pikaday;
window.Dropzone = Dropzone; window.Dropzone = Dropzone;
window.Sortable = Sortable; window.Sortable = Sortable;
......
/* global Pikaday */
/* global dateFormat */ /* global dateFormat */
import Pikaday from 'pikaday';
(() => { (() => {
// Add datepickers to all `js-access-expiration-date` elements. If those elements are // Add datepickers to all `js-access-expiration-date` elements. If those elements are
// children of an element with the `clearable-input` class, and have a sibling // children of an element with the `clearable-input` class, and have a sibling
......
...@@ -372,6 +372,10 @@ table { ...@@ -372,6 +372,10 @@ table {
background: $gl-success !important; background: $gl-success !important;
} }
.dz-message {
margin: 0;
}
.space-right { .space-right {
margin-right: 10px; margin-right: 10px;
} }
......
...@@ -26,7 +26,7 @@ header { ...@@ -26,7 +26,7 @@ header {
&.navbar-gitlab { &.navbar-gitlab {
padding: 0 16px; padding: 0 16px;
z-index: 2000; z-index: 1000;
margin-bottom: 0; margin-bottom: 0;
min-height: $header-height; min-height: $header-height;
background-color: $gray-light; background-color: $gray-light;
......
...@@ -162,3 +162,5 @@ $pre-color: $gl-text-color !default; ...@@ -162,3 +162,5 @@ $pre-color: $gl-text-color !default;
$pre-border-color: $border-color; $pre-border-color: $border-color;
$table-bg-accent: $gray-light; $table-bg-accent: $gray-light;
$zindex-popover: 900;
...@@ -104,11 +104,14 @@ $new-sidebar-collapsed-width: 50px; ...@@ -104,11 +104,14 @@ $new-sidebar-collapsed-width: 50px;
&.sidebar-icons-only { &.sidebar-icons-only {
width: $new-sidebar-collapsed-width; width: $new-sidebar-collapsed-width;
.nav-item-name,
.badge, .badge,
.project-title { .project-title {
display: none; display: none;
} }
.nav-item-name {
opacity: 0;
}
} }
&.nav-sidebar-expanded { &.nav-sidebar-expanded {
...@@ -182,7 +185,7 @@ $new-sidebar-collapsed-width: 50px; ...@@ -182,7 +185,7 @@ $new-sidebar-collapsed-width: 50px;
> li { > li {
a { a {
padding: 8px 16px 8px 50px; padding: 8px 16px 8px 40px;
&:hover, &:hover,
&:focus { &:focus {
...@@ -215,12 +218,15 @@ $new-sidebar-collapsed-width: 50px; ...@@ -215,12 +218,15 @@ $new-sidebar-collapsed-width: 50px;
&:hover { &:hover {
color: $gl-text-color; color: $gl-text-color;
svg {
fill: $gl-text-color;
}
} }
} }
&:not(.active) { &.is-showing-fly-out {
> a { > a {
margin-left: 1px;
margin-right: 2px; margin-right: 2px;
} }
...@@ -229,7 +235,7 @@ $new-sidebar-collapsed-width: 50px; ...@@ -229,7 +235,7 @@ $new-sidebar-collapsed-width: 50px;
position: fixed; position: fixed;
top: 0; top: 0;
left: $new-sidebar-width; left: $new-sidebar-width;
width: 150px; min-width: 150px;
margin-top: -1px; margin-top: -1px;
padding: 8px 1px; padding: 8px 1px;
background-color: $white-light; background-color: $white-light;
...@@ -271,6 +277,14 @@ $new-sidebar-collapsed-width: 50px; ...@@ -271,6 +277,14 @@ $new-sidebar-collapsed-width: 50px;
} }
} }
> .active {
box-shadow: none;
> a {
background-color: transparent;
}
}
a { a {
padding: 8px 16px; padding: 8px 16px;
color: $gl-text-color; color: $gl-text-color;
...@@ -294,6 +308,7 @@ $new-sidebar-collapsed-width: 50px; ...@@ -294,6 +308,7 @@ $new-sidebar-collapsed-width: 50px;
> a { > a {
margin-left: 4px; margin-left: 4px;
padding-left: 12px;
} }
.badge { .badge {
...@@ -354,7 +369,7 @@ $new-sidebar-collapsed-width: 50px; ...@@ -354,7 +369,7 @@ $new-sidebar-collapsed-width: 50px;
.sidebar-icons-only { .sidebar-icons-only {
.context-header { .context-header {
height: 60px; height: 61px;
a { a {
padding: 10px 4px; padding: 10px 4px;
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
.commit-box, .commit-box,
.info-well, .info-well,
.commit-ci-menu, .commit-ci-menu,
.files-changed, .files-changed-inner,
.limited-header-width, .limited-header-width,
.limited-width-notes { .limited-width-notes {
@extend .fixed-width-container; @extend .fixed-width-container;
......
...@@ -216,6 +216,9 @@ ...@@ -216,6 +216,9 @@
} }
.blob-upload-dropzone-previews { .blob-upload-dropzone-previews {
display: flex;
justify-content: center;
align-items: center;
text-align: center; text-align: center;
border: 2px; border: 2px;
border-style: dashed; border-style: dashed;
......
...@@ -117,7 +117,7 @@ class ApplicationController < ActionController::Base ...@@ -117,7 +117,7 @@ class ApplicationController < ActionController::Base
Raven.capture_exception(exception) if sentry_enabled? Raven.capture_exception(exception) if sentry_enabled?
application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
application_trace.map!{ |t| " #{t}\n" } application_trace.map! { |t| " #{t}\n" }
logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}" logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
end end
......
...@@ -68,15 +68,15 @@ class Import::GithubController < Import::BaseController ...@@ -68,15 +68,15 @@ class Import::GithubController < Import::BaseController
end end
def new_import_url def new_import_url
public_send("new_import_#{provider}_url") public_send("new_import_#{provider}_url") # rubocop:disable GitlabSecurity/PublicSend
end end
def status_import_url def status_import_url
public_send("status_import_#{provider}_url") public_send("status_import_#{provider}_url") # rubocop:disable GitlabSecurity/PublicSend
end end
def callback_import_url def callback_import_url
public_send("callback_import_#{provider}_url") public_send("callback_import_#{provider}_url") # rubocop:disable GitlabSecurity/PublicSend
end end
def provider_unauthorized def provider_unauthorized
......
...@@ -15,7 +15,7 @@ class Import::GitlabController < Import::BaseController ...@@ -15,7 +15,7 @@ class Import::GitlabController < Import::BaseController
@already_added_projects = current_user.created_projects.where(import_type: "gitlab") @already_added_projects = current_user.created_projects.where(import_type: "gitlab")
already_added_projects_names = @already_added_projects.pluck(:import_source) already_added_projects_names = @already_added_projects.pluck(:import_source)
@repos = @repos.to_a.reject{ |repo| already_added_projects_names.include? repo["path_with_namespace"] } @repos = @repos.to_a.reject { |repo| already_added_projects_names.include? repo["path_with_namespace"] }
end end
def jobs def jobs
......
...@@ -3,7 +3,7 @@ module GraphHelper ...@@ -3,7 +3,7 @@ module GraphHelper
refs = "" refs = ""
# Commit::ref_names already strips the refs/XXX from important refs (e.g. refs/heads/XXX) # Commit::ref_names already strips the refs/XXX from important refs (e.g. refs/heads/XXX)
# so anything leftover is internally used by GitLab # so anything leftover is internally used by GitLab
commit_refs = commit.ref_names(repo).reject{ |name| name.starts_with?('refs/') } commit_refs = commit.ref_names(repo).reject { |name| name.starts_with?('refs/') }
refs << commit_refs.join(' ') refs << commit_refs.join(' ')
# append note count # append note count
......
...@@ -151,7 +151,7 @@ module IssuablesHelper ...@@ -151,7 +151,7 @@ module IssuablesHelper
end end
def issuable_labels_tooltip(labels, limit: 5) def issuable_labels_tooltip(labels, limit: 5)
first, last = labels.partition.with_index{ |_, i| i < limit } first, last = labels.partition.with_index { |_, i| i < limit }
label_names = first.collect(&:name) label_names = first.collect(&:name)
label_names << "and #{last.size} more" unless last.empty? label_names << "and #{last.size} more" unless last.empty?
...@@ -234,7 +234,7 @@ module IssuablesHelper ...@@ -234,7 +234,7 @@ module IssuablesHelper
end end
def issuables_count_for_state(issuable_type, state, finder: nil) def issuables_count_for_state(issuable_type, state, finder: nil)
finder ||= public_send("#{issuable_type}_finder") finder ||= public_send("#{issuable_type}_finder") # rubocop:disable GitlabSecurity/PublicSend
cache_key = finder.state_counter_cache_key cache_key = finder.state_counter_cache_key
@counts ||= {} @counts ||= {}
...@@ -329,7 +329,7 @@ module IssuablesHelper ...@@ -329,7 +329,7 @@ module IssuablesHelper
end end
def selected_template(issuable) def selected_template(issuable)
params[:issuable_template] if issuable_templates(issuable).any?{ |template| template[:name] == params[:issuable_template] } params[:issuable_template] if issuable_templates(issuable).any? { |template| template[:name] == params[:issuable_template] }
end end
def issuable_todo_button_data(issuable, todo, is_collapsed) def issuable_todo_button_data(issuable, todo, is_collapsed)
......
...@@ -43,11 +43,11 @@ module LabelsHelper ...@@ -43,11 +43,11 @@ module LabelsHelper
def label_filter_path(subject, label, type: :issue) def label_filter_path(subject, label, type: :issue)
case subject case subject
when Group when Group
send("#{type.to_s.pluralize}_group_path", send("#{type.to_s.pluralize}_group_path", # rubocop:disable GitlabSecurity/PublicSend
subject, subject,
label_name: [label.name]) label_name: [label.name])
when Project when Project
send("namespace_project_#{type.to_s.pluralize}_path", send("namespace_project_#{type.to_s.pluralize}_path", # rubocop:disable GitlabSecurity/PublicSend
subject.namespace, subject.namespace,
subject, subject,
label_name: [label.name]) label_name: [label.name])
......
...@@ -55,7 +55,8 @@ class Commit ...@@ -55,7 +55,8 @@ class Commit
end end
def from_hash(hash, project) def from_hash(hash, project)
new(Gitlab::Git::Commit.new(hash), project) raw_commit = Gitlab::Git::Commit.new(project.repository.raw, hash)
new(raw_commit, project)
end end
def valid_hash?(key) def valid_hash?(key)
...@@ -320,21 +321,11 @@ class Commit ...@@ -320,21 +321,11 @@ class Commit
end end
def raw_diffs(*args) def raw_diffs(*args)
if Gitlab::GitalyClient.feature_enabled?(:commit_raw_diffs) raw.diffs(*args)
Gitlab::GitalyClient::CommitService.new(project.repository).diff_from_parent(self, *args)
else
raw.diffs(*args)
end
end end
def raw_deltas def raw_deltas
@deltas ||= Gitlab::GitalyClient.migrate(:commit_deltas) do |is_enabled| @deltas ||= raw.deltas
if is_enabled
Gitlab::GitalyClient::CommitService.new(project.repository).commit_deltas(self)
else
raw.deltas
end
end
end end
def diffs(diff_options = nil) def diffs(diff_options = nil)
......
...@@ -58,7 +58,7 @@ module Spammable ...@@ -58,7 +58,7 @@ module Spammable
options.fetch(:spam_title, false) options.fetch(:spam_title, false)
end end
public_send(attr.first) if attr && respond_to?(attr.first.to_sym) public_send(attr.first) if attr && respond_to?(attr.first.to_sym) # rubocop:disable GitlabSecurity/PublicSend
end end
def spam_description def spam_description
...@@ -66,12 +66,12 @@ module Spammable ...@@ -66,12 +66,12 @@ module Spammable
options.fetch(:spam_description, false) options.fetch(:spam_description, false)
end end
public_send(attr.first) if attr && respond_to?(attr.first.to_sym) public_send(attr.first) if attr && respond_to?(attr.first.to_sym) # rubocop:disable GitlabSecurity/PublicSend
end end
def spammable_text def spammable_text
result = self.class.spammable_attrs.map do |attr| result = self.class.spammable_attrs.map do |attr|
public_send(attr.first) public_send(attr.first) # rubocop:disable GitlabSecurity/PublicSend
end end
result.reject(&:blank?).join("\n") result.reject(&:blank?).join("\n")
......
...@@ -44,7 +44,8 @@ module TokenAuthenticatable ...@@ -44,7 +44,8 @@ module TokenAuthenticatable
end end
define_method("ensure_#{token_field}!") do define_method("ensure_#{token_field}!") do
send("reset_#{token_field}!") if read_attribute(token_field).blank? send("reset_#{token_field}!") if read_attribute(token_field).blank? # rubocop:disable GitlabSecurity/PublicSend
read_attribute(token_field) read_attribute(token_field)
end end
......
...@@ -162,7 +162,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -162,7 +162,7 @@ class MergeRequest < ActiveRecord::Base
target = unscoped.where(target_project_id: relation).select(:id) target = unscoped.where(target_project_id: relation).select(:id)
union = Gitlab::SQL::Union.new([source, target]) union = Gitlab::SQL::Union.new([source, target])
where("merge_requests.id IN (#{union.to_sql})") where("merge_requests.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
end end
WIP_REGEX = /\A\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i.freeze WIP_REGEX = /\A\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i.freeze
......
...@@ -282,9 +282,7 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -282,9 +282,7 @@ class MergeRequestDiff < ActiveRecord::Base
def load_commits def load_commits
commits = st_commits.presence || merge_request_diff_commits commits = st_commits.presence || merge_request_diff_commits
commits.map do |commit| commits.map { |commit| Commit.from_hash(commit.to_hash, project) }
Commit.new(Gitlab::Git::Commit.new(commit.to_hash), merge_request.source_project)
end
end end
def save_diffs def save_diffs
......
...@@ -26,7 +26,7 @@ class MergeRequestDiffCommit < ActiveRecord::Base ...@@ -26,7 +26,7 @@ class MergeRequestDiffCommit < ActiveRecord::Base
def to_hash def to_hash
Gitlab::Git::Commit::SERIALIZE_KEYS.each_with_object({}) do |key, hash| Gitlab::Git::Commit::SERIALIZE_KEYS.each_with_object({}) do |key, hash|
hash[key] = public_send(key) hash[key] = public_send(key) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
......
...@@ -206,7 +206,7 @@ module Network ...@@ -206,7 +206,7 @@ module Network
# Visit branching chains # Visit branching chains
leaves.each do |l| leaves.each do |l|
parents = l.parents(@map).select{|p| p.space.zero?} parents = l.parents(@map).select {|p| p.space.zero?}
parents.each do |p| parents.each do |p|
place_chain(p, l.time) place_chain(p, l.time)
end end
......
...@@ -77,20 +77,20 @@ class Note < ActiveRecord::Base ...@@ -77,20 +77,20 @@ class Note < ActiveRecord::Base
# Scopes # Scopes
scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) } scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) }
scope :system, ->{ where(system: true) } scope :system, -> { where(system: true) }
scope :user, ->{ where(system: false) } scope :user, -> { where(system: false) }
scope :common, ->{ where(noteable_type: ["", nil]) } scope :common, -> { where(noteable_type: ["", nil]) }
scope :fresh, ->{ order(created_at: :asc, id: :asc) } scope :fresh, -> { order(created_at: :asc, id: :asc) }
scope :updated_after, ->(time){ where('updated_at > ?', time) } scope :updated_after, ->(time) { where('updated_at > ?', time) }
scope :inc_author_project, ->{ includes(:project, :author) } scope :inc_author_project, -> { includes(:project, :author) }
scope :inc_author, ->{ includes(:author) } scope :inc_author, -> { includes(:author) }
scope :inc_relations_for_view, -> do scope :inc_relations_for_view, -> do
includes(:project, :author, :updated_by, :resolved_by, :award_emoji, :system_note_metadata) includes(:project, :author, :updated_by, :resolved_by, :award_emoji, :system_note_metadata)
end end
scope :diff_notes, ->{ where(type: %w(LegacyDiffNote DiffNote)) } scope :diff_notes, -> { where(type: %w(LegacyDiffNote DiffNote)) }
scope :new_diff_notes, ->{ where(type: 'DiffNote') } scope :new_diff_notes, -> { where(type: 'DiffNote') }
scope :non_diff_notes, ->{ where(type: ['Note', 'DiscussionNote', nil]) } scope :non_diff_notes, -> { where(type: ['Note', 'DiscussionNote', nil]) }
scope :with_associations, -> do scope :with_associations, -> do
# FYI noteable cannot be loaded for LegacyDiffNote for commits # FYI noteable cannot be loaded for LegacyDiffNote for commits
......
...@@ -66,6 +66,6 @@ class NotificationSetting < ActiveRecord::Base ...@@ -66,6 +66,6 @@ class NotificationSetting < ActiveRecord::Base
alias_method :failed_pipeline?, :failed_pipeline alias_method :failed_pipeline?, :failed_pipeline
def event_enabled?(event) def event_enabled?(event)
respond_to?(event) && !!public_send(event) respond_to?(event) && !!public_send(event) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
...@@ -415,7 +415,7 @@ class Project < ActiveRecord::Base ...@@ -415,7 +415,7 @@ class Project < ActiveRecord::Base
union = Gitlab::SQL::Union.new([projects, namespaces]) union = Gitlab::SQL::Union.new([projects, namespaces])
where("projects.id IN (#{union.to_sql})") where("projects.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
end end
def search_by_title(query) def search_by_title(query)
...@@ -825,7 +825,7 @@ class Project < ActiveRecord::Base ...@@ -825,7 +825,7 @@ class Project < ActiveRecord::Base
if template.nil? if template.nil?
# If no template, we should create an instance. Ex `build_gitlab_ci_service` # If no template, we should create an instance. Ex `build_gitlab_ci_service`
public_send("build_#{service_name}_service") public_send("build_#{service_name}_service") # rubocop:disable GitlabSecurity/PublicSend
else else
Service.build_from_template(id, template) Service.build_from_template(id, template)
end end
...@@ -1046,13 +1046,18 @@ class Project < ActiveRecord::Base ...@@ -1046,13 +1046,18 @@ class Project < ActiveRecord::Base
end end
def change_head(branch) def change_head(branch)
repository.before_change_head if repository.branch_exists?(branch)
repository.rugged.references.create('HEAD', repository.before_change_head
"refs/heads/#{branch}", repository.rugged.references.create('HEAD',
force: true) "refs/heads/#{branch}",
repository.copy_gitattributes(branch) force: true)
repository.after_change_head repository.copy_gitattributes(branch)
reload_default_branch repository.after_change_head
reload_default_branch
else
errors.add(:base, "Could not change HEAD: branch '#{branch}' does not exist")
false
end
end end
def forked_from?(project) def forked_from?(project)
...@@ -1326,7 +1331,7 @@ class Project < ActiveRecord::Base ...@@ -1326,7 +1331,7 @@ class Project < ActiveRecord::Base
end end
def append_or_update_attribute(name, value) def append_or_update_attribute(name, value)
old_values = public_send(name.to_s) old_values = public_send(name.to_s) # rubocop:disable GitlabSecurity/PublicSend
if Project.reflect_on_association(name).try(:macro) == :has_many && old_values.any? if Project.reflect_on_association(name).try(:macro) == :has_many && old_values.any?
update_attribute(name, old_values + value) update_attribute(name, old_values + value)
......
...@@ -55,7 +55,7 @@ class ProjectFeature < ActiveRecord::Base ...@@ -55,7 +55,7 @@ class ProjectFeature < ActiveRecord::Base
end end
def access_level(feature) def access_level(feature)
public_send(ProjectFeature.access_level_attribute(feature)) public_send(ProjectFeature.access_level_attribute(feature)) # rubocop:disable GitlabSecurity/PublicSend
end end
def builds_enabled? def builds_enabled?
...@@ -80,7 +80,7 @@ class ProjectFeature < ActiveRecord::Base ...@@ -80,7 +80,7 @@ class ProjectFeature < ActiveRecord::Base
# which cannot be higher than repository access level # which cannot be higher than repository access level
def repository_children_level def repository_children_level
validator = lambda do |field| validator = lambda do |field|
level = public_send(field) || ProjectFeature::ENABLED level = public_send(field) || ProjectFeature::ENABLED # rubocop:disable GitlabSecurity/PublicSend
not_allowed = level > repository_access_level not_allowed = level > repository_access_level
self.errors.add(field, "cannot have higher visibility level than repository access level") if not_allowed self.errors.add(field, "cannot have higher visibility level than repository access level") if not_allowed
end end
......
...@@ -14,7 +14,7 @@ class ProjectStatistics < ActiveRecord::Base ...@@ -14,7 +14,7 @@ class ProjectStatistics < ActiveRecord::Base
def refresh!(only: nil) def refresh!(only: nil)
STATISTICS_COLUMNS.each do |column, generator| STATISTICS_COLUMNS.each do |column, generator|
if only.blank? || only.include?(column) if only.blank? || only.include?(column)
public_send("update_#{column}") public_send("update_#{column}") # rubocop:disable GitlabSecurity/PublicSend
end end
end end
......
...@@ -64,6 +64,8 @@ class Repository ...@@ -64,6 +64,8 @@ class Repository
@raw_repository ||= initialize_raw_repository @raw_repository ||= initialize_raw_repository
end end
alias_method :raw, :raw_repository
# Return absolute path to repository # Return absolute path to repository
def path_to_repo def path_to_repo
@path_to_repo ||= File.expand_path( @path_to_repo ||= File.expand_path(
...@@ -298,7 +300,7 @@ class Repository ...@@ -298,7 +300,7 @@ class Repository
expire_method_caches(to_refresh) expire_method_caches(to_refresh)
to_refresh.each { |method| send(method) } to_refresh.each { |method| send(method) } # rubocop:disable GitlabSecurity/PublicSend
end end
def expire_branch_cache(branch_name = nil) def expire_branch_cache(branch_name = nil)
...@@ -763,7 +765,7 @@ class Repository ...@@ -763,7 +765,7 @@ class Repository
index = Gitlab::Git::Index.new(raw_repository) index = Gitlab::Git::Index.new(raw_repository)
if start_commit if start_commit
index.read_tree(start_commit.raw_commit.tree) index.read_tree(start_commit.rugged_commit.tree)
parents = [start_commit.sha] parents = [start_commit.sha]
else else
parents = [] parents = []
......
...@@ -148,6 +148,8 @@ class User < ActiveRecord::Base ...@@ -148,6 +148,8 @@ class User < ActiveRecord::Base
uniqueness: { case_sensitive: false } uniqueness: { case_sensitive: false }
validate :namespace_uniq, if: :username_changed? validate :namespace_uniq, if: :username_changed?
validate :namespace_move_dir_allowed, if: :username_changed?
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? } validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validate :unique_email, if: :email_changed? validate :unique_email, if: :email_changed?
validate :owns_notification_email, if: :notification_email_changed? validate :owns_notification_email, if: :notification_email_changed?
...@@ -487,6 +489,12 @@ class User < ActiveRecord::Base ...@@ -487,6 +489,12 @@ class User < ActiveRecord::Base
end end
end end
def namespace_move_dir_allowed
if namespace&.any_project_has_container_registry_tags?
errors.add(:username, 'cannot be changed if a personal project has container registry tags.')
end
end
def avatar_type def avatar_type
unless avatar.image? unless avatar.image?
errors.add :avatar, "only images allowed" errors.add :avatar, "only images allowed"
...@@ -528,7 +536,7 @@ class User < ActiveRecord::Base ...@@ -528,7 +536,7 @@ class User < ActiveRecord::Base
union = Gitlab::SQL::Union union = Gitlab::SQL::Union
.new([groups.select(:id), authorized_projects.select(:namespace_id)]) .new([groups.select(:id), authorized_projects.select(:namespace_id)])
Group.where("namespaces.id IN (#{union.to_sql})") Group.where("namespaces.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
end end
# Returns a relation of groups the user has access to, including their parent # Returns a relation of groups the user has access to, including their parent
...@@ -719,8 +727,8 @@ class User < ActiveRecord::Base ...@@ -719,8 +727,8 @@ class User < ActiveRecord::Base
def sanitize_attrs def sanitize_attrs
%w[username skype linkedin twitter].each do |attr| %w[username skype linkedin twitter].each do |attr|
value = public_send(attr) value = public_send(attr) # rubocop:disable GitlabSecurity/PublicSend
public_send("#{attr}=", Sanitize.clean(value)) if value.present? public_send("#{attr}=", Sanitize.clean(value)) if value.present? # rubocop:disable GitlabSecurity/PublicSend
end end
end end
...@@ -779,7 +787,7 @@ class User < ActiveRecord::Base ...@@ -779,7 +787,7 @@ class User < ActiveRecord::Base
def with_defaults def with_defaults
User.defaults.each do |k, v| User.defaults.each do |k, v|
public_send("#{k}=", v) public_send("#{k}=", v) # rubocop:disable GitlabSecurity/PublicSend
end end
self self
...@@ -825,7 +833,7 @@ class User < ActiveRecord::Base ...@@ -825,7 +833,7 @@ class User < ActiveRecord::Base
{ {
name: name, name: name,
username: username, username: username,
avatar_url: avatar_url avatar_url: avatar_url(only_path: false)
} }
end end
...@@ -919,7 +927,7 @@ class User < ActiveRecord::Base ...@@ -919,7 +927,7 @@ class User < ActiveRecord::Base
def ci_authorized_runners def ci_authorized_runners
@ci_authorized_runners ||= begin @ci_authorized_runners ||= begin
runner_ids = Ci::RunnerProject runner_ids = Ci::RunnerProject
.where("ci_runner_projects.project_id IN (#{ci_projects_union.to_sql})") .where("ci_runner_projects.project_id IN (#{ci_projects_union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
.select(:runner_id) .select(:runner_id)
Ci::Runner.specific.where(id: runner_ids) Ci::Runner.specific.where(id: runner_ids)
end end
......
...@@ -35,6 +35,6 @@ class AnalyticsBuildEntity < Grape::Entity ...@@ -35,6 +35,6 @@ class AnalyticsBuildEntity < Grape::Entity
private private
def url_to(route, build, id = nil) def url_to(route, build, id = nil)
public_send("#{route}_url", build.project.namespace, build.project, id || build) public_send("#{route}_url", build.project.namespace, build.project, id || build) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
...@@ -24,6 +24,6 @@ class AnalyticsIssueEntity < Grape::Entity ...@@ -24,6 +24,6 @@ class AnalyticsIssueEntity < Grape::Entity
private private
def url_to(route, id) def url_to(route, id)
public_send("#{route}_url", request.project.namespace, request.project, id) public_send("#{route}_url", request.project.namespace, request.project, id) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
...@@ -46,6 +46,6 @@ class JobEntity < Grape::Entity ...@@ -46,6 +46,6 @@ class JobEntity < Grape::Entity
end end
def path_to(route, build) def path_to(route, build)
send("#{route}_path", build.project.namespace, build.project, build) send("#{route}_path", build.project.namespace, build.project, build) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
...@@ -16,6 +16,7 @@ module Issues ...@@ -16,6 +16,7 @@ module Issues
spam_check(issue, current_user) spam_check(issue, current_user)
issue.move_to_end issue.move_to_end
# current_user (defined in BaseService) is not available within run_after_commit block
user = current_user user = current_user
issue.run_after_commit do issue.run_after_commit do
NewIssueWorker.perform_async(issue.id, user.id) NewIssueWorker.perform_async(issue.id, user.id)
......
...@@ -37,7 +37,7 @@ module Labels ...@@ -37,7 +37,7 @@ module Labels
union = Gitlab::SQL::Union.new(label_ids) union = Gitlab::SQL::Union.new(label_ids)
Label.where("labels.id IN (#{union.to_sql})").reorder(nil).uniq Label.where("labels.id IN (#{union.to_sql})").reorder(nil).uniq # rubocop:disable GitlabSecurity/SqlInjection
end end
def group_labels_applied_to_issues def group_labels_applied_to_issues
......
...@@ -17,6 +17,7 @@ module MergeRequests ...@@ -17,6 +17,7 @@ module MergeRequests
end end
def before_create(merge_request) def before_create(merge_request)
# current_user (defined in BaseService) is not available within run_after_commit block
user = current_user user = current_user
merge_request.run_after_commit do merge_request.run_after_commit do
NewMergeRequestWorker.perform_async(merge_request.id, user.id) NewMergeRequestWorker.perform_async(merge_request.id, user.id)
......
...@@ -10,7 +10,7 @@ module Projects ...@@ -10,7 +10,7 @@ module Projects
end end
if changing_default_branch? if changing_default_branch?
project.change_head(params[:default_branch]) return error("Could not set the default branch") unless project.change_head(params[:default_branch])
end end
if project.update_attributes(params.except(:default_branch)) if project.update_attributes(params.except(:default_branch))
......
...@@ -74,7 +74,8 @@ ...@@ -74,7 +74,8 @@
= link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username } = link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username }
%li %li
= link_to "Settings", profile_path = link_to "Settings", profile_path
= render 'shared/user_dropdown_experimental_features' %li
= link_to "Turn on new navigation", profile_preferences_path(anchor: "new-navigation")
%li.divider %li.divider
%li %li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link" = link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link"
......
...@@ -68,7 +68,8 @@ ...@@ -68,7 +68,8 @@
= link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username } = link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username }
%li %li
= link_to "Settings", profile_path = link_to "Settings", profile_path
= render 'shared/user_dropdown_experimental_features' %li
= link_to "Turn off new navigation", profile_preferences_path(anchor: "new-navigation")
%li.divider %li.divider
%li %li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link" = link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link"
......
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
= scheme.name = scheme.name
.col-sm-12 .col-sm-12
%hr %hr
%h3#experimental-features Experimental features
%hr
.col-lg-4.profile-settings-sidebar#new-navigation .col-lg-4.profile-settings-sidebar#new-navigation
%h4.prepend-top-0 %h4.prepend-top-0
New Navigation New Navigation
...@@ -42,28 +40,6 @@ ...@@ -42,28 +40,6 @@
New New
.col-sm-12 .col-sm-12
%hr %hr
.col-lg-4.profile-settings-sidebar#new-repository
%h4.prepend-top-0
New Repository
%p
This setting allows you to turn on or off the new upcoming repository concept.
.col-lg-8.syntax-theme
.nav-wip
%p
The new repository is currently a work-in-progress concept and only usable on wide-screens. There are a number of improvements that we are working on in order to further refine the repository view.
%p
%a{ href: 'https://gitlab.com/gitlab-org/gitlab-ce/issues/31890', target: 'blank' } Learn more
about the improvements that are coming soon!
= label_tag do
.preview= image_tag "old_repo.png"
%input.js-experiment-feature-toggle{ type: "radio", value: "false", name: "new_repo", checked: !show_new_repo? }
Old
= label_tag do
.preview= image_tag "new_repo.png"
%input.js-experiment-feature-toggle{ type: "radio", value: "true", name: "new_repo", checked: show_new_repo? }
New
.col-sm-12
%hr
.col-lg-4.profile-settings-sidebar .col-lg-4.profile-settings-sidebar
%h4.prepend-top-0 %h4.prepend-top-0
Behavior Behavior
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
= render 'shared/new_commit_form', placeholder: placeholder = render 'shared/new_commit_form', placeholder: placeholder
.form-actions .form-actions
= button_tag button_title, class: 'btn btn-small btn-create btn-upload-file', id: 'submit-all' = button_tag class: 'btn btn-create btn-upload-file', id: 'submit-all', type: 'button' do
= icon('spin spinner', class: 'js-loading-icon hidden' )
= button_title
= link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal" = link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
- unless can?(current_user, :push_code, @project) - unless can?(current_user, :push_code, @project)
......
...@@ -4,20 +4,21 @@ ...@@ -4,20 +4,21 @@
- diff_files = diffs.diff_files - diff_files = diffs.diff_files
.content-block.oneline-block.files-changed.diff-files-changed.js-diff-files-changed .content-block.oneline-block.files-changed.diff-files-changed.js-diff-files-changed
.inline-parallel-buttons .files-changed-inner
- if !diffs_expanded? && diff_files.any? { |diff_file| diff_file.collapsed? } .inline-parallel-buttons
= link_to 'Expand all', url_for(params.merge(expanded: 1, format: nil)), class: 'btn btn-default' - if !diffs_expanded? && diff_files.any? { |diff_file| diff_file.collapsed? }
- if show_whitespace_toggle = link_to 'Expand all', url_for(params.merge(expanded: 1, format: nil)), class: 'btn btn-default'
- if current_controller?(:commit) - if show_whitespace_toggle
= commit_diff_whitespace_link(diffs.project, @commit, class: 'hidden-xs') - if current_controller?(:commit)
- elsif current_controller?('projects/merge_requests/diffs') = commit_diff_whitespace_link(diffs.project, @commit, class: 'hidden-xs')
= diff_merge_request_whitespace_link(diffs.project, @merge_request, class: 'hidden-xs') - elsif current_controller?('projects/merge_requests/diffs')
- elsif current_controller?(:compare) = diff_merge_request_whitespace_link(diffs.project, @merge_request, class: 'hidden-xs')
= diff_compare_whitespace_link(diffs.project, params[:from], params[:to], class: 'hidden-xs') - elsif current_controller?(:compare)
.btn-group = diff_compare_whitespace_link(diffs.project, params[:from], params[:to], class: 'hidden-xs')
= inline_diff_btn .btn-group
= parallel_diff_btn = inline_diff_btn
= render 'projects/diffs/stats', diff_files: diff_files = parallel_diff_btn
= render 'projects/diffs/stats', diff_files: diff_files
- if render_overflow_warning?(diff_files) - if render_overflow_warning?(diff_files)
= render 'projects/diffs/warning', diff_files: diffs = render 'projects/diffs/warning', diff_files: diffs
......
...@@ -78,8 +78,8 @@ ...@@ -78,8 +78,8 @@
%script#projectChartData{ type: "application/json" } %script#projectChartData{ type: "application/json" }
- projectChartData = {}; - projectChartData = {};
- projectChartData['hour'] = { 'keys' => @commits_per_time.keys, 'values' => @commits_per_time.values } - projectChartData['hour'] = @commits_per_time
- projectChartData['weekDays'] = { 'keys' => @commits_per_week_days.keys, 'values' => @commits_per_week_days.values } - projectChartData['weekDays'] = @commits_per_week_days
- projectChartData['month'] = { 'keys' => @commits_per_month.keys, 'values' => @commits_per_month.values } - projectChartData['month'] = @commits_per_month
- projectChartData['languages'] = @languages - projectChartData['languages'] = @languages
= projectChartData.to_json.html_safe = projectChartData.to_json.html_safe
%li= link_to 'Experimental features', profile_preferences_path(anchor: 'experimental-features')
module NewIssuable module NewIssuable
attr_reader :issuable, :user attr_reader :issuable, :user
def ensure_objects_found(issuable_id, user_id) def objects_found?(issuable_id, user_id)
@issuable = issuable_class.find_by(id: issuable_id) set_user(user_id)
unless @issuable set_issuable(issuable_id)
log_error(issuable_class, issuable_id)
return false user && issuable
end end
def set_user(user_id)
@user = User.find_by(id: user_id) @user = User.find_by(id: user_id)
unless @user
log_error(User, user_id)
return false
end
true log_error(User, user_id) unless @user
end
def set_issuable(issuable_id)
@issuable = issuable_class.find_by(id: issuable_id)
log_error(issuable_class, issuable_id) unless @issuable
end end
def log_error(record_class, record_id) def log_error(record_class, record_id)
......
...@@ -4,7 +4,7 @@ class NewIssueWorker ...@@ -4,7 +4,7 @@ class NewIssueWorker
include NewIssuable include NewIssuable
def perform(issue_id, user_id) def perform(issue_id, user_id)
return unless ensure_objects_found(issue_id, user_id) return unless objects_found?(issue_id, user_id)
EventCreateService.new.open_issue(issuable, user) EventCreateService.new.open_issue(issuable, user)
NotificationService.new.new_issue(issuable, user) NotificationService.new.new_issue(issuable, user)
......
...@@ -4,7 +4,7 @@ class NewMergeRequestWorker ...@@ -4,7 +4,7 @@ class NewMergeRequestWorker
include NewIssuable include NewIssuable
def perform(merge_request_id, user_id) def perform(merge_request_id, user_id)
return unless ensure_objects_found(merge_request_id, user_id) return unless objects_found?(merge_request_id, user_id)
EventCreateService.new.open_mr(issuable, user) EventCreateService.new.open_mr(issuable, user)
NotificationService.new.new_merge_request(issuable, user) NotificationService.new.new_merge_request(issuable, user)
......
...@@ -4,7 +4,7 @@ class PagesWorker ...@@ -4,7 +4,7 @@ class PagesWorker
sidekiq_options queue: :pages, retry: false sidekiq_options queue: :pages, retry: false
def perform(action, *arg) def perform(action, *arg)
send(action, *arg) send(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
end end
def deploy(build_id) def deploy(build_id)
......
#!/usr/bin/env ruby #!/usr/bin/env ruby
require 'bundler/setup'
require 'stackprof' require 'stackprof'
$:.unshift 'spec' $:.unshift 'spec'
require 'rails_helper' require 'rails_helper'
...@@ -13,4 +14,4 @@ StackProf.run(mode: :wall, out: output_file, interval: interval) do ...@@ -13,4 +14,4 @@ StackProf.run(mode: :wall, out: output_file, interval: interval) do
RSpec::Core::Runner.run(ARGV, $stderr, $stdout) RSpec::Core::Runner.run(ARGV, $stderr, $stdout)
end end
system("stackprof #{output_file} --text --limit #{limit}") system("bundle exec stackprof #{output_file} --text --limit #{limit}")
---
title: Expose noteable_iid in Note
merge_request: 13265
author: sue445
---
title: Use full path of user's avatar in webhooks
merge_request: 13401
author: Vitaliy @blackst0ne Klachkov
---
title: improve file upload/replace experience
merge_request:
author:
---
title: Raise guessed encoding confidence threshold to 50
merge_request: 12990
author:
---
title: Fix bar chart does not display label at 0 hour
merge_request: 35136
author: Jason Dai
---
title: Add checks for branch existence before changing HEAD
merge_request: 13359
author: Vitaliy @blackst0ne Klachkov
---
title: Simplify checking if objects exist code in new issaubles workers
merge_request:
author:
---
title: Add missing validation error for username change with container registry tags
merge_request: 13356
author:
---
title: Fix the /projects/:id/repository/commits endpoint to handle dots in the ref
name when the project full path contains a `/`
merge_request: 13370
author:
...@@ -176,7 +176,7 @@ module Gitlab ...@@ -176,7 +176,7 @@ module Gitlab
next unless name.include?('namespace_project') next unless name.include?('namespace_project')
define_method(name.sub('namespace_project', 'project')) do |project, *args| define_method(name.sub('namespace_project', 'project')) do |project, *args|
send(name, project&.namespace, project, *args) send(name, project&.namespace, project, *args) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
end end
......
...@@ -71,7 +71,7 @@ class Settings < Settingslogic ...@@ -71,7 +71,7 @@ class Settings < Settingslogic
# check that `current` (string or integer) is a contant in `modul`. # check that `current` (string or integer) is a contant in `modul`.
def verify_constant(modul, current, default) def verify_constant(modul, current, default)
constant = modul.constants.find{ |name| modul.const_get(name) == current } constant = modul.constants.find { |name| modul.const_get(name) == current }
value = constant.nil? ? default : modul.const_get(constant) value = constant.nil? ? default : modul.const_get(constant)
if current.is_a? String if current.is_a? String
value = modul.const_get(current.upcase) rescue default value = modul.const_get(current.upcase) rescue default
......
...@@ -18,7 +18,7 @@ module ActiveRecord ...@@ -18,7 +18,7 @@ module ActiveRecord
lock_col = self.class.locking_column lock_col = self.class.locking_column
previous_lock_value = send(lock_col).to_i previous_lock_value = send(lock_col).to_i # rubocop:disable GitlabSecurity/PublicSend
# This line is added as a patch # This line is added as a patch
previous_lock_value = nil if previous_lock_value == '0' || previous_lock_value == 0 previous_lock_value = nil if previous_lock_value == '0' || previous_lock_value == 0
...@@ -48,7 +48,7 @@ module ActiveRecord ...@@ -48,7 +48,7 @@ module ActiveRecord
# If something went wrong, revert the version. # If something went wrong, revert the version.
rescue Exception rescue Exception
send(lock_col + '=', previous_lock_value) send(lock_col + '=', previous_lock_value) # rubocop:disable GitlabSecurity/PublicSend
raise raise
end end
end end
......
...@@ -10,7 +10,7 @@ class AddUniqueIndexToLabels < ActiveRecord::Migration ...@@ -10,7 +10,7 @@ class AddUniqueIndexToLabels < ActiveRecord::Migration
def up def up
select_all('SELECT title, project_id, COUNT(id) as cnt FROM labels GROUP BY project_id, title HAVING COUNT(id) > 1').each do |label| select_all('SELECT title, project_id, COUNT(id) as cnt FROM labels GROUP BY project_id, title HAVING COUNT(id) > 1').each do |label|
label_title = quote_string(label['title']) label_title = quote_string(label['title'])
duplicated_ids = select_all("SELECT id FROM labels WHERE project_id = #{label['project_id']} AND title = '#{label_title}' ORDER BY id ASC").map{ |label| label['id'] } duplicated_ids = select_all("SELECT id FROM labels WHERE project_id = #{label['project_id']} AND title = '#{label_title}' ORDER BY id ASC").map { |label| label['id'] }
label_id = duplicated_ids.first label_id = duplicated_ids.first
duplicated_ids.delete(label_id) duplicated_ids.delete(label_id)
......
...@@ -30,7 +30,7 @@ class CleanupNamespacelessPendingDeleteProjects < ActiveRecord::Migration ...@@ -30,7 +30,7 @@ class CleanupNamespacelessPendingDeleteProjects < ActiveRecord::Migration
private private
def pending_delete_batch def pending_delete_batch
connection.exec_query(find_batch).map{ |row| row['id'].to_i } connection.exec_query(find_batch).map { |row| row['id'].to_i }
end end
BATCH_SIZE = 5000 BATCH_SIZE = 5000
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
Welcome to [GitLab](https://about.gitlab.com/), a Git-based fully featured Welcome to [GitLab](https://about.gitlab.com/), a Git-based fully featured
platform for software development! platform for software development!
We offer four different products for you and your company: GitLab offers the most scalable Git-based fully integrated platform for software development, with flexible products and subscription plans:
- **GitLab Community Edition (CE)** is an [opensource product](https://gitlab.com/gitlab-org/gitlab-ce/), - **GitLab Community Edition (CE)** is an [opensource product](https://gitlab.com/gitlab-org/gitlab-ce/),
self-hosted, free to use. Every feature available in GitLab CE is also available on GitLab Enterprise Edition (Starter and Premium) and GitLab.com. self-hosted, free to use. Every feature available in GitLab CE is also available on GitLab Enterprise Edition (Starter and Premium) and GitLab.com.
......
...@@ -9,6 +9,33 @@ documentation](http://docs.gitlab.com/ee/administration/audit_events.html) ...@@ -9,6 +9,33 @@ documentation](http://docs.gitlab.com/ee/administration/audit_events.html)
System log files are typically plain text in a standard log file format. System log files are typically plain text in a standard log file format.
This guide talks about how to read and use these system log files. This guide talks about how to read and use these system log files.
## `production_json.log`
This file lives in `/var/log/gitlab/gitlab-rails/production_json.log` for
Omnibus GitLab packages or in `/home/git/gitlab/log/production_json.log` for
installations from source. (When Gitlab is running in an environment
other than production, the corresponding logfile is shown here.)
It contains a structured log for Rails controller requests received from
GitLab, thanks to [Lograge](https://github.com/roidrage/lograge/). Note that
requests from the API [are not yet logged to this
file](https://gitlab.com/gitlab-org/gitlab-ce/issues/36189).
Each line contains a JSON line that can be ingested by Elasticsearch, Splunk, etc. For example:
```json
{"method":"GET","path":"/gitlab/gitlab-ce/issues/1234","format":"html","controller":"Projects::IssuesController","action":"show","status":200,"duration":229.03,"view":174.07,"db":13.24,"time":"2017-08-08T20:15:54.821Z","params":{"namespace_id":"gitlab","project_id":"gitlab-ce","id":"1234"},"remote_ip":"18.245.0.1","user_id":1,"username":"admin"}
```
In this example, you can see this was a GET request for a specific issue. Notice each line also contains performance data:
1. `duration`: the total time taken to retrieve the request
2. `view`: total time taken inside the Rails views
3. `db`: total time to retrieve data from the database
In addition, the log contains the IP address from which the request originated
(`remote_ip`) as well as the user's ID (`user_id`), and username (`username`).
## `production.log` ## `production.log`
This file lives in `/var/log/gitlab/gitlab-rails/production.log` for This file lives in `/var/log/gitlab/gitlab-rails/production.log` for
......
...@@ -338,6 +338,45 @@ Example response: ...@@ -338,6 +338,45 @@ Example response:
"web_url":"https://gitlab.example.com/ted" "web_url":"https://gitlab.example.com/ted"
}, },
"author_username":"ted" "author_username":"ted"
},
{
"title": null,
"project_id": 1,
"action_name": "commented on",
"target_id": 1312,
"target_iid": 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/root"
},
"created_at": "2015-12-04T10:33:56.698Z",
"system": false,
"noteable_id": 377,
"noteable_type": "Issue",
"noteable_iid": 377
},
"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/root"
},
"author_username": "root"
} }
] ]
``` ```
......
...@@ -35,7 +35,8 @@ Parameters: ...@@ -35,7 +35,8 @@ Parameters:
"updated_at": "2013-10-02T10:22:45Z", "updated_at": "2013-10-02T10:22:45Z",
"system": true, "system": true,
"noteable_id": 377, "noteable_id": 377,
"noteable_type": "Issue" "noteable_type": "Issue",
"noteable_iid": 377
}, },
{ {
"id": 305, "id": 305,
...@@ -53,7 +54,8 @@ Parameters: ...@@ -53,7 +54,8 @@ Parameters:
"updated_at": "2013-10-02T09:56:03Z", "updated_at": "2013-10-02T09:56:03Z",
"system": true, "system": true,
"noteable_id": 121, "noteable_id": 121,
"noteable_type": "Issue" "noteable_type": "Issue",
"noteable_iid": 121
} }
] ]
``` ```
...@@ -267,7 +269,8 @@ Parameters: ...@@ -267,7 +269,8 @@ Parameters:
"updated_at": "2013-10-02T08:57:14Z", "updated_at": "2013-10-02T08:57:14Z",
"system": false, "system": false,
"noteable_id": 2, "noteable_id": 2,
"noteable_type": "MergeRequest" "noteable_type": "MergeRequest",
"noteable_iid": 2
} }
``` ```
......
...@@ -296,9 +296,9 @@ sudo usermod -aG redis git ...@@ -296,9 +296,9 @@ sudo usermod -aG redis git
### Clone the Source ### Clone the Source
# Clone GitLab repository # Clone GitLab repository
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 9-4-stable gitlab sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 9-5-stable gitlab
**Note:** You can change `9-4-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! **Note:** You can change `9-5-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It ### Configure It
...@@ -507,15 +507,17 @@ Check if GitLab and its environment are configured correctly: ...@@ -507,15 +507,17 @@ Check if GitLab and its environment are configured correctly:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
### Compile GetText PO files
sudo -u git -H bundle exec rake gettext:pack RAILS_ENV=production
sudo -u git -H bundle exec rake gettext:po_to_json RAILS_ENV=production
### Compile Assets ### Compile Assets
sudo -u git -H yarn install --production --pure-lockfile sudo -u git -H yarn install --production --pure-lockfile
sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
### Compile GetText PO files
sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
### Start Your GitLab Instance ### Start Your GitLab Instance
sudo service gitlab start sudo service gitlab start
......
...@@ -31,7 +31,7 @@ X-Gitlab-Event: System Hook ...@@ -31,7 +31,7 @@ X-Gitlab-Event: System Hook
"path": "storecloud", "path": "storecloud",
"path_with_namespace": "jsmith/storecloud", "path_with_namespace": "jsmith/storecloud",
"project_id": 74, "project_id": 74,
"project_visibility": "private", "project_visibility": "private"
} }
``` ```
...@@ -48,7 +48,7 @@ X-Gitlab-Event: System Hook ...@@ -48,7 +48,7 @@ X-Gitlab-Event: System Hook
"path": "underscore", "path": "underscore",
"path_with_namespace": "jsmith/underscore", "path_with_namespace": "jsmith/underscore",
"project_id": 73, "project_id": 73,
"project_visibility": "internal", "project_visibility": "internal"
} }
``` ```
...@@ -66,7 +66,7 @@ X-Gitlab-Event: System Hook ...@@ -66,7 +66,7 @@ X-Gitlab-Event: System Hook
"owner_name": "John Smith", "owner_name": "John Smith",
"owner_email": "johnsmith@gmail.com", "owner_email": "johnsmith@gmail.com",
"project_visibility": "internal", "project_visibility": "internal",
"old_path_with_namespace": "jsmith/overscore", "old_path_with_namespace": "jsmith/overscore"
} }
``` ```
...@@ -84,7 +84,7 @@ X-Gitlab-Event: System Hook ...@@ -84,7 +84,7 @@ X-Gitlab-Event: System Hook
"owner_name": "John Smith", "owner_name": "John Smith",
"owner_email": "johnsmith@gmail.com", "owner_email": "johnsmith@gmail.com",
"project_visibility": "internal", "project_visibility": "internal",
"old_path_with_namespace": "jsmith/overscore", "old_path_with_namespace": "jsmith/overscore"
} }
``` ```
...@@ -101,7 +101,7 @@ X-Gitlab-Event: System Hook ...@@ -101,7 +101,7 @@ X-Gitlab-Event: System Hook
"path": "storecloud", "path": "storecloud",
"path_with_namespace": "jsmith/storecloud", "path_with_namespace": "jsmith/storecloud",
"project_id": 74, "project_id": 74,
"project_visibility": "private", "project_visibility": "private"
} }
``` ```
...@@ -121,7 +121,7 @@ X-Gitlab-Event: System Hook ...@@ -121,7 +121,7 @@ X-Gitlab-Event: System Hook
"user_name": "John Smith", "user_name": "John Smith",
"user_username": "johnsmith", "user_username": "johnsmith",
"user_id": 41, "user_id": 41,
"project_visibility": "private", "project_visibility": "private"
} }
``` ```
...@@ -141,7 +141,7 @@ X-Gitlab-Event: System Hook ...@@ -141,7 +141,7 @@ X-Gitlab-Event: System Hook
"user_name": "John Smith", "user_name": "John Smith",
"user_username": "johnsmith", "user_username": "johnsmith",
"user_id": 41, "user_id": 41,
"project_visibility": "private", "project_visibility": "private"
} }
``` ```
......
...@@ -100,6 +100,7 @@ cd /home/git/gitlab ...@@ -100,6 +100,7 @@ cd /home/git/gitlab
sudo -u git -H git fetch --all sudo -u git -H git fetch --all
sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
sudo -u git -H git checkout -- locale
``` ```
For GitLab Community Edition: For GitLab Community Edition:
...@@ -236,6 +237,11 @@ sudo -u git -H bundle clean ...@@ -236,6 +237,11 @@ sudo -u git -H bundle clean
# Run database migrations # Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Compile GetText PO files
sudo -u git -H bundle exec rake gettext:pack RAILS_ENV=production
sudo -u git -H bundle exec rake gettext:po_to_json RAILS_ENV=production
# Update node dependencies and recompile assets # Update node dependencies and recompile assets
sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
......
...@@ -100,6 +100,7 @@ cd /home/git/gitlab ...@@ -100,6 +100,7 @@ cd /home/git/gitlab
sudo -u git -H git fetch --all sudo -u git -H git fetch --all
sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
sudo -u git -H git checkout -- locale
``` ```
For GitLab Community Edition: For GitLab Community Edition:
...@@ -272,6 +273,10 @@ sudo -u git -H bundle clean ...@@ -272,6 +273,10 @@ sudo -u git -H bundle clean
# Run database migrations # Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Compile GetText PO files
sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
# Update node dependencies and recompile assets # Update node dependencies and recompile assets
sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
......
...@@ -100,6 +100,7 @@ cd /home/git/gitlab ...@@ -100,6 +100,7 @@ cd /home/git/gitlab
sudo -u git -H git fetch --all sudo -u git -H git fetch --all
sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
sudo -u git -H git checkout -- locale
``` ```
For GitLab Community Edition: For GitLab Community Edition:
...@@ -285,6 +286,10 @@ sudo -u git -H bundle clean ...@@ -285,6 +286,10 @@ sudo -u git -H bundle clean
# Run database migrations # Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Compile GetText PO files
sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
# Update node dependencies and recompile assets # Update node dependencies and recompile assets
sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
......
...@@ -35,7 +35,7 @@ current version with `cat VERSION`). ...@@ -35,7 +35,7 @@ current version with `cat VERSION`).
cd /home/git/gitlab cd /home/git/gitlab
sudo -u git -H git fetch --all sudo -u git -H git fetch --all
sudo -u git -H git checkout -- Gemfile.lock db/schema.rb sudo -u git -H git checkout -- Gemfile.lock db/schema.rb locale
sudo -u git -H git checkout LATEST_TAG -b LATEST_TAG sudo -u git -H git checkout LATEST_TAG -b LATEST_TAG
``` ```
...@@ -56,11 +56,21 @@ sudo -u git -H bundle clean ...@@ -56,11 +56,21 @@ sudo -u git -H bundle clean
# Run database migrations # Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
### 4. Compile GetText PO files
Internationalization was added in `v9.2.0` so these commands are only
required for versions equal or major to it.
```bash
sudo -u git -H bundle exec rake gettext:pack RAILS_ENV=production
sudo -u git -H bundle exec rake gettext:po_to_json RAILS_ENV=production
```
# Clean up assets and cache # Clean up assets and cache
sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile cache:clear RAILS_ENV=production NODE_ENV=production sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile cache:clear RAILS_ENV=production NODE_ENV=production
``` ```
### 4. Update gitlab-workhorse to the corresponding version ### 5. Update gitlab-workhorse to the corresponding version
```bash ```bash
cd /home/git/gitlab cd /home/git/gitlab
...@@ -68,7 +78,7 @@ cd /home/git/gitlab ...@@ -68,7 +78,7 @@ cd /home/git/gitlab
sudo -u git -H bundle exec rake "gitlab:workhorse:install[/home/git/gitlab-workhorse]" RAILS_ENV=production sudo -u git -H bundle exec rake "gitlab:workhorse:install[/home/git/gitlab-workhorse]" RAILS_ENV=production
``` ```
### 5. Update gitlab-shell to the corresponding version ### 6. Update gitlab-shell to the corresponding version
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
...@@ -78,14 +88,14 @@ sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION` -b v`ca ...@@ -78,14 +88,14 @@ sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION` -b v`ca
sudo -u git -H sh -c 'if [ -x bin/compile ]; then bin/compile; fi' sudo -u git -H sh -c 'if [ -x bin/compile ]; then bin/compile; fi'
``` ```
### 6. Start application ### 7. Start application
```bash ```bash
sudo service gitlab start sudo service gitlab start
sudo service nginx restart sudo service nginx restart
``` ```
### 7. Check application status ### 8. Check application status
Check if GitLab and its environment are configured correctly: Check if GitLab and its environment are configured correctly:
......
...@@ -4,13 +4,14 @@ module API ...@@ -4,13 +4,14 @@ module API
class Commits < Grape::API class Commits < Grape::API
include PaginationParams include PaginationParams
before { authenticate! } COMMIT_ENDPOINT_REQUIREMENTS = API::PROJECT_ENDPOINT_REQUIREMENTS.merge(sha: API::NO_SLASH_URL_PART_REGEX)
before { authorize! :download_code, user_project } before { authorize! :download_code, user_project }
params do params do
requires :id, type: String, desc: 'The ID of a project' requires :id, type: String, desc: 'The ID of a project'
end end
resource :projects, requirements: { id: %r{[^/]+} } do resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a project repository commits' do desc 'Get a project repository commits' do
success Entities::RepoCommit success Entities::RepoCommit
end end
...@@ -21,7 +22,7 @@ module API ...@@ -21,7 +22,7 @@ module API
optional :path, type: String, desc: 'The file path' optional :path, type: String, desc: 'The file path'
use :pagination use :pagination
end end
get ":id/repository/commits" do get ':id/repository/commits' do
path = params[:path] path = params[:path]
before = params[:until] before = params[:until]
after = params[:since] after = params[:since]
...@@ -60,7 +61,7 @@ module API ...@@ -60,7 +61,7 @@ module API
optional :author_email, type: String, desc: 'Author email for commit' optional :author_email, type: String, desc: 'Author email for commit'
optional :author_name, type: String, desc: 'Author name for commit' optional :author_name, type: String, desc: 'Author name for commit'
end end
post ":id/repository/commits" do post ':id/repository/commits' do
authorize! :push_code, user_project authorize! :push_code, user_project
attrs = declared_params attrs = declared_params
...@@ -79,42 +80,42 @@ module API ...@@ -79,42 +80,42 @@ module API
desc 'Get a specific commit of a project' do desc 'Get a specific commit of a project' do
success Entities::RepoCommitDetail success Entities::RepoCommitDetail
failure [[404, 'Not Found']] failure [[404, 'Commit Not Found']]
end end
params do params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end end
get ":id/repository/commits/:sha" do get ':id/repository/commits/:sha', requirements: COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! "Commit" unless commit not_found! 'Commit' unless commit
present commit, with: Entities::RepoCommitDetail present commit, with: Entities::RepoCommitDetail
end end
desc 'Get the diff for a specific commit of a project' do desc 'Get the diff for a specific commit of a project' do
failure [[404, 'Not Found']] failure [[404, 'Commit Not Found']]
end end
params do params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end end
get ":id/repository/commits/:sha/diff" do get ':id/repository/commits/:sha/diff', requirements: COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! "Commit" unless commit not_found! 'Commit' unless commit
commit.raw_diffs.to_a commit.raw_diffs.to_a
end end
desc "Get a commit's comments" do desc "Get a commit's comments" do
success Entities::CommitNote success Entities::CommitNote
failure [[404, 'Not Found']] failure [[404, 'Commit Not Found']]
end end
params do params do
use :pagination use :pagination
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end end
get ':id/repository/commits/:sha/comments' do get ':id/repository/commits/:sha/comments', requirements: COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
...@@ -128,10 +129,10 @@ module API ...@@ -128,10 +129,10 @@ module API
success Entities::RepoCommit success Entities::RepoCommit
end end
params do params do
requires :sha, type: String, desc: 'A commit sha to be cherry picked' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag to be cherry picked'
requires :branch, type: String, desc: 'The name of the branch' requires :branch, type: String, desc: 'The name of the branch'
end end
post ':id/repository/commits/:sha/cherry_pick' do post ':id/repository/commits/:sha/cherry_pick', requirements: COMMIT_ENDPOINT_REQUIREMENTS do
authorize! :push_code, user_project authorize! :push_code, user_project
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
...@@ -160,7 +161,7 @@ module API ...@@ -160,7 +161,7 @@ module API
success Entities::CommitNote success Entities::CommitNote
end end
params do params do
requires :sha, type: String, regexp: /\A\h{6,40}\z/, desc: "The commit's SHA" requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag on which to post a comment'
requires :note, type: String, desc: 'The text of the comment' requires :note, type: String, desc: 'The text of the comment'
optional :path, type: String, desc: 'The file path' optional :path, type: String, desc: 'The file path'
given :path do given :path do
...@@ -168,7 +169,7 @@ module API ...@@ -168,7 +169,7 @@ module API
requires :line_type, type: String, values: %w(new old), default: 'new', desc: 'The type of the line' requires :line_type, type: String, values: %w(new old), default: 'new', desc: 'The type of the line'
end end
end end
post ':id/repository/commits/:sha/comments' do post ':id/repository/commits/:sha/comments', requirements: COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
......
...@@ -132,7 +132,7 @@ module API ...@@ -132,7 +132,7 @@ module API
expose :lfs_enabled?, as: :lfs_enabled expose :lfs_enabled?, as: :lfs_enabled
expose :creator_id expose :creator_id
expose :namespace, using: 'API::Entities::Namespace' expose :namespace, using: 'API::Entities::Namespace'
expose :forked_from_project, using: Entities::BasicProjectDetails, if: lambda{ |project, options| project.forked? } expose :forked_from_project, using: Entities::BasicProjectDetails, if: lambda { |project, options| project.forked? }
expose :import_status expose :import_status
expose :import_error, if: lambda { |_project, options| options[:user_can_admin_project] } expose :import_error, if: lambda { |_project, options| options[:user_can_admin_project] }
expose :avatar_url do |user, options| expose :avatar_url do |user, options|
...@@ -454,6 +454,9 @@ module API ...@@ -454,6 +454,9 @@ module API
end end
class Note < Grape::Entity class Note < Grape::Entity
# Only Issue and MergeRequest have iid
NOTEABLE_TYPES_WITH_IID = %w(Issue MergeRequest).freeze
expose :id expose :id
expose :note, as: :body expose :note, as: :body
expose :attachment_identifier, as: :attachment expose :attachment_identifier, as: :attachment
...@@ -461,6 +464,9 @@ module API ...@@ -461,6 +464,9 @@ module API
expose :created_at, :updated_at expose :created_at, :updated_at
expose :system?, as: :system expose :system?, as: :system
expose :noteable_id, :noteable_type expose :noteable_id, :noteable_type
# Avoid N+1 queries as much as possible
expose(:noteable_iid) { |note| note.noteable.iid if NOTEABLE_TYPES_WITH_IID.include?(note.noteable_type) }
end end
class AwardEmoji < Grape::Entity class AwardEmoji < Grape::Entity
......
# rubocop:disable GitlabSecurity/PublicSend
module API module API
module Helpers module Helpers
module MembersHelpers module MembersHelpers
def find_source(source_type, id) def find_source(source_type, id)
public_send("find_#{source_type}!", id) public_send("find_#{source_type}!", id) # rubocop:disable GitlabSecurity/PublicSend
end end
def authorize_admin_source!(source_type, source) def authorize_admin_source!(source_type, source)
......
...@@ -139,7 +139,7 @@ module API ...@@ -139,7 +139,7 @@ module API
helpers do helpers do
def find_project_noteable(noteables_str, noteable_id) def find_project_noteable(noteables_str, noteable_id)
public_send("find_project_#{noteables_str.singularize}", noteable_id) public_send("find_project_#{noteables_str.singularize}", noteable_id) # rubocop:disable GitlabSecurity/PublicSend
end end
def noteable_read_ability_name(noteable) def noteable_read_ability_name(noteable)
......
...@@ -68,7 +68,7 @@ module API ...@@ -68,7 +68,7 @@ module API
expose :lfs_enabled?, as: :lfs_enabled expose :lfs_enabled?, as: :lfs_enabled
expose :creator_id expose :creator_id
expose :namespace, using: 'API::Entities::Namespace' expose :namespace, using: 'API::Entities::Namespace'
expose :forked_from_project, using: ::API::Entities::BasicProjectDetails, if: lambda{ |project, options| project.forked? } expose :forked_from_project, using: ::API::Entities::BasicProjectDetails, if: lambda { |project, options| project.forked? }
expose :avatar_url do |user, options| expose :avatar_url do |user, options|
user.avatar_url(only_path: false) user.avatar_url(only_path: false)
end end
......
...@@ -198,11 +198,11 @@ module Backup ...@@ -198,11 +198,11 @@ module Backup
end end
def archives_to_backup def archives_to_backup
ARCHIVES_TO_BACKUP.map{ |name| (name + ".tar.gz") unless skipped?(name) }.compact ARCHIVES_TO_BACKUP.map { |name| (name + ".tar.gz") unless skipped?(name) }.compact
end end
def folders_to_backup def folders_to_backup
FOLDERS_TO_BACKUP.reject{ |name| skipped?(name) } FOLDERS_TO_BACKUP.reject { |name| skipped?(name) }
end end
def disabled_features def disabled_features
......
...@@ -254,7 +254,7 @@ module Ci ...@@ -254,7 +254,7 @@ module Ci
def state def state
state = STATE_PARAMS.inject({}) do |h, param| state = STATE_PARAMS.inject({}) do |h, param|
h[param] = send(param) h[param] = send(param) # rubocop:disable GitlabSecurity/PublicSend
h h
end end
Base64.urlsafe_encode64(state.to_json) Base64.urlsafe_encode64(state.to_json)
...@@ -266,7 +266,7 @@ module Ci ...@@ -266,7 +266,7 @@ module Ci
return if state[:offset].to_i > stream.size return if state[:offset].to_i > stream.size
STATE_PARAMS.each do |param| STATE_PARAMS.each do |param|
send("#{param}=".to_sym, state[param]) send("#{param}=".to_sym, state[param]) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
......
...@@ -47,7 +47,7 @@ module Ci ...@@ -47,7 +47,7 @@ module Ci
def collect def collect
query = project.pipelines query = project.pipelines
.where("? > #{Ci::Pipeline.table_name}.created_at AND #{Ci::Pipeline.table_name}.created_at > ?", @to, @from) .where("? > #{Ci::Pipeline.table_name}.created_at AND #{Ci::Pipeline.table_name}.created_at > ?", @to, @from) # rubocop:disable GitlabSecurity/SqlInjection
totals_count = grouped_count(query) totals_count = grouped_count(query)
success_count = grouped_count(query.success) success_count = grouped_count(query.success)
......
...@@ -6,6 +6,8 @@ class ProjectUrlConstrainer ...@@ -6,6 +6,8 @@ class ProjectUrlConstrainer
return false unless DynamicPathValidator.valid_project_path?(full_path) return false unless DynamicPathValidator.valid_project_path?(full_path)
# We intentionally allow SELECT(*) here so result of this query can be used
# as cache for further Project.find_by_full_path calls within request
Project.find_by_full_path(full_path, follow_redirects: request.get?).present? Project.find_by_full_path(full_path, follow_redirects: request.get?).present?
end end
end end
...@@ -77,8 +77,8 @@ EOM ...@@ -77,8 +77,8 @@ EOM
def initialize(merge_request, project) def initialize(merge_request, project)
@merge_request = merge_request @merge_request = merge_request
@our_commit = merge_request.source_branch_head.raw.raw_commit @our_commit = merge_request.source_branch_head.raw.rugged_commit
@their_commit = merge_request.target_branch_head.raw.raw_commit @their_commit = merge_request.target_branch_head.raw.rugged_commit
@project = project @project = project
end end
end end
......
...@@ -54,7 +54,7 @@ module Gitlab ...@@ -54,7 +54,7 @@ module Gitlab
end end
def serialize_commit(event, commit, query) def serialize_commit(event, commit, query)
commit = Commit.new(Gitlab::Git::Commit.new(commit.to_hash), @project) commit = Commit.from_hash(commit.to_hash, @project)
AnalyticsCommitSerializer.new(project: @project, total_time: event['total_time']).represent(commit) AnalyticsCommitSerializer.new(project: @project, total_time: event['total_time']).represent(commit)
end end
......
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
def to_hash def to_hash
hash = {} hash = {}
serialize_keys.each { |key| hash[key] = send(key) } serialize_keys.each { |key| hash[key] = send(key) } # rubocop:disable GitlabSecurity/PublicSend
hash hash
end end
......
...@@ -98,10 +98,11 @@ module Gitlab ...@@ -98,10 +98,11 @@ module Gitlab
if status.zero? if status.zero?
@ee_branch_found = ee_branch_prefix @ee_branch_found = ee_branch_prefix
else return
_, status = step("Fetching origin/#{ee_branch_suffix}", %W[git fetch origin #{ee_branch_suffix}])
end end
_, status = step("Fetching origin/#{ee_branch_suffix}", %W[git fetch origin #{ee_branch_suffix}])
if status.zero? if status.zero?
@ee_branch_found = ee_branch_suffix @ee_branch_found = ee_branch_suffix
else else
......
...@@ -11,7 +11,7 @@ module Gitlab ...@@ -11,7 +11,7 @@ module Gitlab
# obscure encoding with low confidence. # obscure encoding with low confidence.
# There is a lot more info with this merge request: # There is a lot more info with this merge request:
# https://gitlab.com/gitlab-org/gitlab_git/merge_requests/77#note_4754193 # https://gitlab.com/gitlab-org/gitlab_git/merge_requests/77#note_4754193
ENCODING_CONFIDENCE_THRESHOLD = 40 ENCODING_CONFIDENCE_THRESHOLD = 50
def encode!(message) def encode!(message)
return nil unless message.respond_to? :force_encoding return nil unless message.respond_to? :force_encoding
......
...@@ -16,7 +16,7 @@ module Gitlab ...@@ -16,7 +16,7 @@ module Gitlab
def each def each
@blames.each do |blame| @blames.each do |blame|
yield( yield(
Gitlab::Git::Commit.new(blame.commit), Gitlab::Git::Commit.new(@repo, blame.commit),
blame.line blame.line
) )
end end
......
...@@ -14,7 +14,7 @@ module Gitlab ...@@ -14,7 +14,7 @@ module Gitlab
attr_accessor *SERIALIZE_KEYS # rubocop:disable Lint/AmbiguousOperator attr_accessor *SERIALIZE_KEYS # rubocop:disable Lint/AmbiguousOperator
delegate :tree, to: :raw_commit delegate :tree, to: :rugged_commit
def ==(other) def ==(other)
return false unless other.is_a?(Gitlab::Git::Commit) return false unless other.is_a?(Gitlab::Git::Commit)
...@@ -50,19 +50,29 @@ module Gitlab ...@@ -50,19 +50,29 @@ module Gitlab
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/321 # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/321
def find(repo, commit_id = "HEAD") def find(repo, commit_id = "HEAD")
# Already a commit?
return commit_id if commit_id.is_a?(Gitlab::Git::Commit) return commit_id if commit_id.is_a?(Gitlab::Git::Commit)
return decorate(commit_id) if commit_id.is_a?(Rugged::Commit)
obj = if commit_id.is_a?(String) # A rugged reference?
repo.rev_parse_target(commit_id) commit_id = Gitlab::Git::Ref.dereference_object(commit_id)
else return decorate(repo, commit_id) if commit_id.is_a?(Rugged::Commit)
Gitlab::Git::Ref.dereference_object(commit_id)
end
return nil unless obj.is_a?(Rugged::Commit) # Some weird thing?
return nil unless commit_id.is_a?(String)
decorate(obj) commit = repo.gitaly_migrate(:find_commit) do |is_enabled|
rescue Rugged::ReferenceError, Rugged::InvalidError, Rugged::ObjectError, Gitlab::Git::Repository::NoRepository if is_enabled
repo.gitaly_commit_client.find_commit(commit_id)
else
obj = repo.rev_parse_target(commit_id)
obj.is_a?(Rugged::Commit) ? obj : nil
end
end
decorate(repo, commit) if commit
rescue Rugged::ReferenceError, Rugged::InvalidError, Rugged::ObjectError,
Gitlab::Git::CommandError, Gitlab::Git::Repository::NoRepository
nil nil
end end
...@@ -102,7 +112,7 @@ module Gitlab ...@@ -102,7 +112,7 @@ module Gitlab
if is_enabled if is_enabled
repo.gitaly_commit_client.between(base, head) repo.gitaly_commit_client.between(base, head)
else else
repo.rugged_commits_between(base, head).map { |c| decorate(c) } repo.rugged_commits_between(base, head).map { |c| decorate(repo, c) }
end end
end end
rescue Rugged::ReferenceError rescue Rugged::ReferenceError
...@@ -169,7 +179,7 @@ module Gitlab ...@@ -169,7 +179,7 @@ module Gitlab
offset = actual_options[:skip] offset = actual_options[:skip]
limit = actual_options[:max_count] limit = actual_options[:max_count]
walker.each(offset: offset, limit: limit) do |commit| walker.each(offset: offset, limit: limit) do |commit|
commits.push(decorate(commit)) commits.push(decorate(repo, commit))
end end
walker.reset walker.reset
...@@ -183,27 +193,8 @@ module Gitlab ...@@ -183,27 +193,8 @@ module Gitlab
Gitlab::GitalyClient::CommitService.new(repo).find_all_commits(options) Gitlab::GitalyClient::CommitService.new(repo).find_all_commits(options)
end end
def decorate(commit, ref = nil) def decorate(repository, commit, ref = nil)
Gitlab::Git::Commit.new(commit, ref) Gitlab::Git::Commit.new(repository, commit, ref)
end
# Returns a diff object for the changes introduced by +rugged_commit+.
# If +rugged_commit+ doesn't have a parent, then the diff is between
# this commit and an empty repo. See Repository#diff for the keys
# allowed in the +options+ hash.
def diff_from_parent(rugged_commit, options = {})
options ||= {}
break_rewrites = options[:break_rewrites]
actual_options = Gitlab::Git::Diff.filter_diff_options(options)
diff = if rugged_commit.parents.empty?
rugged_commit.diff(actual_options.merge(reverse: true))
else
rugged_commit.parents[0].diff(rugged_commit, actual_options)
end
diff.find_similar!(break_rewrites: break_rewrites)
diff
end end
# Returns the `Rugged` sorting type constant for one or more given # Returns the `Rugged` sorting type constant for one or more given
...@@ -221,7 +212,7 @@ module Gitlab ...@@ -221,7 +212,7 @@ module Gitlab
end end
end end
def initialize(raw_commit, head = nil) def initialize(repository, raw_commit, head = nil)
raise "Nil as raw commit passed" unless raw_commit raise "Nil as raw commit passed" unless raw_commit
case raw_commit case raw_commit
...@@ -229,12 +220,13 @@ module Gitlab ...@@ -229,12 +220,13 @@ module Gitlab
init_from_hash(raw_commit) init_from_hash(raw_commit)
when Rugged::Commit when Rugged::Commit
init_from_rugged(raw_commit) init_from_rugged(raw_commit)
when Gitlab::GitalyClient::Commit when Gitaly::GitCommit
init_from_gitaly(raw_commit) init_from_gitaly(raw_commit)
else else
raise "Invalid raw commit type: #{raw_commit.class}" raise "Invalid raw commit type: #{raw_commit.class}"
end end
@repository = repository
@head = head @head = head
end end
...@@ -269,19 +261,50 @@ module Gitlab ...@@ -269,19 +261,50 @@ module Gitlab
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/324 # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/324
def to_diff def to_diff
diff_from_parent.patch rugged_diff_from_parent.patch
end end
# Returns a diff object for the changes from this commit's first parent. # Returns a diff object for the changes from this commit's first parent.
# If there is no parent, then the diff is between this commit and an # If there is no parent, then the diff is between this commit and an
# empty repo. See Repository#diff for keys allowed in the +options+ # empty repo. See Repository#diff for keys allowed in the +options+
# hash. # hash.
def diff_from_parent(options = {}) def diff_from_parent(options = {})
Commit.diff_from_parent(raw_commit, options) Gitlab::GitalyClient.migrate(:commit_raw_diffs) do |is_enabled|
if is_enabled
@repository.gitaly_commit_client.diff_from_parent(self, options)
else
rugged_diff_from_parent(options)
end
end
end
def rugged_diff_from_parent(options = {})
options ||= {}
break_rewrites = options[:break_rewrites]
actual_options = Gitlab::Git::Diff.filter_diff_options(options)
diff = if rugged_commit.parents.empty?
rugged_commit.diff(actual_options.merge(reverse: true))
else
rugged_commit.parents[0].diff(rugged_commit, actual_options)
end
diff.find_similar!(break_rewrites: break_rewrites)
diff
end end
def deltas def deltas
@deltas ||= diff_from_parent.each_delta.map { |d| Gitlab::Git::Diff.new(d) } @deltas ||= begin
deltas = Gitlab::GitalyClient.migrate(:commit_deltas) do |is_enabled|
if is_enabled
@repository.gitaly_commit_client.commit_deltas(self)
else
rugged_diff_from_parent.each_delta
end
end
deltas.map { |delta| Gitlab::Git::Diff.new(delta) }
end
end end
def has_zero_stats? def has_zero_stats?
...@@ -296,7 +319,7 @@ module Gitlab ...@@ -296,7 +319,7 @@ module Gitlab
def to_hash def to_hash
serialize_keys.map.with_object({}) do |key, hash| serialize_keys.map.with_object({}) do |key, hash|
hash[key] = send(key) hash[key] = send(key) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
...@@ -309,14 +332,7 @@ module Gitlab ...@@ -309,14 +332,7 @@ module Gitlab
end end
def parents def parents
case raw_commit parent_ids.map { |oid| self.class.find(@repository, oid) }.compact
when Rugged::Commit
raw_commit.parents.map { |c| Gitlab::Git::Commit.new(c) }
when Gitlab::GitalyClient::Commit
parent_ids.map { |oid| self.class.find(raw_commit.repository, oid) }.compact
else
raise NotImplementedError, "commit source doesn't support #parents"
end
end end
# Get the gpg signature of this commit. # Get the gpg signature of this commit.
...@@ -334,7 +350,7 @@ module Gitlab ...@@ -334,7 +350,7 @@ module Gitlab
def to_patch(options = {}) def to_patch(options = {})
begin begin
raw_commit.to_mbox(options) rugged_commit.to_mbox(options)
rescue Rugged::InvalidError => ex rescue Rugged::InvalidError => ex
if ex.message =~ /commit \w+ is a merge commit/i if ex.message =~ /commit \w+ is a merge commit/i
'Patch format is not currently supported for merge commits.' 'Patch format is not currently supported for merge commits.'
...@@ -382,13 +398,21 @@ module Gitlab ...@@ -382,13 +398,21 @@ module Gitlab
encode! @committer_email encode! @committer_email
end end
def rugged_commit
@rugged_commit ||= if raw_commit.is_a?(Rugged::Commit)
raw_commit
else
@repository.rev_parse_target(id)
end
end
private private
def init_from_hash(hash) def init_from_hash(hash)
raw_commit = hash.symbolize_keys raw_commit = hash.symbolize_keys
serialize_keys.each do |key| serialize_keys.each do |key|
send("#{key}=", raw_commit[key]) send("#{key}=", raw_commit[key]) # rubocop:disable GitlabSecurity/PublicSend
end end
end end
...@@ -415,10 +439,10 @@ module Gitlab ...@@ -415,10 +439,10 @@ module Gitlab
# subject from the message to make it clearer when there's one # subject from the message to make it clearer when there's one
# available but not the other. # available but not the other.
@message = (commit.body.presence || commit.subject).dup @message = (commit.body.presence || commit.subject).dup
@authored_date = Time.at(commit.author.date.seconds) @authored_date = Time.at(commit.author.date.seconds).utc
@author_name = commit.author.name.dup @author_name = commit.author.name.dup
@author_email = commit.author.email.dup @author_email = commit.author.email.dup
@committed_date = Time.at(commit.committer.date.seconds) @committed_date = Time.at(commit.committer.date.seconds).utc
@committer_name = commit.committer.name.dup @committer_name = commit.committer.name.dup
@committer_email = commit.committer.email.dup @committer_email = commit.committer.email.dup
@parent_ids = commit.parent_ids @parent_ids = commit.parent_ids
......
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