Commit 4c893925 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Merge remote-tracking branch 'upstream/master' into pipeline-emails

* upstream/master: (97 commits)
  Add missing spec for ProtectedBranches::CreateService
  Add specs that target status failure
  Return created status
  Document how to download the latest build artifacts
  Clarify why GH integration is the preferred importing method
  Refactor GitHub importing documentation
  Update GitHub importer documentation  to reflect current importer state
  Formatting fix in doc/ci/examples/README.md
  Refactor boards_spec.rb to avoid code duplication
  Replace contributions calendar timezone payload with dates
  Use oj gem for faster JSON processing
  Render invalid template for merge requests without source project and open
  Bump fog-aws and other dependent modules
  Fix API notes endpoint when posting only emoji
  Doesnt run JS if active element doesnt exist
  Add missing CHANGELOG entry
  Remove schema annotations completely
  fixed incorrect reference to @repository.root_ref in _readme.html.haml. #22083
  Scrolls active tab into middle of nav on mobile
  MergeRequest#environments now returns an empty array when diff_head_commit is nil
  ...
parents e0dbd816 1e7ea64e
*.erb
lib/gitlab/sanitizers/svg/whitelist.rb
......@@ -209,8 +209,12 @@ rubocop: *exec
rake haml_lint: *exec
rake scss_lint: *exec
rake brakeman: *exec
rake flog: *exec
rake flay: *exec
rake flog:
<<: *exec
allow_failure: yes
rake flay:
<<: *exec
allow_failure: yes
license_finder: *exec
rake downtime_check: *exec
......
......@@ -767,26 +767,33 @@ Rails/ScopeArgs:
RSpec/AnyInstance:
Enabled: false
# Check that the first argument to the top level describe is the tested class or
# module.
# Check for expectations where `be(...)` can replace `eql(...)`.
RSpec/BeEql:
Enabled: false
# Check that the first argument to the top level describe is a constant.
RSpec/DescribeClass:
Enabled: false
# Use `described_class` for tested class / module.
# Checks that tests use `described_class`.
RSpec/DescribedClass:
Enabled: false
# Checks that the second argument to `describe` specifies a method.
RSpec/DescribeMethod:
Enabled: false
# Checks that the second argument to top level describe is the tested method
# name.
RSpec/DescribedClass:
# Checks if an example group does not include any tests.
RSpec/EmptyExampleGroup:
Enabled: false
CustomIncludeMethods: []
# Checks for long example.
# Checks for long examples.
RSpec/ExampleLength:
Enabled: false
Max: 5
# Do not use should when describing your tests.
# Checks that example descriptions do not start with "should".
RSpec/ExampleWording:
Enabled: false
CustomTransform:
......@@ -795,6 +802,10 @@ RSpec/ExampleWording:
not: does not
IgnoredWords: []
# Checks for `expect(...)` calls containing literal values.
RSpec/ExpectActual:
Enabled: false
# Checks the file and folder naming of the spec file.
RSpec/FilePath:
Enabled: false
......@@ -806,19 +817,65 @@ RSpec/FilePath:
RSpec/Focus:
Enabled: true
# Checks the arguments passed to `before`, `around`, and `after`.
RSpec/HookArgument:
Enabled: false
EnforcedStyle: implicit
# Check that a consistent implict expectation style is used.
# TODO (rspeicher): Available in rubocop-rspec 1.8.0
# RSpec/ImplicitExpect:
# Enabled: true
# EnforcedStyle: is_expected
# Checks for the usage of instance variables.
RSpec/InstanceVariable:
Enabled: false
# Checks for multiple top-level describes.
# Checks for `subject` definitions that come after `let` definitions.
RSpec/LeadingSubject:
Enabled: false
# Checks unreferenced `let!` calls being used for test setup.
RSpec/LetSetup:
Enabled: false
# Check that chains of messages are not being stubbed.
RSpec/MessageChain:
Enabled: false
# Checks for consistent message expectation style.
RSpec/MessageExpectation:
Enabled: false
EnforcedStyle: allow
# Checks for multiple top level describes.
RSpec/MultipleDescribes:
Enabled: false
# Enforces the usage of the same method on all negative message expectations.
# Checks if examples contain too many `expect` calls.
RSpec/MultipleExpectations:
Enabled: false
Max: 1
# Checks for explicitly referenced test subjects.
RSpec/NamedSubject:
Enabled: false
# Checks for nested example groups.
RSpec/NestedGroups:
Enabled: false
MaxNesting: 2
# Checks for consistent method usage for negating expectations.
RSpec/NotToNot:
EnforcedStyle: not_to
Enabled: true
# Checks for stubbed test subjects.
RSpec/SubjectStub:
Enabled: false
# Prefer using verifying doubles over normal doubles.
RSpec/VerifiedDoubles:
Enabled: false
This diff is collapsed.
......@@ -3,10 +3,12 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.12.0 (unreleased)
- Update the rouge gem to 2.0.6, which adds highlighting support for JSX, Prometheus, and others. !6251
- Only check :can_resolve permission if the note is resolvable
- Bump fog-aws to v0.11.0 to support ap-south-1 region
- Add ability to fork to a specific namespace using API. (ritave)
- Cleanup misalignments in Issue list view !6206
- Prune events older than 12 months. (ritave)
- Prepend blank line to `Closes` message on merge request linked to issue (lukehowell)
- Fix issues/merge-request templates dropdown for forked projects
- Filter tags by name !6121
- Update gitlab shell secret file also when it is empty. !3774 (glensc)
- Give project selection dropdowns responsive width, make non-wrapping.
......@@ -21,27 +23,33 @@ v 8.12.0 (unreleased)
- Use Search::GlobalService.new in the `GET /projects/search/:query` endpoint
- Fix pagination on user snippets page
- Fix sorting of issues in API
- Sort project variables by key. !6275 (Diego Souza)
- Ensure specs on sorting of issues in API are deterministic on MySQL
- Escape search term before passing it to Regexp.new !6241 (winniehell)
- Fix pinned sidebar behavior in smaller viewports !6169
- Fix file permissions change when updating a file on the Gitlab UI !5979
- Change merge_error column from string to text type
- Reduce contributions calendar data payload (ClemMakesApps)
- Replace contributions calendar timezone payload with dates (ClemMakesApps)
- Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
- Enable pipeline events by default !6278
- Add pipeline email service !6019
- Move parsing of sidekiq ps into helper !6245 (pascalbetz)
- Added go to issue boards keyboard shortcut
- Expose `sha` and `merge_commit_sha` in merge request API (Ben Boeckel)
- Set path for all JavaScript cookies to honor GitLab's subdirectory setting !5627 (Mike Greiling)
- Fix blame table layout width
- Fix bug where pagination is still displayed despite all todos marked as done (ClemMakesApps)
- Request only the LDAP attributes we need !6187
- Center build stage columns in pipeline overview (ClemMakesApps)
- Fix bug with tooltip not hiding on discussion toggle button
- Rename behaviour to behavior in bug issue template for consistency (ClemMakesApps)
- Fix bug stopping issue description being scrollable after selecting issue template
- Remove suggested colors hover underline (ClemMakesApps)
- Shorten task status phrase (ClemMakesApps)
- Fix project visibility level fields on settings
- Add hover color to emoji icon (ClemMakesApps)
- Increase ci_builds artifacts_size column to 8-byte integer to allow larger files
- Add textarea autoresize after comment (ClemMakesApps)
- Refresh todos count cache when an Issue/MR is deleted
- Fix branches page dropdown sort alignment (ClemMakesApps)
......@@ -61,10 +69,12 @@ v 8.12.0 (unreleased)
- Use 'git update-ref' for safer web commits !6130
- Sort pipelines requested through the API
- Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling)
- Fix issue boards loading on large screens
- Change pipeline duration to be jobs running time instead of simple wall time from start to end !6084
- Show queued time when showing a pipeline !6084
- Remove unused mixins (ClemMakesApps)
- Add search to all issue board lists
- Scroll active tab into view on mobile
- Fix groups sort dropdown alignment (ClemMakesApps)
- Add horizontal scrolling to all sub-navs on mobile viewports (ClemMakesApps)
- Use JavaScript tooltips for mentions !5301 (winniehell)
......@@ -75,7 +85,8 @@ v 8.12.0 (unreleased)
- Add last commit time to repo view (ClemMakesApps)
- Fix accessibility and visibility of project list dropdown button !6140
- Fix missing flash messages on service edit page (airatshigapov)
- Added project specific enable/disable setting for LFS !5997
- Added project-specific enable/disable setting for LFS !5997
- Added group-specific enable/disable setting for LFS !6164
- Don't expose a user's token in the `/api/v3/user` API (!6047)
- Remove redundant js-timeago-pending from user activity log (ClemMakesApps)
- Ability to manage project issues, snippets, wiki, merge requests and builds access level
......@@ -131,13 +142,23 @@ v 8.12.0 (unreleased)
- Allow bulk update merge requests from merge requests index page
- Add notification_settings API calls !5632 (mahcsig)
- Remove duplication between project builds and admin builds view !5680 (Katarzyna Kobierska Ula Budziszewska)
- Fix URLs with anchors in wiki !6300 (houqp)
- Deleting source project with existing fork link will close all related merge requests !6177 (Katarzyna Kobierska Ula Budziszeska)
- Return 204 instead of 404 for /ci/api/v1/builds/register.json if no builds are scheduled for a runner !6225
- Fix Gitlab::Popen.popen thread-safety issue
v 8.11.6 (unreleased)
- Fix an error where we were unable to create a CommitStatus for running state
- Add specs to removing project (Katarzyna Kobierska Ula Budziszewska)
- Clean environment variables when running git hooks
- Fix non-master branch readme display in tree view
v 8.11.6
- Fix unnecessary horizontal scroll area in pipeline visualizations. !6005
- Make merge conflict file size limit 200 KB, to match the docs. !6052
- Fix an error where we were unable to create a CommitStatus for running state. !6107
- Optimize discussion notes resolving and unresolving. !6141
- Fix GitLab import button. !6167
- Restore SSH Key title auto-population behavior. !6186
- Fix DB schema to match latest migration. !6256
- Exclude some pending or inactivated rows in Member scopes.
v 8.11.5
- Optimize branch lookups and force a repository reload for Repository#find_branch. !6087
......@@ -150,6 +171,7 @@ v 8.11.5
- Scope webhooks/services that will run for confidential issues
- Remove gitorious from import_sources
- Fix confidential issues being exposed as public using gitlab.com export
- Use oj gem for faster JSON processing
v 8.11.4
- Fix resolving conflicts on forks. !6082
......@@ -342,6 +364,13 @@ v 8.11.0
- Update gitlab_git gem to 10.4.7
- Simplify SQL queries of marking a todo as done
v 8.10.9
- Exclude some pending or inactivated rows in Member scopes
v 8.10.8
- Fix information disclosure in issue boards.
- Fix privilege escalation in project import.
v 8.10.7
- Upgrade Hamlit to 2.6.1. !5873
- Upgrade Doorkeeper to 4.2.0. !5881
......@@ -567,6 +596,9 @@ v 8.10.0
- Fix migration corrupting import data for old version upgrades
- Show tooltip on GitLab export link in new project page
v 8.9.9
- Exclude some pending or inactivated rows in Member scopes
v 8.9.8
- Upgrade Doorkeeper to 4.2.0. !5881
......
......@@ -91,19 +91,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
## Implement design & UI elements
### Design reference
The GitLab design reference can be found in the [gitlab-design] project.
The designs are made using Antetype (`.atype` files). You can use the
[free Antetype viewer (Mac OSX only)] or grab an exported PNG from the design
(the PNG is 1:1).
The current designs can be found in the [`gitlab8.atype` file].
### UI development kit
Implemented UI elements can also be found at https://gitlab.com/help/ui. Please
note that this page isn't comprehensive at this time.
Please see the [UI Guide for building GitLab].
## Issue tracker
......@@ -289,6 +277,8 @@ request is as follows:
1. For more complex migrations, write tests.
1. Merge requests **must** adhere to the [merge request performance
guidelines](doc/development/merge_request_performance_guidelines.md).
1. For tests that use Capybara or PhantomJS, see this [article on how
to write reliable asynchronous tests](https://robots.thoughtbot.com/write-reliable-asynchronous-integration-tests-with-capybara).
The **official merge window** is in the beginning of the month from the 1st to
the 7th day of the month. This is the best time to submit an MR and get
......@@ -489,7 +479,5 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab8.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/current/
[UI Guide for building GitLab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/ui_guide.md
[license-finder-doc]: doc/development/licensing.md
......@@ -26,7 +26,7 @@ gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6'
gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-cas3', '~> 1.1.2'
gem 'omniauth-facebook', '~> 3.0.0'
gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.4.1'
......@@ -53,7 +53,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem 'gitlab_git', '~> 10.6.3'
gem 'gitlab_git', '~> 10.6.6'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
......@@ -206,6 +206,9 @@ gem 'mousetrap-rails', '~> 1.4.6'
# Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.7.3'
# Faster JSON
gem 'oj', '~> 2.17.4'
# Parse time & duration
gem 'chronic', '~> 0.10.2'
gem 'chronic_duration', '~> 0.10.6'
......@@ -295,8 +298,8 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.1.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.41.2', require: false
gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'rubocop', '~> 0.42.0', require: false
gem 'rubocop-rspec', '~> 1.7.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'haml_lint', '~> 0.18.2', require: false
gem 'simplecov', '0.12.0', require: false
......
......@@ -189,7 +189,7 @@ GEM
erubis (2.7.0)
escape_utils (1.1.1)
eventmachine (1.0.8)
excon (0.49.0)
excon (0.52.0)
execjs (2.6.0)
expression_parser (0.9.0)
factory_girl (4.5.0)
......@@ -215,8 +215,8 @@ GEM
flowdock (0.7.1)
httparty (~> 0.7)
multi_json
fog-aws (0.9.2)
fog-core (~> 1.27)
fog-aws (0.11.0)
fog-core (~> 1.38)
fog-json (~> 1.0)
fog-xml (~> 0.1)
ipaddress (~> 0.8)
......@@ -225,7 +225,7 @@ GEM
fog-core (~> 1.27)
fog-json (~> 1.0)
fog-xml (~> 0.1)
fog-core (1.40.0)
fog-core (1.42.0)
builder
excon (~> 0.49)
formatador (~> 0.2)
......@@ -279,7 +279,7 @@ GEM
diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3)
gitlab_git (10.6.3)
gitlab_git (10.6.6)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
......@@ -333,7 +333,7 @@ GEM
temple (~> 0.7.6)
thor
tilt
hashie (3.4.3)
hashie (3.4.4)
health_check (2.1.0)
rails (>= 4.0)
hipchat (1.5.2)
......@@ -401,7 +401,7 @@ GEM
mime-types (>= 1.16, < 4)
mail_room (0.8.0)
method_source (0.8.2)
mime-types (2.99.2)
mime-types (2.99.3)
mimemagic (0.3.0)
mini_portile2 (2.1.0)
minitest (5.7.0)
......@@ -427,6 +427,7 @@ GEM
rack (>= 1.2, < 3)
octokit (4.3.0)
sawyer (~> 0.7.0, >= 0.5.3)
oj (2.17.4)
omniauth (1.3.1)
hashie (>= 1.2, < 4)
rack (>= 1.0, < 3)
......@@ -444,7 +445,7 @@ GEM
addressable (~> 2.3)
nokogiri (~> 1.6.6)
omniauth (~> 1.2)
omniauth-facebook (3.0.0)
omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2)
omniauth (~> 1.0)
......@@ -619,14 +620,14 @@ GEM
rspec-retry (0.4.5)
rspec-core
rspec-support (3.5.0)
rubocop (0.41.2)
rubocop (0.42.0)
parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-rspec (1.5.0)
rubocop (>= 0.40.0)
rubocop-rspec (1.7.0)
rubocop (>= 0.42.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-prof (0.15.9)
......@@ -762,7 +763,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
unicode-display_width (1.1.0)
unicode-display_width (1.1.1)
unicorn (4.9.0)
kgio (~> 2.6)
rack
......@@ -866,7 +867,7 @@ DEPENDENCIES
github-linguist (~> 4.7.0)
github-markup (~> 1.4)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_git (~> 10.6.3)
gitlab_git (~> 10.6.6)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2)
......@@ -904,12 +905,13 @@ DEPENDENCIES
nokogiri (~> 1.6.7, >= 1.6.7.2)
oauth2 (~> 1.2.0)
octokit (~> 4.3.0)
oj (~> 2.17.4)
omniauth (~> 1.3.1)
omniauth-auth0 (~> 1.4.1)
omniauth-azure-oauth2 (~> 0.0.6)
omniauth-bitbucket (~> 0.0.2)
omniauth-cas3 (~> 1.1.2)
omniauth-facebook (~> 3.0.0)
omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.4.1)
......@@ -944,8 +946,8 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5)
rubocop (~> 0.41.2)
rubocop-rspec (~> 1.5.0)
rubocop (~> 0.42.0)
rubocop-rspec (~> 1.7.0)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.15.9)
sanitize (~> 2.0)
......
......@@ -251,6 +251,7 @@
} else {
notesHolders.hide();
}
$this.trigger('blur');
return e.preventDefault();
});
$document.off("click", '.js-confirm-danger');
......
......@@ -13,6 +13,9 @@
this.buildDropdown();
this.bindEvents();
this.onFilenameUpdate();
this.autosizeUpdateEvent = document.createEvent('Event');
this.autosizeUpdateEvent.initEvent('autosize:update', true, false);
}
TemplateSelector.prototype.buildDropdown = function() {
......@@ -72,6 +75,10 @@
TemplateSelector.prototype.requestFileSuccess = function(file, skipFocus) {
this.editor.setValue(file.content, 1);
if (!skipFocus) this.editor.focus();
if (this.editor instanceof jQuery) {
this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent);
}
};
TemplateSelector.prototype.startLoadingSpinner = function() {
......
......@@ -34,6 +34,11 @@
},
issues () {
this.$nextTick(() => {
if (this.scrollHeight() <= this.listHeight() && this.list.issuesSize > this.list.issues.length) {
this.list.page++;
this.list.getIssues(false);
}
if (this.scrollHeight() > this.listHeight()) {
this.showCount = true;
} else {
......
......@@ -352,7 +352,13 @@
if (self.options.clicked) {
self.options.clicked(selected, $el, e);
}
return $el.trigger('blur');
// Update label right after all modifications in dropdown has been done
if (self.options.toggleLabel) {
self.updateLabel(selected, $el, self);
}
$el.trigger('blur');
});
}
}
......@@ -529,7 +535,7 @@
} else {
if (!selected) {
value = this.options.id ? this.options.id(data) : data.id;
fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName() : this.options.fieldName;
fieldName = this.options.fieldName;
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']");
if (field.length) {
......@@ -589,6 +595,7 @@
GitLabDropdown.prototype.rowClicked = function(el) {
var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value;
fieldName = this.options.fieldName;
isInput = $(this.el).is('input');
if (this.renderedData) {
groupName = el.data('group');
......@@ -600,7 +607,6 @@
selectedObject = this.renderedData[selectedIndex];
}
}
fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName(selectedObject) : this.options.fieldName;
value = this.options.id ? this.options.id(selectedObject, el) : selectedObject.id;
if (isInput) {
field = $(this.el);
......@@ -644,11 +650,6 @@
}
}
// Update label right after input has been added
if (this.options.toggleLabel) {
this.updateLabel(selectedObject, el, this);
}
return selectedObject;
};
......@@ -659,9 +660,6 @@
if (this.options.inputId != null) {
$input.attr('id', this.options.inputId);
}
if (selectedObject && selectedObject.type) {
$input.attr('data-type', selectedObject.type);
}
return this.dropdown.before($input);
};
......
......@@ -10,11 +10,13 @@
};
$(function() {
hideEndFade($('.scrolling-tabs'));
var $scrollingTabs = $('.scrolling-tabs');
hideEndFade($scrollingTabs);
$(window).off('resize.nav').on('resize.nav', function() {
return hideEndFade($('.scrolling-tabs'));
return hideEndFade($scrollingTabs);
});
return $('.scrolling-tabs').on('scroll', function(event) {
$scrollingTabs.off('scroll').on('scroll', function(event) {
var $this, currentPosition, maxPosition;
$this = $(this);
currentPosition = $this.scrollLeft();
......@@ -22,6 +24,23 @@
$this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0);
return $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1);
});
$scrollingTabs.each(function () {
var $this = $(this),
scrollingTabWidth = $this.width(),
$active = $this.find('.active'),
activeWidth = $active.width();
if ($active.length) {
var offset = $active.offset().left + activeWidth;
if (offset > scrollingTabWidth - 30) {
var scrollLeft = scrollingTabWidth / 2;
scrollLeft = (offset - scrollLeft) - (activeWidth / 2);
$this.scrollLeft(scrollLeft);
}
}
});
});
}).call(this);
......@@ -232,10 +232,10 @@
$('.hll').removeClass('hll');
locationHash = window.location.hash;
if (locationHash !== '') {
hashClassString = "." + (locationHash.replace('#', ''));
dataLineString = '[data-line-code="' + locationHash.replace('#', '') + '"]';
$diffLine = $(locationHash + ":not(.match)", $('#diffs'));
if (!$diffLine.is('tr')) {
$diffLine = $('#diffs').find("td" + locationHash + ", td" + hashClassString);
$diffLine = $('#diffs').find("td" + locationHash + ", td" + dataLineString);
} else {
$diffLine = $diffLine.find('td');
}
......
......@@ -34,6 +34,9 @@
Mousetrap.bind('g i', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues');
});
Mousetrap.bind('g l', function() {
ShortcutsNavigation.findAndFollowLink('.shortcuts-issue-boards');
});
Mousetrap.bind('g m', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests');
});
......
......@@ -29,7 +29,7 @@
date.setDate(date.getDate() + i);
var day = date.getDay();
var count = timestamps[date.getTime() * 0.001];
var count = timestamps[dateFormat(date, 'yyyy-mm-dd')];
// Create a new group array if this is the first day of the week
// or if is first object
......
......@@ -162,6 +162,10 @@ ul.content-list {
margin-right: 0;
}
}
.no-comments {
opacity: 0.5;
}
}
// When dragging a list item
......
......@@ -164,7 +164,7 @@
text-decoration: none;
&:after {
content: url('icon_anchor.svg');
content: image-url('icon_anchor.svg');
visibility: hidden;
}
}
......
lex
[v-cloak] {
display: none;
}
......@@ -18,6 +19,10 @@
}
}
.is-ghost {
opacity: 0.3;
}
.dropdown-menu-issues-board-new {
width: 320px;
......@@ -34,47 +39,13 @@
> p {
margin: 0;
font-size: 14px;
color: #9c9c9c;
}
}
.issue-boards-page {
.content-wrapper {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
}
.sub-nav,
.issues-filters {
-webkit-flex: none;
flex: none;
}
.page-with-sidebar {
display: -webkit-flex;
display: flex;
min-height: 100vh;
max-height: 100vh;
padding-bottom: 0;
}
.issue-boards-content {
display: -webkit-flex;
display: flex;
-webkit-flex: 1;
flex: 1;
width: 100%;
.content {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
width: 100%;
}
}
}
.boards-app-loading {
......@@ -83,46 +54,38 @@
}
.boards-list {
display: -webkit-flex;
display: flex;
-webkit-flex: 1;
flex: 1;
-webkit-flex-basis: 0;
flex-basis: 0;
min-height: calc(100vh - 152px);
max-height: calc(100vh - 152px);
height: calc(100vh - 152px);
width: 100%;
padding-top: 25px;
padding-bottom: 25px;
padding-right: ($gl-padding / 2);
padding-left: ($gl-padding / 2);
overflow-x: scroll;
white-space: nowrap;
@media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
height: calc(100vh - 220px);
min-height: 475px;
max-height: none;
}
}
.board {
display: -webkit-flex;
display: flex;
min-width: calc(85vw - 15px);
max-width: calc(85vw - 15px);
margin-bottom: 25px;
display: inline-block;
width: calc(85vw - 15px);
height: 100%;
padding-right: ($gl-padding / 2);
padding-left: ($gl-padding / 2);
white-space: normal;
vertical-align: top;
@media (min-width: $screen-sm-min) {
min-width: 400px;
max-width: 400px;
width: 400px;
}
}
.board-inner {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
width: 100%;
height: 100%;
font-size: $issue-boards-font-size;
background: $background-color;
border: 1px solid $border-color;
......@@ -193,45 +156,31 @@
}
.board-list {
-webkit-flex: 1;
flex: 1;
height: 400px;
height: calc(100% - 49px);
margin-bottom: 0;
padding: 5px;
list-style: none;
overflow-y: scroll;
overflow-x: hidden;
}
.board-list-loading {
margin-top: 10px;
font-size: 26px;
}
.is-ghost {
opacity: 0.3;
font-size: (26px / $issue-boards-font-size) * 1em;
}
.card {
position: relative;
width: 100%;
padding: 10px $gl-padding;
background: #fff;
border-radius: $border-radius-default;
box-shadow: 0 1px 2px rgba(186, 186, 186, 0.5);
list-style: none;
&.user-can-drag {
padding-left: $gl-padding;
}
&:not(:last-child) {
margin-bottom: 5px;
}
a {
cursor: pointer;
}
.label {
border: 0;
outline: 0;
......@@ -256,14 +205,13 @@
line-height: 25px;
.label {
margin-right: 4px;
margin-right: 5px;
font-size: (14px / $issue-boards-font-size) * 1em;
}
}
.card-number {
margin-right: 8px;
font-weight: 500;
margin-right: 5px;
}
.issue-boards-search {
......
......@@ -10,10 +10,6 @@
.issue-labels {
display: inline-block;
}
.issue-no-comments {
opacity: 0.5;
}
}
}
......
......@@ -231,10 +231,6 @@
.merge-request-labels {
display: inline-block;
}
.merge-request-no-comments {
opacity: 0.5;
}
}
.merge-request-angle {
......
......@@ -147,14 +147,37 @@
}
.stage-cell {
text-align: center;
font-size: 0;
svg {
height: 18px;
width: 18px;
position: relative;
z-index: 2;
vertical-align: middle;
overflow: visible;
}
.stage-container {
display: inline-block;
position: relative;
margin-right: 6px;
.tooltip {
white-space: nowrap;
}
&:not(:last-child) {
&::after {
content: '';
width: 8px;
position: absolute;;
right: -7px;
bottom: 8px;
border-bottom: 2px solid $border-color;
}
}
}
}
.duration,
......@@ -318,9 +341,17 @@
.build-content {
width: 130px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.ci-status-text {
width: 110px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
display: inline-block;
position: relative;
top: -1px;
}
a {
color: $layout-link-gray;
......@@ -331,13 +362,74 @@
text-decoration: underline;
}
}
}
.dropdown-menu-toggle {
border: none;
width: auto;
padding: 0;
color: $layout-link-gray;
.ci-status-text {
width: 80px;
}
}
.grouped-pipeline-dropdown {
padding: 8px 0;
width: 200px;
left: auto;
right: -214px;
top: -9px;
a:hover {
.ci-status-text {
text-decoration: none;
}
}
.ci-status-text {
width: 145px;
}
.arrow {
&:before,
&:after {
content: '';
display: inline-block;
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
top: 18px;
}
&:before {
left: -5px;
margin-top: -6px;
border-width: 7px 5px 7px 0;
border-right-color: $border-color;
}
&:after {
left: -4px;
margin-top: -9px;
border-width: 10px 7px 10px 0;
border-right-color: $white-light;
}
}
}
.badge {
background-color: $gray-dark;
color: $layout-link-gray;
font-weight: normal;
}
}
svg {
position: relative;
top: 2px;
vertical-align: middle;
margin-right: 5px;
}
......@@ -442,7 +534,7 @@
width: 21px;
height: 25px;
position: absolute;
top: -28.5px;
top: -29px;
border-top: 2px solid $border-color;
}
......
......@@ -334,6 +334,10 @@ a.deploy-project-label {
a {
color: $gl-dark-link-color;
}
.dropdown-menu {
width: 240px;
}
}
.last-push-widget {
......
......@@ -2,20 +2,6 @@
padding: 2px;
}
.snippet-holder {
margin-bottom: -$gl-padding;
.file-holder {
border-top: 0;
}
.file-actions {
.btn-clipboard {
@extend .btn;
}
}
}
.markdown-snippet-copy {
position: fixed;
top: -10px;
......@@ -24,29 +10,18 @@
max-width: 0;
}
.file-holder.snippet-file-content {
padding-bottom: $gl-padding;
border-bottom: 1px solid $border-color;
.file-title {
padding-top: $gl-padding;
padding-bottom: $gl-padding;
}
.file-actions {
top: 12px;
}
.file-content {
border-left: 1px solid $border-color;
border-right: 1px solid $border-color;
border-bottom: 1px solid $border-color;
.snippet-file-content {
border-radius: 3px;
.btn-clipboard {
@extend .btn;
}
}
.snippet-title {
font-size: 24px;
font-weight: normal;
font-weight: 600;
padding: $gl-padding;
padding-left: 0;
}
.snippet-actions {
......
......@@ -60,6 +60,14 @@ class Admin::GroupsController < Admin::ApplicationController
end
def group_params
params.require(:group).permit(:name, :description, :path, :avatar, :visibility_level, :request_access_enabled)
params.require(:group).permit(
:avatar,
:description,
:lfs_enabled,
:name,
:path,
:request_access_enabled,
:visibility_level
)
end
end
......@@ -121,7 +121,17 @@ class GroupsController < Groups::ApplicationController
end
def group_params
params.require(:group).permit(:name, :description, :path, :avatar, :public, :visibility_level, :share_with_group_lock, :request_access_enabled)
params.require(:group).permit(
:avatar,
:description,
:lfs_enabled,
:name,
:path,
:public,
:request_access_enabled,
:share_with_group_lock,
:visibility_level
)
end
def load_events
......
......@@ -74,7 +74,7 @@ class Projects::BuildsController < Projects::ApplicationController
def erase
@build.erase(erased_by: current_user)
redirect_to namespace_project_build_path(project.namespace, project, @build),
notice: "Build has been sucessfully erased!"
notice: "Build has been successfully erased!"
end
def raw
......
......@@ -428,6 +428,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def validates_merge_request
# If source project was removed and merge request for some reason
# wasn't close (Ex. mr from fork to origin)
return invalid_mr if !@merge_request.source_project && @merge_request.open?
# Show git not found page
# if there is no saved commits between source & target branch
if @merge_request.commits.blank?
......
......@@ -73,7 +73,7 @@ class UsersController < ApplicationController
def calendar
calendar = contributions_calendar
@timestamps = calendar.timestamps
@activity_dates = calendar.activity_dates
render 'calendar', layout: false
end
......
......@@ -23,4 +23,29 @@ module GroupsHelper
full_title
end
end
def projects_lfs_status(group)
lfs_status =
if group.lfs_enabled?
group.projects.select(&:lfs_enabled?).size
else
group.projects.reject(&:lfs_enabled?).size
end
size = group.projects.size
if lfs_status == size
'for all projects'
else
"for #{lfs_status} out of #{pluralize(size, 'project')}"
end
end
def group_lfs_status(group)
status = group.lfs_enabled? ? 'enabled' : 'disabled'
content_tag(:span, class: "lfs-#{status}") do
"#{status.humanize} #{projects_lfs_status(group)}"
end
end
end
......@@ -27,7 +27,7 @@ module ProjectsHelper
author_html = ""
# Build avatar image tag
author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar]
author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]} #{opts[:avatar_class] if opts[:avatar_class]}", alt: '') if opts[:avatar]
# Build name span tag
if opts[:by_username]
......
......@@ -30,6 +30,37 @@ module SearchHelper
"Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\""
end
def parse_search_result(result)
ref = nil
filename = nil
basename = nil
startline = 0
result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
startline = startline.to_i - index
extname = Regexp.escape(File.extname(filename))
basename = filename.sub(/#{extname}$/, '')
break
end
end
data = ""
result.each_line do |line|
data << line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
end
OpenStruct.new(
filename: filename,
basename: basename,
ref: ref,
startline: startline,
data: data
)
end
private
# Autocomplete results for various settings pages
......
module SnippetsHelper
def reliable_snippet_path(snippet)
def reliable_snippet_path(snippet, opts = nil)
if snippet.project_id?
namespace_project_snippet_path(snippet.project.namespace,
snippet.project, snippet)
snippet.project, snippet, opts)
else
snippet_path(snippet)
snippet_path(snippet, opts)
end
end
......
......@@ -22,6 +22,18 @@ class Blob < SimpleDelegator
new(blob)
end
# Returns the data of the blob.
#
# If the blob is a text based blob the content is converted to UTF-8 and any
# invalid byte sequences are replaced.
def data
if binary?
super
else
@data ||= super.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
end
end
def no_highlighting?
size && size > 1.megabyte
end
......
module Ci
class Variable < ActiveRecord::Base
extend Ci::Model
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
validates_uniqueness_of :key, scope: :gl_project_id
......@@ -11,7 +11,9 @@ module Ci
format: { with: /\A[a-zA-Z0-9_]+\z/,
message: "can contain only letters, digits and '_'." }
attr_encrypted :value,
scope :order_key_asc, -> { reorder(key: :asc) }
attr_encrypted :value,
mode: :per_attribute_iv_and_salt,
insecure_mode: true,
key: Gitlab::Application.secrets.db_key_base,
......
......@@ -69,17 +69,15 @@ class CommitStatus < ActiveRecord::Base
commit_status.update_attributes finished_at: Time.now
end
# We use around_transition to process pipeline on next stages as soon as possible, before the `after_*` is executed
around_transition any => [:success, :failed, :canceled] do |commit_status, block|
block.call
commit_status.pipeline.try(:process!)
end
after_transition do |commit_status, transition|
commit_status.pipeline.try(:build_updated) unless transition.loopback?
end
after_transition any => [:success, :failed, :canceled] do |commit_status|
commit_status.pipeline.try(:process!)
true
end
after_transition [:created, :pending, :running] => :success do |commit_status|
MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status)
end
......@@ -95,6 +93,10 @@ class CommitStatus < ActiveRecord::Base
pipeline.before_sha || Gitlab::Git::BLANK_SHA
end
def group_name
name.gsub(/\d+[\s:\/\\]+\d+\s*/, '').strip
end
def self.stages
# We group by stage name, but order stages by theirs' index
unscoped.from(all, :sg).group('stage').order('max(stage_idx)', 'stage').pluck('sg.stage')
......@@ -113,6 +115,10 @@ class CommitStatus < ActiveRecord::Base
allow_failure? && (failed? || canceled?)
end
def playable?
false
end
def duration
calculate_duration
end
......
......@@ -8,8 +8,9 @@ module HasStatus
class_methods do
def status_sql
scope = all.relevant
scope = all
builds = scope.select('count(*)').to_sql
created = scope.created.select('count(*)').to_sql
success = scope.success.select('count(*)').to_sql
ignored = scope.ignored.select('count(*)').to_sql if scope.respond_to?(:ignored)
ignored ||= '0'
......@@ -19,12 +20,12 @@ module HasStatus
skipped = scope.skipped.select('count(*)').to_sql
deduce_status = "(CASE
WHEN (#{builds})=0 THEN NULL
WHEN (#{builds})=(#{created}) THEN 'created'
WHEN (#{builds})=(#{skipped}) THEN 'skipped'
WHEN (#{builds})=(#{success})+(#{ignored})+(#{skipped}) THEN 'success'
WHEN (#{builds})=(#{pending})+(#{skipped}) THEN 'pending'
WHEN (#{builds})=(#{created})+(#{pending})+(#{skipped}) THEN 'pending'
WHEN (#{builds})=(#{canceled})+(#{success})+(#{ignored})+(#{skipped}) THEN 'canceled'
WHEN (#{running})+(#{pending})>0 THEN 'running'
WHEN (#{running})+(#{pending})+(#{created})>0 THEN 'running'
ELSE 'failed'
END)"
......
......@@ -95,6 +95,13 @@ class Group < Namespace
end
end
def lfs_enabled?
return false unless Gitlab.config.lfs.enabled
return Gitlab.config.lfs.enabled if self[:lfs_enabled].nil?
self[:lfs_enabled]
end
def add_users(user_ids, access_level, current_user: nil, expires_at: nil)
user_ids.each do |user_id|
Member.add_user(
......
......@@ -28,17 +28,34 @@ class Member < ActiveRecord::Base
allow_nil: true
}
# This scope encapsulates (most of) the conditions a row in the member table
# must satisfy if it is a valid permission. Of particular note:
#
# * Access requests must be excluded
# * Blocked users must be excluded
# * Invitations take effect immediately
# * expires_at is not implemented. A background worker purges expired rows
scope :active, -> do
is_external_invite = arel_table[:user_id].eq(nil).and(arel_table[:invite_token].not_eq(nil))
user_is_active = User.arel_table[:state].eq(:active)
includes(:user).references(:users)
.where(is_external_invite.or(user_is_active))
.where(requested_at: nil)
end
scope :invite, -> { where.not(invite_token: nil) }
scope :non_invite, -> { where(invite_token: nil) }
scope :request, -> { where.not(requested_at: nil) }
scope :has_access, -> { where('access_level > 0') }
scope :guests, -> { where(access_level: GUEST) }
scope :reporters, -> { where(access_level: REPORTER) }
scope :developers, -> { where(access_level: DEVELOPER) }
scope :masters, -> { where(access_level: MASTER) }
scope :owners, -> { where(access_level: OWNER) }
scope :owners_and_masters, -> { where(access_level: [OWNER, MASTER]) }
scope :has_access, -> { active.where('access_level > 0') }
scope :guests, -> { active.where(access_level: GUEST) }
scope :reporters, -> { active.where(access_level: REPORTER) }
scope :developers, -> { active.where(access_level: DEVELOPER) }
scope :masters, -> { active.where(access_level: MASTER) }
scope :owners, -> { active.where(access_level: OWNER) }
scope :owners_and_masters, -> { active.where(access_level: [OWNER, MASTER]) }
before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? }
......
......@@ -652,7 +652,7 @@ class MergeRequest < ActiveRecord::Base
end
def environments
return unless diff_head_commit
return [] unless diff_head_commit
target_project.environments.select do |environment|
environment.includes_commit?(diff_head_commit)
......
......@@ -141,6 +141,11 @@ class Namespace < ActiveRecord::Base
projects.joins(:forked_project_link).find_by('forked_project_links.forked_from_project_id = ?', project.id)
end
def lfs_enabled?
# User namespace will always default to the global setting
Gitlab.config.lfs.enabled
end
private
def repository_storage_paths
......
......@@ -394,10 +394,9 @@ class Project < ActiveRecord::Base
end
def lfs_enabled?
return false unless Gitlab.config.lfs.enabled
return Gitlab.config.lfs.enabled if self[:lfs_enabled].nil?
return namespace.lfs_enabled? if self[:lfs_enabled].nil?
self[:lfs_enabled]
self[:lfs_enabled] && Gitlab.config.lfs.enabled
end
def repository_storage_path
......
......@@ -990,37 +990,6 @@ class Repository
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end
def parse_search_result(result)
ref = nil
filename = nil
basename = nil
startline = 0
result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
startline = startline.to_i - index
extname = Regexp.escape(File.extname(filename))
basename = filename.sub(/#{extname}$/, '')
break
end
end
data = ""
result.each_line do |line|
data << line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
end
OpenStruct.new(
filename: filename,
basename: basename,
ref: ref,
startline: startline,
data: data
)
end
def fetch_ref(source_path, source_ref, target_ref)
args = %W(#{Gitlab.config.git.bin_path} fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo)
......@@ -1048,7 +1017,7 @@ class Repository
GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do
update_ref!(ref, newrev, oldrev)
if was_empty || !target_branch
# If repo was empty expire cache
after_create if was_empty
......
......@@ -16,11 +16,29 @@ module Commits
error(ex.message)
end
private
def commit
raise NotImplementedError
end
private
def commit_change(action)
raise NotImplementedError unless repository.respond_to?(action)
into = @create_merge_request ? @commit.public_send("#{action}_branch_name") : @target_branch
tree_id = repository.public_send("check_#{action}_content", @commit, @target_branch)
if tree_id
create_target_branch(into) if @create_merge_request
repository.public_send(action, current_user, @commit, into, tree_id)
success
else
error_msg = "Sorry, we cannot #{action.to_s.dasherize} this #{@commit.change_type_title} automatically.
It may have already been #{action.to_s.dasherize}, or a more recent commit may have updated some of its content."
raise ChangeError, error_msg
end
end
def check_push_permissions
allowed = ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(@target_branch)
......
module Commits
class CherryPickService < ChangeService
def commit
cherry_pick_into = @create_merge_request ? @commit.cherry_pick_branch_name : @target_branch
cherry_pick_tree_id = repository.check_cherry_pick_content(@commit, @target_branch)
if cherry_pick_tree_id
create_target_branch(cherry_pick_into) if @create_merge_request
repository.cherry_pick(current_user, @commit, cherry_pick_into, cherry_pick_tree_id)
success
else
error_msg = "Sorry, we cannot cherry-pick this #{@commit.change_type_title} automatically.
It may have already been cherry-picked, or a more recent commit may have updated some of its content."
raise ChangeError, error_msg
end
commit_change(:cherry_pick)
end
end
end
module Commits
class RevertService < ChangeService
def commit
revert_into = @create_merge_request ? @commit.revert_branch_name : @target_branch
revert_tree_id = repository.check_revert_content(@commit, @target_branch)
if revert_tree_id
create_target_branch(revert_into) if @create_merge_request
repository.revert(current_user, @commit, revert_into, revert_tree_id)
success
else
error_msg = "Sorry, we cannot revert this #{@commit.change_type_title} automatically.
It may have already been reverted, or a more recent commit may have updated some of its content."
raise ChangeError, error_msg
end
commit_change(:revert)
end
end
end
......@@ -13,6 +13,8 @@
.col-sm-offset-2.col-sm-10
= render 'shared/allow_request_access', form: f
= render 'groups/group_lfs_settings', f: f
- if @group.new_record?
.form-group
.col-sm-offset-2.col-sm-10
......
......@@ -37,6 +37,12 @@
%strong
= @group.created_at.to_s(:medium)
%li
%span.light Group Git LFS status:
%strong
= group_lfs_status(@group)
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
.panel.panel-default
.panel-heading
%h3.panel-title
......
- if current_user.admin?
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :lfs_enabled do
= f.check_box :lfs_enabled, checked: @group.lfs_enabled?
%strong
Allow projects within this group to use Git LFS
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
%br/
%span.descr This setting can be overridden in each project.
\ No newline at end of file
......@@ -25,6 +25,8 @@
.col-sm-offset-2.col-sm-10
= render 'shared/allow_request_access', form: f
= render 'group_lfs_settings', f: f
.form-group
%hr
= f.label :share_with_group_lock, class: 'control-label' do
......
......@@ -162,6 +162,12 @@
.key i
%td
Go to issues
%tr
%td.shortcut
.key g
.key l
%td
Go to issue boards
%tr
%td.shortcut
.key g
......
......@@ -113,3 +113,7 @@
%li.hidden
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
Commits
-# Shortcut to issue boards
%li.hidden
= link_to 'Issue Boards', namespace_project_board_path(@project.namespace, @project), title: 'Issue Boards', class: 'shortcuts-issue-boards'
- if @user.valid?
:plain
new Flash("Username sucessfully changed", "notice")
new Flash("Username successfully changed", "notice")
- else
:plain
new Flash("Username change failed - #{@user.errors.full_messages.first}", "alert")
- is_playable = subject.playable? && can?(current_user, :update_build, @project)
%li.build{class: ("playable" if is_playable)}
.curve
.build-content
- if is_playable
= link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do
= render_status_with_link('build', 'play')
%span.ci-status-text= subject.name
- elsif can?(current_user, :read_build, @project)
= link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do
= render_status_with_link('build', subject.status)
%span.ci-status-text= subject.name
- else
= render_status_with_link('build', subject.status)
= ci_icon_for_status(subject.status)
- if is_playable
= link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do
= render_status_with_link('build', 'play')
.ci-status-text= subject.name
- elsif can?(current_user, :read_build, @project)
= link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do
= render_status_with_link('build', subject.status)
.ci-status-text= subject.name
- else
= render_status_with_link('build', subject.status)
= ci_icon_for_status(subject.status)
......@@ -36,16 +36,14 @@
- stages_status = pipeline.statuses.relevant.latest.stages_status
- stages.each do |stage|
%td.stage-cell
%td.stage-cell
- stages.each do |stage|
- status = stages_status[stage]
- tooltip = "#{stage.titleize}: #{status || 'not found'}"
- if status
= link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do
= ci_icon_for_status(status)
- else
.light.has-tooltip{ title: tooltip }
\-
.stage-container
= link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do
= ci_icon_for_status(status)
%td
- if pipeline.duration
......
......@@ -39,8 +39,7 @@
= stage.titleize
.builds-container
%ul
- statuses.each do |status|
= render "projects/#{status.to_partial_path}_pipeline", subject: status
= render "projects/commit/pipeline_stage", statuses: statuses
- if pipeline.yaml_errors.present?
......
- status_groups = statuses.group_by(&:group_name)
- status_groups.each do |group_name, grouped_statuses|
- if grouped_statuses.one?
- status = grouped_statuses.first
- is_playable = status.playable? && can?(current_user, :update_build, @project)
%li.build{ class: ("playable" if is_playable) }
.curve
.build-content
= render "projects/#{status.to_partial_path}_pipeline", subject: status
- else
%li.build
.curve
.build-content
= render "projects/commit/pipeline_status_group", name: group_name, subject: grouped_statuses
- group_status = CommitStatus.where(id: subject).status
= render_status_with_link('build', group_status)
.dropdown.inline
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown' } }
%span.ci-status-text
= name
%span.badge= subject.size
%ul.dropdown-menu.grouped-pipeline-dropdown
.arrow
- subject.each do |status|
= render "projects/#{status.to_partial_path}_pipeline", subject: status
......@@ -84,15 +84,14 @@
= project_feature_access_select(:snippets_access_level)
- if Gitlab.config.lfs.enabled && current_user.admin?
.form-group
.checkbox
= f.label :lfs_enabled do
= f.check_box :lfs_enabled, checked: @project.lfs_enabled?
%strong LFS
%br
%span.descr
Git Large File Storage
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
.row
.col-md-9
= f.label :lfs_enabled, 'LFS', class: 'label-light'
%span.help-block
Git Large File Storage
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
.col-md-3
= f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control'
- if Gitlab.config.registry.enabled
.form-group
......
%li.build
.curve
.build-content
- if subject.target_url
- link_to subject.target_url do
= render_status_with_link('commit status', subject.status)
%span.ci-status-text= subject.name
- else
= render_status_with_link('commit status', subject.status)
%span.ci-status-text= subject.name
- if subject.target_url
= link_to subject.target_url do
= render_status_with_link('commit status', subject.status)
%span.ci-status-text= subject.name
- else
= render_status_with_link('commit status', subject.status)
%span.ci-status-text= subject.name
......@@ -29,7 +29,7 @@
- note_count = issue.notes.user.count
%li
= link_to issue_path(issue, anchor: 'notes'), class: ('issue-no-comments' if note_count.zero?) do
= link_to issue_path(issue, anchor: 'notes'), class: ('no-comments' if note_count.zero?) do
= icon('comments')
= note_count
......
......@@ -41,7 +41,7 @@
- note_count = merge_request.mr_and_commit_notes.user.count
%li
= link_to merge_request_path(merge_request, anchor: 'notes'), class: ('merge-request-no-comments' if note_count.zero?) do
= link_to merge_request_path(merge_request, anchor: 'notes'), class: ('no-comments' if note_count.zero?) do
= icon('comments')
= note_count
......
......@@ -47,13 +47,7 @@
%tbody
%th Status
%th Commit
- stages.each do |stage|
%th.stage
- if stage.titleize.length > 12
%span.has-tooltip{ title: "#{stage.titleize}" }
= stage.titleize
- else
= stage.titleize
%th Stages
%th
%th
= render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages
......
......@@ -2,12 +2,12 @@
- if can?(current_user, :create_project_snippet, @project)
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped btn-create new-snippet-link', title: "New Snippet" do
New Snippet
- if can?(current_user, :update_project_snippet, @snippet)
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
Edit
- if can?(current_user, :update_project_snippet, @snippet)
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do
Delete
- if can?(current_user, :update_project_snippet, @snippet)
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
Edit
- if can?(current_user, :create_project_snippet, @project) || can?(current_user, :update_project_snippet, @snippet)
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
......@@ -19,11 +19,11 @@
%li
= link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
New Snippet
- if can?(current_user, :update_project_snippet, @snippet)
%li
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do
Edit
- if can?(current_user, :update_project_snippet, @snippet)
%li
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
- if can?(current_user, :update_project_snippet, @snippet)
%li
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do
Edit
- page_title @snippet.title, "Snippets"
.snippet-holder
= render 'shared/snippets/header'
= render 'shared/snippets/header'
%article.file-holder.file-holder-no-border.snippet-file-content
.file-title.file-title-clear
= blob_icon 0, @snippet.file_name
= @snippet.file_name
.file-actions.hidden-xs
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
= link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
= render 'shared/snippets/blob'
%article.file-holder.snippet-file-content
.file-title
= blob_icon 0, @snippet.file_name
= @snippet.file_name
.file-actions
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
= link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
= render 'shared/snippets/blob'
%div#notes= render "projects/notes/notes_with_form"
%div#notes= render "projects/notes/notes_with_form"
%article.file-holder.readme-holder
.file-title
= blob_icon readme.mode, readme.name
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, @path, readme.name)) do
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, @path, readme.name)) do
%strong
= readme.name
.file-content.wiki
......
......@@ -9,7 +9,7 @@
%th Value
%th
%tbody
- @project.variables.each do |variable|
- @project.variables.order_key_asc.each do |variable|
- if variable.id?
%tr
%td= variable.key
......
......@@ -10,12 +10,16 @@
in group #{link_to @group.name, @group}
.results.prepend-top-10
.search-results
- if @scope == 'projects'
.term
= render 'shared/projects/list', projects: @search_objects
- else
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects
- if @scope == 'commits'
%ul.list-unstyled
= render partial: "search/results/commit", collection: @search_objects
- else
.search-results
- if @scope == 'projects'
.term
= render 'shared/projects/list', projects: @search_objects
- else
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects
- if @scope != 'projects'
= paginate(@search_objects, theme: 'gitlab')
- blob = @project.repository.parse_search_result(blob)
- blob = parse_search_result(blob)
.blob-result
.file-holder
.file-title
......
.search-result-row
= render 'projects/commits/commit', project: @project, commit: commit
= render 'projects/commits/commit', project: @project, commit: commit
- wiki_blob = @project.repository.parse_search_result(wiki_blob)
- wiki_blob = parse_search_result(wiki_blob)
.blob-result
.file-holder
.file-title
......
.form-group.project-visibility-level-holder
= f.label :visibility_level, class: 'control-label' do
Visibility Level
= link_to "(?)", help_page_path("public_access/public_access")
= link_to icon('question-circle'), help_page_path("public_access/public_access")
.col-sm-10
- if can_change_visibility_level
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model)
......
......@@ -19,7 +19,7 @@
= dropdown_tag(title, options: { toggle_class: 'js-issuable-selector',
title: title, filter: true, placeholder: 'Filter', footer_content: true,
data: { data: issuable_template_names, field_name: 'issuable_template', selected: selected_template(issuable), project_path: @project.path, namespace_path: @project.namespace.path } } ) do
data: { data: issuable_template_names, field_name: 'issuable_template', selected: selected_template(issuable), project_path: ref_project.path, namespace_path: ref_project.namespace.path } } ) do
%ul.dropdown-footer-list
%li
%a.reset-template
......
......@@ -6,12 +6,13 @@
%strong.item-title
Snippet #{@snippet.to_reference}
%span.creator
created by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title")}
authored
= time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
- if @snippet.updated_at != @snippet.created_at
%span
= icon('edit', title: 'edited')
= time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago')
by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title", avatar_class: "hidden-xs")}
.snippet-actions
- if @snippet.project_id?
......@@ -19,6 +20,5 @@
- else
= render "snippets/actions"
.content-block.second-block
%h2.snippet-title.prepend-top-0.append-bottom-0
= markdown escape_once(@snippet.title), pipeline: :single_line, author: @snippet.author
%h2.snippet-title.prepend-top-0.append-bottom-0
= markdown escape_once(@snippet.title), pipeline: :single_line, author: @snippet.author
......@@ -3,19 +3,30 @@
.title
= link_to reliable_snippet_path(snippet) do
= truncate(snippet.title, length: 60)
= snippet.title
- if snippet.private?
%span.label.label-gray
%span.label.label-gray.hidden-xs
= icon('lock')
private
%span.monospace.pull-right
%span.monospace.pull-right.hidden-xs
= snippet.file_name
%small.pull-right.cgray
%ul.controls.visible-xs
%li
- note_count = snippet.notes.user.count
= link_to reliable_snippet_path(snippet, anchor: 'notes'), class: ('no-comments' if note_count.zero?) do
= icon('comments')
= note_count
%li
%span.sr-only
= visibility_level_label(snippet.visibility_level)
= visibility_level_icon(snippet.visibility_level, fw: false)
%small.pull-right.cgray.hidden-xs
- if snippet.project_id?
= link_to snippet.project.name_with_namespace, namespace_project_path(snippet.project.namespace, snippet.project)
.snippet-info
.snippet-info.hidden-xs
= link_to user_snippets_path(snippet.author) do
= snippet.author_name
authored #{time_ago_with_tooltip(snippet.created_at)}
......@@ -2,12 +2,12 @@
- if current_user
= link_to new_snippet_path, class: "btn btn-grouped btn-create new-snippet-link", title: "New Snippet" do
New Snippet
- if can?(current_user, :update_personal_snippet, @snippet)
= link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-danger", title: 'Delete Snippet' do
Delete
- if can?(current_user, :update_personal_snippet, @snippet)
= link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
Edit
- if current_user
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
......@@ -18,11 +18,11 @@
%li
= link_to new_snippet_path, title: "New Snippet" do
New Snippet
- if can?(current_user, :update_personal_snippet, @snippet)
%li
= link_to edit_snippet_path(@snippet) do
Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
%li
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
- if can?(current_user, :update_personal_snippet, @snippet)
%li
= link_to edit_snippet_path(@snippet) do
Edit
- page_title @snippet.title, "Snippets"
.snippet-holder
= render 'shared/snippets/header'
= render 'shared/snippets/header'
%article.file-holder.file-holder-no-border.snippet-file-content
.file-title.file-title-clear
= blob_icon 0, @snippet.file_name
= @snippet.file_name
.file-actions.hidden-xs
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
= link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
= render 'shared/snippets/blob'
%article.file-holder.snippet-file-content
.file-title
= blob_icon 0, @snippet.file_name
= @snippet.file_name
.file-actions
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
= link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
= render 'shared/snippets/blob'
......@@ -4,6 +4,6 @@
Summary of issues, merge requests, and push events
:javascript
new Calendar(
#{@timestamps.to_json},
#{@activity_dates.to_json},
'#{user_calendar_activities_path}'
);
);
\ No newline at end of file
......@@ -3,9 +3,13 @@ class Gitlab::Seeder::Pipelines
BUILDS = [
{ name: 'build:linux', stage: 'build', status: :success },
{ name: 'build:osx', stage: 'build', status: :success },
{ name: 'rspec:linux', stage: 'test', status: :success },
{ name: 'rspec:windows', stage: 'test', status: :success },
{ name: 'rspec:windows', stage: 'test', status: :success },
{ name: 'rspec:linux 0 3', stage: 'test', status: :success },
{ name: 'rspec:linux 1 3', stage: 'test', status: :success },
{ name: 'rspec:linux 2 3', stage: 'test', status: :success },
{ name: 'rspec:windows 0 3', stage: 'test', status: :success },
{ name: 'rspec:windows 1 3', stage: 'test', status: :success },
{ name: 'rspec:windows 2 3', stage: 'test', status: :success },
{ name: 'rspec:windows 2 3', stage: 'test', status: :success },
{ name: 'rspec:osx', stage: 'test', status_event: :success },
{ name: 'spinach:linux', stage: 'test', status: :success },
{ name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true},
......
# rubocop:disable all
class MigrateRepoSize < ActiveRecord::Migration
DOWNTIME = false
def up
project_data = execute('SELECT projects.id, namespaces.path AS namespace_path, projects.path AS project_path FROM projects LEFT JOIN namespaces ON projects.namespace_id = namespaces.id')
project_data.each do |project|
id = project['id']
namespace_path = project['namespace_path'] || ''
path = File.join(Gitlab.config.gitlab_shell.repos_path, namespace_path, project['project_path'] + '.git')
repos_path = Gitlab.config.gitlab_shell['repos_path'] || Gitlab.config.repositories.storages.default
path = File.join(repos_path, namespace_path, project['project_path'] + '.git')
begin
repo = Gitlab::Git::Repository.new(path)
......
......@@ -8,14 +8,28 @@ class MergeRequestDiffRemoveUniq < ActiveRecord::Migration
DOWNTIME = false
def up
if index_exists?(:merge_request_diffs, :merge_request_id)
remove_index :merge_request_diffs, :merge_request_id
constraint_name = 'merge_request_diffs_merge_request_id_key'
transaction do
if index_exists?(:merge_request_diffs, :merge_request_id)
remove_index(:merge_request_diffs, :merge_request_id)
end
# In some bizarre cases PostgreSQL might have a separate unique constraint
# that we'll need to drop.
if constraint_exists?(constraint_name) && Gitlab::Database.postgresql?
execute("ALTER TABLE merge_request_diffs DROP CONSTRAINT IF EXISTS #{constraint_name};")
end
end
end
def down
unless index_exists?(:merge_request_diffs, :merge_request_id)
add_concurrent_index :merge_request_diffs, :merge_request_id, unique: true
add_concurrent_index(:merge_request_diffs, :merge_request_id, unique: true)
end
end
def constraint_exists?(name)
indexes(:merge_request_diffs).map(&:name).include?(name)
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddLfsEnabledToNamespaces < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :namespaces, :lfs_enabled, :boolean
end
end
......@@ -14,6 +14,6 @@ class RemoveProjectsPushesSinceGc < ActiveRecord::Migration
end
def down
add_column_with_default! :projects, :pushes_since_gc, :integer, default: 0
add_column_with_default :projects, :pushes_since_gc, :integer, default: 0
end
end
class ChangeArtifactsSizeColumn < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = true
DOWNTIME_REASON = 'Changing an integer column size requires a full table rewrite.'
def up
change_column :ci_builds, :artifacts_size, :integer, limit: 8
end
def down
# do nothing
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160913162434) do
ActiveRecord::Schema.define(version: 20160913212128) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -177,7 +177,7 @@ ActiveRecord::Schema.define(version: 20160913162434) do
t.datetime "erased_at"
t.datetime "artifacts_expire_at"
t.string "environment"
t.integer "artifacts_size"
t.integer "artifacts_size", limit: 8
t.string "when"
t.text "yaml_variables"
t.datetime "queued_at"
......@@ -650,6 +650,7 @@ ActiveRecord::Schema.define(version: 20160913162434) do
t.integer "visibility_level", default: 20, null: false
t.boolean "request_access_enabled", default: true, null: false
t.datetime "deleted_at"
t.boolean "lfs_enabled"
end
add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree
......
......@@ -288,6 +288,7 @@ Parameters:
- `path` (required) - The path of the group
- `description` (optional) - The group's description
- `visibility_level` (optional) - The group's visibility. 0 for private, 10 for internal, 20 for public.
- `lfs_enabled` (optional) - Enable/disable Large File Storage (LFS) for the projects in this group
## Transfer project to group
......@@ -317,6 +318,7 @@ PUT /groups/:id
| `path` | string | no | The path of the group |
| `description` | string | no | The description of the group |
| `visibility_level` | integer | no | The visibility level of the group. 0 for private, 10 for internal, 20 for public. |
| `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group |
```bash
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/groups/5?name=Experimental"
......
......@@ -78,7 +78,8 @@ Parameters:
### Create new issue note
Creates a new note to a single project issue.
Creates a new note to a single project issue. If you create a note where the body
only contains an Award Emoji, you'll receive this object back.
```
POST /projects/:id/issues/:issue_id/notes
......@@ -204,6 +205,7 @@ Parameters:
### Create new snippet note
Creates a new note for a single snippet. Snippet notes are comments users can post to a snippet.
If you create a note where the body only contains an Award Emoji, you'll receive this object back.
```
POST /projects/:id/snippets/:snippet_id/notes
......@@ -332,6 +334,8 @@ Parameters:
### Create new merge request note
Creates a new note for a single merge request.
If you create a note where the body only contains an Award Emoji, you'll receive
this object back.
```
POST /projects/:id/merge_requests/:merge_request_id/notes
......
......@@ -67,7 +67,7 @@ PUT /application/settings
| `default_snippet_visibility` | integer | no | What visibility level new snippets receive. Can take `0` _(Private)_, `1` _(Internal)_ and `2` _(Public)_ as a parameter. Default is `0`.|
| `domain_whitelist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is null, meaning there is no restriction. |
| `domain_blacklist_enabled` | boolean | no | Enable/disable the `domain_blacklist` |
| `domain_blacklist` | array of strings | yes (if `domain_whitelist_enabled` is `true` | People trying to sign-up with emails from this domain will not be allowed to do so. |
| `domain_blacklist` | array of strings | yes (if `domain_blacklist_enabled` is `true`) | People trying to sign-up with emails from this domain will not be allowed to do so. |
| `user_oauth_applications` | boolean | no | Allow users to register any application to use GitLab as an OAuth provider |
| `after_sign_out_path` | string | no | Where to redirect users after logout |
| `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes |
......
......@@ -16,4 +16,4 @@ Apart from those, here is an collection of tutorials and guides on setting up yo
- [Repo's with examples for various languages](https://gitlab.com/groups/gitlab-examples)
- [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
[gitlab-ci-templates][https://gitlab.com/gitlab-org/gitlab-ci-yml]
[gitlab-ci-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml
......@@ -105,7 +105,8 @@ What is important is that each job is run independently from each other.
If you want to check whether your `.gitlab-ci.yml` file is valid, there is a
Lint tool under the page `/ci/lint` of your GitLab instance. You can also find
the link under **Settings > CI settings** in your project.
a "CI Lint" button to go to this page under **Pipelines > Pipelines** and
**Pipelines > Builds** in your project.
For more information and a complete `.gitlab-ci.yml` syntax, please read
[the documentation on .gitlab-ci.yml](../yaml/README.md).
......
......@@ -78,9 +78,9 @@ delete them.
> **Note:**
This feature requires GitLab 8.8 and GitLab Runner 1.2.
Make sure that your GitLab Runner is configured to allow building docker images.
You have to check the [Using Docker Build documentation](../ci/docker/using_docker_build.md).
Then see the CI documentation on [Using the GitLab Container Registry](../ci/docker/using_docker_build.md#using-the-gitlab-container-registry).
Make sure that your GitLab Runner is configured to allow building Docker images by
following the [Using Docker Build](../ci/docker/using_docker_build.md)
and [Using the GitLab Container Registry documentation](../ci/docker/using_docker_build.md#using-the-gitlab-container-registry).
## Limitations
......
......@@ -111,6 +111,28 @@ class MyMigration < ActiveRecord::Migration
end
```
## Integer column type
By default, an integer column can hold up to a 4-byte (32-bit) number. That is
a max value of 2,147,483,647. Be aware of this when creating a column that will
hold file sizes in byte units. If you are tracking file size in bytes this
restricts the maximum file size to just over 2GB.
To allow an integer column to hold up to an 8-byte (64-bit) number, explicitly
set the limit to 8-bytes. This will allow the column to hold a value up to
9,223,372,036,854,775,807.
Rails migration example:
```
add_column_with_default(:projects, :foo, :integer, default: 10, limit: 8)
# or
add_column(:projects, :foo, :integer, default: 10, limit: 8)
```
## Testing
Make sure that your migration works with MySQL and PostgreSQL with data. An empty database does not guarantee that your migration is correct.
......
......@@ -79,6 +79,9 @@ gitlab_rails['backup_upload_connection'] = {
'region' => 'eu-west-1',
'aws_access_key_id' => 'AKIAKIAKI',
'aws_secret_access_key' => 'secret123'
# If using an IAM Profile, leave aws_access_key_id & aws_secret_access_key empty
# ie. 'aws_access_key_id' => '',
# 'use_iam_profile' => 'true'
}
gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket'
```
......@@ -95,6 +98,9 @@ For installations from source:
region: eu-west-1
aws_access_key_id: AKIAKIAKI
aws_secret_access_key: 'secret123'
# If using an IAM Profile, leave aws_access_key_id & aws_secret_access_key empty
# ie. aws_access_key_id: ''
# use_iam_profile: 'true'
# The remote 'directory' to store your backups. For S3, this would be the bucket name.
remote_directory: 'my.s3.bucket'
# Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional
......
......@@ -63,7 +63,7 @@ The following table depicts the various user permission levels in a project.
| Force push to protected branches [^2] | | | | | |
| Remove protected branches [^2] | | | | | |
[^1]: If **Allow guest to access builds** is enabled in CI settings
[^1]: If **Public pipelines** is enabled in **Project Settings > CI/CD Pipelines**
[^2]: Not allowed for Guest, Reporter, Developer, Master, or Owner
## Group
......
......@@ -101,4 +101,36 @@ inside GitLab that make that possible.
![Build artifacts browser](img/build_artifacts_browser.png)
## Downloading the latest build artifacts
It is possible to download the latest artifacts of a build via a well known URL
so you can use it for scripting purposes.
The structure of the URL is the following:
```
https://example.com/<namespace>/<project>/builds/artifacts/<ref>/download?job=<job_name>
```
For example, to download the latest artifacts of the job named `rspec 6 20` of
the `master` branch of the `gitlab-ce` project that belongs to the `gitlab-org`
namespace, the URL would be:
```
https://gitlab.com/gitlab-org/gitlab-ce/builds/artifacts/master/download?job=rspec+6+20
```
The latest builds are also exposed in the UI in various places. Specifically,
look for the download button in:
- the main project's page
- the branches page
- the tags page
If the latest build has failed to upload the artifacts, you can see that
information in the UI.
![Latest artifacts button](img/build_latest_artifacts_browser.png)
[gitlab workhorse]: https://gitlab.com/gitlab-org/gitlab-workhorse "GitLab Workhorse repository"
# Import your project from GitHub to GitLab
Import your projects from GitHub to GitLab with minimal effort.
## Overview
>**Note:**
In order to enable the GitHub import setting, you may also want to
enable the [GitHub integration][gh-import] in your GitLab instance. This
configuration is optional, you will be able import your GitHub repositories
with a Personal Access Token.
If you are an administrator you can enable the [GitHub integration][gh-import]
in your GitLab instance sitewide. This configuration is optional, users will be
able import their GitHub repositories with a [personal access token][gh-token].
At its current state, GitHub importer can import:
- At its current state, GitHub importer can import:
- the repository description (GitLab 7.7+)
- the Git repository data (GitLab 7.7+)
- the issues (GitLab 7.7+)
- the pull requests (GitLab 8.4+)
- the wiki pages (GitLab 8.4+)
- the milestones (GitLab 8.7+)
- the labels (GitLab 8.7+)
- the release note descriptions (GitLab 8.12+)
- References to pull requests and issues are preserved (GitLab 8.7+)
- Repository public access is retained. If a repository is private in GitHub
it will be created as private in GitLab as well.
- the repository description (introduced in GitLab 7.7)
- the git repository data (introduced in GitLab 7.7)
- the issues (introduced in GitLab 7.7)
- the pull requests (introduced in GitLab 8.4)
- the wiki pages (introduced in GitLab 8.4)
- the milestones (introduced in GitLab 8.7)
- the labels (introduced in GitLab 8.7)
- the release note descriptions (introduced in GitLab 8.12)
## How it works
With GitLab 8.7+, references to pull requests and issues are preserved.
When issues/pull requests are being imported, the GitHub importer tries to find
the GitHub author/assignee in GitLab's database using the GitHub ID. For this
to work, the GitHub author/assignee should have signed in beforehand in GitLab
and [**associated their GitHub account**][social sign-in]. If the user is not
found in GitLab's database, the project creator (most of the times the current
user that started the import process) is set as the author, but a reference on
the issue about the original GitHub author is kept.
The importer page is visible when you [create a new project][new-project].
Click on the **GitHub** link and, if you are logged in via the GitHub
integration, you will be redirected to GitHub for permission to access your
projects. After accepting, you'll be automatically redirected to the importer.
The importer will create any new namespaces (groups) if they don't exist or in
the case the namespace is taken, the repository will be imported under the user's
namespace that started the import process.
If you are not using the GitHub integration, you can still perform a one-off
authorization with GitHub to access your projects.
## Importing your GitHub repositories
Alternatively, you can also enter a GitHub Personal Access Token. Once you enter
your token, you'll be taken to the importer.
The importer page is visible when you create a new project.
![New project page on GitLab](img/import_projects_from_github_new_project_page.png)
---
Click on the **GitHub** link and the import authorization process will start.
There are two ways to authorize access to your GitHub repositories:
While at the GitHub importer page, you can see the import statuses of your
GitHub projects. Those that are being imported will show a _started_ status,
those already imported will be green, whereas those that are not yet imported
have an **Import** button on the right side of the table. If you want, you can
import all your GitHub projects in one go by hitting **Import all projects**
in the upper left corner.
1. [Using the GitHub integration][gh-integration] (if it's enabled by your
GitLab administrator). This is the preferred way as it's possible to
preserve the GitHub authors/assignees. Read more in the [How it works](#how-it-works)
section.
1. [Using a personal access token][gh-token] provided by GitHub.
![GitHub importer page](img/import_projects_from_github_importer.png)
![Select authentication method](img/import_projects_from_github_select_auth_method.png)
### Authorize access to your repositories using the GitHub integration
---
If the [GitHub integration][gh-import] is enabled by your GitLab administrator,
you can use it instead of the personal access token.
1. First you may want to connect your GitHub account to GitLab in order for
the username mapping to be correct. Follow the [social sign-in] documentation
on how to do so.
1. Once you connect GitHub, click the **List your GitHub repositories** button
and you will be redirected to GitHub for permission to access your projects.
1. After accepting, you'll be automatically redirected to the importer.
You can now go on and [select which repositories to import](#select-which-repositories-to-import).
### Authorize access to your repositories using a personal access token
>**Note:**
For a proper author/assignee mapping for issues and pull requests, the
[GitHub integration][gh-integration] should be used instead of the
[personal access token][gh-token]. If the GitHub integration is enabled by your
GitLab administrator, it should be the preferred method to import your repositories.
Read more in the [How it works](#how-it-works) section.
The importer will create any new namespaces if they don't exist or in the
case the namespace is taken, the project will be imported on the user's
namespace.
If you are not using the GitHub integration, you can still perform a one-off
authorization with GitHub to grant GitLab access your repositories:
1. Go to <https://github.com/settings/tokens/new>.
1. Enter a token description.
1. Check the `repo` scope.
1. Click **Generate token**.
1. Copy the token hash.
1. Go back to GitLab and provide the token to the GitHub importer.
1. Hit the **List your GitHub repositories** button and wait while GitLab reads
your repositories' information. Once done, you'll be taken to the importer
page to select the repositories to import.
### Select which repositories to import
After you've authorized access to your GitHub repositories, you will be
redirected to the GitHub importer page.
From there, you can see the import statuses of your GitHub repositories.
- Those that are being imported will show a _started_ status,
- those already successfully imported will be green with a _done_ status,
- whereas those that are not yet imported will have an **Import** button on the
right side of the table.
If you want, you can import all your GitHub projects in one go by hitting
**Import all projects** in the upper left corner.
![GitHub importer page](img/import_projects_from_github_importer.png)
[gh-import]: ../../integration/github.md "GitHub integration"
[ee-gh]: http://docs.gitlab.com/ee/integration/github.html "GitHub integration for GitLab EE"
[new-project]: ../../gitlab-basics/create-project.md "How to create a new project in GitLab"
[gh-integration]: #authorize-access-to-your-repositories-using-the-github-integration
[gh-token]: #authorize-access-to-your-repositories-using-a-personal-access-token
[social sign-in]: ../../profile/account/social_sign_in.md
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