Commit e1cff4bb authored by Robert Speicher's avatar Robert Speicher

Merge branch 'ce-to-ee-2018-04-13' into 'master'

CE upstream - 2018-04-13 09:32 UTC

See merge request gitlab-org/gitlab-ee!5359
parents 6cbc7dd2 adbf8b8a
...@@ -7,11 +7,7 @@ import flash from './flash'; ...@@ -7,11 +7,7 @@ import flash from './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion'; import BlobForkSuggestion from './blob/blob_fork_suggestion';
import initChangesDropdown from './init_changes_dropdown'; import initChangesDropdown from './init_changes_dropdown';
import bp from './breakpoints'; import bp from './breakpoints';
import { import { parseUrlPathname, handleLocationHash, isMetaClick } from './lib/utils/common_utils';
parseUrlPathname,
handleLocationHash,
isMetaClick,
} from './lib/utils/common_utils';
import { getLocationHash } from './lib/utils/url_utility'; import { getLocationHash } from './lib/utils/url_utility';
import initDiscussionTab from './image_diff/init_discussion_tab'; import initDiscussionTab from './image_diff/init_discussion_tab';
import Diff from './diff'; import Diff from './diff';
...@@ -69,11 +65,10 @@ import Notes from './notes'; ...@@ -69,11 +65,10 @@ import Notes from './notes';
let location = window.location; let location = window.location;
export default class MergeRequestTabs { export default class MergeRequestTabs {
constructor({ action, setUrl, stubLocation } = {}) { constructor({ action, setUrl, stubLocation } = {}) {
const mergeRequestTabs = document.querySelector('.js-tabs-affix'); const mergeRequestTabs = document.querySelector('.js-tabs-affix');
const navbar = document.querySelector('.navbar-gitlab'); const navbar = document.querySelector('.navbar-gitlab');
const peek = document.getElementById('peek'); const peek = document.getElementById('js-peek');
const paddingTop = 16; const paddingTop = 16;
this.diffsLoaded = false; this.diffsLoaded = false;
...@@ -109,8 +104,7 @@ export default class MergeRequestTabs { ...@@ -109,8 +104,7 @@ export default class MergeRequestTabs {
.on('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown) .on('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown)
.on('click', '.js-show-tab', this.showTab); .on('click', '.js-show-tab', this.showTab);
$('.merge-request-tabs a[data-toggle="tab"]') $('.merge-request-tabs a[data-toggle="tab"]').on('click', this.clickTab);
.on('click', this.clickTab);
} }
// Used in tests // Used in tests
...@@ -119,8 +113,7 @@ export default class MergeRequestTabs { ...@@ -119,8 +113,7 @@ export default class MergeRequestTabs {
.off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown) .off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown)
.off('click', '.js-show-tab', this.showTab); .off('click', '.js-show-tab', this.showTab);
$('.merge-request-tabs a[data-toggle="tab"]') $('.merge-request-tabs a[data-toggle="tab"]').off('click', this.clickTab);
.off('click', this.clickTab);
} }
destroyPipelinesView() { destroyPipelinesView() {
...@@ -183,10 +176,7 @@ export default class MergeRequestTabs { ...@@ -183,10 +176,7 @@ export default class MergeRequestTabs {
scrollToElement(container) { scrollToElement(container) {
if (location.hash) { if (location.hash) {
const offset = 0 - ( const offset = 0 - ($('.navbar-gitlab').outerHeight() + $('.js-tabs-affix').outerHeight());
$('.navbar-gitlab').outerHeight() +
$('.js-tabs-affix').outerHeight()
);
const $el = $(`${container} ${location.hash}:not(.match)`); const $el = $(`${container} ${location.hash}:not(.match)`);
if ($el.length) { if ($el.length) {
$.scrollTo($el[0], { offset }); $.scrollTo($el[0], { offset });
...@@ -240,9 +230,13 @@ export default class MergeRequestTabs { ...@@ -240,9 +230,13 @@ export default class MergeRequestTabs {
// Turbolinks' history. // Turbolinks' history.
// //
// See https://github.com/rails/turbolinks/issues/363 // See https://github.com/rails/turbolinks/issues/363
window.history.replaceState({ window.history.replaceState(
url: newState, {
}, document.title, newState); url: newState,
},
document.title,
newState,
);
return newState; return newState;
} }
...@@ -258,7 +252,8 @@ export default class MergeRequestTabs { ...@@ -258,7 +252,8 @@ export default class MergeRequestTabs {
this.toggleLoading(true); this.toggleLoading(true);
axios.get(`${source}.json`) axios
.get(`${source}.json`)
.then(({ data }) => { .then(({ data }) => {
document.querySelector('div#commits').innerHTML = data.html; document.querySelector('div#commits').innerHTML = data.html;
localTimeAgo($('.js-timeago', 'div#commits')); localTimeAgo($('.js-timeago', 'div#commits'));
...@@ -303,7 +298,8 @@ export default class MergeRequestTabs { ...@@ -303,7 +298,8 @@ export default class MergeRequestTabs {
this.toggleLoading(true); this.toggleLoading(true);
axios.get(`${urlPathname}.json${location.search}`) axios
.get(`${urlPathname}.json${location.search}`)
.then(({ data }) => { .then(({ data }) => {
const $container = $('#diffs'); const $container = $('#diffs');
$container.html(data.html); $container.html(data.html);
...@@ -332,8 +328,7 @@ export default class MergeRequestTabs { ...@@ -332,8 +328,7 @@ export default class MergeRequestTabs {
cancelButtons: $(el).find('.js-cancel-fork-suggestion-button'), cancelButtons: $(el).find('.js-cancel-fork-suggestion-button'),
suggestionSections: $(el).find('.js-file-fork-suggestion-section'), suggestionSections: $(el).find('.js-file-fork-suggestion-section'),
actionTextPieces: $(el).find('.js-file-fork-suggestion-section-action'), actionTextPieces: $(el).find('.js-file-fork-suggestion-section-action'),
}) }).init();
.init();
}); });
// Scroll any linked note into view // Scroll any linked note into view
...@@ -388,8 +383,7 @@ export default class MergeRequestTabs { ...@@ -388,8 +383,7 @@ export default class MergeRequestTabs {
resetViewContainer() { resetViewContainer() {
if (this.fixedLayoutPref !== null) { if (this.fixedLayoutPref !== null) {
$('.content-wrapper .container-fluid') $('.content-wrapper .container-fluid').toggleClass('container-limited', this.fixedLayoutPref);
.toggleClass('container-limited', this.fixedLayoutPref);
} }
} }
...@@ -438,12 +432,11 @@ export default class MergeRequestTabs { ...@@ -438,12 +432,11 @@ export default class MergeRequestTabs {
const $diffTabs = $('#diff-notes-app'); const $diffTabs = $('#diff-notes-app');
$tabs.off('affix.bs.affix affix-top.bs.affix') $tabs
.off('affix.bs.affix affix-top.bs.affix')
.affix({ .affix({
offset: { offset: {
top: () => ( top: () => $diffTabs.offset().top - $tabs.height() - $fixedNav.height(),
$diffTabs.offset().top - $tabs.height() - $fixedNav.height()
),
}, },
}) })
.on('affix.bs.affix', () => $diffTabs.css({ marginTop: $tabs.height() })) .on('affix.bs.affix', () => $diffTabs.css({ marginTop: $tabs.height() }))
......
...@@ -429,6 +429,7 @@ ...@@ -429,6 +429,7 @@
.projects-sidebar { .projects-sidebar {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%;
.context-header { .context-header {
width: auto; width: auto;
...@@ -438,8 +439,8 @@ ...@@ -438,8 +439,8 @@
.multi-file-commit-panel-inner { .multi-file-commit-panel-inner {
display: flex; display: flex;
flex: 1;
flex-direction: column; flex-direction: column;
height: 100%;
} }
.multi-file-commit-panel-inner-scroll { .multi-file-commit-panel-inner-scroll {
......
---
title: Do not use '-f' with 'rm' in gitlab-basics docs
merge_request: 18027
author: Elias Werberich
type: changed
---
title: Add documentation for Pipelines failure reasons
merge_request: 18352
author:
type: other
---
title: 'API: add languages of project GET /projects/:id/languages'
merge_request: 17770
author: Roger Rüttimann
type: added
deprecator = ActiveSupport::Deprecation.new('11.0', 'GitLab')
if Gitlab.inc_controlled? || Rails.env.development?
ActiveSupport::Deprecation.deprecate_methods(Gitlab::GitalyClient::StorageSettings, :legacy_disk_path, deprecator: deprecator)
end
...@@ -942,6 +942,29 @@ Example response: ...@@ -942,6 +942,29 @@ Example response:
} }
``` ```
## Languages
Get languages used in a project with percentage value.
```
GET /projects/:id/languages
```
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/languages"
```
Example response:
```json
{
"Ruby": 66.69,
"JavaScript": 22.98,
"HTML": 7.91,
"CoffeeScript": 2.42
}
```
## Archive a project ## Archive a project
Archives the project if the user is either admin or the project owner of this project. This action is Archives the project if the user is either admin or the project owner of this project. This action is
......
...@@ -73,6 +73,21 @@ cancel the job, retry it, or erase the job trace. ...@@ -73,6 +73,21 @@ cancel the job, retry it, or erase the job trace.
![Pipelines example](img/pipelines.png) ![Pipelines example](img/pipelines.png)
## Seeing the failure reason for jobs
> [Introduced][ce-5742] in GitLab 10.7.
When a pipeline fails or is allowed to fail, there are several places where you
can quickly check the reason it failed:
- **In the pipeline graph** present on the pipeline detail view.
- **In the pipeline widgets** present in the merge requests and commit pages.
- **In the job views** present in the global and detailed views of a job.
In any case, if you hover over the failed job you can see the reason it failed.
![Pipeline detail](img/job_failure_reason.png)
## Pipeline graphs ## Pipeline graphs
> [Introduced][ce-5742] in GitLab 8.11. > [Introduced][ce-5742] in GitLab 8.11.
...@@ -270,6 +285,7 @@ runners will not use regular runners, they must be tagged accordingly. ...@@ -270,6 +285,7 @@ runners will not use regular runners, they must be tagged accordingly.
[ce-6242]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6242 [ce-6242]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6242
[ce-7931]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7931 [ce-7931]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7931
[ce-9760]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9760 [ce-9760]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9760
[ce-17782]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17782
[regexp]: https://gitlab.com/gitlab-org/gitlab-ce/blob/2f3dc314f42dbd79813e6251792853bc231e69dd/app/models/commit_status.rb#L99 [regexp]: https://gitlab.com/gitlab-org/gitlab-ce/blob/2f3dc314f42dbd79813e6251792853bc231e69dd/app/models/commit_status.rb#L99
[eep]: https://about.gitlab.com/products/ "GitLab Premium" [eep]: https://about.gitlab.com/products/ "GitLab Premium"
[ee-2121]: https://gitlab.com/gitlab-org/gitlab-ee/issues/2121 [ee-2121]: https://gitlab.com/gitlab-org/gitlab-ee/issues/2121
...@@ -71,7 +71,7 @@ rm NAME-OF-FILE ...@@ -71,7 +71,7 @@ rm NAME-OF-FILE
### Remove a directory and all of its contents ### Remove a directory and all of its contents
``` ```
rm -rf NAME-OF-DIRECTORY rm -r NAME-OF-DIRECTORY
``` ```
### View history in the command line ### View history in the command line
......
...@@ -345,6 +345,11 @@ module API ...@@ -345,6 +345,11 @@ module API
end end
end end
desc 'Get languages in project repository'
get ':id/languages' do
user_project.repository.languages.map { |language| language.values_at(:label, :value) }.to_h
end
desc 'Remove a project' desc 'Remove a project'
delete ":id" do delete ":id" do
authorize! :remove_project, user_project authorize! :remove_project, user_project
......
...@@ -19,4 +19,12 @@ module Gitlab ...@@ -19,4 +19,12 @@ module Gitlab
def self.dev_env_or_com? def self.dev_env_or_com?
Rails.env.test? || Rails.env.development? || com? Rails.env.test? || Rails.env.development? || com?
end end
def self.dev?
Gitlab.config.gitlab.url == 'https://dev.gitlab.org'
end
def self.inc_controlled?
dev? || com?
end
end end
...@@ -75,9 +75,6 @@ module Gitlab ...@@ -75,9 +75,6 @@ module Gitlab
end end
end end
# Full path to repo
attr_reader :path
# Directory name of repo # Directory name of repo
attr_reader :name attr_reader :name
...@@ -96,14 +93,13 @@ module Gitlab ...@@ -96,14 +93,13 @@ module Gitlab
@relative_path = relative_path @relative_path = relative_path
@gl_repository = gl_repository @gl_repository = gl_repository
storage_path = Gitlab.config.repositories.storages[@storage].legacy_disk_path
@gitlab_projects = Gitlab::Git::GitlabProjects.new( @gitlab_projects = Gitlab::Git::GitlabProjects.new(
storage, storage,
relative_path, relative_path,
global_hooks_path: Gitlab.config.gitlab_shell.hooks_path, global_hooks_path: Gitlab.config.gitlab_shell.hooks_path,
logger: Rails.logger logger: Rails.logger
) )
@path = File.join(storage_path, @relative_path)
@name = @relative_path.split("/").last @name = @relative_path.split("/").last
end end
...@@ -111,6 +107,12 @@ module Gitlab ...@@ -111,6 +107,12 @@ module Gitlab
path == other.path path == other.path
end end
def path
@path ||= File.join(
Gitlab.config.repositories.storages[@storage].legacy_disk_path, @relative_path
)
end
# Default branch in the repository # Default branch in the repository
def root_ref def root_ref
@root_ref ||= gitaly_migrate(:root_ref) do |is_enabled| @root_ref ||= gitaly_migrate(:root_ref) do |is_enabled|
...@@ -139,12 +141,12 @@ module Gitlab ...@@ -139,12 +141,12 @@ module Gitlab
end end
def exists? def exists?
Gitlab::GitalyClient.migrate(:repository_exists, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled| Gitlab::GitalyClient.migrate(:repository_exists, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled if enabled
gitaly_repository_client.exists? gitaly_repository_client.exists?
else else
circuit_breaker.perform do circuit_breaker.perform do
File.exist?(File.join(@path, 'refs')) File.exist?(File.join(path, 'refs'))
end end
end end
end end
...@@ -1022,7 +1024,7 @@ module Gitlab ...@@ -1022,7 +1024,7 @@ module Gitlab
if is_enabled if is_enabled
gitaly_repository_client.info_attributes gitaly_repository_client.info_attributes
else else
attributes_path = File.join(File.expand_path(@path), 'info', 'attributes') attributes_path = File.join(File.expand_path(path), 'info', 'attributes')
if File.exist?(attributes_path) if File.exist?(attributes_path)
File.read(attributes_path) File.read(attributes_path)
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
require 'spec_helper' require 'spec_helper'
shared_examples 'languages and percentages JSON response' do
let(:expected_languages) { project.repository.languages.map { |language| language.values_at(:label, :value)}.to_h }
it 'returns expected language values' do
get api("/projects/#{project.id}/languages", user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq(expected_languages)
expect(json_response.count).to be > 1
end
end
describe API::Projects do describe API::Projects do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:user2) { create(:user) }
...@@ -1760,6 +1772,42 @@ describe API::Projects do ...@@ -1760,6 +1772,42 @@ describe API::Projects do
end end
end end
describe 'GET /projects/:id/languages' do
context 'with an authorized user' do
it_behaves_like 'languages and percentages JSON response' do
let(:project) { project3 }
end
it 'returns not_found(404) for not existing project' do
get api("/projects/9999999999/languages", user)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'with not authorized user' do
it 'returns not_found for existing but unauthorized project' do
get api("/projects/#{project3.id}/languages", user3)
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'without user' do
let(:project_public) { create(:project, :public, :repository) }
it_behaves_like 'languages and percentages JSON response' do
let(:project) { project_public }
end
it 'returns not_found for existing but unauthorized project' do
get api("/projects/#{project3.id}/languages", nil)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
describe 'DELETE /projects/:id' do describe 'DELETE /projects/:id' do
context 'when authenticated as user' do context 'when authenticated as user' do
it 'removes project' do it 'removes project' do
......
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