Merge remote-tracking branch 'origin/master' into deprecation-warning-for-dynamic-milestones

This commit is contained in:
Luke Bennett 2018-03-23 19:24:13 +00:00
commit 54a3514180
No known key found for this signature in database
GPG key ID: A738E9C68D3BF31A
368 changed files with 3262 additions and 1776 deletions

View file

@ -1,20 +1,20 @@
{
"presets": [
["latest", { "es2015": { "modules": false } }],
"stage-2"
],
"presets": [["latest", { "es2015": { "modules": false } }], "stage-2"],
"env": {
"coverage": {
"plugins": [
["istanbul", {
"exclude": [
"spec/javascripts/**/*",
"app/assets/javascripts/locale/**/app.js"
]
}],
["transform-define", {
"process.env.BABEL_ENV": "coverage"
}]
[
"istanbul",
{
"exclude": ["spec/javascripts/**/*", "app/assets/javascripts/locale/**/app.js"]
}
],
[
"transform-define",
{
"process.env.BABEL_ENV": "coverage"
}
]
]
}
}

View file

@ -1,11 +1,12 @@
/app/assets/javascripts/locale/**/app.js
/config/
/builds/
/coverage/
/coverage-javascript/
/node_modules/
/public/
/scripts/
/tmp/
/vendor/
karma.config.js
webpack.config.js
svg.config.js
/app/assets/javascripts/locale/**/app.js

View file

@ -544,7 +544,7 @@ migration:path-mysql:
.db-rollback: &db-rollback
<<: *dedicated-no-docs-pull-cache-job
script:
- bundle exec rake db:rollback STEP=119
- bundle exec rake db:migrate VERSION=20170523121229
- bundle exec rake db:migrate
db:rollback-pg:

5
.prettierignore Normal file
View file

@ -0,0 +1,5 @@
/app/assets/javascripts/locale/**/app.js
/node_modules/
/public/
/vendor/
/tmp/

View file

@ -1,4 +1,13 @@
{
"printWidth": 100,
"singleQuote": true,
"trailingComma": "all"
"trailingComma": "es5",
"overrides": [
{
"files": ["**/app/**/*", "**/spec/**/*"],
"options": {
"trailingComma": "all"
}
}
]
}

View file

@ -118,6 +118,9 @@ Gitlab/ModuleWithInstanceVariables:
- spec/support/**/*.rb
- features/steps/**/*.rb
Gitlab/HTTParty:
Enabled: true
GitlabSecurity/PublicSend:
Enabled: true
Exclude:

View file

@ -2,6 +2,198 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 10.6.0 (2018-03-22)
### Security (4 changes)
- Fixed some SSRF vulnerabilities in services, hooks and integrations. !2337
- Ensure that OTP backup codes are always invalidated.
- Add verification for GitLab Pages custom domains.
- Fix GitLab Auth0 integration signing in the wrong user.
### Fixed (75 changes, 17 of them are from the community)
- Ensure users cannot create environments with leading or trailing slashes (Fixes #39885). !15273
- Fix new project path input overlapping. !16755 (George Tsiolis)
- Respect description and visibility when creating project from template. !16820 (George Tsiolis)
- Remove user notification settings for groups and projects when user leaves. !16906 (Jacopo Beschi @jacopo-beschi)
- Fix Teleporting Emoji. !16963 (Jared Deckard <jared.deckard@gmail.com>)
- Fix duplicate system notes when merging a merge request. !17035
- Fix breadcrumb on labels page for groups. !17045 (Onuwa Nnachi Isaac)
- Fix user avatar's vertical align on the issues and merge requests pages. !17072 (Laszlo Karpati)
- Fix settings panels not expanding when fragment hash linked. !17074
- Fix 404 when listing archived projects in a group where all projects have been archived. !17077 (Ashley Dumaine)
- Allow to call PUT /projects/:id API with only ci_config_path specified. !17105 (Laszlo Karpati)
- Fix long list of recipients on group request membership email. !17121 (Jacopo Beschi @jacopo-beschi)
- Remove duplicated error message on duplicate variable validation. !17135
- Keep "Import project" tab/form active when validation fails trying to import "Repo by URL". !17136
- Fixed bug with unauthenticated requests through git ssh. !17149
- Allows project rename after validation error. !17150
- Fix "Remove source branch" button in Merge request widget during merge when pipeline succeeds state. !17192
- Add missing pagination on the commit diff endpoint. !17203 (Maxime Roussin-Bélanger)
- Fix get a single pages domain when project path contains a period. !17206 (Travis Miller)
- remove avater underline. !17219 (Ken Ding)
- Allows the usage of /milestone quick action for group milestones. !17239 (Jacopo Beschi @jacopo-beschi)
- Encode branch name as binary before creating a RPC request to copy attributes. !17291
- Restart Unicorn and Sidekiq when GRPC throws 14:Endpoint read failed. !17293
- Do not persist Google Project verification flash errors after a page reload. !17299
- Ensure group issues and merge requests pages show results from subgroups when there are no results from the current group. !17312
- Prevent trace artifact migration to incur data loss. !17313
- Fixes gpg popover layout. !17323
- Return a 404 instead of 403 if the repository does not exist on disk. !17341
- Fix Slack/Mattermost notifications not respecting `notify_only_default_branch` setting for pushes. !17345
- Fix Group labels load failure when there are duplicate labels present. !17353
- Allow Prometheus application to be installed from Cluster applications. !17372
- Fixes Prometheus admin configuration page. !17377
- Enable filtering MR list based on clicked label in MR sidebar. !17390
- Fix code and wiki search results pages when non-ASCII text is displayed. !17413
- Count comments on diffs and discussions as contributions for the contributions calendar. !17418 (Riccardo Padovani)
- Add Assignees vue component missing data container. !17426 (George Tsiolis)
- Update tooltip on pipeline cancel to Stop (#42946). !17444
- Removing the two factor check when the user sets a new password. !17457
- Fix quick actions for users who cannot update issues and merge requests. !17482
- Stop loading spinner on error of milestone update on issue. !17507 (Takuya Noguchi)
- Set margins around dropdown dividers to 4px. !17517
- Fix pages flaky failure by reloading stale object. !17522
- Remove extra breadcrumb on tags. !17562 (Takuya Noguchi)
- Fix missing uploads after group transfer. !17658
- Fix markdown table showing extra column. !17669
- Ensure the API returns https links when https is configured. !17681
- Sanitize extra blank spaces used when uploading a SSH key. !40552
- Render htmlentities correctly for links not supported by Rinku.
- Keep link when redacting unauthorized object links.
- Handle empty state in Pipelines page.
- Revert Project.public_or_visible_to_user changes and only apply to snippets.
- Release libgit2 cache and open file descriptors after `git gc` run.
- Fix project dashboard showing the wrong timestamps.
- Fix "Can't modify frozen hash" error when project is destroyed.
- Fix Error 500 when viewing a commit with a GPG signature in Geo.
- Don't error out in system hook if user has `nil` datetime columns.
- Remove double caching of Repository#empty?.
- Don't delete todos or unassign issues and MRs when a user leaves a project.
- Don't cache a nil repository root ref to prevent caching issues.
- Escape HTML entities in commit messages.
- Verify project import status again before marking as failed.
- [GitHub Import] Create an empty wiki if wiki import failed.
- Create empty wiki when import from GitLab and wiki is not there.
- Make sure wiki exists when it's enabled.
- Fix broken loading state for close issue button.
- Fix code and wiki search results when filename is non-ASCII.
- Fix file upload on project show page.
- Fix squashing when a file is renamed.
- Show loading button inline in refresh button in MR widget.
- Fix close button on issues not working on mobile.
- Adds tooltip in environment names to increase readability.
- Fixed issue edit shortcut not opening edit form.
- Fix 500 error being shown when diff has context marker with invalid encoding.
- Render modified icon for moved file in changes dropdown.
- Remember assignee when moving an issue.
### Changed (16 changes, 9 of them are from the community)
- Allow including custom attributes in API responses. !16526 (Markus Koller)
- Apply new default and inline label design. !16956 (George Tsiolis)
- Remove whitespace from the username/email sign in form field. !17020 (Peter lauck)
- CI charts now include the current day. !17032 (Dakkaron)
- Hide CI secret variable values after saving. !17044
- Add new modal Vue component. !17108
- Asciidoc now support inter-document cross references between files in repository. !17125 (Turo Soisenniemi)
- Update issue closing pattern to allow variations in punctuation. !17198 (Vicky Chijwani)
- Add a button to deploy a runner to a Kubernetes cluster in the settings page. !17278
- Pages custom domain: allow update of key/certificate. !17376 (rfwatson)
- Clear the Labels dropdown search filter after a selection is made. !17393 (Andrew Torres)
- Hook data for pipelines includes detailed_status. !17607
- Avoid showing unnecessary Trigger checkboxes for project Integrations with only one event. !17607
- Display a link to external issue tracker when enabled.
- Allow token authentication on go-get request.
- Update SSH key link to include existing keys. (Brendan O'Leary)
### Performance (24 changes, 5 of them are from the community)
- Add catch-up background migration to migrate pipeline stages. !15741
- Move BoardNewIssue vue component. !16947 (George Tsiolis)
- Move IssuableTimeTracker vue component. !16948 (George Tsiolis)
- Move RecentSearchesDropdownContent vue component. !16951 (George Tsiolis)
- Move Assignees vue component. !16952 (George Tsiolis)
- Improve performance of pipeline page by reducing DB queries. !17168
- Store sha256 checksum to job artifacts. !17354
- Move SidebarAssignees vue component. !17398 (George Tsiolis)
- Improve database response time for user activity listing. !17454
- Use persisted/memoized value for MRs shas instead of doing git lookups. !17555
- Cache MergeRequests can_be_resolved_in_ui? git operations. !17589
- Prevent the graphs page from generating unnecessary Gitaly requests. !37602
- Use a user object in ApplicationHelper#avatar_icon where possible to avoid N+1 queries. !42800
- Submit a single batch blob RPC to Gitaly per HTTP request when viewing diffs.
- Avoid re-fetching merge-base SHA from Gitaly unnecessarily.
- Don't use ProjectsFinder in TodosFinder.
- Adding missing indexes on taggings table.
- Add index on section_name_id on ci_build_trace_sections table.
- Cache column_exists? for application settings.
- Cache table_exists?('application_settings') to reduce repeated schema reloads.
- Make --prune a configurable parameter in fetching a git remote.
- Fix timeouts loading /admin/projects page.
- Add partial indexes on todos to handle users with many todos.
- Optimize search queries on the search page by setting a limit for matching records in project scope.
### Added (30 changes, 9 of them are from the community)
- Add CommonMark markdown engine (experimental). !14835 (blackst0ne)
- API: Get references a commit is pushed to. !15026 (Robert Schilling)
- Add overview of branches and a filter for active/stale branches. !15402 (Takuya Noguchi)
- Add project export API. !15860 (Travis Miller)
- expose more metrics in merge requests api. !16589 (haseebeqx)
- #28481: Display time tracking totals on milestone page. !16753 (Riccardo Padovani)
- Add a button on the project page to set up a Kubernetes cluster and enable Auto DevOps. !16900
- Include cycle time in usage ping data. !16973
- Add ability to use external plugins as an alternative to system hooks. !17003
- Add search param to Branches API. !17005 (bunufi)
- API endpoint for importing a project export. !17025
- Display ingress IP address in the Kubernetes page. !17052
- Implemented badge API endpoints. !17082
- Allow installation of GitLab Runner with a single click. !17134
- Allow commits endpoint to work over all commits of a repository. !17182
- Display Runner IP Address. !17286
- Add archive feature to trace. !17314
- Allow maintainers to push to forks of their projects when a merge request is open. !17395
- Foreground verification of uploads and LFS objects. !17402
- Adds updated_at filter to issues and merge_requests API. !17417 (Jacopo Beschi @jacopo-beschi)
- Port /wip quick action command to Merge Request creation (on description). !17463 (Adam Pahlevi)
- Add a paragraph about security implications on Cluster's page. !17486
- Add plugins list to the system hooks page. !17518
- Enable privileged mode for GitLab Runner. !17528
- Expose GITLAB_FEATURES as CI/CD variable (fixes #40994).
- Upgrade GitLab Workhorse to 4.0.0.
- Allow CI/CD Jobs being grouped on version strings.
- Add discussions API for Issues and Snippets.
- Add one group board to Libre.
- Add support for filtering by source and target branch to merge requests API.
### Other (14 changes, 3 of them are from the community)
- Update vue component naming guidelines. !17018 (George Tsiolis)
- Added new design for promotion modals. !17197
- Update to github-linguist 5.3.x. !17241 (Ken Ding)
- update toml-rb to 1.0.0. !17259 (Ken Ding)
- Keep track of projects a user interacted with. !17327
- Enables eslint in codeclimate job. !17392
- Port Labels Select dropdown to Vue. !17411
- Add NOT NULL constraint to projects.namespace_id. !17448
- Ensure foreign keys on clusters applications. !17488
- Started translation into Turkish, Indonesian and Filipino. !17526
- Add documentation for displayed K8s Ingress IP address (#44330). !17836
- Move Ruby endpoints to OPT_OUT.
- Upgrade Workhorse to version 3.8.0 to support structured logging.
- Use host URL to build JIRA remote link icon.
## 10.5.6 (2018-03-16)
### Security (2 changes)
- Fixed some SSRF vulnerabilities in services, hooks and integrations. !2337
- Fix GitLab Auth0 integration signing in the wrong user.
## 10.5.5 (2018-03-15)
### Fixed (3 changes)
@ -261,6 +453,14 @@ entry.
- Adds empty state illustration for pending job.
## 10.4.6 (2018-03-16)
### Security (2 changes)
- Fixed some SSRF vulnerabilities in services, hooks and integrations. !2337
- Fix GitLab Auth0 integration signing in the wrong user.
## 10.4.5 (2018-03-01)
### Security (1 change)
@ -492,6 +692,15 @@ entry.
- Use a background migration for issues.closed_at.
## 10.3.9 (2018-03-16)
### Security (3 changes)
- Fixed some SSRF vulnerabilities in services, hooks and integrations. !2337
- Update nokogiri to 1.8.2. !16807
- Fix GitLab Auth0 integration signing in the wrong user.
## 10.3.8 (2018-03-01)
### Security (1 change)

View file

@ -1 +1 @@
7.1.0
7.1.1

View file

@ -38,7 +38,7 @@ gem 'devise', '~> 4.2'
gem 'doorkeeper', '~> 4.3'
gem 'doorkeeper-openid_connect', '~> 1.3'
gem 'omniauth', '~> 1.8'
gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-auth0', '~> 2.0.0'
gem 'omniauth-azure-oauth2', '~> 0.0.9'
gem 'omniauth-cas3', '~> 1.1.4'
gem 'omniauth-facebook', '~> 4.0.0'
@ -231,7 +231,7 @@ gem 'sanitize', '~> 2.0'
gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input
gem 'loofah', '~> 2.0.3'
gem 'loofah', '~> 2.2'
# Working with license
gem 'licensee', '~> 8.9'

View file

@ -143,6 +143,7 @@ GEM
connection_pool (2.2.1)
crack (0.4.3)
safe_yaml (~> 1.0.0)
crass (1.0.3)
creole (0.5.0)
css_parser (1.5.0)
addressable
@ -485,7 +486,8 @@ GEM
actionpack (>= 4, < 5.2)
activesupport (>= 4, < 5.2)
railties (>= 4, < 5.2)
loofah (2.0.3)
loofah (2.2.2)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
mini_mime (>= 0.1.1)
@ -527,8 +529,8 @@ GEM
omniauth (1.8.1)
hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3)
omniauth-auth0 (1.4.1)
omniauth-oauth2 (~> 1.1)
omniauth-auth0 (2.0.0)
omniauth-oauth2 (~> 1.4)
omniauth-authentiq (0.3.1)
omniauth-oauth2 (~> 1.3, >= 1.3.1)
omniauth-azure-oauth2 (0.0.9)
@ -679,8 +681,8 @@ GEM
activesupport (>= 4.2.0, < 5.0)
nokogiri (~> 1.6)
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
rails-i18n (4.0.9)
i18n (~> 0.7)
railties (~> 4.0)
@ -1093,7 +1095,7 @@ DEPENDENCIES
license_finder (~> 3.1)
licensee (~> 8.9)
lograge (~> 0.5)
loofah (~> 2.0.3)
loofah (~> 2.2)
mail_room (~> 0.9.1)
method_source (~> 0.8)
minitest (~> 5.7.0)
@ -1105,7 +1107,7 @@ DEPENDENCIES
oauth2 (~> 1.4)
octokit (~> 4.8)
omniauth (~> 1.8)
omniauth-auth0 (~> 1.4.1)
omniauth-auth0 (~> 2.0.0)
omniauth-authentiq (~> 0.3.1)
omniauth-azure-oauth2 (~> 0.0.9)
omniauth-cas3 (~> 1.1.4)

View file

@ -1 +1 @@
10.6.0-pre
10.7.0-pre

View file

@ -1,6 +1,6 @@
import $ from 'jquery';
import Vue from 'vue';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import eventHub from '../eventhub';
const Store = gl.issueBoards.BoardsStore;
@ -45,7 +45,7 @@ gl.issueBoards.IssueCardInner = Vue.extend({
};
},
components: {
userAvatarLink,
UserAvatarLink,
},
computed: {
numberOverLimit() {

View file

@ -4,7 +4,7 @@
import $ from 'jquery';
import { s__ } from '~/locale';
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import modal from '~/vue_shared/components/modal.vue';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import { getParameterByName } from '~/lib/utils/common_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility';
@ -15,7 +15,7 @@ import groupsComponent from './groups.vue';
export default {
components: {
loadingIcon,
modal,
DeprecatedModal,
groupsComponent,
},
props: {
@ -52,8 +52,9 @@ export default {
},
},
created() {
this.searchEmptyMessage = this.hideProjects ?
COMMON_STR.GROUP_SEARCH_EMPTY : COMMON_STR.GROUP_PROJECT_SEARCH_EMPTY;
this.searchEmptyMessage = this.hideProjects
? COMMON_STR.GROUP_SEARCH_EMPTY
: COMMON_STR.GROUP_PROJECT_SEARCH_EMPTY;
eventHub.$on('fetchPage', this.fetchPage);
eventHub.$on('toggleChildren', this.toggleChildren);
@ -72,22 +73,30 @@ export default {
eventHub.$off('updateGroups', this.updateGroups);
},
methods: {
fetchGroups({ parentId, page, filterGroupsBy, sortBy, archived, updatePagination }) {
return this.service.getGroups(parentId, page, filterGroupsBy, sortBy, archived)
.then((res) => {
if (updatePagination) {
this.updatePagination(res.headers);
}
fetchGroups({
parentId,
page,
filterGroupsBy,
sortBy,
archived,
updatePagination,
}) {
return this.service
.getGroups(parentId, page, filterGroupsBy, sortBy, archived)
.then(res => {
if (updatePagination) {
this.updatePagination(res.headers);
}
return res;
})
.then(res => res.json())
.catch(() => {
this.isLoading = false;
$.scrollTo(0);
return res;
})
.then(res => res.json())
.catch(() => {
this.isLoading = false;
$.scrollTo(0);
Flash(COMMON_STR.FAILURE);
});
Flash(COMMON_STR.FAILURE);
});
},
fetchAllGroups() {
const page = getParameterByName('page') || null;
@ -103,7 +112,7 @@ export default {
sortBy,
archived,
updatePagination: true,
}).then((res) => {
}).then(res => {
this.isLoading = false;
this.updateGroups(res, Boolean(filterGroupsBy));
});
@ -118,14 +127,18 @@ export default {
sortBy,
archived,
updatePagination: true,
}).then((res) => {
}).then(res => {
this.isLoading = false;
$.scrollTo(0);
const currentPath = mergeUrlParams({ page }, window.location.href);
window.history.replaceState({
page: currentPath,
}, document.title, currentPath);
window.history.replaceState(
{
page: currentPath,
},
document.title,
currentPath,
);
this.updateGroups(res);
});
@ -138,11 +151,13 @@ export default {
// eslint-disable-next-line promise/catch-or-return
this.fetchGroups({
parentId: parentGroup.id,
}).then((res) => {
this.store.setGroupChildren(parentGroup, res);
}).catch(() => {
parentGroup.isChildrenLoading = false;
});
})
.then(res => {
this.store.setGroupChildren(parentGroup, res);
})
.catch(() => {
parentGroup.isChildrenLoading = false;
});
} else {
parentGroup.isOpen = true;
}
@ -154,7 +169,11 @@ export default {
this.targetGroup = group;
this.targetParentGroup = parentGroup;
this.showModal = true;
this.groupLeaveConfirmationMessage = s__(`GroupsTree|Are you sure you want to leave the "${group.fullName}" group?`);
this.groupLeaveConfirmationMessage = s__(
`GroupsTree|Are you sure you want to leave the "${
group.fullName
}" group?`,
);
},
hideLeaveGroupModal() {
this.showModal = false;
@ -162,14 +181,15 @@ export default {
leaveGroup() {
this.showModal = false;
this.targetGroup.isBeingRemoved = true;
this.service.leaveGroup(this.targetGroup.leavePath)
this.service
.leaveGroup(this.targetGroup.leavePath)
.then(res => res.json())
.then((res) => {
.then(res => {
$.scrollTo(0);
this.store.removeGroup(this.targetGroup, this.targetParentGroup);
Flash(res.notice, 'notice');
})
.catch((err) => {
.catch(err => {
let message = COMMON_STR.FAILURE;
if (err.status === 403) {
message = COMMON_STR.LEAVE_FORBIDDEN;
@ -208,8 +228,8 @@ export default {
:search-empty-message="searchEmptyMessage"
:page-info="pageInfo"
/>
<modal
v-if="showModal"
<deprecated-modal
v-show="showModal"
kind="warning"
:primary-button-label="__('Leave')"
:title="__('Are you sure?')"

View file

@ -1,75 +1,75 @@
<script>
import { __ } from '~/locale';
import modal from '~/vue_shared/components/modal.vue';
import { __ } from '~/locale';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
export default {
components: {
modal,
export default {
components: {
DeprecatedModal,
},
props: {
branchId: {
type: String,
required: true,
},
props: {
branchId: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
path: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
data() {
return {
entryName: this.path !== '' ? `${this.path}/` : '',
};
path: {
type: String,
required: true,
},
computed: {
modalTitle() {
if (this.type === 'tree') {
return __('Create new directory');
}
},
data() {
return {
entryName: this.path !== '' ? `${this.path}/` : '',
};
},
computed: {
modalTitle() {
if (this.type === 'tree') {
return __('Create new directory');
}
return __('Create new file');
},
buttonLabel() {
if (this.type === 'tree') {
return __('Create directory');
}
return __('Create file');
},
formLabelName() {
if (this.type === 'tree') {
return __('Directory name');
}
return __('File name');
},
return __('Create new file');
},
mounted() {
this.$refs.fieldName.focus();
},
methods: {
createEntryInStore() {
this.$emit('create', {
branchId: this.branchId,
name: this.entryName,
type: this.type,
});
buttonLabel() {
if (this.type === 'tree') {
return __('Create directory');
}
this.hideModal();
},
hideModal() {
this.$emit('hide');
},
return __('Create file');
},
};
formLabelName() {
if (this.type === 'tree') {
return __('Directory name');
}
return __('File name');
},
},
mounted() {
this.$refs.fieldName.focus();
},
methods: {
createEntryInStore() {
this.$emit('create', {
branchId: this.branchId,
name: this.entryName,
type: this.type,
});
this.hideModal();
},
hideModal() {
this.$emit('hide');
},
},
};
</script>
<template>
<modal
<deprecated-modal
:title="modalTitle"
:primary-button-label="buttonLabel"
kind="success"
@ -95,5 +95,5 @@
</div>
</fieldset>
</form>
</modal>
</deprecated-modal>
</template>

View file

@ -2,7 +2,7 @@
import { mapState, mapActions, mapGetters } from 'vuex';
import tooltip from '~/vue_shared/directives/tooltip';
import icon from '~/vue_shared/components/icon.vue';
import modal from '~/vue_shared/components/modal.vue';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import commitFilesList from './commit_sidebar/list.vue';
import * as consts from '../stores/modules/commit/constants';
@ -10,7 +10,7 @@ import Actions from './commit_sidebar/actions.vue';
export default {
components: {
modal,
DeprecatedModal,
icon,
commitFilesList,
Actions,
@ -37,23 +37,20 @@ export default {
'lastCommitMsg',
'changedFiles',
]),
...mapState('commit', [
'commitMessage',
'submitCommitLoading',
]),
...mapState('commit', ['commitMessage', 'submitCommitLoading']),
...mapGetters('commit', [
'commitButtonDisabled',
'discardDraftButtonDisabled',
'branchName',
]),
statusSvg() {
return this.lastCommitMsg ? this.committedStateSvgPath : this.noChangesStateSvgPath;
return this.lastCommitMsg
? this.committedStateSvgPath
: this.noChangesStateSvgPath;
},
},
methods: {
...mapActions([
'setPanelCollapsedStatus',
]),
...mapActions(['setPanelCollapsedStatus']),
...mapActions('commit', [
'updateCommitMessage',
'discardDraft',
@ -67,8 +64,9 @@ export default {
});
},
forceCreateNewBranch() {
return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH)
.then(() => this.commitChanges());
return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() =>
this.commitChanges(),
);
},
},
};
@ -81,7 +79,7 @@ export default {
'multi-file-commit-empty-state-container': !changedFiles.length
}"
>
<modal
<deprecated-modal
id="ide-create-branch-modal"
:primary-button-label="__('Create new branch')"
kind="success"
@ -92,7 +90,7 @@ export default {
{{ __(`This branch has changed since you started editing.
Would you like to create a new branch?`) }}
</template>
</modal>
</deprecated-modal>
<commit-files-list
title="Staged"
:file-list="changedFiles"

View file

@ -1727,6 +1727,7 @@ export default class Notes {
// Get Form metadata
const $submitBtn = $(e.target);
$submitBtn.prop('disabled', true);
let $form = $submitBtn.parents('form');
const $closeBtn = $form.find('.js-note-target-close');
const isDiscussionNote =
@ -1761,7 +1762,6 @@ export default class Notes {
// If comment is to resolve discussion, disable submit buttons while
// comment posting is finished.
if (isDiscussionResolve) {
$submitBtn.disable();
$form.find('.js-comment-submit-button').disable();
}
@ -1816,6 +1816,7 @@ export default class Notes {
.then(res => {
const note = res.data;
$submitBtn.prop('disabled', false);
// Submission successful! remove placeholder
$notesContainer.find(`#${noteUniqueId}`).remove();
@ -1899,7 +1900,7 @@ export default class Notes {
.catch(() => {
// Submission failed, remove placeholder note and show Flash error message
$notesContainer.find(`#${noteUniqueId}`).remove();
$submitBtn.prop('disabled', false);
const blurEvent = new CustomEvent('blur.imageDiff', {
detail: e,
});

View file

@ -1,11 +1,11 @@
<script>
import _ from 'underscore';
import modal from '~/vue_shared/components/modal.vue';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import { s__, sprintf } from '~/locale';
export default {
components: {
modal,
DeprecatedModal,
},
props: {
deleteProjectUrl: {
@ -79,7 +79,7 @@
</script>
<template>
<modal
<deprecated-modal
id="delete-project-modal"
:title="title"
:text="text"
@ -121,5 +121,5 @@
/>
</form>
</template>
</modal>
</deprecated-modal>
</template>

View file

@ -1,11 +1,11 @@
<script>
import _ from 'underscore';
import modal from '~/vue_shared/components/modal.vue';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import { s__, sprintf } from '~/locale';
export default {
components: {
modal,
DeprecatedModal,
},
props: {
deleteUserUrl: {
@ -113,7 +113,7 @@
</script>
<template>
<modal
<deprecated-modal
id="delete-user-modal"
:title="title"
:text="text"
@ -170,5 +170,5 @@
{{ secondaryButtonLabel }}
</button>
</template>
</modal>
</deprecated-modal>
</template>

View file

@ -2,14 +2,14 @@
import axios from '~/lib/utils/axios_utils';
import Flash from '~/flash';
import modal from '~/vue_shared/components/modal.vue';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import { n__, s__, sprintf } from '~/locale';
import { redirectTo } from '~/lib/utils/url_utility';
import eventHub from '../event_hub';
export default {
components: {
modal,
DeprecatedModal,
},
props: {
issueCount: {
@ -92,7 +92,7 @@ Once deleted, it cannot be undone or recovered.`),
</script>
<template>
<modal
<deprecated-modal
id="delete-milestone-modal"
:title="title"
:text="text"
@ -106,5 +106,5 @@ Once deleted, it cannot be undone or recovered.`),
<p v-html="props.text"></p>
</template>
</modal>
</deprecated-modal>
</template>

View file

@ -27,12 +27,21 @@ export default {
required: true,
},
},
computed: {
metricDetails() {
return this.currentRequest.details[this.metric];
},
detailsList() {
return this.metricDetails[this.details];
},
},
};
</script>
<template>
<div
:id="`peek-view-${metric}`"
class="view"
v-if="currentRequest.details"
>
<button
:data-target="`#modal-peek-${metric}-details`"
@ -40,34 +49,40 @@ export default {
type="button"
data-toggle="modal"
>
<span
v-if="currentRequest.details"
class="bold"
>
{{ currentRequest.details[metric].duration }}
/
{{ currentRequest.details[metric].calls }}
</span>
{{ metricDetails.duration }}
/
{{ metricDetails.calls }}
</button>
<gl-modal
v-if="currentRequest.details"
:id="`modal-peek-${metric}-details`"
:header-title-text="header"
class="performance-bar-modal"
>
<table class="table">
<tr
v-for="(item, index) in currentRequest.details[metric][details]"
:key="index"
>
<td><strong>{{ item.duration }}ms</strong></td>
<td
v-for="key in keys"
:key="key"
<table
class="table"
>
<template v-if="detailsList.length">
<tr
v-for="(item, index) in detailsList"
:key="index"
>
{{ item[key] }}
</td>
</tr>
<td><strong>{{ item.duration }}ms</strong></td>
<td
v-for="key in keys"
:key="key"
class="break-word"
>
{{ item[key] }}
</td>
</tr>
</template>
<template v-else>
<tr>
<td>
No {{ header.toLowerCase() }} for this request.
</td>
</tr>
</template>
</table>
<div slot="footer">

View file

@ -113,27 +113,21 @@ export default {
id="js-peek"
:class="env"
>
<request-selector
v-if="currentRequest"
:current-request="currentRequest"
:requests="requests"
@change-current-request="changeCurrentRequest"
/>
<div
id="peek-view-host"
class="view prepend-left-5"
v-if="currentRequest"
class="container-fluid container-limited"
>
<span
v-if="currentRequest && currentRequest.details"
class="current-host"
<div
id="peek-view-host"
class="view"
>
{{ currentRequest.details.host.hostname }}
</span>
</div>
<div
v-if="currentRequest"
class="wrapper"
>
<span
v-if="currentRequest.details"
class="current-host"
>
{{ currentRequest.details.host.hostname }}
</span>
</div>
<upstream-performance-bar
v-if="initialRequest && currentRequest.details"
/>
@ -186,6 +180,12 @@ export default {
gc
</span>
</div>
<request-selector
v-if="currentRequest"
:current-request="currentRequest"
:requests="requests"
@change-current-request="changeCurrentRequest"
/>
</div>
</div>
</template>

View file

@ -37,7 +37,7 @@ export default {
<template>
<div
id="peek-request-selector"
class="append-right-5 pull-right"
class="pull-right"
>
<select v-model="currentRequestId">
<option

View file

@ -5,6 +5,8 @@ export default {
.getElementById('peek-view-performance-bar')
.cloneNode(true);
upstreamPerformanceBar.classList.remove('hidden');
this.$refs.wrapper.appendChild(upstreamPerformanceBar);
},
};

View file

@ -4,9 +4,9 @@ import Vue from 'vue';
import performanceBarApp from './components/performance_bar_app.vue';
import PerformanceBarStore from './stores/performance_bar_store';
export default () =>
export default ({ container }) =>
new Vue({
el: '#js-peek',
el: container,
components: {
performanceBarApp,
},

View file

@ -1,11 +1,28 @@
import Vue from 'vue';
import _ from 'underscore';
import axios from '../../lib/utils/axios_utils';
let vueResourceInterceptor;
export default class PerformanceBarService {
static fetchRequestDetails(peekUrl, requestId) {
return axios.get(peekUrl, { params: { request_id: requestId } });
}
static registerInterceptor(peekUrl, callback) {
vueResourceInterceptor = (request, next) => {
next(response => {
const requestId = response.headers['x-request-id'];
const requestUrl = response.url;
if (requestUrl !== peekUrl && requestId) {
callback(requestId, requestUrl);
}
});
};
Vue.http.interceptors.push(vueResourceInterceptor);
return axios.interceptors.response.use(response => {
const requestId = response.headers['x-request-id'];
const requestUrl = response.config.url;
@ -20,5 +37,9 @@ export default class PerformanceBarService {
static removeInterceptor(interceptor) {
axios.interceptors.response.eject(interceptor);
Vue.http.interceptors = _.without(
Vue.http.interceptors,
vueResourceInterceptor,
);
}
}

View file

@ -1,5 +1,5 @@
<script>
import modal from '~/vue_shared/components/modal.vue';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import { s__, sprintf } from '~/locale';
import pipelinesTableRowComponent from './pipelines_table_row.vue';
import eventHub from '../event_hub';
@ -12,7 +12,7 @@
export default {
components: {
pipelinesTableRowComponent,
modal,
DeprecatedModal,
},
props: {
pipelines: {
@ -120,7 +120,7 @@
:auto-devops-help-path="autoDevopsHelpPath"
:view-type="viewType"
/>
<modal
<deprecated-modal
id="confirmation-modal"
:title="modalTitle"
:text="modalText"
@ -134,6 +134,6 @@
>
<p v-html="props.text"></p>
</template>
</modal>
</deprecated-modal>
</div>
</template>

View file

@ -1,11 +1,11 @@
<script>
import modal from '~/vue_shared/components/modal.vue';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import { __, s__, sprintf } from '~/locale';
import csrf from '~/lib/utils/csrf';
export default {
components: {
modal,
DeprecatedModal,
},
props: {
actionUrl: {
@ -76,7 +76,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
</script>
<template>
<modal
<deprecated-modal
id="delete-account-modal"
:title="s__('Profiles|Delete your account?')"
:text="text"
@ -131,5 +131,5 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
</form>
</template>
</modal>
</deprecated-modal>
</template>

View file

@ -1,4 +1,5 @@
<script>
import { sprintf, s__ } from '~/locale';
import statusCodes from '../../lib/utils/http_status';
import { bytesToMiB } from '../../lib/utils/number_utils';
import { backOff } from '../../lib/utils/common_utils';
@ -45,17 +46,28 @@ export default {
shouldShowMetricsUnavailable() {
return !this.loadingMetrics && !this.hasMetrics && !this.loadFailed;
},
memoryChangeType() {
memoryChangeMessage() {
const messageProps = {
memoryFrom: this.memoryFrom,
memoryTo: this.memoryTo,
metricsLinkStart: `<a href="${this.metricsMonitoringUrl}">`,
metricsLinkEnd: '</a>',
emphasisStart: '<b>',
emphasisEnd: '</b>',
};
const memoryTo = Number(this.memoryTo);
const memoryFrom = Number(this.memoryFrom);
let memoryUsageMsg = '';
if (memoryTo > memoryFrom) {
return 'increased';
memoryUsageMsg = sprintf(s__('mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} increased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB'), messageProps, false);
} else if (memoryTo < memoryFrom) {
return 'decreased';
memoryUsageMsg = sprintf(s__('mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} decreased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB'), messageProps, false);
} else {
memoryUsageMsg = sprintf(s__('mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB'), messageProps, false);
}
return 'unchanged';
return memoryUsageMsg;
},
},
mounted() {
@ -130,24 +142,22 @@ export default {
<i
class="fa fa-spinner fa-spin usage-info-load-spinner"
aria-hidden="true">
</i>Loading deployment statistics
</i>{{ s__('mrWidget|Loading deployment statistics') }}
</p>
<p
v-if="shouldShowMemoryGraph"
class="usage-info js-usage-info">
<a
:href="metricsMonitoringUrl"
>Memory</a> usage <b>{{ memoryChangeType }}</b> from {{ memoryFrom }}MB to {{ memoryTo }}MB
{{ memoryChangeMessage }}
</p>
<p
v-if="shouldShowLoadFailure"
class="usage-info js-usage-info usage-info-failed">
Failed to load deployment statistics
{{ s__('mrWidget|Failed to load deployment statistics') }}
</p>
<p
v-if="shouldShowMetricsUnavailable"
class="usage-info js-usage-info usage-info-unavailable">
Deployment statistics are not available currently
{{ s__('mrWidget|Deployment statistics are not available currently') }}
</p>
<memory-graph
v-if="shouldShowMemoryGraph"

View file

@ -1,7 +1,7 @@
<script>
/* eslint-disable vue/require-default-prop */
export default {
name: 'Modal',
name: 'DeprecatedModal', // use GlModal instead
props: {
id: {

View file

@ -1,11 +1,11 @@
<script>
import modal from './modal.vue';
import DeprecatedModal from './deprecated_modal.vue';
export default {
name: 'RecaptchaModal',
components: {
modal,
DeprecatedModal,
},
props: {
@ -65,7 +65,7 @@
</script>
<template>
<modal
<deprecated-modal
kind="warning"
class="recaptcha-modal js-recaptcha-modal"
:hide-footer="true"
@ -82,5 +82,5 @@
>
</div>
</div>
</modal>
</deprecated-modal>
</template>

View file

@ -446,6 +446,10 @@ img.emoji {
opacity: .5;
}
.break-word {
word-wrap: break-word;
}
/** COMMON CLASSES **/
.prepend-top-0 { margin-top: 0; }
.prepend-top-5 { margin-top: 5px; }

View file

@ -622,7 +622,7 @@
}
.dropdown-content {
max-height: $dropdown-max-height;
max-height: 252px;
overflow-y: auto;
}
@ -699,6 +699,31 @@
border-radius: $border-radius-base;
}
.git-revision-dropdown {
.dropdown-content {
max-height: 215px;
}
}
.sidebar-move-issue-dropdown {
.dropdown-content {
max-height: 160px;
}
}
.dropdown-menu-author {
.dropdown-content {
max-height: 215px;
}
}
.dropdown-menu-labels {
.dropdown-content {
max-height: 128px;
}
}
.dropdown-menu-due-date {
.dropdown-content {
max-height: 230px;

View file

@ -152,3 +152,4 @@
.sidebar-collapsed-icon .sidebar-collapsed-value {
font-size: 12px;
}

View file

@ -31,8 +31,12 @@
.dropdown-menu-issues-board-new {
width: 320px;
.open & {
max-height: 400px;
}
.dropdown-content {
max-height: 150px;
max-height: 162px;
}
}

View file

@ -1,6 +1,17 @@
.content-list > .branch-item,
.branch-title {
display: flex;
align-items: center;
}
.branch-info {
flex: auto;
min-width: 0;
overflow: hidden;
}
.divergence-graph {
padding: 12px 12px 0 0;
float: right;
padding: 0 6px;
.graph-side {
position: relative;
@ -53,3 +64,9 @@
background-color: $divergence-graph-separator-bg;
}
}
.divergence-graph,
.branch-item .controls {
flex: 0 0 auto;
white-space: nowrap;
}

View file

@ -162,17 +162,14 @@
* Last push widget
*/
.event-last-push {
overflow: auto;
width: 100%;
display: flex;
align-items: center;
.event-last-push-text {
@include str-truncated(100%);
padding: 4px 0;
font-size: 13px;
float: left;
margin-right: -150px;
padding-right: 150px;
line-height: 20px;
margin-right: $gl-padding;
}
}

View file

@ -26,9 +26,15 @@
}
}
.dropdown-menu-labels {
.dropdown-content {
max-height: 135px;
}
}
.dropdown-new-label {
.dropdown-content {
max-height: 260px;
max-height: 136px;
}
}

View file

@ -9,7 +9,6 @@
.new_project,
.edit-project,
.import-project {
.help-block {
margin-bottom: 10px;
}
@ -18,18 +17,25 @@
border-radius: $border-radius-base;
}
.input-group > div {
.input-group {
display: flex;
&:last-child {
padding-right: 0;
.select2-container {
display: unset;
max-width: unset;
width: unset !important;
flex-grow: 1;
}
> div {
&:last-child {
padding-right: 0;
}
}
}
@media (max-width: $screen-xs-max) {
.input-group > div {
margin-bottom: 14px;
&:last-child {
margin-bottom: 0;
}
@ -41,17 +47,24 @@
}
.input-group-addon {
overflow: hidden;
text-overflow: ellipsis;
line-height: unset;
width: unset;
max-width: 50%;
text-align: left;
&.static-namespace {
height: 35px;
border-radius: 3px;
border: 1px solid $border-color;
max-width: 100%;
flex-grow: 1;
}
+ .select2 a,
+ .btn-default {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-radius: 0 $border-radius-base $border-radius-base 0;
}
}
}
@ -290,7 +303,7 @@
font-size: 13px;
font-weight: $gl-font-weight-bold;
line-height: 13px;
letter-spacing: .4px;
letter-spacing: 0.4px;
padding: 6px 14px;
text-align: center;
vertical-align: middle;
@ -443,7 +456,7 @@ a.deploy-project-label {
text-decoration: none;
&.disabled {
opacity: .3;
opacity: 0.3;
cursor: not-allowed;
}
}
@ -600,26 +613,26 @@ a.deploy-project-label {
}
.first-column {
@media(min-width: $screen-xs-min) {
@media (min-width: $screen-xs-min) {
max-width: 50%;
padding-right: 30px;
}
@media(max-width: $screen-xs-max) {
@media (max-width: $screen-xs-max) {
max-width: 100%;
width: 100%;
}
}
.second-column {
@media(min-width: $screen-xs-min) {
@media (min-width: $screen-xs-min) {
width: 50%;
flex: 1;
padding-left: 30px;
position: relative;
}
@media(max-width: $screen-xs-max) {
@media (max-width: $screen-xs-max) {
max-width: 100%;
width: 100%;
padding-left: 0;
@ -632,7 +645,7 @@ a.deploy-project-label {
}
&::before {
content: "OR";
content: 'OR';
position: absolute;
left: -10px;
top: 50%;
@ -656,7 +669,7 @@ a.deploy-project-label {
}
&::after {
content: "";
content: '';
position: absolute;
background-color: $border-color;
bottom: 0;
@ -921,10 +934,7 @@ pre.light-well {
border-right: solid 1px transparent;
}
}
}
.protected-tags-list,
.protected-branches-list {
.dropdown-menu-toggle {
width: 100%;
max-width: 300px;

View file

@ -112,7 +112,7 @@ input[type="checkbox"]:hover {
}
.dropdown-content {
max-height: 350px;
max-height: 302px;
}
}

View file

@ -15,6 +15,10 @@
line-height: $performance-bar-height;
color: $perf-bar-text;
select {
width: 200px;
}
&.disabled {
display: none;
}
@ -43,12 +47,6 @@
}
}
.wrapper {
width: 80%;
height: $performance-bar-height;
margin: 0 auto;
}
// UI Elements
.bucket {
background: $perf-bar-bucket-bg;
@ -108,8 +106,14 @@
}
}
.performance-bar-modal .modal-footer {
display: none;
.performance-bar-modal {
.modal-footer {
display: none;
}
.modal-dialog {
width: 860px;
}
}
}

View file

@ -3,23 +3,9 @@
# Automatically sets the layout and ensures an administrator is logged in
class Admin::ApplicationController < ApplicationController
before_action :authenticate_admin!
before_action :display_read_only_information
layout 'admin'
def authenticate_admin!
render_404 unless current_user.admin?
end
def display_read_only_information
return unless Gitlab::Database.read_only?
flash.now[:notice] = read_only_message
end
private
# Overridden in EE
def read_only_message
_('You are on a read-only GitLab instance.')
end
end

View file

@ -18,6 +18,18 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
end
end
# Extend the standard implementation to also increment
# the number of failed sign in attempts
def failure
if params[:username].present? && AuthHelper.form_based_provider?(failed_strategy.name)
user = User.by_login(params[:username])
user&.increment_failed_attempts!
end
super
end
# Extend the standard message generation to accept our custom exception
def failure_message
exception = env["omniauth.error"]
@ -95,6 +107,14 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
handle_omniauth
end
def auth0
if oauth['uid'].blank?
fail_auth0_login
else
handle_omniauth
end
end
private
def handle_omniauth
@ -170,6 +190,12 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
redirect_to new_user_session_path
end
def fail_auth0_login
flash[:alert] = 'Wrong extern UID provided. Make sure Auth0 is configured correctly.'
redirect_to new_user_session_path
end
def handle_disabled_provider
label = Gitlab::Auth::OAuth::Provider.label_for(oauth['provider'])
flash[:alert] = "Signing in using #{label} has been disabled"

View file

@ -21,4 +21,26 @@ class Projects::PagesController < Projects::ApplicationController
end
end
end
def update
result = Projects::UpdateService.new(@project, current_user, project_params).execute
respond_to do |format|
format.html do
if result[:status] == :success
flash[:notice] = 'Your changes have been saved'
else
flash[:alert] = 'Something went wrong on our end'
end
redirect_to project_pages_path(@project)
end
end
end
private
def project_params
params.require(:project).permit(:pages_https_only)
end
end

View file

@ -10,10 +10,7 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
if service.execute
flash[:notice] = "Pipelines settings for '#{@project.name}' were successfully updated."
if service.run_auto_devops_pipeline?
CreatePipelineWorker.perform_async(project.id, current_user.id, project.default_branch, :web, ignore_skip_ci: true, save_on_errors: false)
flash[:success] = "A new Auto DevOps pipeline has been created, go to <a href=\"#{project_pipelines_path(@project)}\">Pipelines page</a> for details".html_safe
end
run_autodevops_pipeline(service)
redirect_to project_settings_ci_cd_path(@project)
else
@ -24,6 +21,18 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
private
def run_autodevops_pipeline(service)
return unless service.run_auto_devops_pipeline?
if @project.empty_repo?
flash[:warning] = "This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch."
return
end
CreatePipelineWorker.perform_async(project.id, current_user.id, project.default_branch, :web, ignore_skip_ci: true, save_on_errors: false)
flash[:success] = "A new Auto DevOps pipeline has been created, go to <a href=\"#{project_pipelines_path(@project)}\">Pipelines page</a> for details".html_safe
end
def update_params
params.require(:project).permit(
:runners_token, :builds_enabled, :build_allow_git_fetch,

View file

@ -323,4 +323,11 @@ module ApplicationHelper
def locale_path
asset_path("locale/#{Gitlab::I18n.locale}/app.js")
end
# Overridden in EE
def read_only_message
return unless Gitlab::Database.read_only?
_('You are on a read-only GitLab instance.')
end
end

View file

@ -96,7 +96,7 @@ module ApplicationSettingsHelper
def repository_storages_options_for_select(selected)
options = Gitlab.config.repositories.storages.map do |name, storage|
["#{name} - #{storage['path']}", name]
["#{name} - #{storage['gitaly_address']}", name]
end
options_for_select(options, selected)
@ -245,7 +245,8 @@ module ApplicationSettingsHelper
:usage_ping_enabled,
:user_default_external,
:user_oauth_applications,
:version_check_enabled
:version_check_enabled,
:allow_local_requests_from_hooks_and_services
]
end
end

View file

@ -531,4 +531,22 @@ module ProjectsHelper
def can_show_last_commit_in_list?(project)
can?(current_user, :read_cross_project) && project.commit
end
def pages_https_only_disabled?
!@project.pages_domains.all?(&:https?)
end
def pages_https_only_title
return unless pages_https_only_disabled?
"You must enable HTTPS for all your domains first"
end
def pages_https_only_label_class
if pages_https_only_disabled?
"list-label disabled"
else
"list-label"
end
end
end

View file

@ -330,7 +330,8 @@ class ApplicationSetting < ActiveRecord::Base
usage_ping_enabled: Settings.gitlab['usage_ping_enabled'],
gitaly_timeout_fast: 10,
gitaly_timeout_medium: 30,
gitaly_timeout_default: 55
gitaly_timeout_default: 55,
allow_local_requests_from_hooks_and_services: false
}
end

View file

@ -14,7 +14,7 @@ module Ci
has_many :stages
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
has_many :variables, class_name: 'Ci::PipelineVariable'

View file

@ -21,7 +21,7 @@ module Avatarable
def avatar_type
unless self.avatar.image?
self.errors.add :avatar, "only images allowed"
errors.add :avatar, "file format is not supported. Please try one of the following supported formats: #{AvatarUploader::IMAGE_EXT.join(', ')}"
end
end

View file

@ -189,12 +189,6 @@ class Group < Namespace
owners.include?(user) && owners.size == 1
end
def avatar_type
unless self.avatar.image?
self.errors.add :avatar, "only images allowed"
end
end
def post_create_hook
Gitlab::AppLogger.info("Group \"#{name}\" was created")

View file

@ -6,8 +6,10 @@ class PagesDomain < ActiveRecord::Base
validates :domain, hostname: { allow_numeric_hostname: true }
validates :domain, uniqueness: { case_sensitive: false }
validates :certificate, certificate: true, allow_nil: true, allow_blank: true
validates :key, certificate_key: true, allow_nil: true, allow_blank: true
validates :certificate, presence: { message: 'must be present if HTTPS-only is enabled' }, if: ->(domain) { domain.project&.pages_https_only? }
validates :certificate, certificate: true, if: ->(domain) { domain.certificate.present? }
validates :key, presence: { message: 'must be present if HTTPS-only is enabled' }, if: ->(domain) { domain.project&.pages_https_only? }
validates :key, certificate_key: true, if: ->(domain) { domain.key.present? }
validates :verification_code, presence: true, allow_blank: false
validate :validate_pages_domain
@ -46,6 +48,10 @@ class PagesDomain < ActiveRecord::Base
!Gitlab::CurrentSettings.pages_domain_verification_enabled? || enabled_until.present?
end
def https?
certificate.present?
end
def to_param
domain
end

View file

@ -38,6 +38,9 @@ class Project < ActiveRecord::Base
attachments: 2
}.freeze
# Valids ports to import from
VALID_IMPORT_PORTS = [22, 80, 443].freeze
cache_markdown_field :description, pipeline: :description
delegate :feature_available?, :builds_enabled?, :wiki_enabled?,
@ -264,6 +267,7 @@ class Project < ActiveRecord::Base
validate :visibility_level_allowed_by_group
validate :visibility_level_allowed_as_fork
validate :check_wiki_path_conflict
validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) }
validates :repository_storage,
presence: true,
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
@ -500,7 +504,7 @@ class Project < ActiveRecord::Base
end
def repository_storage_path
Gitlab.config.repositories.storages[repository_storage].try(:[], 'path')
Gitlab.config.repositories.storages[repository_storage]&.legacy_disk_path
end
def team
@ -734,6 +738,26 @@ class Project < ActiveRecord::Base
end
end
def pages_https_only
return false unless Gitlab.config.pages.external_https
super
end
def pages_https_only?
return false unless Gitlab.config.pages.external_https
super
end
def validate_pages_https_only
return unless pages_https_only?
unless pages_domains.all?(&:https?)
errors.add(:pages_https_only, "cannot be enabled unless all domains have TLS certificates")
end
end
def to_param
if persisted? && errors.include?(:path)
path_was

View file

@ -1,6 +1,4 @@
class AssemblaService < Service
include HTTParty
prop_accessor :token, :subdomain
validates :token, presence: true, if: :activated?
@ -31,6 +29,6 @@ class AssemblaService < Service
return unless supported_events.include?(data[:object_kind])
url = "https://atlas.assembla.com/spaces/#{subdomain}/github_tool?secret_key=#{token}"
AssemblaService.post(url, body: { payload: data }.to_json, headers: { 'Content-Type' => 'application/json' })
Gitlab::HTTP.post(url, body: { payload: data }.to_json, headers: { 'Content-Type' => 'application/json' })
end
end

View file

@ -117,14 +117,14 @@ class BambooService < CiService
url = build_url(path)
if username.blank? && password.blank?
HTTParty.get(url, verify: false)
Gitlab::HTTP.get(url, verify: false)
else
url << '&os_authType=basic'
HTTParty.get(url, verify: false,
basic_auth: {
username: username,
password: password
})
Gitlab::HTTP.get(url, verify: false,
basic_auth: {
username: username,
password: password
})
end
end
end

View file

@ -71,7 +71,7 @@ class BuildkiteService < CiService
end
def calculate_reactive_cache(sha, ref)
response = HTTParty.get(commit_status_path(sha), verify: false)
response = Gitlab::HTTP.get(commit_status_path(sha), verify: false)
status =
if response.code == 200 && response['status']

View file

@ -1,6 +1,4 @@
class CampfireService < Service
include HTTParty
prop_accessor :token, :subdomain, :room
validates :token, presence: true, if: :activated?
@ -31,7 +29,6 @@ class CampfireService < Service
def execute(data)
return unless supported_events.include?(data[:object_kind])
self.class.base_uri base_uri
message = build_message(data)
speak(self.room, message, auth)
end
@ -69,14 +66,14 @@ class CampfireService < Service
}
}
}
res = self.class.post(path, auth.merge(body))
res = Gitlab::HTTP.post(path, base_uri: base_uri, **auth.merge(body))
res.code == 201 ? res : nil
end
# Returns a list of rooms, or [].
# https://github.com/basecamp/campfire-api/blob/master/sections/rooms.md#get-rooms
def rooms(auth)
res = self.class.get("/rooms.json", auth)
res = Gitlab::HTTP.get("/rooms.json", base_uri: base_uri, **auth)
res.code == 200 ? res["rooms"] : []
end

View file

@ -49,7 +49,7 @@ class DroneCiService < CiService
end
def calculate_reactive_cache(sha, ref)
response = HTTParty.get(commit_status_path(sha, ref), verify: enable_ssl_verification)
response = Gitlab::HTTP.get(commit_status_path(sha, ref), verify: enable_ssl_verification)
status =
if response.code == 200 && response['status']

View file

@ -1,6 +1,4 @@
class ExternalWikiService < Service
include HTTParty
prop_accessor :external_wiki_url
validates :external_wiki_url, presence: true, url: true, if: :activated?
@ -24,7 +22,7 @@ class ExternalWikiService < Service
end
def execute(_data)
@response = HTTParty.get(properties['external_wiki_url'], verify: true) rescue nil
@response = Gitlab::HTTP.get(properties['external_wiki_url'], verify: true) rescue nil
if @response != 200
nil
end

View file

@ -77,13 +77,13 @@ class IssueTrackerService < Service
result = false
begin
response = HTTParty.head(self.project_url, verify: true)
response = Gitlab::HTTP.head(self.project_url, verify: true)
if response
message = "#{self.type} received response #{response.code} when attempting to connect to #{self.project_url}"
result = true
end
rescue HTTParty::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => error
rescue Gitlab::HTTP::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => error
message = "#{self.type} had an error when trying to connect to #{self.project_url}: #{error.message}"
end
Rails.logger.info(message)

View file

@ -52,7 +52,7 @@ class MockCiService < CiService
#
#
def commit_status(sha, ref)
response = HTTParty.get(commit_status_path(sha), verify: false)
response = Gitlab::HTTP.get(commit_status_path(sha), verify: false)
read_commit_status(response)
rescue Errno::ECONNREFUSED
:error

View file

@ -1,6 +1,4 @@
class PackagistService < Service
include HTTParty
prop_accessor :username, :token, :server
validates :username, presence: true, if: :activated?

View file

@ -1,6 +1,4 @@
class PivotaltrackerService < Service
include HTTParty
API_ENDPOINT = 'https://www.pivotaltracker.com/services/v5/source_commits'.freeze
prop_accessor :token, :restrict_to_branch
@ -52,7 +50,7 @@ class PivotaltrackerService < Service
'message' => commit[:message]
}
}
PivotaltrackerService.post(
Gitlab::HTTP.post(
API_ENDPOINT,
body: message.to_json,
headers: {

View file

@ -1,6 +1,5 @@
class PushoverService < Service
include HTTParty
base_uri 'https://api.pushover.net/1'
BASE_URI = 'https://api.pushover.net/1'.freeze
prop_accessor :api_key, :user_key, :device, :priority, :sound
validates :api_key, :user_key, :priority, presence: true, if: :activated?
@ -99,6 +98,6 @@ class PushoverService < Service
pushover_data[:sound] = sound
end
PushoverService.post('/messages.json', body: pushover_data)
Gitlab::HTTP.post('/messages.json', base_uri: BASE_URI, body: pushover_data)
end
end

View file

@ -83,7 +83,7 @@ class TeamcityService < CiService
branch = Gitlab::Git.ref_name(data[:ref])
HTTParty.post(
Gitlab::HTTP.post(
build_url('httpAuth/app/rest/buildQueue'),
body: "<build branchName=\"#{branch}\">"\
"<buildType id=\"#{build_type}\"/>"\
@ -134,10 +134,10 @@ class TeamcityService < CiService
end
def get_path(path)
HTTParty.get(build_url(path), verify: false,
basic_auth: {
username: username,
password: password
})
Gitlab::HTTP.get(build_url(path), verify: false,
basic_auth: {
username: username,
password: password
})
end
end

View file

@ -65,7 +65,7 @@ module Ci
project.pipelines
.where(ref: pipeline.ref)
.where.not(id: pipeline.id)
.where.not(sha: project.repository.sha_from_ref(pipeline.ref))
.where.not(sha: project.commit(pipeline.ref).try(:id))
.created_or_pending
end

View file

@ -28,7 +28,7 @@ module Projects
def add_repository_to_project
if project.external_import? && !unknown_url?
raise Error, 'Blocked import URL.' if Gitlab::UrlBlocker.blocked_url?(project.import_url)
raise Error, 'Blocked import URL.' if Gitlab::UrlBlocker.blocked_url?(project.import_url, valid_ports: Project::VALID_IMPORT_PORTS)
end
# We should skip the repository for a GitHub import or GitLab project import,

View file

@ -18,7 +18,8 @@ module Projects
def pages_config
{
domains: pages_domains_config
domains: pages_domains_config,
https_only: project.pages_https_only?
}
end
@ -27,7 +28,8 @@ module Projects
{
domain: domain.domain,
certificate: domain.certificate,
key: domain.key
key: domain.key,
https_only: project.pages_https_only? && domain.https?
}
end
end

View file

@ -24,6 +24,8 @@ module Projects
system_hook_service.execute_hooks_for(project, :update)
end
update_pages_config if changing_pages_https_only?
success
else
model_errors = project.errors.full_messages.to_sentence
@ -67,5 +69,13 @@ module Projects
log_error("Could not create wiki for #{project.full_name}")
Gitlab::Metrics.counter(:wiki_can_not_be_created_total, 'Counts the times we failed to create a wiki')
end
def update_pages_config
Projects::UpdatePagesConfigurationService.new(project).execute
end
def changing_pages_https_only?
project.previous_changes.include?(:pages_https_only)
end
end
end

View file

@ -14,16 +14,17 @@ class SubmitUsagePingService
def execute
return false unless Gitlab::CurrentSettings.usage_ping_enabled?
response = HTTParty.post(
response = Gitlab::HTTP.post(
URL,
body: Gitlab::UsageData.to_json(force_refresh: true),
allow_local_requests: true,
headers: { 'Content-type' => 'application/json' }
)
store_metrics(response)
true
rescue HTTParty::Error => e
rescue Gitlab::HTTP::Error => e
Rails.logger.info "Unable to contact GitLab, Inc.: #{e}"
false

View file

@ -3,23 +3,20 @@ class WebHookService
attr_reader :body, :headers, :code
def initialize
@headers = HTTParty::Response::Headers.new({})
@headers = Gitlab::HTTP::Response::Headers.new({})
@body = ''
@code = 'internal error'
end
end
include HTTParty
# HTTParty timeout
default_timeout Gitlab.config.gitlab.webhook_timeout
attr_accessor :hook, :data, :hook_name
attr_accessor :hook, :data, :hook_name, :request_options
def initialize(hook, data, hook_name)
@hook = hook
@data = data
@hook_name = hook_name.to_s
@request_options = { timeout: Gitlab.config.gitlab.webhook_timeout }
@request_options.merge!(allow_local_requests: true) if @hook.is_a?(SystemHook)
end
def execute
@ -73,11 +70,12 @@ class WebHookService
end
def make_request(url, basic_auth = false)
self.class.post(url,
Gitlab::HTTP.post(url,
body: data.to_json,
headers: build_headers(hook_name),
verify: hook.enable_ssl_verification,
basic_auth: basic_auth)
basic_auth: basic_auth,
**request_options)
end
def make_request_with_auth

View file

@ -16,8 +16,6 @@ class CertificateValidator < ActiveModel::EachValidator
private
def valid_certificate_pem?(value)
return false unless value
OpenSSL::X509::Certificate.new(value).present?
rescue OpenSSL::X509::CertificateError
false

View file

@ -4,7 +4,7 @@
# protect against Server-side Request Forgery (SSRF).
class ImportableUrlValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if Gitlab::UrlBlocker.blocked_url?(value)
if Gitlab::UrlBlocker.blocked_url?(value, valid_ports: Project::VALID_IMPORT_PORTS)
record.errors.add(attribute, "imports are not allowed from that URL")
end
end

View file

@ -860,5 +860,14 @@
.col-sm-10
= f.number_field :throttle_authenticated_web_period_in_seconds, class: 'form-control'
%fieldset
%legend Outbound requests
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :allow_local_requests_from_hooks_and_services do
= f.check_box :allow_local_requests_from_hooks_and_services
Allow requests to the local network from hooks and services
.form-actions
= f.submit 'Save', class: 'btn btn-save'

View file

@ -13,13 +13,13 @@
.form-group
.input-group
- if current_user.can_select_namespace?
.input-group-addon
.input-group-addon.has-tooltip{ title: root_url }
= root_url
= select_tag :namespace_id, namespaces_options(namespace_id_from(params) || :current_user, display_path: true, extra_group: namespace_id_from(params)), class: 'select2 js-select-namespace', tabindex: 1
- else
.input-group-addon.static-namespace
#{root_url}#{current_user.username}/
.input-group-addon.static-namespace.has-tooltip{ title: user_url(current_user.username) + '/' }
#{user_url(current_user.username)}/
= hidden_field_tag :namespace_id, value: current_user.namespace_id
.form-group.col-xs-12.col-sm-6.project-path
= label_tag :path, 'Project name', class: 'label-light'

View file

@ -67,12 +67,8 @@
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" }
%img{ alt: "GitLab", height: "33", src: image_url('mailers/gitlab_footer_logo.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/
%div
%a{ href: profile_notifications_url, style: "color:#3777b0;text-decoration:none;" } Manage all notifications
&middot;
%a{ href: help_url, style: "color:#3777b0;text-decoration:none;" } Help
%div
You're receiving this email because of your account on
= succeed "." do
%a{ href: root_url, style: "color:#3777b0;text-decoration:none;" }= Gitlab.config.gitlab.host
- manage_notifications_link = link_to(_("Manage all notifications"), profile_notifications_url, style: "color:#3777b0;text-decoration:none;")
- help_link = link_to(_("Help"), help_url, style: "color:#3777b0;text-decoration:none;")
= _("You're receiving this email because of your account on %{host}. %{manage_notifications_link} &middot; %{help_link}").html_safe % { host: Gitlab.config.gitlab.host, manage_notifications_link: manage_notifications_link, help_link: help_link }
= yield :additional_footer

View file

@ -6,6 +6,7 @@
.mobile-overlay
.alert-wrapper
= render "layouts/broadcast"
= render 'layouts/header/read_only_banner'
= yield :flash_message
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"

View file

@ -0,0 +1,7 @@
- message = read_only_message
- if message
.flash-container.flash-container-page
.flash-notice
%div{ class: (container_class) }
%span
= message

View file

@ -6,7 +6,7 @@
profile_url: url_for(params.merge(lineprofiler: 'true')) },
class: Peek.env }
#peek-view-performance-bar
#peek-view-performance-bar.hidden
= render_server_response_time
%span#serverstats
%ul.performance-bar

View file

@ -13,6 +13,6 @@
#{time_ago_with_tooltip(event.created_at)}
.pull-right
.flex-right
= link_to new_mr_path_from_push_event(event), title: _("New merge request"), class: "btn btn-info btn-sm qa-create-merge-request" do
#{ _('Create merge request') }

View file

@ -9,12 +9,12 @@
Project path
.input-group
- if current_user.can_select_namespace?
.input-group-addon
.input-group-addon.has-tooltip{ title: root_url }
= root_url
= f.select :namespace_id, namespaces_options(namespace_id_from(params) || :current_user, display_path: true, extra_group: namespace_id_from(params)), {}, { class: 'select2 js-select-namespace qa-project-namespace-select', tabindex: 1}
- else
.input-group-addon.static-namespace
.input-group-addon.static-namespace.has-tooltip{ title: user_url(current_user.username) + '/' }
#{user_url(current_user.username)}/
= f.hidden_field :namespace_id, value: current_user.namespace_id
.form-group.project-path.col-sm-6

View file

@ -5,81 +5,82 @@
- number_commits_behind = diverging_commit_counts[:behind]
- number_commits_ahead = diverging_commit_counts[:ahead]
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
%li{ class: "js-branch-#{branch.name}" }
%div
= link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated ref-name' do
= sprite_icon('fork', size: 12)
= branch.name
&nbsp;
- if branch.name == @repository.root_ref
%span.label.label-primary default
- elsif merged
%span.label.label-info.has-tooltip{ title: s_('Branches|Merged into %{default_branch}') % { default_branch: @repository.root_ref } }
= s_('Branches|merged')
%li{ class: "branch-item js-branch-#{branch.name}" }
.branch-info
.branch-title
= link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated-100 ref-name' do
= sprite_icon('fork', size: 12)
= branch.name
&nbsp;
- if branch.name == @repository.root_ref
%span.label.label-primary default
- elsif merged
%span.label.label-info.has-tooltip{ title: s_('Branches|Merged into %{default_branch}') % { default_branch: @repository.root_ref } }
= s_('Branches|merged')
- if protected_branch?(@project, branch)
%span.label.label-success
= s_('Branches|protected')
.controls.hidden-xs<
- if merge_project && create_mr_button?(@repository.root_ref, branch.name)
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-default' do
= _('Merge request')
- if protected_branch?(@project, branch)
%span.label.label-success
= s_('Branches|protected')
- if branch.name != @repository.root_ref
= link_to project_compare_index_path(@project, from: @repository.root_ref, to: branch.name),
class: "btn btn-default #{'prepend-left-10' unless merge_project}",
method: :post,
title: s_('Branches|Compare') do
= s_('Branches|Compare')
.block-truncated
- if commit
= render 'projects/branches/commit', commit: commit, project: @project
- else
= s_('Branches|Cant find HEAD commit for this branch')
= render 'projects/buttons/download', project: @project, ref: branch.name, pipeline: @refs_pipelines[branch.name]
- if branch.name != @repository.root_ref
.divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: diverging_count_label(number_commits_behind),
default_branch: @repository.root_ref,
number_commits_ahead: diverging_count_label(number_commits_ahead) } }
.graph-side
.bar.bar-behind{ style: "width: #{number_commits_behind * bar_graph_width_factor}%" }
%span.count.count-behind= diverging_count_label(number_commits_behind)
.graph-separator
.graph-side
.bar.bar-ahead{ style: "width: #{number_commits_ahead * bar_graph_width_factor}%" }
%span.count.count-ahead= diverging_count_label(number_commits_ahead)
- if can?(current_user, :push_code, @project)
- if branch.name == @project.repository.root_ref
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled",
disabled: true,
title: s_('Branches|The default branch cannot be deleted') }
= icon("trash-o")
- elsif protected_branch?(@project, branch)
- if can?(current_user, :delete_protected_branch, @project)
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip",
title: s_('Branches|Delete protected branch'),
data: { toggle: "modal",
target: "#modal-delete-branch",
delete_path: project_branch_path(@project, branch.name),
branch_name: branch.name,
is_merged: ("true" if merged) } }
= icon("trash-o")
- else
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled",
disabled: true,
title: s_('Branches|Only a project master or owner can delete a protected branch') }
= icon("trash-o")
- else
= link_to project_branch_path(@project, branch.name),
class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip",
title: s_('Branches|Delete branch'),
method: :delete,
data: { confirm: s_("Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?") % { branch_name: branch.name } },
remote: true,
'aria-label' => s_('Branches|Delete branch') do
= icon("trash-o")
.controls.hidden-xs<
- if merge_project && create_mr_button?(@repository.root_ref, branch.name)
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-default' do
= _('Merge request')
- if branch.name != @repository.root_ref
.divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: diverging_count_label(number_commits_behind),
default_branch: @repository.root_ref,
number_commits_ahead: diverging_count_label(number_commits_ahead) } }
.graph-side
.bar.bar-behind{ style: "width: #{number_commits_behind * bar_graph_width_factor}%" }
%span.count.count-behind= diverging_count_label(number_commits_behind)
.graph-separator
.graph-side
.bar.bar-ahead{ style: "width: #{number_commits_ahead * bar_graph_width_factor}%" }
%span.count.count-ahead= diverging_count_label(number_commits_ahead)
= link_to project_compare_index_path(@project, from: @repository.root_ref, to: branch.name),
class: "btn btn-default #{'prepend-left-10' unless merge_project}",
method: :post,
title: s_('Branches|Compare') do
= s_('Branches|Compare')
= render 'projects/buttons/download', project: @project, ref: branch.name, pipeline: @refs_pipelines[branch.name]
- if commit
= render 'projects/branches/commit', commit: commit, project: @project
- else
%p
= s_('Branches|Cant find HEAD commit for this branch')
- if can?(current_user, :push_code, @project)
- if branch.name == @project.repository.root_ref
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled",
disabled: true,
title: s_('Branches|The default branch cannot be deleted') }
= icon("trash-o")
- elsif protected_branch?(@project, branch)
- if can?(current_user, :delete_protected_branch, @project)
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip",
title: s_('Branches|Delete protected branch'),
data: { toggle: "modal",
target: "#modal-delete-branch",
delete_path: project_branch_path(@project, branch.name),
branch_name: branch.name,
is_merged: ("true" if merged) } }
= icon("trash-o")
- else
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled",
disabled: true,
title: s_('Branches|Only a project master or owner can delete a protected branch') }
= icon("trash-o")
- else
= link_to project_branch_path(@project, branch.name),
class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip",
title: s_('Branches|Delete branch'),
method: :delete,
data: { confirm: s_("Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?") % { branch_name: branch.name } },
remote: true,
'aria-label' => s_('Branches|Delete branch') do
= icon("trash-o")

View file

@ -0,0 +1,10 @@
= form_for @project, url: namespace_project_pages_path(@project.namespace.becomes(Namespace), @project), html: { class: 'inline', title: pages_https_only_title } do |f|
= f.check_box :pages_https_only, class: 'pull-left', disabled: pages_https_only_disabled?
.prepend-left-20
= f.label :pages_https_only, class: pages_https_only_label_class do
%strong Force domains with SSL certificates to use HTTPS
- unless pages_https_only_disabled?
.prepend-top-10
= f.submit 'Save', class: 'btn btn-success'

View file

@ -13,6 +13,9 @@
Combined with the power of GitLab CI and the help of GitLab Runner
you can deploy static pages for your individual projects, your user or your group.
- if Gitlab.config.pages.external_https
= render 'https_only'
%hr.clearfix
= render 'access'

View file

@ -1,5 +0,0 @@
---
title: Add missing pagination on the commit diff endpoint
merge_request: 17203
author: Maxime Roussin-Bélanger
type: fixed

View file

@ -1,4 +0,0 @@
---
title: Moved o_auth/saml/ldap modules under gitlab/auth
merge_request: 17359
author: Horatiu Eugen Vlad

View file

@ -1,5 +0,0 @@
---
title: Update issue closing pattern to allow variations in punctuation
merge_request: 17198
author: Vicky Chijwani
type: changed

View file

@ -1,5 +0,0 @@
---
title: Clear the Labels dropdown search filter after a selection is made
merge_request: 17393
author: Andrew Torres
type: changed

View file

@ -1,5 +0,0 @@
---
title: Update to github-linguist 5.3.x
merge_request: 17241
author: Ken Ding
type: other

View file

@ -1,4 +0,0 @@
---
title: Group MRs on issue page by project and namespace.
merge_request: 8494
author: Jeff Stubler

View file

@ -1,5 +0,0 @@
---
title: Add project export API
merge_request: 15860
author: Travis Miller
type: added

View file

@ -1,5 +0,0 @@
---
title: Add verification for GitLab Pages custom domains
merge_request:
author:
type: security

View file

@ -1,4 +0,0 @@
---
title: Add email button to new issue by email
merge_request: 10942
author: Islam Wazery

View file

@ -1,5 +0,0 @@
---
title: Fix duplicate system notes when merging a merge request.
merge_request: 17035
author:
type: fixed

View file

@ -1,5 +0,0 @@
---
title: Allow installation of GitLab Runner with a single click
merge_request: 17134
author:
type: added

View file

@ -1,5 +0,0 @@
---
title: Fix Slack/Mattermost notifications not respecting `notify_only_default_branch` setting for pushes
merge_request: 17345
author:
type: fixed

View file

@ -1,5 +0,0 @@
---
title: remove avater underline
merge_request: 17219
author: Ken Ding
type: fixed

View file

@ -1,5 +0,0 @@
---
title: Fix Teleporting Emoji
merge_request: 16963
author: Jared Deckard <jared.deckard@gmail.com>
type: fixed

View file

@ -1,5 +0,0 @@
---
title: update toml-rb to 1.0.0
merge_request: 17259
author: Ken Ding
type: other

View file

@ -1,5 +0,0 @@
---
title: Display a link to external issue tracker when enabled
merge_request:
author:
type: changed

Some files were not shown because too many files have changed in this diff Show more