Commit b84cd8bd authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-11-06

# Conflicts:
#	app/assets/javascripts/reports/components/report_item.vue

[ci skip]
parents d9260cc3 d19a6f68
...@@ -31,7 +31,7 @@ class DirtySubmitForm { ...@@ -31,7 +31,7 @@ class DirtySubmitForm {
updateDirtyInput(event) { updateDirtyInput(event) {
const input = event.target; const input = event.target;
if (!input.dataset.dirtySubmitOriginalValue) return; if (!input.dataset.isDirtySubmitInput) return;
this.updateDirtyInputs(input); this.updateDirtyInputs(input);
this.toggleSubmission(); this.toggleSubmission();
...@@ -65,6 +65,7 @@ class DirtySubmitForm { ...@@ -65,6 +65,7 @@ class DirtySubmitForm {
} }
static initInput(element) { static initInput(element) {
element.dataset.isDirtySubmitInput = true;
element.dataset.dirtySubmitOriginalValue = DirtySubmitForm.inputCurrentValue(element); element.dataset.dirtySubmitOriginalValue = DirtySubmitForm.inputCurrentValue(element);
} }
......
<script> <script>
import IssueStatusIcon from '~/reports/components/issue_status_icon.vue'; import IssueStatusIcon from '~/reports/components/issue_status_icon.vue';
import { components, componentNames } from 'ee/vue_shared/components/reports/issue_body'; import { components, componentNames } from '~/reports/components/issue_body';
export default { export default {
name: 'ReportItem', name: 'ReportItem',
......
...@@ -73,6 +73,7 @@ export default { ...@@ -73,6 +73,7 @@ export default {
linkStart: `<a href="${this.troubleshootingDocsPath}">`, linkStart: `<a href="${this.troubleshootingDocsPath}">`,
linkEnd: '</a>', linkEnd: '</a>',
}, },
false,
); );
}, },
/* We typically set defaults ([]) in the store or prop declarations, but because triggered /* We typically set defaults ([]) in the store or prop declarations, but because triggered
......
...@@ -251,6 +251,10 @@ module Ci ...@@ -251,6 +251,10 @@ module Ci
end end
end end
def self.latest_successful_ids_per_project
success.group(:project_id).select('max(id) as id')
end
def self.truncate_sha(sha) def self.truncate_sha(sha)
sha[0...8] sha[0...8]
end end
......
...@@ -233,6 +233,12 @@ class Namespace < ActiveRecord::Base ...@@ -233,6 +233,12 @@ class Namespace < ActiveRecord::Base
Project.inside_path(full_path) Project.inside_path(full_path)
end end
# Includes pipelines from this namespace and pipelines from all subgroups
# that belongs to this namespace
def all_pipelines
Ci::Pipeline.where(project: all_projects)
end
def has_parent? def has_parent?
parent.present? parent.present?
end end
......
---
title: Make index.* render like README.* when it's present in a repository
merge_request: 22639
author: Jakub Jirutka
type: added
---
title: Render unescaped link for failed pipeline status
merge_request: 22807
author:
type: fixed
...@@ -23,6 +23,9 @@ one of the [Merge request coaches][team]. ...@@ -23,6 +23,9 @@ one of the [Merge request coaches][team].
Depending on the areas your merge request touches, it must be **approved** by one Depending on the areas your merge request touches, it must be **approved** by one
or more [maintainers](https://about.gitlab.com/handbook/engineering/#maintainer): or more [maintainers](https://about.gitlab.com/handbook/engineering/#maintainer):
For approvals, we use the approval functionality found in the merge request
widget. Reviewers can add their approval by [approving additionally](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html#adding-or-removing-an-approval).
1. If your merge request includes backend changes [^1], it must be 1. If your merge request includes backend changes [^1], it must be
**approved by a [backend maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab-ce_maintainers_backend)**. **approved by a [backend maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab-ce_maintainers_backend)**.
1. If your merge request includes frontend changes [^1], it must be 1. If your merge request includes frontend changes [^1], it must be
...@@ -97,6 +100,9 @@ If a developer who happens to also be a maintainer was involved in a merge reque ...@@ -97,6 +100,9 @@ If a developer who happens to also be a maintainer was involved in a merge reque
as a domain expert and/or reviewer, it is recommended that they are not also picked as a domain expert and/or reviewer, it is recommended that they are not also picked
as the maintainer to ultimately approve and merge it. as the maintainer to ultimately approve and merge it.
Maintainers should check before merging if the merge request is approved by the
required approvers.
## Best practices ## Best practices
### Everyone ### Everyone
......
...@@ -53,6 +53,32 @@ To get started with the command line, please read through the ...@@ -53,6 +53,32 @@ To get started with the command line, please read through the
Use GitLab's [file finder](../../../workflow/file_finder.md) to search for files in a repository. Use GitLab's [file finder](../../../workflow/file_finder.md) to search for files in a repository.
### Repository README and index files
When a `README` or `index` file is present in a repository, its contents will be
automatically pre-rendered by GitLab without opening it.
They can either be plain text or have an extension of a supported markup language:
- Asciidoc: `README.adoc` or `index.adoc`
- Markdown: `README.md` or `index.md`
- reStructuredText: `README.rst` or `index.rst`
- Text: `README.txt` or `index.txt`
Some things to note about precedence:
1. When both a `README` and an `index` file are present, the `README` will always
take precedence.
1. When more than one file is present with different extensions, they are
ordered alphabetically, with the exception of a file without an extension
which will always be last in precedence. For example, `README.adoc` will take
precedence over `README.md`, and `README.rst` will take precedence over
`README`.
NOTE: **Note:**
`index` files without an extension will not automatically pre-render. You'll
have to explicitly open them to see their contents.
### Jupyter Notebook files ### Jupyter Notebook files
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/2508) in GitLab 9.1 > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/2508) in GitLab 9.1
...@@ -165,7 +191,7 @@ minutes. ...@@ -165,7 +191,7 @@ minutes.
![Repository Languages bar](img/repository_languages.png) ![Repository Languages bar](img/repository_languages.png)
Not all files are detected, among others; documentation, Not all files are detected, among others; documentation,
vendored code, and most markup languages are excluded. This behaviour can be vendored code, and most markup languages are excluded. This behaviour can be
adjusted by overriding the default. For example, to enable `.proto` files to be adjusted by overriding the default. For example, to enable `.proto` files to be
detected, add the following to `.gitattributes` in the root of your repository. detected, add the following to `.gitattributes` in the root of your repository.
......
...@@ -8,7 +8,7 @@ module Gitlab ...@@ -8,7 +8,7 @@ module Gitlab
module FileDetector module FileDetector
PATTERNS = { PATTERNS = {
# Project files # Project files
readme: %r{\Areadme[^/]*\z}i, readme: %r{\A(readme|index)[^/]*\z}i,
changelog: %r{\A(changelog|history|changes|news)[^/]*\z}i, changelog: %r{\A(changelog|history|changes|news)[^/]*\z}i,
license: %r{\A((un)?licen[sc]e|copying)(\.[^/]+)?\z}i, license: %r{\A((un)?licen[sc]e|copying)(\.[^/]+)?\z}i,
contributing: %r{\Acontributing[^/]*\z}i, contributing: %r{\Acontributing[^/]*\z}i,
......
...@@ -4,10 +4,11 @@ module Gitlab ...@@ -4,10 +4,11 @@ module Gitlab
module MarkupHelper module MarkupHelper
extend self extend self
MARKDOWN_EXTENSIONS = %w(mdown mkd mkdn md markdown).freeze MARKDOWN_EXTENSIONS = %w[mdown mkd mkdn md markdown].freeze
ASCIIDOC_EXTENSIONS = %w(adoc ad asciidoc).freeze ASCIIDOC_EXTENSIONS = %w[adoc ad asciidoc].freeze
OTHER_EXTENSIONS = %w(textile rdoc org creole wiki mediawiki rst).freeze OTHER_EXTENSIONS = %w[textile rdoc org creole wiki mediawiki rst].freeze
EXTENSIONS = MARKDOWN_EXTENSIONS + ASCIIDOC_EXTENSIONS + OTHER_EXTENSIONS EXTENSIONS = MARKDOWN_EXTENSIONS + ASCIIDOC_EXTENSIONS + OTHER_EXTENSIONS
PLAIN_FILENAMES = %w[readme index].freeze
# Public: Determines if a given filename is compatible with GitHub::Markup. # Public: Determines if a given filename is compatible with GitHub::Markup.
# #
...@@ -43,7 +44,7 @@ module Gitlab ...@@ -43,7 +44,7 @@ module Gitlab
# #
# Returns boolean # Returns boolean
def plain?(filename) def plain?(filename)
extension(filename) == 'txt' || filename.casecmp('readme').zero? extension(filename) == 'txt' || plain_filename?(filename)
end end
def previewable?(filename) def previewable?(filename)
...@@ -55,5 +56,9 @@ module Gitlab ...@@ -55,5 +56,9 @@ module Gitlab
def extension(filename) def extension(filename)
File.extname(filename).downcase.delete('.') File.extname(filename).downcase.delete('.')
end end
def plain_filename?(filename)
PLAIN_FILENAMES.include?(filename.downcase)
end
end end
end end
...@@ -179,7 +179,7 @@ describe 'Merge request > User sees merge widget', :js do ...@@ -179,7 +179,7 @@ describe 'Merge request > User sees merge widget', :js do
# Wait for the `ci_status` and `merge_check` requests # Wait for the `ci_status` and `merge_check` requests
wait_for_requests wait_for_requests
expect(page).to have_text(%r{Could not retrieve the pipeline status\. For troubleshooting steps, read the <a href=\".+\">documentation\.</a>}) expect(page).to have_text("Could not retrieve the pipeline status. For troubleshooting steps, read the documentation.")
end end
end end
......
...@@ -41,8 +41,7 @@ describe 'Merge request > User sees pipelines', :js do ...@@ -41,8 +41,7 @@ describe 'Merge request > User sees pipelines', :js do
visit project_merge_request_path(project, merge_request) visit project_merge_request_path(project, merge_request)
wait_for_requests wait_for_requests
expect(page.find('.ci-widget')).to have_text( expect(page.find('.ci-widget')).to have_text("Could not retrieve the pipeline status. For troubleshooting steps, read the documentation.")
%r{Could not retrieve the pipeline status\. For troubleshooting steps, read the <a href=\".+\">documentation\.</a>})
end end
end end
......
import DirtySubmitForm from '~/dirty_submit/dirty_submit_form'; import DirtySubmitForm from '~/dirty_submit/dirty_submit_form';
import { setInput, createForm } from './helper'; import { setInput, createForm } from './helper';
function expectToToggleDisableOnDirtyUpdate(submit, input) {
const originalValue = input.value;
expect(submit.disabled).toBe(true);
return setInput(input, `${originalValue} changes`)
.then(() => expect(submit.disabled).toBe(false))
.then(() => setInput(input, originalValue))
.then(() => expect(submit.disabled).toBe(true));
}
describe('DirtySubmitForm', () => { describe('DirtySubmitForm', () => {
it('disables submit until there are changes', done => { it('disables submit until there are changes', done => {
const { form, input, submit } = createForm(); const { form, input, submit } = createForm();
const originalValue = input.value;
new DirtySubmitForm(form); // eslint-disable-line no-new new DirtySubmitForm(form); // eslint-disable-line no-new
expect(submit.disabled).toBe(true); return expectToToggleDisableOnDirtyUpdate(submit, input)
.then(done)
.catch(done.fail);
});
it('disables submit until there are changes when initializing with a falsy value', done => {
const { form, input, submit } = createForm();
input.value = '';
new DirtySubmitForm(form); // eslint-disable-line no-new
return setInput(input, `${originalValue} changes`) return expectToToggleDisableOnDirtyUpdate(submit, input)
.then(() => {
expect(submit.disabled).toBe(false);
})
.then(() => setInput(input, originalValue))
.then(() => {
expect(submit.disabled).toBe(true);
})
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
......
...@@ -74,7 +74,7 @@ describe('MRWidgetPipeline', () => { ...@@ -74,7 +74,7 @@ describe('MRWidgetPipeline', () => {
}); });
expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain( expect(vm.$el.querySelector('.media-body').textContent.trim()).toContain(
'Could not retrieve the pipeline status. For troubleshooting steps, read the <a href="help">documentation.</a>', 'Could not retrieve the pipeline status. For troubleshooting steps, read the documentation.',
); );
}); });
......
...@@ -15,7 +15,12 @@ describe Gitlab::FileDetector do ...@@ -15,7 +15,12 @@ describe Gitlab::FileDetector do
describe '.type_of' do describe '.type_of' do
it 'returns the type of a README file' do it 'returns the type of a README file' do
expect(described_class.type_of('README.md')).to eq(:readme) %w[README readme INDEX index].each do |filename|
expect(described_class.type_of(filename)).to eq(:readme)
%w[.md .adoc .rst].each do |extname|
expect(described_class.type_of(filename + extname)).to eq(:readme)
end
end
end end
it 'returns nil for a README file in a directory' do it 'returns nil for a README file in a directory' do
......
...@@ -1157,6 +1157,19 @@ describe Ci::Pipeline, :mailer do ...@@ -1157,6 +1157,19 @@ describe Ci::Pipeline, :mailer do
end end
end end
describe '.latest_successful_ids_per_project' do
let(:projects) { create_list(:project, 2) }
let!(:pipeline1) { create(:ci_pipeline, :success, project: projects[0]) }
let!(:pipeline2) { create(:ci_pipeline, :success, project: projects[0]) }
let!(:pipeline3) { create(:ci_pipeline, :failed, project: projects[0]) }
let!(:pipeline4) { create(:ci_pipeline, :success, project: projects[1]) }
it 'returns expected pipeline ids' do
expect(described_class.latest_successful_ids_per_project)
.to contain_exactly(pipeline2, pipeline4)
end
end
describe '.internal_sources' do describe '.internal_sources' do
subject { described_class.internal_sources } subject { described_class.internal_sources }
......
...@@ -37,8 +37,8 @@ describe Awardable do ...@@ -37,8 +37,8 @@ describe Awardable do
create(:award_emoji, awardable: issue3, name: "star", user: award_emoji.user) create(:award_emoji, awardable: issue3, name: "star", user: award_emoji.user)
create(:award_emoji, awardable: issue3, name: "star", user: award_emoji2.user) create(:award_emoji, awardable: issue3, name: "star", user: award_emoji2.user)
expect(Issue.awarded(award_emoji.user)).to eq [issue, issue3] expect(Issue.awarded(award_emoji.user)).to contain_exactly(issue, issue3)
expect(Issue.awarded(award_emoji2.user)).to eq [issue2, issue3] expect(Issue.awarded(award_emoji2.user)).to contain_exactly(issue2, issue3)
end end
end end
......
...@@ -574,6 +574,17 @@ describe Namespace do ...@@ -574,6 +574,17 @@ describe Namespace do
it { expect(group.all_projects.to_a).to match_array([project2, project1]) } it { expect(group.all_projects.to_a).to match_array([project2, project1]) }
end end
describe '#all_pipelines' do
let(:group) { create(:group) }
let(:child) { create(:group, parent: group) }
let!(:project1) { create(:project_empty_repo, namespace: group) }
let!(:project2) { create(:project_empty_repo, namespace: child) }
let!(:pipeline1) { create(:ci_empty_pipeline, project: project1) }
let!(:pipeline2) { create(:ci_empty_pipeline, project: project2) }
it { expect(group.all_pipelines.to_a).to match_array([pipeline1, pipeline2]) }
end
describe '#share_with_group_lock with subgroups', :nested_groups do describe '#share_with_group_lock with subgroups', :nested_groups do
context 'when creating a subgroup' do context 'when creating a subgroup' do
let(:subgroup) { create(:group, parent: root_group )} let(:subgroup) { create(:group, parent: root_group )}
......
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