Commit fd43419a authored by Phil Hughes's avatar Phil Hughes

Merge branch 'master' into ide-tree-changes-count

parents 1724594a 87f1736a
...@@ -72,3 +72,4 @@ eslint-report.html ...@@ -72,3 +72,4 @@ eslint-report.html
/locale/**/*.time_stamp /locale/**/*.time_stamp
/.rspec /.rspec
/plugins/* /plugins/*
/.gitlab_pages_secret
...@@ -110,7 +110,7 @@ stages: ...@@ -110,7 +110,7 @@ stages:
# Jobs that only need to pull cache # Jobs that only need to pull cache
.dedicated-no-docs-pull-cache-job: &dedicated-no-docs-pull-cache-job .dedicated-no-docs-pull-cache-job: &dedicated-no-docs-pull-cache-job
<<: *dedicated-runner <<: *dedicated-runner
<<: *except-docs-and-qa <<: *except-docs
<<: *pull-cache <<: *pull-cache
dependencies: dependencies:
- setup-test-env - setup-test-env
...@@ -122,6 +122,10 @@ stages: ...@@ -122,6 +122,10 @@ stages:
variables: variables:
SETUP_DB: "false" SETUP_DB: "false"
.dedicated-no-docs-and-no-qa-pull-cache-job: &dedicated-no-docs-and-no-qa-pull-cache-job
<<: *dedicated-no-docs-pull-cache-job
<<: *except-docs-and-qa
.rake-exec: &rake-exec .rake-exec: &rake-exec
<<: *dedicated-no-docs-no-db-pull-cache-job <<: *dedicated-no-docs-no-db-pull-cache-job
script: script:
...@@ -222,7 +226,7 @@ stages: ...@@ -222,7 +226,7 @@ stages:
- master@gitlab/gitlab-ee - master@gitlab/gitlab-ee
.gitlab-setup: &gitlab-setup .gitlab-setup: &gitlab-setup
<<: *dedicated-no-docs-pull-cache-job <<: *dedicated-no-docs-and-no-qa-pull-cache-job
<<: *use-pg <<: *use-pg
variables: variables:
CREATE_DB_USER: "true" CREATE_DB_USER: "true"
...@@ -262,12 +266,12 @@ stages: ...@@ -262,12 +266,12 @@ stages:
# DB migration, rollback, and seed jobs # DB migration, rollback, and seed jobs
.db-migrate-reset: &db-migrate-reset .db-migrate-reset: &db-migrate-reset
<<: *dedicated-no-docs-pull-cache-job <<: *dedicated-no-docs-and-no-qa-pull-cache-job
script: script:
- bundle exec rake db:migrate:reset - bundle exec rake db:migrate:reset
.migration-paths: &migration-paths .migration-paths: &migration-paths
<<: *dedicated-no-docs-pull-cache-job <<: *dedicated-no-docs-and-no-qa-pull-cache-job
variables: variables:
CREATE_DB_USER: "true" CREATE_DB_USER: "true"
script: script:
...@@ -289,7 +293,6 @@ stages: ...@@ -289,7 +293,6 @@ stages:
# Trigger a package build in omnibus-gitlab repository # Trigger a package build in omnibus-gitlab repository
# #
package-and-qa: package-and-qa:
<<: *dedicated-runner
image: ruby:2.4-alpine image: ruby:2.4-alpine
before_script: [] before_script: []
stage: build stage: build
...@@ -648,7 +651,7 @@ migration:path-mysql: ...@@ -648,7 +651,7 @@ migration:path-mysql:
<<: *use-mysql <<: *use-mysql
.db-rollback: &db-rollback .db-rollback: &db-rollback
<<: *dedicated-no-docs-pull-cache-job <<: *dedicated-no-docs-and-no-qa-pull-cache-job
script: script:
- bundle exec rake db:migrate VERSION=20170523121229 - bundle exec rake db:migrate VERSION=20170523121229
- bundle exec rake db:migrate - bundle exec rake db:migrate
...@@ -671,7 +674,7 @@ gitlab:setup-mysql: ...@@ -671,7 +674,7 @@ gitlab:setup-mysql:
# Frontend-related jobs # Frontend-related jobs
gitlab:assets:compile: gitlab:assets:compile:
<<: *dedicated-no-docs-no-db-pull-cache-job <<: *dedicated-no-docs-and-no-qa-pull-cache-job
dependencies: [] dependencies: []
variables: variables:
NODE_ENV: "production" NODE_ENV: "production"
...@@ -692,7 +695,7 @@ gitlab:assets:compile: ...@@ -692,7 +695,7 @@ gitlab:assets:compile:
- webpack-report/ - webpack-report/
karma: karma:
<<: *dedicated-no-docs-pull-cache-job <<: *dedicated-no-docs-and-no-qa-pull-cache-job
<<: *use-pg <<: *use-pg
dependencies: dependencies:
- compile-assets - compile-assets
...@@ -816,7 +819,7 @@ coverage: ...@@ -816,7 +819,7 @@ coverage:
- coverage/assets/ - coverage/assets/
lint:javascript:report: lint:javascript:report:
<<: *dedicated-no-docs-no-db-pull-cache-job <<: *dedicated-no-docs-and-no-qa-pull-cache-job
stage: post-test stage: post-test
dependencies: dependencies:
- compile-assets - compile-assets
......
...@@ -25,12 +25,12 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._ ...@@ -25,12 +25,12 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
- [Workflow labels](#workflow-labels) - [Workflow labels](#workflow-labels)
- [Type labels (~"feature proposal", ~bug, ~customer, etc.)](#type-labels-feature-proposal-bug-customer-etc) - [Type labels (~"feature proposal", ~bug, ~customer, etc.)](#type-labels-feature-proposal-bug-customer-etc)
- [Subject labels (~wiki, ~"container registry", ~ldap, ~api, etc.)](#subject-labels-wiki-container-registry-ldap-api-etc) - [Subject labels (~wiki, ~"container registry", ~ldap, ~api, etc.)](#subject-labels-wiki-container-registry-ldap-api-etc)
- [Team labels (~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.)](#team-labels-cicd-discussion-edge-platform-etc) - [Team labels (~"CI/CD", ~Discussion, ~Quality, ~Platform, etc.)](#team-labels-cicd-discussion-quality-platform-etc)
- [Milestone labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#milestone-labels-deliverable-stretch-next-patch-release) - [Milestone labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#milestone-labels-deliverable-stretch-next-patch-release)
- [Priority labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-priority-labels-p1-p2-p3-etc) - [Priority labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-priority-labels-p1-p2-p3-etc)
- [Severity labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-severity-labels-s1-s2-s3-etc) - [Severity labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-severity-labels-s1-s2-s3-etc)
- [Label for community contributors (~"Accepting Merge Requests")](#label-for-community-contributors-accepting-merge-requests) - [Label for community contributors (~"Accepting Merge Requests")](#label-for-community-contributors-accepting-merge-requests)
- [Implement design & UI elements](#implement-design-ui-elements) - [Implement design & UI elements](#implement-design--ui-elements)
- [Issue tracker](#issue-tracker) - [Issue tracker](#issue-tracker)
- [Issue triaging](#issue-triaging) - [Issue triaging](#issue-triaging)
- [Feature proposals](#feature-proposals) - [Feature proposals](#feature-proposals)
...@@ -114,7 +114,7 @@ is a great place to start. Issues with a lower weight (1 or 2) are deemed ...@@ -114,7 +114,7 @@ is a great place to start. Issues with a lower weight (1 or 2) are deemed
suitable for beginners. These issues will be of reasonable size and challenge, suitable for beginners. These issues will be of reasonable size and challenge,
for anyone to start contributing to GitLab. If you have any questions or need help visit [Getting Help](https://about.gitlab.com/getting-help/#discussion) to for anyone to start contributing to GitLab. If you have any questions or need help visit [Getting Help](https://about.gitlab.com/getting-help/#discussion) to
learn how to communicate with GitLab. If you're looking for a Gitter or Slack channel learn how to communicate with GitLab. If you're looking for a Gitter or Slack channel
please consider we favor please consider we favor
[asynchronous communication](https://about.gitlab.com/handbook/communication/#internal-communication) over real time communication. Thanks for your contribution! [asynchronous communication](https://about.gitlab.com/handbook/communication/#internal-communication) over real time communication. Thanks for your contribution!
## Workflow labels ## Workflow labels
...@@ -127,7 +127,7 @@ Most issues will have labels for at least one of the following: ...@@ -127,7 +127,7 @@ Most issues will have labels for at least one of the following:
- Type: ~"feature proposal", ~bug, ~customer, etc. - Type: ~"feature proposal", ~bug, ~customer, etc.
- Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc. - Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc.
- Team: ~"CI/CD", ~Discussion, ~Edge, ~Platform, etc. - Team: ~"CI/CD", ~Discussion, ~Quality, ~Platform, etc.
- Milestone: ~Deliverable, ~Stretch, ~"Next Patch Release" - Milestone: ~Deliverable, ~Stretch, ~"Next Patch Release"
- Priority: ~P1, ~P2, ~P3, ~P4 - Priority: ~P1, ~P2, ~P3, ~P4
- Severity: ~S1, ~S2, ~S3, ~S4 - Severity: ~S1, ~S2, ~S3, ~S4
...@@ -171,13 +171,13 @@ Examples of subject labels are ~wiki, ~"container registry", ~ldap, ~api, ...@@ -171,13 +171,13 @@ Examples of subject labels are ~wiki, ~"container registry", ~ldap, ~api,
Subject labels are always all-lowercase. Subject labels are always all-lowercase.
### Team labels (~"CI/CD", ~Discussion, ~Edge, ~Platform, etc.) ### Team labels (~"CI/CD", ~Discussion, ~Quality, ~Platform, etc.)
Team labels specify what team is responsible for this issue. Team labels specify what team is responsible for this issue.
Assigning a team label makes sure issues get the attention of the appropriate Assigning a team label makes sure issues get the attention of the appropriate
people. people.
The current team labels are ~Build, ~"CI/CD", ~Discussion, ~Documentation, ~Edge, The current team labels are ~Build, ~"CI/CD", ~Discussion, ~Documentation, ~Quality,
~Geo, ~Gitaly, ~Monitoring, ~Platform, ~Release, ~"Security Products" and ~"UX". ~Geo, ~Gitaly, ~Monitoring, ~Platform, ~Release, ~"Security Products" and ~"UX".
The descriptions on the [labels page][labels-page] explain what falls under the The descriptions on the [labels page][labels-page] explain what falls under the
...@@ -199,12 +199,12 @@ release. There are three levels of Milestone labels: ...@@ -199,12 +199,12 @@ release. There are three levels of Milestone labels:
- ~Stretch: Issues that are a stretch goal for delivering in the current - ~Stretch: Issues that are a stretch goal for delivering in the current
milestone. If these issues are not done in the current release, they will milestone. If these issues are not done in the current release, they will
strongly be considered for the next release. strongly be considered for the next release.
- ~"Next Patch Release": Issues to put in the next patch release. Work on these - ~"Next Patch Release": Issues to put in the next patch release. Work on these
first, and add the "Pick Into X" label to the merge request, along with the first, and add the "Pick Into X" label to the merge request, along with the
appropriate milestone. appropriate milestone.
Each issue scheduled for the current milestone should be labeled ~Deliverable Each issue scheduled for the current milestone should be labeled ~Deliverable
or ~"Stretch". Any open issue for a previous milestone should be labeled or ~"Stretch". Any open issue for a previous milestone should be labeled
~"Next Patch Release", or otherwise rescheduled to a different milestone. ~"Next Patch Release", or otherwise rescheduled to a different milestone.
### Bug Priority labels (~P1, ~P2, ~P3 & etc.) ### Bug Priority labels (~P1, ~P2, ~P3 & etc.)
...@@ -221,16 +221,16 @@ This label documents the planned timeline & urgency which is used to measure aga ...@@ -221,16 +221,16 @@ This label documents the planned timeline & urgency which is used to measure aga
#### Specific Priority guidance #### Specific Priority guidance
| Label | Availability / Performance | | Label | Availability / Performance |
|-------|--------------------------------------------------------------| |-------|--------------------------------------------------------------|
| ~P1 | | | ~P1 | |
| ~P2 | The issue is (almost) guaranteed to occur in the near future | | ~P2 | The issue is (almost) guaranteed to occur in the near future |
| ~P3 | The issue is likely to occur in the near future | | ~P3 | The issue is likely to occur in the near future |
| ~P4 | The issue _may_ occur but it's not likely | | ~P4 | The issue _may_ occur but it's not likely |
### Bug Severity labels (~S1, ~S2, ~S3 & etc.) ### Bug Severity labels (~S1, ~S2, ~S3 & etc.)
Severity labels help us clearly communicate the impact of a ~bug on users. Severity labels help us clearly communicate the impact of a ~bug on users.
| Label | Meaning | Impact of the defect | Example | | Label | Meaning | Impact of the defect | Example |
|-------|-------------------|-------------------------------------------------------|---------| |-------|-------------------|-------------------------------------------------------|---------|
...@@ -241,9 +241,9 @@ Severity labels help us clearly communicate the impact of a ~bug on users. ...@@ -241,9 +241,9 @@ Severity labels help us clearly communicate the impact of a ~bug on users.
#### Specific Severity guidance #### Specific Severity guidance
| Label | Security Impact | | Label | Security Impact |
|-------|-------------------------------------------------------------------| |-------|-------------------------------------------------------------------|
| ~S1 | >50% customers impacted (possible company extinction level event) | | ~S1 | >50% customers impacted (possible company extinction level event) |
| ~S2 | Multiple customers impacted (but not apocalyptic) | | ~S2 | Multiple customers impacted (but not apocalyptic) |
| ~S3 | A single customer impacted | | ~S3 | A single customer impacted |
| ~S4 | No customer impact, or expected impact within 30 days | | ~S4 | No customer impact, or expected impact within 30 days |
...@@ -727,4 +727,3 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor ...@@ -727,4 +727,3 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[^1]: Please note that specs other than JavaScript specs are considered backend [^1]: Please note that specs other than JavaScript specs are considered backend
code. code.
\ No newline at end of file
...@@ -283,7 +283,6 @@ gem 'batch-loader', '~> 1.2.1' ...@@ -283,7 +283,6 @@ gem 'batch-loader', '~> 1.2.1'
gem 'peek', '~> 1.0.1' gem 'peek', '~> 1.0.1'
gem 'peek-gc', '~> 0.0.2' gem 'peek-gc', '~> 0.0.2'
gem 'peek-mysql2', '~> 1.1.0', group: :mysql gem 'peek-mysql2', '~> 1.1.0', group: :mysql
gem 'peek-performance_bar', '~> 1.3.0'
gem 'peek-pg', '~> 1.3.0', group: :postgres gem 'peek-pg', '~> 1.3.0', group: :postgres
gem 'peek-rblineprof', '~> 0.2.0' gem 'peek-rblineprof', '~> 0.2.0'
gem 'peek-redis', '~> 1.2.0' gem 'peek-redis', '~> 1.2.0'
......
...@@ -603,8 +603,6 @@ GEM ...@@ -603,8 +603,6 @@ GEM
atomic (>= 1.0.0) atomic (>= 1.0.0)
mysql2 mysql2
peek peek
peek-performance_bar (1.3.1)
peek (>= 0.1.0)
peek-pg (1.3.0) peek-pg (1.3.0)
concurrent-ruby concurrent-ruby
concurrent-ruby-ext concurrent-ruby-ext
...@@ -1130,7 +1128,6 @@ DEPENDENCIES ...@@ -1130,7 +1128,6 @@ DEPENDENCIES
peek (~> 1.0.1) peek (~> 1.0.1)
peek-gc (~> 0.0.2) peek-gc (~> 0.0.2)
peek-mysql2 (~> 1.1.0) peek-mysql2 (~> 1.1.0)
peek-performance_bar (~> 1.3.0)
peek-pg (~> 1.3.0) peek-pg (~> 1.3.0)
peek-rblineprof (~> 0.2.0) peek-rblineprof (~> 0.2.0)
peek-redis (~> 1.2.0) peek-redis (~> 1.2.0)
......
...@@ -26,11 +26,18 @@ export default { ...@@ -26,11 +26,18 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
forceModifiedIcon: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
changedIcon() { changedIcon() {
const suffix = this.file.staged && !this.showStagedIcon ? '-solid' : ''; const suffix = this.file.staged && !this.showStagedIcon ? '-solid' : '';
return this.file.tempFile ? `file-addition${suffix}` : `file-modified${suffix}`; return this.file.tempFile && !this.forceModifiedIcon
? `file-addition${suffix}`
: `file-modified${suffix}`;
}, },
stagedIcon() { stagedIcon() {
return `${this.changedIcon}-solid`; return `${this.changedIcon}-solid`;
......
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import newModal from './modal.vue'; import newModal from './modal.vue';
import upload from './upload.vue'; import upload from './upload.vue';
export default { export default {
components: { components: {
icon, icon,
newModal, newModal,
upload, upload,
},
props: {
branch: {
type: String,
required: true,
}, },
props: { path: {
branch: { type: String,
type: String, required: true,
required: true,
},
path: {
type: String,
required: true,
},
}, },
data() { },
return { data() {
openModal: false, return {
modalType: '', openModal: false,
dropdownOpen: false, modalType: '',
}; dropdownOpen: false,
};
},
watch: {
dropdownOpen() {
this.$nextTick(() => {
this.$refs.dropdownMenu.scrollIntoView();
});
}, },
methods: { },
...mapActions([ methods: {
'createTempEntry', ...mapActions(['createTempEntry']),
]), createNewItem(type) {
createNewItem(type) { this.modalType = type;
this.modalType = type; this.openModal = true;
this.openModal = true; this.dropdownOpen = false;
this.dropdownOpen = false;
},
hideModal() {
this.openModal = false;
},
openDropdown() {
this.dropdownOpen = !this.dropdownOpen;
},
}, },
}; hideModal() {
this.openModal = false;
},
openDropdown() {
this.dropdownOpen = !this.dropdownOpen;
},
},
};
</script> </script>
<template> <template>
...@@ -71,7 +76,10 @@ ...@@ -71,7 +76,10 @@
css-classes="pull-left" css-classes="pull-left"
/> />
</button> </button>
<ul class="dropdown-menu dropdown-menu-right"> <ul
class="dropdown-menu dropdown-menu-right"
ref="dropdownMenu"
>
<li> <li>
<a <a
href="#" href="#"
......
...@@ -40,13 +40,6 @@ export default { ...@@ -40,13 +40,6 @@ export default {
return __('Create file'); return __('Create file');
}, },
formLabelName() {
if (this.type === 'tree') {
return __('Directory name');
}
return __('File name');
},
}, },
mounted() { mounted() {
this.$refs.fieldName.focus(); this.$refs.fieldName.focus();
...@@ -82,8 +75,8 @@ export default { ...@@ -82,8 +75,8 @@ export default {
@submit.prevent="createEntryInStore" @submit.prevent="createEntryInStore"
> >
<fieldset class="form-group append-bottom-0"> <fieldset class="form-group append-bottom-0">
<label class="label-light col-sm-3"> <label class="label-light col-sm-3 ide-new-modal-label">
{{ formLabelName }} {{ __('Name') }}
</label> </label>
<div class="col-sm-9"> <div class="col-sm-9">
<input <input
......
...@@ -99,7 +99,7 @@ export default { ...@@ -99,7 +99,7 @@ export default {
:file="file" :file="file"
/> />
</span> </span>
<span class="pull-right"> <span class="pull-right ide-file-icon-holder">
<mr-file-icon <mr-file-icon
v-if="file.mrChange" v-if="file.mrChange"
/> />
...@@ -119,7 +119,8 @@ export default { ...@@ -119,7 +119,8 @@ export default {
:file="file" :file="file"
:show-tooltip="true" :show-tooltip="true"
:show-staged-icon="true" :show-staged-icon="true"
class="prepend-top-5 pull-right" :force-modified-icon="true"
class="pull-right"
/> />
</span> </span>
<new-dropdown <new-dropdown
......
...@@ -84,6 +84,7 @@ export default { ...@@ -84,6 +84,7 @@ export default {
<changed-file-icon <changed-file-icon
v-else v-else
:file="tab" :file="tab"
:force-modified-icon="true"
/> />
</button> </button>
......
...@@ -33,10 +33,7 @@ export const setPanelCollapsedStatus = ({ commit }, { side, collapsed }) => { ...@@ -33,10 +33,7 @@ export const setPanelCollapsedStatus = ({ commit }, { side, collapsed }) => {
} }
}; };
export const toggleRightPanelCollapsed = ( export const toggleRightPanelCollapsed = ({ dispatch, state }, e = undefined) => {
{ dispatch, state },
e = undefined,
) => {
if (e) { if (e) {
$(e.currentTarget) $(e.currentTarget)
.tooltip('hide') .tooltip('hide')
...@@ -77,7 +74,7 @@ export const createTempEntry = ( ...@@ -77,7 +74,7 @@ export const createTempEntry = (
} }
worker.addEventListener('message', ({ data }) => { worker.addEventListener('message', ({ data }) => {
const { file } = data; const { file, parentPath } = data;
worker.terminate(); worker.terminate();
...@@ -93,6 +90,10 @@ export const createTempEntry = ( ...@@ -93,6 +90,10 @@ export const createTempEntry = (
dispatch('setFileActive', file.path); dispatch('setFileActive', file.path);
} }
if (parentPath && !state.entries[parentPath].opened) {
commit(types.TOGGLE_TREE_OPEN, parentPath);
}
resolve(file); resolve(file);
}); });
...@@ -137,6 +138,14 @@ export const updateDelayViewerUpdated = ({ commit }, delay) => { ...@@ -137,6 +138,14 @@ export const updateDelayViewerUpdated = ({ commit }, delay) => {
commit(types.UPDATE_DELAY_VIEWER_CHANGE, delay); commit(types.UPDATE_DELAY_VIEWER_CHANGE, delay);
}; };
export const updateTempFlagForEntry = ({ commit, dispatch, state }, { file, tempFile }) => {
commit(types.UPDATE_TEMP_FLAG, { path: file.path, tempFile });
if (file.parentPath) {
dispatch('updateTempFlagForEntry', { file: state.entries[file.parentPath], tempFile });
}
};
export const toggleFileFinder = ({ commit }, fileFindVisible) => export const toggleFileFinder = ({ commit }, fileFindVisible) =>
commit(types.TOGGLE_FILE_FINDER, fileFindVisible); commit(types.TOGGLE_FILE_FINDER, fileFindVisible);
......
...@@ -63,7 +63,7 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive ...@@ -63,7 +63,7 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive
const file = state.entries[path]; const file = state.entries[path];
commit(types.TOGGLE_LOADING, { entry: file }); commit(types.TOGGLE_LOADING, { entry: file });
return service return service
.getFileData(file.url) .getFileData(`${gon.relative_url_root ? gon.relative_url_root : ''}${file.url}`)
.then(res => { .then(res => {
const pageTitle = decodeURI(normalizeHeaders(res.headers)['PAGE-TITLE']); const pageTitle = decodeURI(normalizeHeaders(res.headers)['PAGE-TITLE']);
setPageTitle(pageTitle); setPageTitle(pageTitle);
......
...@@ -110,6 +110,17 @@ export const updateFilesAfterCommit = ( ...@@ -110,6 +110,17 @@ export const updateFilesAfterCommit = (
{ root: true }, { root: true },
); );
commit(
rootTypes.TOGGLE_FILE_CHANGED,
{
file,
changed: false,
},
{ root: true },
);
dispatch('updateTempFlagForEntry', { file, tempFile: false }, { root: true });
eventHub.$emit(`editor.update.model.content.${file.key}`, { eventHub.$emit(`editor.update.model.content.${file.key}`, {
content: file.content, content: file.content,
changed: !!changedFile, changed: !!changedFile,
......
...@@ -60,4 +60,5 @@ export const UPDATE_FILE_AFTER_COMMIT = 'UPDATE_FILE_AFTER_COMMIT'; ...@@ -60,4 +60,5 @@ export const UPDATE_FILE_AFTER_COMMIT = 'UPDATE_FILE_AFTER_COMMIT';
export const ADD_PENDING_TAB = 'ADD_PENDING_TAB'; export const ADD_PENDING_TAB = 'ADD_PENDING_TAB';
export const REMOVE_PENDING_TAB = 'REMOVE_PENDING_TAB'; export const REMOVE_PENDING_TAB = 'REMOVE_PENDING_TAB';
export const UPDATE_TEMP_FLAG = 'UPDATE_TEMP_FLAG';
export const TOGGLE_FILE_FINDER = 'TOGGLE_FILE_FINDER'; export const TOGGLE_FILE_FINDER = 'TOGGLE_FILE_FINDER';
...@@ -4,6 +4,7 @@ import mergeRequestMutation from './mutations/merge_request'; ...@@ -4,6 +4,7 @@ import mergeRequestMutation from './mutations/merge_request';
import fileMutations from './mutations/file'; import fileMutations from './mutations/file';
import treeMutations from './mutations/tree'; import treeMutations from './mutations/tree';
import branchMutations from './mutations/branch'; import branchMutations from './mutations/branch';
import { sortTree } from './utils';
export default { export default {
[types.SET_INITIAL_DATA](state, data) { [types.SET_INITIAL_DATA](state, data) {
...@@ -73,7 +74,7 @@ export default { ...@@ -73,7 +74,7 @@ export default {
f => foundEntry.tree.find(e => e.path === f.path) === undefined, f => foundEntry.tree.find(e => e.path === f.path) === undefined,
); );
Object.assign(foundEntry, { Object.assign(foundEntry, {
tree: foundEntry.tree.concat(tree), tree: sortTree(foundEntry.tree.concat(tree)),
}); });
} }
...@@ -86,10 +87,16 @@ export default { ...@@ -86,10 +87,16 @@ export default {
if (!foundEntry) { if (!foundEntry) {
Object.assign(state.trees[`${projectId}/${branchId}`], { Object.assign(state.trees[`${projectId}/${branchId}`], {
tree: state.trees[`${projectId}/${branchId}`].tree.concat(data.treeList), tree: sortTree(state.trees[`${projectId}/${branchId}`].tree.concat(data.treeList)),
}); });
} }
}, },
[types.UPDATE_TEMP_FLAG](state, { path, tempFile }) {
Object.assign(state.entries[path], {
tempFile,
changed: tempFile,
});
},
[types.UPDATE_VIEWER](state, viewer) { [types.UPDATE_VIEWER](state, viewer) {
Object.assign(state, { Object.assign(state, {
viewer, viewer,
......
...@@ -33,6 +33,7 @@ export const dataStructure = () => ({ ...@@ -33,6 +33,7 @@ export const dataStructure = () => ({
raw: '', raw: '',
content: '', content: '',
parentTreeUrl: '', parentTreeUrl: '',
parentPath: '',
renderError: false, renderError: false,
base64: false, base64: false,
editorRow: 1, editorRow: 1,
...@@ -84,6 +85,7 @@ export const decorateData = entity => { ...@@ -84,6 +85,7 @@ export const decorateData = entity => {
opened, opened,
active, active,
parentTreeUrl, parentTreeUrl,
parentPath,
changed, changed,
renderError, renderError,
content, content,
...@@ -125,8 +127,8 @@ const sortTreesByTypeAndName = (a, b) => { ...@@ -125,8 +127,8 @@ const sortTreesByTypeAndName = (a, b) => {
} else if (a.type === 'blob' && b.type === 'tree') { } else if (a.type === 'blob' && b.type === 'tree') {
return 1; return 1;
} }
if (a.name.toLowerCase() < b.name.toLowerCase()) return -1; if (a.name < b.name) return -1;
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1; if (a.name > b.name) return 1;
return 0; return 0;
}; };
......
...@@ -6,6 +6,7 @@ self.addEventListener('message', e => { ...@@ -6,6 +6,7 @@ self.addEventListener('message', e => {
const treeList = []; const treeList = [];
let file; let file;
let parentPath;
const entries = data.reduce((acc, path) => { const entries = data.reduce((acc, path) => {
const pathSplit = path.split('/'); const pathSplit = path.split('/');
const blobName = pathSplit.pop().trim(); const blobName = pathSplit.pop().trim();
...@@ -17,6 +18,8 @@ self.addEventListener('message', e => { ...@@ -17,6 +18,8 @@ self.addEventListener('message', e => {
const foundEntry = acc[folderPath]; const foundEntry = acc[folderPath];
if (!foundEntry) { if (!foundEntry) {
parentPath = parentFolder ? parentFolder.path : null;
const tree = decorateData({ const tree = decorateData({
projectId, projectId,
branchId, branchId,
...@@ -30,6 +33,7 @@ self.addEventListener('message', e => { ...@@ -30,6 +33,7 @@ self.addEventListener('message', e => {
tempFile, tempFile,
changed: tempFile, changed: tempFile,
opened: tempFile, opened: tempFile,
parentPath,
}); });
Object.assign(acc, { Object.assign(acc, {
...@@ -53,6 +57,8 @@ self.addEventListener('message', e => { ...@@ -53,6 +57,8 @@ self.addEventListener('message', e => {
if (blobName !== '') { if (blobName !== '') {
const fileFolder = acc[pathSplit.join('/')]; const fileFolder = acc[pathSplit.join('/')];
parentPath = fileFolder ? fileFolder.path : null;
file = decorateData({ file = decorateData({
projectId, projectId,
branchId, branchId,
...@@ -68,6 +74,7 @@ self.addEventListener('message', e => { ...@@ -68,6 +74,7 @@ self.addEventListener('message', e => {
content, content,
base64, base64,
previewMode: viewerInformationForPath(blobName), previewMode: viewerInformationForPath(blobName),
parentPath,
}); });
Object.assign(acc, { Object.assign(acc, {
...@@ -88,5 +95,6 @@ self.addEventListener('message', e => { ...@@ -88,5 +95,6 @@ self.addEventListener('message', e => {
entries, entries,
treeList: sortTree(treeList), treeList: sortTree(treeList),
file, file,
parentPath,
}); });
}); });
...@@ -12,7 +12,8 @@ import ModalStore from './boards/stores/modal_store'; ...@@ -12,7 +12,8 @@ import ModalStore from './boards/stores/modal_store';
export default class MilestoneSelect { export default class MilestoneSelect {
constructor(currentProject, els, options = {}) { constructor(currentProject, els, options = {}) {
if (currentProject !== null) { if (currentProject !== null) {
this.currentProject = typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject; this.currentProject =
typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject;
} }
this.init(els, options); this.init(els, options);
...@@ -26,7 +27,10 @@ export default class MilestoneSelect { ...@@ -26,7 +27,10 @@ export default class MilestoneSelect {
} }
$els.each((i, dropdown) => { $els.each((i, dropdown) => {
let milestoneLinkNoneTemplate, milestoneLinkTemplate, selectedMilestone, selectedMilestoneDefault; let milestoneLinkNoneTemplate,
milestoneLinkTemplate,
selectedMilestone,
selectedMilestoneDefault;
const $dropdown = $(dropdown); const $dropdown = $(dropdown);
const projectId = $dropdown.data('projectId'); const projectId = $dropdown.data('projectId');
const milestonesUrl = $dropdown.data('milestones'); const milestonesUrl = $dropdown.data('milestones');
...@@ -46,45 +50,47 @@ export default class MilestoneSelect { ...@@ -46,45 +50,47 @@ export default class MilestoneSelect {
const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon'); const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon');
const $value = $block.find('.value'); const $value = $block.find('.value');
const $loading = $block.find('.block-loading').fadeOut(); const $loading = $block.find('.block-loading').fadeOut();
selectedMilestoneDefault = (showAny ? '' : null); selectedMilestoneDefault = showAny ? '' : null;
selectedMilestoneDefault = (showNo && defaultNo ? 'No Milestone' : selectedMilestoneDefault); selectedMilestoneDefault = showNo && defaultNo ? 'No Milestone' : selectedMilestoneDefault;
selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault; selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault;
if (issueUpdateURL) { if (issueUpdateURL) {
milestoneLinkTemplate = _.template('<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>'); milestoneLinkTemplate = _.template(
'<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>',
);
milestoneLinkNoneTemplate = '<span class="no-value">None</span>'; milestoneLinkNoneTemplate = '<span class="no-value">None</span>';
} }
return $dropdown.glDropdown({ return $dropdown.glDropdown({
showMenuAbove: showMenuAbove, showMenuAbove: showMenuAbove,
data: (term, callback) => axios.get(milestonesUrl) data: (term, callback) =>
.then(({ data }) => { axios.get(milestonesUrl).then(({ data }) => {
const extraOptions = []; const extraOptions = [];
if (showAny) { if (showAny) {
extraOptions.push({ extraOptions.push({
id: 0, id: null,
name: '', name: null,
title: 'Any Milestone' title: 'Any Milestone',
}); });
} }
if (showNo) { if (showNo) {
extraOptions.push({ extraOptions.push({
id: -1, id: -1,
name: 'No Milestone', name: 'No Milestone',
title: 'No Milestone' title: 'No Milestone',
}); });
} }
if (showUpcoming) { if (showUpcoming) {
extraOptions.push({ extraOptions.push({
id: -2, id: -2,
name: '#upcoming', name: '#upcoming',
title: 'Upcoming' title: 'Upcoming',
}); });
} }
if (showStarted) { if (showStarted) {
extraOptions.push({ extraOptions.push({
id: -3, id: -3,
name: '#started', name: '#started',
title: 'Started' title: 'Started',
}); });
} }
if (extraOptions.length) { if (extraOptions.length) {
...@@ -106,7 +112,7 @@ export default class MilestoneSelect { ...@@ -106,7 +112,7 @@ export default class MilestoneSelect {
`, `,
filterable: true, filterable: true,
search: { search: {
fields: ['title'] fields: ['title'],
}, },
selectable: true, selectable: true,
toggleLabel: (selected, el, e) => { toggleLabel: (selected, el, e) => {
...@@ -119,7 +125,7 @@ export default class MilestoneSelect { ...@@ -119,7 +125,7 @@ export default class MilestoneSelect {
defaultLabel: defaultLabel, defaultLabel: defaultLabel,
fieldName: $dropdown.data('fieldName'), fieldName: $dropdown.data('fieldName'),
text: milestone => _.escape(milestone.title), text: milestone => _.escape(milestone.title),
id: (milestone) => { id: milestone => {
if (!useId && !$dropdown.is('.js-issuable-form-dropdown')) { if (!useId && !$dropdown.is('.js-issuable-form-dropdown')) {
return milestone.name; return milestone.name;
} else { } else {
...@@ -131,7 +137,7 @@ export default class MilestoneSelect { ...@@ -131,7 +137,7 @@ export default class MilestoneSelect {
// display:block overrides the hide-collapse rule // display:block overrides the hide-collapse rule
return $value.css('display', ''); return $value.css('display', '');
}, },
opened: (e) => { opened: e => {
const $el = $(e.currentTarget); const $el = $(e.currentTarget);
if ($dropdown.hasClass('js-issue-board-sidebar') || options.handleClick) { if ($dropdown.hasClass('js-issue-board-sidebar') || options.handleClick) {
selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault; selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault;
...@@ -140,7 +146,7 @@ export default class MilestoneSelect { ...@@ -140,7 +146,7 @@ export default class MilestoneSelect {
$(`[data-milestone-id="${_.escape(selectedMilestone)}"] > a`, $el).addClass('is-active'); $(`[data-milestone-id="${_.escape(selectedMilestone)}"] > a`, $el).addClass('is-active');
}, },
vue: $dropdown.hasClass('js-issue-board-sidebar'), vue: $dropdown.hasClass('js-issue-board-sidebar'),
clicked: (clickEvent) => { clicked: clickEvent => {
const { $el, e } = clickEvent; const { $el, e } = clickEvent;
let selected = clickEvent.selectedObj; let selected = clickEvent.selectedObj;
...@@ -155,11 +161,14 @@ export default class MilestoneSelect { ...@@ -155,11 +161,14 @@ export default class MilestoneSelect {
const page = $('body').attr('data-page'); const page = $('body').attr('data-page');
const isIssueIndex = page === 'projects:issues:index'; const isIssueIndex = page === 'projects:issues:index';
const isMRIndex = (page === page && page === 'projects:merge_requests:index'); const isMRIndex = page === page && page === 'projects:merge_requests:index';
const isSelecting = (selected.name !== selectedMilestone); const isSelecting = selected.name !== selectedMilestone;
selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault; selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault;
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) { if (
$dropdown.hasClass('js-filter-bulk-update') ||
$dropdown.hasClass('js-issuable-form-dropdown')
) {
e.preventDefault(); e.preventDefault();
return; return;
} }
...@@ -177,10 +186,13 @@ export default class MilestoneSelect { ...@@ -177,10 +186,13 @@ export default class MilestoneSelect {
return $dropdown.closest('form').submit(); return $dropdown.closest('form').submit();
} else if ($dropdown.hasClass('js-issue-board-sidebar')) { } else if ($dropdown.hasClass('js-issue-board-sidebar')) {
if (selected.id !== -1 && isSelecting) { if (selected.id !== -1 && isSelecting) {
gl.issueBoards.boardStoreIssueSet('milestone', new ListMilestone({ gl.issueBoards.boardStoreIssueSet(
id: selected.id, 'milestone',
title: selected.name new ListMilestone({
})); id: selected.id,
title: selected.name,
}),
);
} else { } else {
gl.issueBoards.boardStoreIssueDelete('milestone'); gl.issueBoards.boardStoreIssueDelete('milestone');
} }
...@@ -188,7 +200,8 @@ export default class MilestoneSelect { ...@@ -188,7 +200,8 @@ export default class MilestoneSelect {
$dropdown.trigger('loading.gl.dropdown'); $dropdown.trigger('loading.gl.dropdown');
$loading.removeClass('hidden').fadeIn(); $loading.removeClass('hidden').fadeIn();
gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update')) gl.issueBoards.BoardsStore.detail.issue
.update($dropdown.attr('data-issue-update'))
.then(() => { .then(() => {
$dropdown.trigger('loaded.gl.dropdown'); $dropdown.trigger('loaded.gl.dropdown');
$loading.fadeOut(); $loading.fadeOut();
...@@ -203,7 +216,8 @@ export default class MilestoneSelect { ...@@ -203,7 +216,8 @@ export default class MilestoneSelect {
data[abilityName].milestone_id = selected != null ? selected : null; data[abilityName].milestone_id = selected != null ? selected : null;
$loading.removeClass('hidden').fadeIn(); $loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown'); $dropdown.trigger('loading.gl.dropdown');
return axios.put(issueUpdateURL, data) return axios
.put(issueUpdateURL, data)
.then(({ data }) => { .then(({ data }) => {
$dropdown.trigger('loaded.gl.dropdown'); $dropdown.trigger('loaded.gl.dropdown');
$loading.fadeOut(); $loading.fadeOut();
...@@ -215,7 +229,10 @@ export default class MilestoneSelect { ...@@ -215,7 +229,10 @@ export default class MilestoneSelect {
data.milestone.name = data.milestone.title; data.milestone.name = data.milestone.title;
$value.html(milestoneLinkTemplate(data.milestone)); $value.html(milestoneLinkTemplate(data.milestone));
return $sidebarCollapsedValue return $sidebarCollapsedValue
.attr('data-original-title', `${data.milestone.name}<br />${data.milestone.remaining}`) .attr(
'data-original-title',
`${data.milestone.name}<br />${data.milestone.remaining}`,
)
.find('span') .find('span')
.text(data.milestone.title); .text(data.milestone.title);
} else { } else {
...@@ -230,7 +247,7 @@ export default class MilestoneSelect { ...@@ -230,7 +247,7 @@ export default class MilestoneSelect {
$loading.fadeOut(); $loading.fadeOut();
}); });
} }
} },
}); });
}); });
} }
......
...@@ -52,16 +52,15 @@ ...@@ -52,16 +52,15 @@
text() { text() {
const keepContributionsText = s__(`AdminArea| const keepContributionsText = s__(`AdminArea|
You are about to permanently delete the user %{username}. You are about to permanently delete the user %{username}.
This will delete all of the issues, merge requests, and groups linked to them. Issues, merge requests, and groups linked to them will be transferred to a system-wide "Ghost-user".
To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead.
Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered.`); Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered.`);
const deleteContributionsText = s__(`AdminArea| const deleteContributionsText = s__(`AdminArea|
You are about to permanently delete the user %{username}. You are about to permanently delete the user %{username}.
Issues, merge requests, and groups linked to them will be transferred to a system-wide "Ghost-user". This will delete all of the issues, merge requests, and groups linked to them.
To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead.
Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered.`); Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered.`);
return sprintf(this.deleteContributions ? deleteContributionsText : keepContributionsText, return sprintf(this.deleteContributions ? deleteContributionsText : keepContributionsText,
{ {
username: `<strong>${_.escape(this.username)}</strong>`, username: `<strong>${_.escape(this.username)}</strong>`,
......
...@@ -188,11 +188,11 @@ export default class ActivityCalendar { ...@@ -188,11 +188,11 @@ export default class ActivityCalendar {
}, },
{ {
text: 'W', text: 'W',
y: 29 + this.dayYPos(2), y: 29 + this.dayYPos(3),
}, },
{ {
text: 'F', text: 'F',
y: 29 + this.dayYPos(3), y: 29 + this.dayYPos(5),
}, },
]; ];
this.svg this.svg
......
...@@ -5,7 +5,6 @@ import PerformanceBarService from '../services/performance_bar_service'; ...@@ -5,7 +5,6 @@ import PerformanceBarService from '../services/performance_bar_service';
import detailedMetric from './detailed_metric.vue'; import detailedMetric from './detailed_metric.vue';
import requestSelector from './request_selector.vue'; import requestSelector from './request_selector.vue';
import simpleMetric from './simple_metric.vue'; import simpleMetric from './simple_metric.vue';
import upstreamPerformanceBar from './upstream_performance_bar.vue';
import Flash from '../../flash'; import Flash from '../../flash';
...@@ -14,7 +13,6 @@ export default { ...@@ -14,7 +13,6 @@ export default {
detailedMetric, detailedMetric,
requestSelector, requestSelector,
simpleMetric, simpleMetric,
upstreamPerformanceBar,
}, },
props: { props: {
store: { store: {
...@@ -128,9 +126,6 @@ export default { ...@@ -128,9 +126,6 @@ export default {
{{ currentRequest.details.host.hostname }} {{ currentRequest.details.host.hostname }}
</span> </span>
</div> </div>
<upstream-performance-bar
v-if="initialRequest && currentRequest.details"
/>
<detailed-metric <detailed-metric
v-for="metric in $options.detailedMetrics" v-for="metric in $options.detailedMetrics"
:key="metric.metric" :key="metric.metric"
......
<script>
export default {
mounted() {
const upstreamPerformanceBar = document
.getElementById('peek-view-performance-bar')
.cloneNode(true);
upstreamPerformanceBar.classList.remove('hidden');
this.$refs.wrapper.appendChild(upstreamPerformanceBar);
},
};
</script>
<template>
<div
id="peek-view-performance-bar-vue"
class="view"
ref="wrapper"
></div>
</template>
import 'vendor/peek.performance_bar';
import Vue from 'vue'; import Vue from 'vue';
import performanceBarApp from './components/performance_bar_app.vue'; import performanceBarApp from './components/performance_bar_app.vue';
import PerformanceBarStore from './stores/performance_bar_store'; import PerformanceBarStore from './stores/performance_bar_store';
......
<script> <script>
import { n__ } from '~/locale'; import { n__ } from '~/locale';
import statusIcon from '../mr_widget_status_icon.vue'; import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
export default { export default {
name: 'MRWidgetFailedToMerge', name: 'MRWidgetFailedToMerge',
components: { components: {
statusIcon, statusIcon,
}, },
props: { props: {
mr: { mr: {
type: Object, type: Object,
required: true, required: true,
default: () => ({}), default: () => ({}),
},
}, },
},
data() { data() {
return { return {
timer: 10, timer: 10,
isRefreshing: false, isRefreshing: false,
}; intervalId: null,
}, };
},
computed: { computed: {
timerText() { timerText() {
return n__( return n__(
'Refreshing in a second to show the updated status...', 'Refreshing in a second to show the updated status...',
'Refreshing in %d seconds to show the updated status...', 'Refreshing in %d seconds to show the updated status...',
this.timer, this.timer,
); );
},
}, },
},
mounted() { mounted() {
setInterval(() => { this.intervalId = setInterval(this.updateTimer, 1000);
this.updateTimer(); },
}, 1000);
},
created() { created() {
eventHub.$emit('DisablePolling'); eventHub.$emit('DisablePolling');
}, },
methods: { beforeDestroy() {
refresh() { if (this.intervalId) {
this.isRefreshing = true; clearInterval(this.intervalId);
eventHub.$emit('MRWidgetUpdateRequested'); }
eventHub.$emit('EnablePolling'); },
},
updateTimer() {
this.timer = this.timer - 1;
if (this.timer === 0) { methods: {
this.refresh(); refresh() {
} this.isRefreshing = true;
}, eventHub.$emit('MRWidgetUpdateRequested');
eventHub.$emit('EnablePolling');
}, },
updateTimer() {
this.timer = this.timer - 1;
}; if (this.timer === 0) {
this.refresh();
}
},
},
};
</script> </script>
<template> <template>
<div class="mr-widget-body media"> <div class="mr-widget-body media">
......
<script> <script>
import getIconForFile from './file_icon/file_icon_map'; import getIconForFile from './file_icon/file_icon_map';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import icon from '../../vue_shared/components/icon.vue'; import icon from '../../vue_shared/components/icon.vue';
/* This is a re-usable vue component for rendering a svg sprite /* This is a re-usable vue component for rendering a svg sprite
icon icon
Sample configuration: Sample configuration:
...@@ -15,60 +15,60 @@ ...@@ -15,60 +15,60 @@
/> />
*/ */
export default { export default {
components: { components: {
loadingIcon, loadingIcon,
icon, icon,
},
props: {
fileName: {
type: String,
required: true,
}, },
props: {
fileName: {
type: String,
required: true,
},
folder: { folder: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
opened: { opened: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
loading: { loading: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
size: { size: {
type: Number, type: Number,
required: false, required: false,
default: 16, default: 16,
}, },
cssClasses: { cssClasses: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
}, },
},
computed: {
spriteHref() {
const iconName = getIconForFile(this.fileName) || 'file';
return `${gon.sprite_file_icons}#${iconName}`;
},
folderIconName() {
return this.opened ? 'folder-open' : 'folder';
}, },
computed: { iconSizeClass() {
spriteHref() { return this.size ? `s${this.size}` : '';
const iconName = getIconForFile(this.fileName) || 'file';
return `${gon.sprite_file_icons}#${iconName}`;
},
folderIconName() {
return this.opened ? 'folder-open' : 'folder';
},
iconSizeClass() {
return this.size ? `s${this.size}` : '';
},
}, },
}; },
};
</script> </script>
<template> <template>
<span> <span>
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
v-if="!loading && folder" v-if="!loading && folder"
:name="folderIconName" :name="folderIconName"
:size="size" :size="size"
css-classes="folder-icon"
/> />
<loading-icon <loading-icon
v-if="loading" v-if="loading"
......
class ListLabel { export default class ListLabel {
constructor(obj) { constructor(obj) {
this.id = obj.id; this.id = obj.id;
this.title = obj.title; this.title = obj.title;
......
...@@ -241,8 +241,6 @@ ...@@ -241,8 +241,6 @@
} }
.scrolling-tabs-container { .scrolling-tabs-container {
position: relative;
.merge-request-tabs-container & { .merge-request-tabs-container & {
overflow: hidden; overflow: hidden;
} }
...@@ -272,8 +270,6 @@ ...@@ -272,8 +270,6 @@
} }
.inner-page-scroll-tabs { .inner-page-scroll-tabs {
position: relative;
.fade-right { .fade-right {
@include fade(left, $white-light); @include fade(left, $white-light);
right: 0; right: 0;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
.fork-svg { .fork-svg {
margin-right: 4px; margin-right: 4px;
vertical-align: bottom;
} }
} }
......
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
} }
.branch-info .commit-icon { .branch-info .commit-icon {
margin-right: 3px; margin-right: 8px;
svg { svg {
top: 3px; top: 3px;
......
...@@ -314,6 +314,10 @@ ...@@ -314,6 +314,10 @@
display: inline-flex; display: inline-flex;
vertical-align: top; vertical-align: top;
&:hover .color-label {
text-decoration: underline;
}
.label { .label {
vertical-align: inherit; vertical-align: inherit;
font-size: $label-font-size; font-size: $label-font-size;
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
max-width: inherit; max-width: inherit;
line-height: 22px;
svg { svg {
vertical-align: middle; vertical-align: middle;
...@@ -67,9 +68,24 @@ ...@@ -67,9 +68,24 @@
} }
} }
<<<<<<< HEAD
=======
.ide-file-icon-holder {
display: flex;
align-items: center;
}
.ide-file-changed-icon {
margin-left: auto;
> svg {
display: block;
}
}
>>>>>>> master
.ide-new-btn { .ide-new-btn {
display: none; display: none;
margin-bottom: -4px;
margin-right: -8px; margin-right: -8px;
} }
...@@ -82,10 +98,8 @@ ...@@ -82,10 +98,8 @@
} }
} }
&.folder { .folder-icon {
svg { fill: $gl-text-color-secondary;
fill: $gl-text-color-secondary;
}
} }
} }
...@@ -103,6 +117,7 @@ ...@@ -103,6 +117,7 @@
.file-col-commit-message { .file-col-commit-message {
display: flex; display: flex;
overflow: visible; overflow: visible;
align-items: center;
padding: 6px 12px; padding: 6px 12px;
} }
...@@ -430,7 +445,7 @@ ...@@ -430,7 +445,7 @@
.projects-sidebar { .projects-sidebar {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; flex: 1;
.context-header { .context-header {
width: auto; width: auto;
...@@ -965,3 +980,7 @@ ...@@ -965,3 +980,7 @@
align-items: center; align-items: center;
font-size: 12px; font-size: 12px;
} }
.ide-new-modal-label {
line-height: 34px;
}
@import 'framework/variables'; @import 'framework/variables';
@import 'peek/views/performance_bar';
@import 'peek/views/rblineprof'; @import 'peek/views/rblineprof';
#js-peek { #js-peek {
......
...@@ -14,6 +14,7 @@ class PipelinesFinder ...@@ -14,6 +14,7 @@ class PipelinesFinder
items = by_scope(items) items = by_scope(items)
items = by_status(items) items = by_status(items)
items = by_ref(items) items = by_ref(items)
items = by_sha(items)
items = by_name(items) items = by_name(items)
items = by_username(items) items = by_username(items)
items = by_yaml_errors(items) items = by_yaml_errors(items)
...@@ -69,6 +70,14 @@ class PipelinesFinder ...@@ -69,6 +70,14 @@ class PipelinesFinder
end end
end end
def by_sha(items)
if params[:sha].present?
items.where(sha: params[:sha])
else
items
end
end
def by_name(items) def by_name(items)
if params[:name].present? if params[:name].present?
items.joins(:user).where(users: { name: params[:name] }) items.joins(:user).where(users: { name: params[:name] })
......
...@@ -17,7 +17,7 @@ module BlobHelper ...@@ -17,7 +17,7 @@ module BlobHelper
end end
def ide_edit_path(project = @project, ref = @ref, path = @path, options = {}) def ide_edit_path(project = @project, ref = @ref, path = @path, options = {})
"#{ide_path}/project#{edit_blob_path(project, ref, path, options)}" "#{ide_path}/project#{url_for([project, "edit", "blob", id: [ref, path], script_name: "/"])}"
end end
def edit_blob_button(project = @project, ref = @ref, path = @path, options = {}) def edit_blob_button(project = @project, ref = @ref, path = @path, options = {})
......
...@@ -63,7 +63,7 @@ module CommitsHelper ...@@ -63,7 +63,7 @@ module CommitsHelper
# Returns a link formatted as a commit branch link # Returns a link formatted as a commit branch link
def commit_branch_link(url, text) def commit_branch_link(url, text)
link_to(url, class: 'label label-gray ref-name branch-link') do link_to(url, class: 'label label-gray ref-name branch-link') do
sprite_icon('fork', size: 16, css_class: 'fork-svg') + "#{text}" sprite_icon('fork', size: 12, css_class: 'fork-svg') + "#{text}"
end end
end end
......
...@@ -400,7 +400,8 @@ module ProjectsHelper ...@@ -400,7 +400,8 @@ module ProjectsHelper
exports_path = File.join(Settings.shared['path'], 'tmp/project_exports') exports_path = File.join(Settings.shared['path'], 'tmp/project_exports')
filtered_message = message.strip.gsub(exports_path, "[REPO EXPORT PATH]") filtered_message = message.strip.gsub(exports_path, "[REPO EXPORT PATH]")
filtered_message.gsub(project.repository_storage_path.chomp('/'), "[REPOS PATH]") disk_path = Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path
filtered_message.gsub(disk_path.chomp('/'), "[REPOS PATH]")
end end
def project_child_container_class(view_path) def project_child_container_class(view_path)
......
...@@ -45,25 +45,25 @@ module Storage ...@@ -45,25 +45,25 @@ module Storage
# Hooks # Hooks
# Save the storage paths before the projects are destroyed to use them on after destroy # Save the storages before the projects are destroyed to use them on after destroy
def prepare_for_destroy def prepare_for_destroy
old_repository_storage_paths old_repository_storages
end end
private private
def move_repositories def move_repositories
# Move the namespace directory in all storage paths used by member projects # Move the namespace directory in all storages used by member projects
repository_storage_paths.each do |repository_storage_path| repository_storages.each do |repository_storage|
# Ensure old directory exists before moving it # Ensure old directory exists before moving it
gitlab_shell.add_namespace(repository_storage_path, full_path_was) gitlab_shell.add_namespace(repository_storage, full_path_was)
# Ensure new directory exists before moving it (if there's a parent) # Ensure new directory exists before moving it (if there's a parent)
gitlab_shell.add_namespace(repository_storage_path, parent.full_path) if parent gitlab_shell.add_namespace(repository_storage, parent.full_path) if parent
unless gitlab_shell.mv_namespace(repository_storage_path, full_path_was, full_path) unless gitlab_shell.mv_namespace(repository_storage, full_path_was, full_path)
Rails.logger.error "Exception moving path #{repository_storage_path} from #{full_path_was} to #{full_path}" Rails.logger.error "Exception moving path #{repository_storage} from #{full_path_was} to #{full_path}"
# if we cannot move namespace directory we should rollback # if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs # db changes in order to prevent out of sync between db and fs
...@@ -72,33 +72,33 @@ module Storage ...@@ -72,33 +72,33 @@ module Storage
end end
end end
def old_repository_storage_paths def old_repository_storages
@old_repository_storage_paths ||= repository_storage_paths @old_repository_storage_paths ||= repository_storages
end end
def repository_storage_paths def repository_storages
# We need to get the storage paths for all the projects, even the ones that are # We need to get the storage paths for all the projects, even the ones that are
# pending delete. Unscoping also get rids of the default order, which causes # pending delete. Unscoping also get rids of the default order, which causes
# problems with SELECT DISTINCT. # problems with SELECT DISTINCT.
Project.unscoped do Project.unscoped do
all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path) all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage)
end end
end end
def rm_dir def rm_dir
# Remove the namespace directory in all storages paths used by member projects # Remove the namespace directory in all storages paths used by member projects
old_repository_storage_paths.each do |repository_storage_path| old_repository_storages.each do |repository_storage|
# Move namespace directory into trash. # Move namespace directory into trash.
# We will remove it later async # We will remove it later async
new_path = "#{full_path}+#{id}+deleted" new_path = "#{full_path}+#{id}+deleted"
if gitlab_shell.mv_namespace(repository_storage_path, full_path, new_path) if gitlab_shell.mv_namespace(repository_storage, full_path, new_path)
Gitlab::AppLogger.info %Q(Namespace directory "#{full_path}" moved to "#{new_path}") Gitlab::AppLogger.info %Q(Namespace directory "#{full_path}" moved to "#{new_path}")
# Remove namespace directroy async with delay so # Remove namespace directroy async with delay so
# GitLab has time to remove all projects first # GitLab has time to remove all projects first
run_after_commit do run_after_commit do
GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path) GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage, new_path)
end end
end end
end end
......
...@@ -197,10 +197,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -197,10 +197,6 @@ class MergeRequestDiff < ActiveRecord::Base
CompareService.new(project, head_commit_sha).execute(project, sha, straight: true) CompareService.new(project, head_commit_sha).execute(project, sha, straight: true)
end end
def commits_count
super || merge_request_diff_commits.size
end
private private
def create_merge_request_diff_files(diffs) def create_merge_request_diff_files(diffs)
......
...@@ -518,10 +518,6 @@ class Project < ActiveRecord::Base ...@@ -518,10 +518,6 @@ class Project < ActiveRecord::Base
repository.empty? repository.empty?
end end
def repository_storage_path
Gitlab.config.repositories.storages[repository_storage]&.legacy_disk_path
end
def team def team
@team ||= ProjectTeam.new(self) @team ||= ProjectTeam.new(self)
end end
...@@ -1105,7 +1101,7 @@ class Project < ActiveRecord::Base ...@@ -1105,7 +1101,7 @@ class Project < ActiveRecord::Base
# Check if repository already exists on disk # Check if repository already exists on disk
def check_repository_path_availability def check_repository_path_availability
return true if skip_disk_validation return true if skip_disk_validation
return false unless repository_storage_path return false unless repository_storage
expires_full_path_cache # we need to clear cache to validate renames correctly expires_full_path_cache # we need to clear cache to validate renames correctly
...@@ -1910,14 +1906,14 @@ class Project < ActiveRecord::Base ...@@ -1910,14 +1906,14 @@ class Project < ActiveRecord::Base
def check_repository_absence! def check_repository_absence!
return if skip_disk_validation return if skip_disk_validation
if repository_storage_path.blank? || repository_with_same_path_already_exists? if repository_storage.blank? || repository_with_same_path_already_exists?
errors.add(:base, 'There is already a repository with that name on disk') errors.add(:base, 'There is already a repository with that name on disk')
throw :abort throw :abort
end end
end end
def repository_with_same_path_already_exists? def repository_with_same_path_already_exists?
gitlab_shell.exists?(repository_storage_path, "#{disk_path}.git") gitlab_shell.exists?(repository_storage, "#{disk_path}.git")
end end
# set last_activity_at to the same as created_at # set last_activity_at to the same as created_at
......
...@@ -21,7 +21,7 @@ class ProjectWiki ...@@ -21,7 +21,7 @@ class ProjectWiki
end end
delegate :empty?, to: :pages delegate :empty?, to: :pages
delegate :repository_storage_path, :hashed_storage?, to: :project delegate :repository_storage, :hashed_storage?, to: :project
def path def path
@project.path + '.wiki' @project.path + '.wiki'
......
...@@ -84,9 +84,14 @@ class Repository ...@@ -84,9 +84,14 @@ class Repository
# Return absolute path to repository # Return absolute path to repository
def path_to_repo def path_to_repo
@path_to_repo ||= File.expand_path( @path_to_repo ||=
File.join(repository_storage_path, disk_path + '.git') begin
) storage = Gitlab.config.repositories.storages[@project.repository_storage]
File.expand_path(
File.join(storage.legacy_disk_path, disk_path + '.git')
)
end
end end
def inspect def inspect
...@@ -915,10 +920,6 @@ class Repository ...@@ -915,10 +920,6 @@ class Repository
raw_repository.fetch_ref(source_repository.raw_repository, source_ref: source_ref, target_ref: target_ref) raw_repository.fetch_ref(source_repository.raw_repository, source_ref: source_ref, target_ref: target_ref)
end end
def repository_storage_path
@project.repository_storage_path
end
def rebase(user, merge_request) def rebase(user, merge_request)
raw.rebase(user, merge_request.id, branch: merge_request.source_branch, raw.rebase(user, merge_request.id, branch: merge_request.source_branch,
branch_sha: merge_request.source_branch_sha, branch_sha: merge_request.source_branch_sha,
......
module Storage module Storage
class HashedProject class HashedProject
attr_accessor :project attr_accessor :project
delegate :gitlab_shell, :repository_storage_path, to: :project delegate :gitlab_shell, :repository_storage, to: :project
ROOT_PATH_PREFIX = '@hashed'.freeze ROOT_PATH_PREFIX = '@hashed'.freeze
...@@ -24,7 +24,7 @@ module Storage ...@@ -24,7 +24,7 @@ module Storage
end end
def ensure_storage_path_exists def ensure_storage_path_exists
gitlab_shell.add_namespace(repository_storage_path, base_dir) gitlab_shell.add_namespace(repository_storage, base_dir)
end end
def rename_repo def rename_repo
......
module Storage module Storage
class LegacyProject class LegacyProject
attr_accessor :project attr_accessor :project
delegate :namespace, :gitlab_shell, :repository_storage_path, to: :project delegate :namespace, :gitlab_shell, :repository_storage, to: :project
def initialize(project) def initialize(project)
@project = project @project = project
...@@ -24,18 +24,18 @@ module Storage ...@@ -24,18 +24,18 @@ module Storage
def ensure_storage_path_exists def ensure_storage_path_exists
return unless namespace return unless namespace
gitlab_shell.add_namespace(repository_storage_path, base_dir) gitlab_shell.add_namespace(repository_storage, base_dir)
end end
def rename_repo def rename_repo
new_full_path = project.build_full_path new_full_path = project.build_full_path
if gitlab_shell.mv_repository(repository_storage_path, project.full_path_was, new_full_path) if gitlab_shell.mv_repository(repository_storage, project.full_path_was, new_full_path)
# If repository moved successfully we need to send update instructions to users. # If repository moved successfully we need to send update instructions to users.
# However we cannot allow rollback since we moved repository # However we cannot allow rollback since we moved repository
# So we basically we mute exceptions in next actions # So we basically we mute exceptions in next actions
begin begin
gitlab_shell.mv_repository(repository_storage_path, "#{project.full_path_was}.wiki", "#{new_full_path}.wiki") gitlab_shell.mv_repository(repository_storage, "#{project.full_path_was}.wiki", "#{new_full_path}.wiki")
return true return true
rescue => e rescue => e
Rails.logger.error "Exception renaming #{project.full_path_was} -> #{new_full_path}: #{e}" Rails.logger.error "Exception renaming #{project.full_path_was} -> #{new_full_path}: #{e}"
......
...@@ -91,7 +91,7 @@ module Projects ...@@ -91,7 +91,7 @@ module Projects
project.run_after_commit do project.run_after_commit do
# self is now project # self is now project
GitlabShellWorker.perform_in(5.minutes, :remove_repository, self.repository_storage_path, new_path) GitlabShellWorker.perform_in(5.minutes, :remove_repository, self.repository_storage, new_path)
end end
else else
false false
...@@ -100,9 +100,9 @@ module Projects ...@@ -100,9 +100,9 @@ module Projects
def mv_repository(from_path, to_path) def mv_repository(from_path, to_path)
# There is a possibility project does not have repository or wiki # There is a possibility project does not have repository or wiki
return true unless gitlab_shell.exists?(project.repository_storage_path, from_path + '.git') return true unless gitlab_shell.exists?(project.repository_storage, from_path + '.git')
gitlab_shell.mv_repository(project.repository_storage_path, from_path, to_path) gitlab_shell.mv_repository(project.repository_storage, from_path, to_path)
end end
def attempt_rollback(project, message) def attempt_rollback(project, message)
......
...@@ -47,8 +47,8 @@ module Projects ...@@ -47,8 +47,8 @@ module Projects
private private
def move_repository(from_name, to_name) def move_repository(from_name, to_name)
from_exists = gitlab_shell.exists?(project.repository_storage_path, "#{from_name}.git") from_exists = gitlab_shell.exists?(project.repository_storage, "#{from_name}.git")
to_exists = gitlab_shell.exists?(project.repository_storage_path, "#{to_name}.git") to_exists = gitlab_shell.exists?(project.repository_storage, "#{to_name}.git")
# If we don't find the repository on either original or target we should log that as it could be an issue if the # If we don't find the repository on either original or target we should log that as it could be an issue if the
# project was not originally empty. # project was not originally empty.
...@@ -60,7 +60,7 @@ module Projects ...@@ -60,7 +60,7 @@ module Projects
return true return true
end end
gitlab_shell.mv_repository(project.repository_storage_path, from_name, to_name) gitlab_shell.mv_repository(project.repository_storage, from_name, to_name)
end end
def rollback_folder_move def rollback_folder_move
......
...@@ -127,7 +127,7 @@ module Projects ...@@ -127,7 +127,7 @@ module Projects
end end
def move_repo_folder(from_name, to_name) def move_repo_folder(from_name, to_name)
gitlab_shell.mv_repository(project.repository_storage_path, from_name, to_name) gitlab_shell.mv_repository(project.repository_storage, from_name, to_name)
end end
def execute_system_hooks def execute_system_hooks
......
...@@ -159,7 +159,7 @@ module SystemNoteService ...@@ -159,7 +159,7 @@ module SystemNoteService
body = if noteable.time_estimate == 0 body = if noteable.time_estimate == 0
"removed time estimate" "removed time estimate"
else else
"changed time estimate to #{parsed_time}," "changed time estimate to #{parsed_time}"
end end
create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking')) create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking'))
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
delete_user_url: admin_user_path(user), delete_user_url: admin_user_path(user),
block_user_url: block_admin_user_path(user), block_user_url: block_admin_user_path(user),
username: user.name, username: user.name,
delete_contributions: 'false' }, type: 'button' } delete_contributions: false }, type: 'button' }
= s_('AdminUsers|Delete user') = s_('AdminUsers|Delete user')
%li %li
...@@ -52,5 +52,5 @@ ...@@ -52,5 +52,5 @@
delete_user_url: admin_user_path(user, hard_delete: true), delete_user_url: admin_user_path(user, hard_delete: true),
block_user_url: block_admin_user_path(user), block_user_url: block_admin_user_path(user),
username: user.name, username: user.name,
delete_contributions: 'true' }, type: 'button' } delete_contributions: true }, type: 'button' }
= s_('AdminUsers|Delete user and contributions') = s_('AdminUsers|Delete user and contributions')
...@@ -183,7 +183,7 @@ ...@@ -183,7 +183,7 @@
delete_user_url: admin_user_path(@user), delete_user_url: admin_user_path(@user),
block_user_url: block_admin_user_path(@user), block_user_url: block_admin_user_path(@user),
username: @user.name, username: @user.name,
delete_contributions: 'false' }, type: 'button' } delete_contributions: false }, type: 'button' }
= s_('AdminUsers|Delete user') = s_('AdminUsers|Delete user')
- else - else
- if @user.solo_owned_groups.present? - if @user.solo_owned_groups.present?
...@@ -215,7 +215,7 @@ ...@@ -215,7 +215,7 @@
delete_user_url: admin_user_path(@user, hard_delete: true), delete_user_url: admin_user_path(@user, hard_delete: true),
block_user_url: block_admin_user_path(@user), block_user_url: block_admin_user_path(@user),
username: @user.name, username: @user.name,
delete_contributions: 'true' }, type: 'button' } delete_contributions: true }, type: 'button' }
= s_('AdminUsers|Delete user and contributions') = s_('AdminUsers|Delete user and contributions')
- else - else
%p %p
......
...@@ -17,14 +17,14 @@ ...@@ -17,14 +17,14 @@
.ci-variable-row-body .ci-variable-row-body
%input.js-ci-variable-input-id{ type: "hidden", name: id_input_name, value: id } %input.js-ci-variable-input-id{ type: "hidden", name: id_input_name, value: id }
%input.js-ci-variable-input-destroy{ type: "hidden", name: destroy_input_name } %input.js-ci-variable-input-destroy{ type: "hidden", name: destroy_input_name }
%input.js-ci-variable-input-key.ci-variable-body-item.form-control{ type: "text", %input.js-ci-variable-input-key.ci-variable-body-item.qa-ci-variable-input-key.form-control{ type: "text",
name: key_input_name, name: key_input_name,
value: key, value: key,
placeholder: s_('CiVariables|Input variable key') } placeholder: s_('CiVariables|Input variable key') }
.ci-variable-body-item .ci-variable-body-item
.form-control.js-secret-value-placeholder{ class: ('hide' unless id) } .form-control.js-secret-value-placeholder.qa-ci-variable-input-value{ class: ('hide' unless id) }
= '*' * 20 = '*' * 20
%textarea.js-ci-variable-input-value.js-secret-value.form-control{ class: ('hide' if id), %textarea.js-ci-variable-input-value.js-secret-value.qa-ci-variable-input-value.form-control{ class: ('hide' if id),
rows: 1, rows: 1,
name: value_input_name, name: value_input_name,
placeholder: s_('CiVariables|Input variable value') } placeholder: s_('CiVariables|Input variable value') }
......
- breadcrumb_title "General Settings" - breadcrumb_title "General Settings"
- @content_class = "limit-container-width" unless fluid_layout
.panel.panel-default.prepend-top-default .panel.panel-default.prepend-top-default
.panel-heading .panel-heading
Group settings Group settings
......
...@@ -5,8 +5,3 @@ ...@@ -5,8 +5,3 @@
peek_url: peek_routes.results_url, peek_url: peek_routes.results_url,
profile_url: url_for(params.merge(lineprofiler: 'true')) }, profile_url: url_for(params.merge(lineprofiler: 'true')) },
class: Peek.env } class: Peek.env }
#peek-view-performance-bar.hidden
= render_server_response_time
%span#serverstats
%ul.performance-bar
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
- if @namespaces.present? - if @namespaces.present?
.fork-thumbnail-container.js-fork-content .fork-thumbnail-container.js-fork-content
%h5.prepend-top-0.append-bottom-0.prepend-left-default.append-right-default %h5.prepend-top-0.append-bottom-0.prepend-left-default.append-right-default
Click to fork the project = _("Select a namespace to fork the project")
- @namespaces.each do |namespace| - @namespaces.each do |namespace|
= render 'fork_button', namespace: namespace = render 'fork_button', namespace: namespace
- else - else
......
- content_for :merge_access_levels do - content_for :merge_access_levels do
.merge_access_levels-container .merge_access_levels-container
= dropdown_tag('Select', = dropdown_tag('Select',
options: { toggle_class: 'js-allowed-to-merge wide', options: { toggle_class: 'js-allowed-to-merge qa-allowed-to-merge-select wide',
dropdown_class: 'dropdown-menu-selectable capitalize-header', dropdown_class: 'dropdown-menu-selectable qa-allowed-to-merge-dropdown capitalize-header',
data: { field_name: 'protected_branch[merge_access_levels_attributes][0][access_level]', input_id: 'merge_access_levels_attributes' }}) data: { field_name: 'protected_branch[merge_access_levels_attributes][0][access_level]', input_id: 'merge_access_levels_attributes' }})
- content_for :push_access_levels do - content_for :push_access_levels do
.push_access_levels-container .push_access_levels-container
......
%td %td
= hidden_field_tag "allowed_to_merge_#{protected_branch.id}", protected_branch.merge_access_levels.first.access_level = hidden_field_tag "allowed_to_merge_#{protected_branch.id}", protected_branch.merge_access_levels.first.access_level
= dropdown_tag( (protected_branch.merge_access_levels.first.humanize || 'Select') , = dropdown_tag( (protected_branch.merge_access_levels.first.humanize || 'Select') ,
options: { toggle_class: 'js-allowed-to-merge', dropdown_class: 'dropdown-menu-selectable js-allowed-to-merge-container capitalize-header', options: { toggle_class: 'js-allowed-to-merge qa-allowed-to-merge', dropdown_class: 'dropdown-menu-selectable js-allowed-to-merge-container capitalize-header',
data: { field_name: "allowed_to_merge_#{protected_branch.id}", access_level_id: protected_branch.merge_access_levels.first.id }}) data: { field_name: "allowed_to_merge_#{protected_branch.id}", access_level_id: protected_branch.merge_access_levels.first.id }})
%td %td
= hidden_field_tag "allowed_to_push_#{protected_branch.id}", protected_branch.push_access_levels.first.access_level = hidden_field_tag "allowed_to_push_#{protected_branch.id}", protected_branch.push_access_levels.first.access_level
......
...@@ -36,5 +36,6 @@ ...@@ -36,5 +36,6 @@
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com' = form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
.help-block .help-block
= s_('CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.') = s_('CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.')
= link_to icon('question-circle'), help_page_path('topics/autodevops/index.md', anchor: 'auto-devops-base-domain'), target: '_blank'
= f.submit 'Save changes', class: "btn btn-success prepend-top-15" = f.submit 'Save changes', class: "btn btn-success prepend-top-15"
...@@ -32,6 +32,13 @@ ...@@ -32,6 +32,13 @@
required: true, required: true,
title: 'You can choose a descriptive name different from the path.' title: 'You can choose a descriptive name different from the path.'
- if @group.persisted?
.form-group.group-name-holder
= f.label :id, class: 'control-label' do
= _("Group ID")
.col-sm-10
= f.text_field :id, class: 'form-control', readonly: true
.form-group.group-description-holder .form-group.group-description-holder
= f.label :description, class: 'control-label' = f.label :description, class: 'control-label'
.col-sm-10 .col-sm-10
......
...@@ -13,7 +13,9 @@ class RepositoryForkWorker ...@@ -13,7 +13,9 @@ class RepositoryForkWorker
# See https://gitlab.com/gitlab-org/gitaly/issues/1110 # See https://gitlab.com/gitlab-org/gitaly/issues/1110
if args.empty? if args.empty?
source_project = target_project.forked_from_project source_project = target_project.forked_from_project
return target_project.mark_import_as_failed('Source project cannot be found.') unless source_project unless source_project
return target_project.mark_import_as_failed('Source project cannot be found.')
end
fork_repository(target_project, source_project.repository_storage, source_project.disk_path) fork_repository(target_project, source_project.repository_storage, source_project.disk_path)
else else
......
---
title: Fix tabs container styles to make RSS button clickable
merge_request: 18559
author:
type: fixed
---
title: Correct text and functionality for delete user / delete user and contributions
modal.
merge_request: 18463
author: Marc Schwede
type: fixed
---
title: Replace "Click" with "Select" to be more inclusive of people with accessibility
requirements
merge_request: 18386
author: Mark Lapierre
type: other
---
title: Add sha filter to pipelines list API
merge_request: 18125
author:
type: changed
---
title: Improve performance of a service responsible for creating a pipeline
merge_request: 18582
author:
type: performance
---
title: Restore label underline color
merge_request: 18407
author: George Tsiolis
type: fixed
---
title: Fix size and position for fork icon
merge_request: 18449
author: George Tsiolis
type: changed
---
title: Show group id in group settings
merge_request: 18482
author: George Tsiolis
type: added
---
title: Reset milestone filter when clicking "Any Milestone" in dashboard
merge_request: 18531
author:
type: fixed
---
title: Repository#exists? is always executed through Gitaly
merge_request:
author:
type: performance
...@@ -184,18 +184,18 @@ production: &base ...@@ -184,18 +184,18 @@ production: &base
# base_dir: uploads/-/system # base_dir: uploads/-/system
object_store: object_store:
enabled: false enabled: false
# remote_directory: uploads # Bucket name remote_directory: uploads # Bucket name
# direct_upload: false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false) # direct_upload: false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false)
# background_upload: false # Temporary option to limit automatic upload (Default: true) # background_upload: false # Temporary option to limit automatic upload (Default: true)
# proxy_download: false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage # proxy_download: false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage
connection: connection:
provider: AWS provider: AWS
aws_access_key_id: AWS_ACCESS_KEY_ID aws_access_key_id: AWS_ACCESS_KEY_ID
aws_secret_access_key: AWS_SECRET_ACCESS_KEY aws_secret_access_key: AWS_SECRET_ACCESS_KEY
region: us-east-1 region: us-east-1
# host: 'localhost' # default: s3.amazonaws.com # host: 'localhost' # default: s3.amazonaws.com
# endpoint: 'http://127.0.0.1:9000' # default: nil # endpoint: 'http://127.0.0.1:9000' # default: nil
# path_style: true # Use 'host/bucket_name/object' instead of 'bucket_name.host/object' # path_style: true # Use 'host/bucket_name/object' instead of 'bucket_name.host/object'
## GitLab Pages ## GitLab Pages
pages: pages:
...@@ -212,6 +212,8 @@ production: &base ...@@ -212,6 +212,8 @@ production: &base
artifacts_server: true artifacts_server: true
# external_http: ["1.1.1.1:80", "[2001::1]:80"] # If defined, enables custom domain support in GitLab Pages # external_http: ["1.1.1.1:80", "[2001::1]:80"] # If defined, enables custom domain support in GitLab Pages
# external_https: ["1.1.1.1:443", "[2001::1]:443"] # If defined, enables custom domain and certificate support in GitLab Pages # external_https: ["1.1.1.1:443", "[2001::1]:443"] # If defined, enables custom domain and certificate support in GitLab Pages
admin:
address: unix:/home/git/gitlab/tmp/sockets/private/pages-admin.socket # TCP connections are supported too (e.g. tcp://host:port)
## Mattermost ## Mattermost
## For enabling Add to Mattermost button ## For enabling Add to Mattermost button
......
...@@ -215,6 +215,9 @@ Settings.pages['external_http'] ||= false unless Settings.pages['external_ht ...@@ -215,6 +215,9 @@ Settings.pages['external_http'] ||= false unless Settings.pages['external_ht
Settings.pages['external_https'] ||= false unless Settings.pages['external_https'].present? Settings.pages['external_https'] ||= false unless Settings.pages['external_https'].present?
Settings.pages['artifacts_server'] ||= Settings.pages['enabled'] if Settings.pages['artifacts_server'].nil? Settings.pages['artifacts_server'] ||= Settings.pages['enabled'] if Settings.pages['artifacts_server'].nil?
Settings.pages['admin'] ||= Settingslogic.new({})
Settings.pages.admin['certificate'] ||= ''
# #
# Git LFS # Git LFS
# #
......
Gitlab::PagesClient.read_or_create_token
Gitlab::PagesClient.load_certificate
Rails.application.config.peek.adapter = :redis, { client: ::Redis.new(Gitlab::Redis::Cache.params) } Rails.application.config.peek.adapter = :redis, { client: ::Redis.new(Gitlab::Redis::Cache.params) }
Peek.into Peek::Views::Host Peek.into Peek::Views::Host
Peek.into Peek::Views::PerformanceBar
if Gitlab::Database.mysql? if Gitlab::Database.mysql?
require 'peek-mysql2' require 'peek-mysql2'
......
...@@ -59,17 +59,17 @@ class RemoveDotGitFromGroupNames < ActiveRecord::Migration ...@@ -59,17 +59,17 @@ class RemoveDotGitFromGroupNames < ActiveRecord::Migration
end end
def move_namespace(group_id, path_was, path) def move_namespace(group_id, path_was, path)
repository_storage_paths = select_all("SELECT distinct(repository_storage) FROM projects WHERE namespace_id = #{group_id}").map do |row| repository_storages = select_all("SELECT distinct(repository_storage) FROM projects WHERE namespace_id = #{group_id}").map do |row|
Gitlab.config.repositories.storages[row['repository_storage']].legacy_disk_path row['repository_storage']
end.compact end.compact
# Move the namespace directory in all storages paths used by member projects # Move the namespace directory in all storages paths used by member projects
repository_storage_paths.each do |repository_storage_path| repository_storages.each do |repository_storage|
# Ensure old directory exists before moving it # Ensure old directory exists before moving it
gitlab_shell.add_namespace(repository_storage_path, path_was) gitlab_shell.add_namespace(repository_storage, path_was)
unless gitlab_shell.mv_namespace(repository_storage_path, path_was, path) unless gitlab_shell.mv_namespace(repository_storage, path_was, path)
Rails.logger.error "Exception moving path #{repository_storage_path} from #{path_was} to #{path}" Rails.logger.error "Exception moving on shard #{repository_storage} from #{path_was} to #{path}"
# if we cannot move namespace directory we should rollback # if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs # db changes in order to prevent out of sync between db and fs
......
...@@ -53,8 +53,8 @@ class RemoveDotGitFromUsernames < ActiveRecord::Migration ...@@ -53,8 +53,8 @@ class RemoveDotGitFromUsernames < ActiveRecord::Migration
select_all("SELECT id, path FROM routes WHERE path = '#{quote_string(path)}'").present? select_all("SELECT id, path FROM routes WHERE path = '#{quote_string(path)}'").present?
end end
def path_exists?(path, repository_storage_path) def path_exists?(shard, repository_storage_path)
repository_storage_path && gitlab_shell.exists?(repository_storage_path, path) repository_storage_path && gitlab_shell.exists?(shard, repository_storage_path)
end end
# Accepts invalid path like test.git and returns test_git or # Accepts invalid path like test.git and returns test_git or
...@@ -70,8 +70,8 @@ class RemoveDotGitFromUsernames < ActiveRecord::Migration ...@@ -70,8 +70,8 @@ class RemoveDotGitFromUsernames < ActiveRecord::Migration
def check_routes(base, counter, path) def check_routes(base, counter, path)
route_exists = route_exists?(path) route_exists = route_exists?(path)
Gitlab.config.repositories.storages.each_value do |storage| Gitlab.config.repositories.storages.each do |shard, storage|
if route_exists || path_exists?(path, storage.legacy_disk_path) if route_exists || path_exists?(shard, storage.legacy_disk_path)
counter += 1 counter += 1
path = "#{base}#{counter}" path = "#{base}#{counter}"
...@@ -83,17 +83,17 @@ class RemoveDotGitFromUsernames < ActiveRecord::Migration ...@@ -83,17 +83,17 @@ class RemoveDotGitFromUsernames < ActiveRecord::Migration
end end
def move_namespace(namespace_id, path_was, path) def move_namespace(namespace_id, path_was, path)
repository_storage_paths = select_all("SELECT distinct(repository_storage) FROM projects WHERE namespace_id = #{namespace_id}").map do |row| repository_storages = select_all("SELECT distinct(repository_storage) FROM projects WHERE namespace_id = #{namespace_id}").map do |row|
Gitlab.config.repositories.storages[row['repository_storage']].legacy_disk_path row['repository_storage']
end.compact end.compact
# Move the namespace directory in all storages paths used by member projects # Move the namespace directory in all storages used by member projects
repository_storage_paths.each do |repository_storage_path| repository_storages.each do |repository_storage|
# Ensure old directory exists before moving it # Ensure old directory exists before moving it
gitlab_shell.add_namespace(repository_storage_path, path_was) gitlab_shell.add_namespace(repository_storage, path_was)
unless gitlab_shell.mv_namespace(repository_storage_path, path_was, path) unless gitlab_shell.mv_namespace(repository_storage, path_was, path)
Rails.logger.error "Exception moving path #{repository_storage_path} from #{path_was} to #{path}" Rails.logger.error "Exception moving on shard #{repository_storage} from #{path_was} to #{path}"
# if we cannot move namespace directory we should rollback # if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs # db changes in order to prevent out of sync between db and fs
......
class AssureCommitsCountForMergeRequestDiff < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class MergeRequestDiff < ActiveRecord::Base
self.table_name = 'merge_request_diffs'
include ::EachBatch
end
def up
Gitlab::BackgroundMigration.steal('AddMergeRequestDiffCommitsCount')
MergeRequestDiff.where(commits_count: nil).each_batch(of: 50) do |batch|
range = batch.pluck('MIN(id)', 'MAX(id)').first
Gitlab::BackgroundMigration::AddMergeRequestDiffCommitsCount.new.perform(*range)
end
end
def down
# noop
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180418053107) do ActiveRecord::Schema.define(version: 20180425131009) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
......
...@@ -323,7 +323,7 @@ The prerequisites for a HA Redis setup are the following: ...@@ -323,7 +323,7 @@ The prerequisites for a HA Redis setup are the following:
# machines to connect to it. # machines to connect to it.
redis['port'] = 6379 redis['port'] = 6379
# The same password for Redeis authentication you set up for the master node. # The same password for Redis authentication you set up for the master node.
redis['password'] = 'redis-password-goes-here' redis['password'] = 'redis-password-goes-here'
# The IP of the master Redis node. # The IP of the master Redis node.
......
...@@ -107,7 +107,7 @@ For source installations the following settings are nested under `artifacts:` an ...@@ -107,7 +107,7 @@ For source installations the following settings are nested under `artifacts:` an
| Setting | Description | Default | | Setting | Description | Default |
|---------|-------------|---------| |---------|-------------|---------|
| `enabled` | Enable/disable object storage | `false` | | `enabled` | Enable/disable object storage | `false` |
| `remote_directory` | The bucket name where Artfacts will be stored| | | `remote_directory` | The bucket name where Artifacts will be stored| |
| `direct_upload` | Set to true to enable direct upload of Artifacts without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. Currently only `Google` provider is supported | `false` | | `direct_upload` | Set to true to enable direct upload of Artifacts without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. Currently only `Google` provider is supported | `false` |
| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 | `true` | | `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` | | `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
...@@ -148,7 +148,7 @@ _The artifacts are stored by default in ...@@ -148,7 +148,7 @@ _The artifacts are stored by default in
``` ```
NOTE: For GitLab 9.4+, if you are using AWS IAM profiles, be sure to omit the NOTE: For GitLab 9.4+, if you are using AWS IAM profiles, be sure to omit the
AWS access key and secret acces key/value pairs. For example: AWS access key and secret access key/value pairs. For example:
```ruby ```ruby
gitlab_rails['artifacts_object_store_connection'] = { gitlab_rails['artifacts_object_store_connection'] = {
......
...@@ -46,7 +46,7 @@ In this experimental phase, only a few metrics are available: ...@@ -46,7 +46,7 @@ In this experimental phase, only a few metrics are available:
| redis_ping_latency_seconds | Gauge | 9.4 | Round trip time of the redis ping | | redis_ping_latency_seconds | Gauge | 9.4 | Round trip time of the redis ping |
| user_session_logins_total | Counter | 9.4 | Counter of how many users have logged in | | user_session_logins_total | Counter | 9.4 | Counter of how many users have logged in |
| filesystem_circuitbreaker_latency_seconds | Gauge | 9.5 | Time spent validating if a storage is accessible | | filesystem_circuitbreaker_latency_seconds | Gauge | 9.5 | Time spent validating if a storage is accessible |
| filesystem_circuitbreaker | Gauge | 9.5 | Wether or not the circuit for a certain shard is broken or not | | filesystem_circuitbreaker | Gauge | 9.5 | Whether or not the circuit for a certain shard is broken or not |
| circuitbreaker_storage_check_duration_seconds | Histogram | 10.3 | Time a single storage probe took | | circuitbreaker_storage_check_duration_seconds | Histogram | 10.3 | Time a single storage probe took |
## Metrics shared directory ## Metrics shared directory
......
...@@ -31,7 +31,7 @@ GitLab Shell provides a way to authorize SSH users via a fast, indexed lookup ...@@ -31,7 +31,7 @@ GitLab Shell provides a way to authorize SSH users via a fast, indexed lookup
to the GitLab database. GitLab Shell uses the fingerprint of the SSH key to to the GitLab database. GitLab Shell uses the fingerprint of the SSH key to
check whether the user is authorized to access GitLab. check whether the user is authorized to access GitLab.
Add the following to your `sshd_config` file. This is usuaully located at Add the following to your `sshd_config` file. This is usually located at
`/etc/ssh/sshd_config`, but it will be `/assets/sshd_config` if you're using `/etc/ssh/sshd_config`, but it will be `/assets/sshd_config` if you're using
Omnibus Docker: Omnibus Docker:
......
...@@ -104,7 +104,7 @@ _The uploads are stored by default in ...@@ -104,7 +104,7 @@ _The uploads are stored by default in
``` ```
>**Note:** >**Note:**
If you are using AWS IAM profiles, be sure to omit the AWS access key and secret acces key/value pairs. If you are using AWS IAM profiles, be sure to omit the AWS access key and secret access key/value pairs.
```ruby ```ruby
gitlab_rails['uploads_object_store_connection'] = { gitlab_rails['uploads_object_store_connection'] = {
......
...@@ -13,6 +13,7 @@ following locations: ...@@ -13,6 +13,7 @@ following locations:
- [Broadcast Messages](broadcast_messages.md) - [Broadcast Messages](broadcast_messages.md)
- [Project-level Variables](project_level_variables.md) - [Project-level Variables](project_level_variables.md)
- [Group-level Variables](group_level_variables.md) - [Group-level Variables](group_level_variables.md)
- [Code Snippets](snippets.md)
- [Commits](commits.md) - [Commits](commits.md)
- [Custom Attributes](custom_attributes.md) - [Custom Attributes](custom_attributes.md)
- [Deployments](deployments.md) - [Deployments](deployments.md)
...@@ -85,6 +86,29 @@ have been resolved to our satisfaction by the relicensing of the reference ...@@ -85,6 +86,29 @@ have been resolved to our satisfaction by the relicensing of the reference
implementations under MIT, and the use of the OWF license for the GraphQL implementations under MIT, and the use of the OWF license for the GraphQL
specification. specification.
## Compatibility Guidelines
The HTTP API is versioned using a single number, the current one being 4. This
number symbolises the same as the major version number as described by
[SemVer](https://semver.org/). This mean that backward incompatible changes
will require this version number to change. However, the minor version is
not explicit. This allows for a stable API endpoint, but also means new
features can be added to the API in the same version number.
New features and bug fixes are released in tandem with a new GitLab, and apart
from incidental patch and security releases, are released on the 22nd each
month. Backward incompatible changes (e.g. endpoints removal, parameters
removal etc.), as well as removal of entire API versions are done in tandem
with a major point release of GitLab itself. All deprecations and changes
between two versions should be listed in the documentation. For the changes
between v3 and v4; please read the [v3 to v4 documentation](v3_to_v4.md)
#### Current status
Currently two API versions are available, v3 and v4. v3 is deprecated and
will soon be removed. Deletion is scheduled for
[GitLab 11.0](https://gitlab.com/gitlab-org/gitlab-ce/issues/36819).
## Basic usage ## Basic usage
API requests should be prefixed with `api` and the API version. The API version API requests should be prefixed with `api` and the API version. The API version
...@@ -269,7 +293,7 @@ The following table gives an overview of how the API functions generally behave. ...@@ -269,7 +293,7 @@ The following table gives an overview of how the API functions generally behave.
| `GET` | Access one or more resources and return the result as JSON. | | `GET` | Access one or more resources and return the result as JSON. |
| `POST` | Return `201 Created` if the resource is successfully created and return the newly created resource as JSON. | | `POST` | Return `201 Created` if the resource is successfully created and return the newly created resource as JSON. |
| `GET` / `PUT` | Return `200 OK` if the resource is accessed or modified successfully. The (modified) result is returned as JSON. | | `GET` / `PUT` | Return `200 OK` if the resource is accessed or modified successfully. The (modified) result is returned as JSON. |
| `DELETE` | Returns `204 No Content` if the resuource was deleted successfully. | | `DELETE` | Returns `204 No Content` if the resource was deleted successfully. |
The following table shows the possible return codes for API requests. The following table shows the possible return codes for API requests.
......
...@@ -12,7 +12,7 @@ Badges support placeholders that will be replaced in real time in both the link ...@@ -12,7 +12,7 @@ Badges support placeholders that will be replaced in real time in both the link
- **%{default_branch}**: will be replaced by the project default branch. - **%{default_branch}**: will be replaced by the project default branch.
- **%{commit_sha}**: will be replaced by the last project's commit sha. - **%{commit_sha}**: will be replaced by the last project's commit sha.
Because these enpoints aren't inside a project's context, the information used to replace the placeholders will be Because these endpoints aren't inside a project's context, the information used to replace the placeholders will be
from the first group's project by creation date. If the group hasn't got any project the original URL with the placeholders will be returned. from the first group's project by creation date. If the group hasn't got any project the original URL with the placeholders will be returned.
## List all badges of a group ## List all badges of a group
......
...@@ -108,7 +108,7 @@ POST /projects/:id/pipeline_schedules ...@@ -108,7 +108,7 @@ POST /projects/:id/pipeline_schedules
| `description` | string | yes | The description of pipeline schedule | | `description` | string | yes | The description of pipeline schedule |
| `ref` | string | yes | The branch/tag name will be triggered | | `ref` | string | yes | The branch/tag name will be triggered |
| `cron ` | string | yes | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) | | `cron ` | string | yes | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) |
| `cron_timezone ` | string | no | The timezone supproted by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) (default: `'UTC'`) | | `cron_timezone ` | string | no | The timezone supported by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) (default: `'UTC'`) |
| `active ` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially (default: `true`) | | `active ` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially (default: `true`) |
```sh ```sh
...@@ -153,7 +153,7 @@ PUT /projects/:id/pipeline_schedules/:pipeline_schedule_id ...@@ -153,7 +153,7 @@ PUT /projects/:id/pipeline_schedules/:pipeline_schedule_id
| `description` | string | no | The description of pipeline schedule | | `description` | string | no | The description of pipeline schedule |
| `ref` | string | no | The branch/tag name will be triggered | | `ref` | string | no | The branch/tag name will be triggered |
| `cron ` | string | no | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) | | `cron ` | string | no | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) |
| `cron_timezone ` | string | no | The timezone supproted by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) or `TZInfo::Timezone` (e.g. `America/Los_Angeles`) | | `cron_timezone ` | string | no | The timezone supported by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) or `TZInfo::Timezone` (e.g. `America/Los_Angeles`) |
| `active ` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially. | | `active ` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially. |
```sh ```sh
......
...@@ -14,6 +14,7 @@ GET /projects/:id/pipelines ...@@ -14,6 +14,7 @@ GET /projects/:id/pipelines
| `scope` | string | no | The scope of pipelines, one of: `running`, `pending`, `finished`, `branches`, `tags` | | `scope` | string | no | The scope of pipelines, one of: `running`, `pending`, `finished`, `branches`, `tags` |
| `status` | string | no | The status of pipelines, one of: `running`, `pending`, `success`, `failed`, `canceled`, `skipped` | | `status` | string | no | The status of pipelines, one of: `running`, `pending`, `success`, `failed`, `canceled`, `skipped` |
| `ref` | string | no | The ref of pipelines | | `ref` | string | no | The ref of pipelines |
| `sha` | string | no | The sha or pipelines |
| `yaml_errors`| boolean | no | Returns pipelines with invalid configurations | | `yaml_errors`| boolean | no | Returns pipelines with invalid configurations |
| `name`| string | no | The name of the user who triggered pipelines | | `name`| string | no | The name of the user who triggered pipelines |
| `username`| string | no | The username of the user who triggered pipelines | | `username`| string | no | The username of the user who triggered pipelines |
......
...@@ -509,7 +509,7 @@ and unit tests, all running and deployed at every push to master - with shocking ...@@ -509,7 +509,7 @@ and unit tests, all running and deployed at every push to master - with shocking
Errors can be easily debugged through GitLab's build logs, and within minutes of a successful commit, Errors can be easily debugged through GitLab's build logs, and within minutes of a successful commit,
you can see the changes live on your game. you can see the changes live on your game.
Setting up Continous Integration and Continuous Deployment from the start with Dark Nova enables Setting up Continuous Integration and Continuous Deployment from the start with Dark Nova enables
rapid but stable development. We can easily test changes in a separate [environment](../../../ci/environments.md#introduction-to-environments-and-deployments), rapid but stable development. We can easily test changes in a separate [environment](../../../ci/environments.md#introduction-to-environments-and-deployments),
or multiple environments if needed. Balancing and updating a multiplayer game can be ongoing or multiple environments if needed. Balancing and updating a multiplayer game can be ongoing
and tedious, but having faith in a stable deployment with GitLab CI/CD allows and tedious, but having faith in a stable deployment with GitLab CI/CD allows
......
...@@ -30,7 +30,7 @@ and GitLab UI._ ...@@ -30,7 +30,7 @@ and GitLab UI._
Many components and concepts are similar to Ruby on Rails or Python's Django. High developer Many components and concepts are similar to Ruby on Rails or Python's Django. High developer
productivity and high application performance are only a few advantages on learning how to use it. productivity and high application performance are only a few advantages on learning how to use it.
Working on the MVC pattern, it's was designed to be modular and flexible. Easy to mantain a growing Working on the MVC pattern, it's was designed to be modular and flexible. Easy to maintain a growing
app is a plus. app is a plus.
Phoenix can run in any OS where Erlang is supported: Phoenix can run in any OS where Erlang is supported:
...@@ -48,7 +48,7 @@ Check the [Phoenix learning guide][phoenix-learning-guide] for more information. ...@@ -48,7 +48,7 @@ Check the [Phoenix learning guide][phoenix-learning-guide] for more information.
### What is Elixir? ### What is Elixir?
[Elixir][elixir-site] is a dynamic, functional language created to use all the maturity of Erlang [Elixir][elixir-site] is a dynamic, functional language created to use all the maturity of Erlang
(30 years old!) in these days, in an easy way. It has similarities with Ruby, specially on sintax, (30 years old!) in these days, in an easy way. It has similarities with Ruby, specially on syntax,
so Ruby developers are quite excited with the rapid growing of Elixir. A full-stack Ruby developer so Ruby developers are quite excited with the rapid growing of Elixir. A full-stack Ruby developer
can learn how to use Elixir and Phoenix in just a few weeks! can learn how to use Elixir and Phoenix in just a few weeks!
...@@ -162,7 +162,7 @@ productive, because every time we, or our co-workers push any code, GitLab CI/CD ...@@ -162,7 +162,7 @@ productive, because every time we, or our co-workers push any code, GitLab CI/CD
test the changes, telling us in realtime if anything goes wrong. test the changes, telling us in realtime if anything goes wrong.
Certainly, when our application starts to grow, we'll need more developers working on the same Certainly, when our application starts to grow, we'll need more developers working on the same
project and this process of building and testing can easely become a mess without proper management. project and this process of building and testing can easily become a mess without proper management.
That's also why GitLab CI/CD is so important to our application. Every time someone pushes its code to That's also why GitLab CI/CD is so important to our application. Every time someone pushes its code to
GitLab, we'll quickly know if their changes broke something or not. We don't need to stop everything GitLab, we'll quickly know if their changes broke something or not. We don't need to stop everything
we're doing to test manually and locally every change our team does. we're doing to test manually and locally every change our team does.
...@@ -237,7 +237,7 @@ Finished in 0.7 seconds ...@@ -237,7 +237,7 @@ Finished in 0.7 seconds
Randomized with seed 610000 Randomized with seed 610000
``` ```
Our test was successfull. It's time to push our files to GitLab. Our test was successful. It's time to push our files to GitLab.
## Configuring CI/CD Pipeline ## Configuring CI/CD Pipeline
...@@ -302,7 +302,7 @@ template** and select **Elixir**: ...@@ -302,7 +302,7 @@ template** and select **Elixir**:
``` ```
It's important to install `postgresql-client` to let GitLab CI/CD access PostgreSQL and create our It's important to install `postgresql-client` to let GitLab CI/CD access PostgreSQL and create our
database with the login information provided earlier. More important is to respect the identation, database with the login information provided earlier. More important is to respect the indentation,
to avoid syntax errors when running the build. to avoid syntax errors when running the build.
- And finally, we'll let `mix` session intact. - And finally, we'll let `mix` session intact.
...@@ -333,7 +333,7 @@ mix: ...@@ -333,7 +333,7 @@ mix:
- mix test - mix test
``` ```
For safety, we can check if we get any syntax errors before submiting this file to GitLab. Copy the For safety, we can check if we get any syntax errors before submitting this file to GitLab. Copy the
contents of `.gitlab-ci.yml` and paste it on [GitLab CI/CD Lint tool][ci-lint]. Please note that contents of `.gitlab-ci.yml` and paste it on [GitLab CI/CD Lint tool][ci-lint]. Please note that
this link will only work for logged in users. this link will only work for logged in users.
...@@ -384,7 +384,7 @@ working properly. ...@@ -384,7 +384,7 @@ working properly.
When we have a growing application with many developers working on it, or when we have an open When we have a growing application with many developers working on it, or when we have an open
source project being watched and contributed by the community, it is really important to have our source project being watched and contributed by the community, it is really important to have our
code permanently working. GitLab CI/CD is a time saving powerfull tool to help us mantain our code code permanently working. GitLab CI/CD is a time saving powerful tool to help us maintain our code
organized and working. organized and working.
As we could see in this post, GitLab CI/CD is really really easy to configure and use. We have [many As we could see in this post, GitLab CI/CD is really really easy to configure and use. We have [many
......
...@@ -298,6 +298,28 @@ Mentioned briefly earlier, but the following things of Runners can be exploited. ...@@ -298,6 +298,28 @@ Mentioned briefly earlier, but the following things of Runners can be exploited.
We're always looking for contributions that can mitigate these We're always looking for contributions that can mitigate these
[Security Considerations](https://docs.gitlab.com/runner/security/). [Security Considerations](https://docs.gitlab.com/runner/security/).
### Resetting the registration token for a Project
If you think that registration token for a Project was revealed, you should
reset them. It's recommended because such token can be used to register another
Runner to thi Project. It may be next used to obtain the values of secret
variables or clone the project code, that normally may be unavailable for the
attacker.
To reset the token:
1. Go to **Settings > CI/CD** for a specified Project
1. Expand the **General pipelines settings** section
1. Find the **Runner token** form field and click the **Reveal value** button
1. Delete the value and save the form
1. After the page is refreshed, expand the **Runners settings** section
and check the registration token - it should be changed
From now on the old token is not valid anymore and will not allow to register
a new Runner to the project. If you are using any tools to provision and
register new Runners, you should now update the token that is used to the
new value.
## Determining the IP address of a Runner ## Determining the IP address of a Runner
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17286) in GitLab 10.6. > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17286) in GitLab 10.6.
......
...@@ -61,7 +61,7 @@ future GitLab releases.** ...@@ -61,7 +61,7 @@ future GitLab releases.**
| **CI_RUNNER_EXECUTABLE_ARCH** | all | 10.6 | The OS/architecture of the GitLab Runner executable (note that this is not necessarily the same as the environment of the executor) | | **CI_RUNNER_EXECUTABLE_ARCH** | all | 10.6 | The OS/architecture of the GitLab Runner executable (note that this is not necessarily the same as the environment of the executor) |
| **CI_PIPELINE_ID** | 8.10 | 0.5 | The unique id of the current pipeline that GitLab CI uses internally | | **CI_PIPELINE_ID** | 8.10 | 0.5 | The unique id of the current pipeline that GitLab CI uses internally |
| **CI_PIPELINE_TRIGGERED** | all | all | The flag to indicate that job was [triggered] | | **CI_PIPELINE_TRIGGERED** | all | all | The flag to indicate that job was [triggered] |
| **CI_PIPELINE_SOURCE** | 10.0 | all | The source for this pipeline, one of: push, web, trigger, schedule, api, external. Pipelines created before 9.5 will have unknown as source | | **CI_PIPELINE_SOURCE** | 10.0 | all | Indicates how the pipeline was triggered. Possible options are: `push`, `web`, `trigger`, `schedule`, `api`, and `pipeline`. For pipelines created before GitLab 9.5, this will show as `unknown` |
| **CI_PROJECT_DIR** | all | all | The full path where the repository is cloned and where the job is run | | **CI_PROJECT_DIR** | all | all | The full path where the repository is cloned and where the job is run |
| **CI_PROJECT_ID** | all | all | The unique id of the current project that GitLab CI uses internally | | **CI_PROJECT_ID** | all | all | The unique id of the current project that GitLab CI uses internally |
| **CI_PROJECT_NAME** | 8.10 | 0.5 | The project name that is currently being built (actually it is project folder name) | | **CI_PROJECT_NAME** | 8.10 | 0.5 | The project name that is currently being built (actually it is project folder name) |
...@@ -551,7 +551,7 @@ You can find a full list of unsupported variables below: ...@@ -551,7 +551,7 @@ You can find a full list of unsupported variables below:
- `CI_DEPLOY_USER` - `CI_DEPLOY_USER`
- `CI_DEPLOY_PASSWORD` - `CI_DEPLOY_PASSWORD`
These variables are also not supported in a contex of a These variables are also not supported in a context of a
[dynamic environment name][dynamic-environments]. [dynamic environment name][dynamic-environments].
[ce-13784]: https://gitlab.com/gitlab-org/gitlab-ce/issues/13784 "Simple protection of CI secret variables" [ce-13784]: https://gitlab.com/gitlab-org/gitlab-ce/issues/13784 "Simple protection of CI secret variables"
......
...@@ -39,7 +39,6 @@ comments: false ...@@ -39,7 +39,6 @@ comments: false
- [Sidekiq debugging](sidekiq_debugging.md) - [Sidekiq debugging](sidekiq_debugging.md)
- [Gotchas](gotchas.md) to avoid - [Gotchas](gotchas.md) to avoid
- [Avoid modules with instance variables](module_with_instance_variables.md) if possible - [Avoid modules with instance variables](module_with_instance_variables.md) if possible
- [Issue and merge requests state models](object_state_models.md)
- [How to dump production data to staging](db_dump.md) - [How to dump production data to staging](db_dump.md)
- [Working with the GitHub importer](github_importer.md) - [Working with the GitHub importer](github_importer.md)
......
...@@ -24,7 +24,7 @@ Some examples where background migrations can be useful: ...@@ -24,7 +24,7 @@ Some examples where background migrations can be useful:
* Migrating events from one table to multiple separate tables. * Migrating events from one table to multiple separate tables.
* Populating one column based on JSON stored in another column. * Populating one column based on JSON stored in another column.
* Migrating data that depends on the output of exernal services (e.g. an API). * Migrating data that depends on the output of external services (e.g. an API).
## Isolation ## Isolation
...@@ -46,7 +46,7 @@ See [Sidekiq best practices guidelines](https://github.com/mperham/sidekiq/wiki/ ...@@ -46,7 +46,7 @@ See [Sidekiq best practices guidelines](https://github.com/mperham/sidekiq/wiki/
for more details. for more details.
Make sure that in case that your migration job is going to be retried data Make sure that in case that your migration job is going to be retried data
integrity is guarateed. integrity is guaranteed.
## How It Works ## How It Works
......
...@@ -4,7 +4,7 @@ The documentation style guide defines the markup structure used in ...@@ -4,7 +4,7 @@ The documentation style guide defines the markup structure used in
GitLab documentation. Check the GitLab documentation. Check the
[documentation guidelines](writing_documentation.md) for general development instructions. [documentation guidelines](writing_documentation.md) for general development instructions.
Check the GitLab hanbook for the [writing styles guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines). Check the GitLab handbook for the [writing styles guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines).
## Text ## Text
...@@ -19,7 +19,7 @@ Check the GitLab hanbook for the [writing styles guidelines](https://about.gitla ...@@ -19,7 +19,7 @@ Check the GitLab hanbook for the [writing styles guidelines](https://about.gitla
- Unless there's a logical reason not to, add documents in alphabetical order - Unless there's a logical reason not to, add documents in alphabetical order
- Write in US English - Write in US English
- Use [single spaces][] instead of double spaces - Use [single spaces][] instead of double spaces
- Jump a line between different markups (e.g., after every paragraph, hearder, list, etc) - Jump a line between different markups (e.g., after every paragraph, header, list, etc)
- Capitalize "G" and "L" in GitLab - Capitalize "G" and "L" in GitLab
- Capitalize feature, products, and methods names. E.g.: GitLab Runner, Geo, - Capitalize feature, products, and methods names. E.g.: GitLab Runner, Geo,
Issue Boards, Git, Prometheus, Continuous Integration. Issue Boards, Git, Prometheus, Continuous Integration.
......
...@@ -279,7 +279,7 @@ end ...@@ -279,7 +279,7 @@ end
``` ```
In `lib/gitlab/visibility_level.rb` this method is used to return the In `lib/gitlab/visibility_level.rb` this method is used to return the
allowed visibilty levels: allowed visibility levels:
```ruby ```ruby
def levels_for_user(user = nil) def levels_for_user(user = nil)
......
...@@ -236,7 +236,7 @@ export class Foo { ...@@ -236,7 +236,7 @@ export class Foo {
} }
``` ```
On the other hand, if a class only needs to extend a third party/add event listeners in some specific cases, they should be initialized oustside of the constructor. On the other hand, if a class only needs to extend a third party/add event listeners in some specific cases, they should be initialized outside of the constructor.
1. Prefer `.map`, `.reduce` or `.filter` over `.forEach` 1. Prefer `.map`, `.reduce` or `.filter` over `.forEach`
A forEach will most likely cause side effects, it will be mutating the array being iterated. Prefer using `.map`, A forEach will most likely cause side effects, it will be mutating the array being iterated. Prefer using `.map`,
......
...@@ -84,7 +84,7 @@ The `RecordsUploads::Concern` concern will create an `Upload` entry for every fi ...@@ -84,7 +84,7 @@ The `RecordsUploads::Concern` concern will create an `Upload` entry for every fi
By including the `ObjectStorage::Concern` in the `GitlabUploader` derived class, you may enable the object storage for this uploader. To enable the object storage By including the `ObjectStorage::Concern` in the `GitlabUploader` derived class, you may enable the object storage for this uploader. To enable the object storage
in your uploader, you need to either 1) include `RecordsUpload::Concern` and prepend `ObjectStorage::Extension::RecordsUploads` or 2) mount the uploader and create a new field named `<mount>_store`. in your uploader, you need to either 1) include `RecordsUpload::Concern` and prepend `ObjectStorage::Extension::RecordsUploads` or 2) mount the uploader and create a new field named `<mount>_store`.
The `CarrierWave::Uploader#store_dir` is overriden to The `CarrierWave::Uploader#store_dir` is overridden to
- `GitlabUploader.base_dir` + `GitlabUploader.dynamic_segment` when the store is LOCAL - `GitlabUploader.base_dir` + `GitlabUploader.dynamic_segment` when the store is LOCAL
- `GitlabUploader.dynamic_segment` when the store is REMOTE (the bucket name is used to namespace) - `GitlabUploader.dynamic_segment` when the store is REMOTE (the bucket name is used to namespace)
......
...@@ -270,7 +270,7 @@ If there are merge conflicts in the `gitlab.pot` file, you can delete the file ...@@ -270,7 +270,7 @@ If there are merge conflicts in the `gitlab.pot` file, you can delete the file
and regenerate it using the same command. Confirm that you are not deleting any strings accidentally by looking over the diff. and regenerate it using the same command. Confirm that you are not deleting any strings accidentally by looking over the diff.
The command also updates the translation files for each language: `locale/*/gitlab.po` The command also updates the translation files for each language: `locale/*/gitlab.po`
These changes can be discarded, the languange files will be updated by Crowdin These changes can be discarded, the language files will be updated by Crowdin
automatically. automatically.
Discard all of them at once like this: Discard all of them at once like this:
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment