Standardize markdown in dev and workflow
Delete trailing whitespace, fix blockquotes, fix note boxes, with indentation, clean up tables, etc.
This commit is contained in:
parent
a749fcbea7
commit
3bc0a1185c
13 changed files with 331 additions and 328 deletions
|
@ -38,7 +38,7 @@ Advantages over [`spyOn()`]:
|
|||
|
||||
- no need to create response objects
|
||||
- does not allow call through (which we want to avoid)
|
||||
- simple API to test error cases
|
||||
- simple API to test error cases
|
||||
- provides `replyOnce()` to allow for different responses
|
||||
|
||||
We have also decided against using [axios interceptors] because they are not suitable for mocking.
|
||||
|
|
|
@ -21,31 +21,31 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
|
|||
1. **Never Ever EVER** disable eslint globally for a file
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
/* eslint-disable */
|
||||
// bad
|
||||
/* eslint-disable */
|
||||
|
||||
// better
|
||||
/* eslint-disable some-rule, some-other-rule */
|
||||
// better
|
||||
/* eslint-disable some-rule, some-other-rule */
|
||||
|
||||
// best
|
||||
// nothing :)
|
||||
// best
|
||||
// nothing :)
|
||||
```
|
||||
|
||||
1. If you do need to disable a rule for a single violation, try to do it as locally as possible
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
/* eslint-disable no-new */
|
||||
// bad
|
||||
/* eslint-disable no-new */
|
||||
|
||||
import Foo from 'foo';
|
||||
import Foo from 'foo';
|
||||
|
||||
new Foo();
|
||||
new Foo();
|
||||
|
||||
// better
|
||||
import Foo from 'foo';
|
||||
// better
|
||||
import Foo from 'foo';
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new Foo();
|
||||
// eslint-disable-next-line no-new
|
||||
new Foo();
|
||||
```
|
||||
|
||||
1. There are few rules that we need to disable due to technical debt. Which are:
|
||||
|
@ -56,16 +56,16 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
|
|||
followed by any global declarations, then a blank newline prior to any imports or code.
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
/* global Foo */
|
||||
/* eslint-disable no-new */
|
||||
import Bar from './bar';
|
||||
// bad
|
||||
/* global Foo */
|
||||
/* eslint-disable no-new */
|
||||
import Bar from './bar';
|
||||
|
||||
// good
|
||||
/* eslint-disable no-new */
|
||||
/* global Foo */
|
||||
// good
|
||||
/* eslint-disable no-new */
|
||||
/* global Foo */
|
||||
|
||||
import Bar from './bar';
|
||||
import Bar from './bar';
|
||||
```
|
||||
|
||||
1. **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead.
|
||||
|
@ -73,23 +73,23 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
|
|||
1. When declaring multiple globals, always use one `/* global [name] */` line per variable.
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
/* globals Flash, Cookies, jQuery */
|
||||
// bad
|
||||
/* globals Flash, Cookies, jQuery */
|
||||
|
||||
// good
|
||||
/* global Flash */
|
||||
/* global Cookies */
|
||||
/* global jQuery */
|
||||
// good
|
||||
/* global Flash */
|
||||
/* global Cookies */
|
||||
/* global jQuery */
|
||||
```
|
||||
|
||||
1. Use up to 3 parameters for a function or class. If you need more accept an Object instead.
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
fn(p1, p2, p3, p4) {}
|
||||
// bad
|
||||
fn(p1, p2, p3, p4) {}
|
||||
|
||||
// good
|
||||
fn(options) {}
|
||||
// good
|
||||
fn(options) {}
|
||||
```
|
||||
|
||||
#### Modules, Imports, and Exports
|
||||
|
@ -97,32 +97,32 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
|
|||
1. Use ES module syntax to import modules
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
const SomeClass = require('some_class');
|
||||
// bad
|
||||
const SomeClass = require('some_class');
|
||||
|
||||
// good
|
||||
import SomeClass from 'some_class';
|
||||
// good
|
||||
import SomeClass from 'some_class';
|
||||
|
||||
// bad
|
||||
module.exports = SomeClass;
|
||||
// bad
|
||||
module.exports = SomeClass;
|
||||
|
||||
// good
|
||||
export default SomeClass;
|
||||
// good
|
||||
export default SomeClass;
|
||||
```
|
||||
|
||||
Import statements are following usual naming guidelines, for example object literals use camel case:
|
||||
|
||||
```javascript
|
||||
// some_object file
|
||||
export default {
|
||||
key: 'value',
|
||||
};
|
||||
// some_object file
|
||||
export default {
|
||||
key: 'value',
|
||||
};
|
||||
|
||||
// bad
|
||||
import ObjectLiteral from 'some_object';
|
||||
// bad
|
||||
import ObjectLiteral from 'some_object';
|
||||
|
||||
// good
|
||||
import objectLiteral from 'some_object';
|
||||
// good
|
||||
import objectLiteral from 'some_object';
|
||||
```
|
||||
|
||||
1. Relative paths: when importing a module in the same directory, a child
|
||||
|
@ -171,22 +171,22 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
|
|||
1. Avoid adding to the global namespace.
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
window.MyClass = class { /* ... */ };
|
||||
// bad
|
||||
window.MyClass = class { /* ... */ };
|
||||
|
||||
// good
|
||||
export default class MyClass { /* ... */ }
|
||||
// good
|
||||
export default class MyClass { /* ... */ }
|
||||
```
|
||||
|
||||
1. Side effects are forbidden in any script which contains export
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
export default class MyClass { /* ... */ }
|
||||
// bad
|
||||
export default class MyClass { /* ... */ }
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
new MyClass();
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
new MyClass();
|
||||
}
|
||||
```
|
||||
|
||||
#### Data Mutation and Pure functions
|
||||
|
@ -257,17 +257,17 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
|
|||
`.reduce` or `.filter`
|
||||
|
||||
```javascript
|
||||
const users = [ { name: 'Foo' }, { name: 'Bar' } ];
|
||||
const users = [ { name: 'Foo' }, { name: 'Bar' } ];
|
||||
|
||||
// bad
|
||||
users.forEach((user, index) => {
|
||||
user.id = index;
|
||||
});
|
||||
// bad
|
||||
users.forEach((user, index) => {
|
||||
user.id = index;
|
||||
});
|
||||
|
||||
// good
|
||||
const usersWithId = users.map((user, index) => {
|
||||
return Object.assign({}, user, { id: index });
|
||||
});
|
||||
// good
|
||||
const usersWithId = users.map((user, index) => {
|
||||
return Object.assign({}, user, { id: index });
|
||||
});
|
||||
```
|
||||
|
||||
#### Parse Strings into Numbers
|
||||
|
@ -275,14 +275,14 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
|
|||
1. `parseInt()` is preferable over `Number()` or `+`
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
+'10' // 10
|
||||
// bad
|
||||
+'10' // 10
|
||||
|
||||
// good
|
||||
Number('10') // 10
|
||||
// good
|
||||
Number('10') // 10
|
||||
|
||||
// better
|
||||
parseInt('10', 10);
|
||||
// better
|
||||
parseInt('10', 10);
|
||||
```
|
||||
|
||||
#### CSS classes used for JavaScript
|
||||
|
@ -290,15 +290,15 @@ See [our current .eslintrc](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/
|
|||
1. If the class is being used in Javascript it needs to be prepend with `js-`
|
||||
|
||||
```html
|
||||
// bad
|
||||
<button class="add-user">
|
||||
Add User
|
||||
</button>
|
||||
// bad
|
||||
<button class="add-user">
|
||||
Add User
|
||||
</button>
|
||||
|
||||
// good
|
||||
<button class="js-add-user">
|
||||
Add User
|
||||
</button>
|
||||
// good
|
||||
<button class="js-add-user">
|
||||
Add User
|
||||
</button>
|
||||
```
|
||||
|
||||
### Vue.js
|
||||
|
@ -315,41 +315,41 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
|
|||
1. Use a function in the bundle file to instantiate the Vue component:
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
class {
|
||||
init() {
|
||||
new Component({})
|
||||
}
|
||||
// bad
|
||||
class {
|
||||
init() {
|
||||
new Component({})
|
||||
}
|
||||
}
|
||||
|
||||
// good
|
||||
document.addEventListener('DOMContentLoaded', () => new Vue({
|
||||
el: '#element',
|
||||
components: {
|
||||
componentName
|
||||
},
|
||||
render: createElement => createElement('component-name'),
|
||||
}));
|
||||
// good
|
||||
document.addEventListener('DOMContentLoaded', () => new Vue({
|
||||
el: '#element',
|
||||
components: {
|
||||
componentName
|
||||
},
|
||||
render: createElement => createElement('component-name'),
|
||||
}));
|
||||
```
|
||||
|
||||
1. Do not use a singleton for the service or the store
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
class Store {
|
||||
constructor() {
|
||||
if (!this.prototype.singleton) {
|
||||
// do something
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// good
|
||||
class Store {
|
||||
constructor() {
|
||||
// bad
|
||||
class Store {
|
||||
constructor() {
|
||||
if (!this.prototype.singleton) {
|
||||
// do something
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// good
|
||||
class Store {
|
||||
constructor() {
|
||||
// do something
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. Use `.vue` for Vue templates. Do not use `%template` in HAML.
|
||||
|
@ -360,36 +360,36 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
|
|||
1. **Reference Naming**: Use PascalCase for their instances:
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
import cardBoard from 'cardBoard.vue'
|
||||
// bad
|
||||
import cardBoard from 'cardBoard.vue'
|
||||
|
||||
components: {
|
||||
cardBoard,
|
||||
};
|
||||
components: {
|
||||
cardBoard,
|
||||
};
|
||||
|
||||
// good
|
||||
import CardBoard from 'cardBoard.vue'
|
||||
// good
|
||||
import CardBoard from 'cardBoard.vue'
|
||||
|
||||
components: {
|
||||
CardBoard,
|
||||
};
|
||||
components: {
|
||||
CardBoard,
|
||||
};
|
||||
```
|
||||
|
||||
1. **Props Naming:** Avoid using DOM component prop names.
|
||||
1. **Props Naming:** Use kebab-case instead of camelCase to provide props in templates.
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
<component class="btn">
|
||||
// bad
|
||||
<component class="btn">
|
||||
|
||||
// good
|
||||
<component css-class="btn">
|
||||
// good
|
||||
<component css-class="btn">
|
||||
|
||||
// bad
|
||||
<component myProp="prop" />
|
||||
// bad
|
||||
<component myProp="prop" />
|
||||
|
||||
// good
|
||||
<component my-prop="prop" />
|
||||
// good
|
||||
<component my-prop="prop" />
|
||||
```
|
||||
|
||||
[#34371]: https://gitlab.com/gitlab-org/gitlab-ce/issues/34371
|
||||
|
@ -401,37 +401,37 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
|
|||
1. With more than one attribute, all attributes should be on a new line:
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
<component v-if="bar"
|
||||
param="baz" />
|
||||
// bad
|
||||
<component v-if="bar"
|
||||
param="baz" />
|
||||
|
||||
<button class="btn">Click me</button>
|
||||
<button class="btn">Click me</button>
|
||||
|
||||
// good
|
||||
<component
|
||||
v-if="bar"
|
||||
param="baz"
|
||||
/>
|
||||
// good
|
||||
<component
|
||||
v-if="bar"
|
||||
param="baz"
|
||||
/>
|
||||
|
||||
<button class="btn">
|
||||
Click me
|
||||
</button>
|
||||
<button class="btn">
|
||||
Click me
|
||||
</button>
|
||||
```
|
||||
|
||||
1. The tag can be inline if there is only one attribute:
|
||||
|
||||
```javascript
|
||||
// good
|
||||
<component bar="bar" />
|
||||
// good
|
||||
<component bar="bar" />
|
||||
|
||||
// good
|
||||
<component
|
||||
bar="bar"
|
||||
/>
|
||||
// good
|
||||
<component
|
||||
bar="bar"
|
||||
/>
|
||||
|
||||
// bad
|
||||
<component
|
||||
bar="bar" />
|
||||
// bad
|
||||
<component
|
||||
bar="bar" />
|
||||
```
|
||||
|
||||
#### Quotes
|
||||
|
@ -439,15 +439,15 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
|
|||
1. Always use double quotes `"` inside templates and single quotes `'` for all other JS.
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
template: `
|
||||
<button :class='style'>Button</button>
|
||||
`
|
||||
// bad
|
||||
template: `
|
||||
<button :class='style'>Button</button>
|
||||
`
|
||||
|
||||
// good
|
||||
template: `
|
||||
<button :class="style">Button</button>
|
||||
`
|
||||
// good
|
||||
template: `
|
||||
<button :class="style">Button</button>
|
||||
`
|
||||
```
|
||||
|
||||
#### Props
|
||||
|
@ -455,37 +455,37 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
|
|||
1. Props should be declared as an object
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
props: ['foo']
|
||||
// bad
|
||||
props: ['foo']
|
||||
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'bar'
|
||||
}
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'bar'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. Required key should always be provided when declaring a prop
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
}
|
||||
// bad
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
}
|
||||
}
|
||||
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'bar'
|
||||
}
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'bar'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. Default key should be provided if the prop is not required.
|
||||
|
@ -493,30 +493,30 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
|
|||
On those a default key should not be provided.
|
||||
|
||||
```javascript
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: false,
|
||||
}
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: false,
|
||||
}
|
||||
}
|
||||
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'bar'
|
||||
}
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'bar'
|
||||
}
|
||||
}
|
||||
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
// good
|
||||
props: {
|
||||
foo: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Data
|
||||
|
@ -524,17 +524,17 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
|
|||
1. `data` method should always be a function
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
data: {
|
||||
foo: 'foo'
|
||||
}
|
||||
// bad
|
||||
data: {
|
||||
foo: 'foo'
|
||||
}
|
||||
|
||||
// good
|
||||
data() {
|
||||
return {
|
||||
foo: 'foo'
|
||||
};
|
||||
}
|
||||
// good
|
||||
data() {
|
||||
return {
|
||||
foo: 'foo'
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### Directives
|
||||
|
@ -542,31 +542,31 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
|
|||
1. Shorthand `@` is preferable over `v-on`
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
<component v-on:click="eventHandler"/>
|
||||
// bad
|
||||
<component v-on:click="eventHandler"/>
|
||||
|
||||
// good
|
||||
<component @click="eventHandler"/>
|
||||
// good
|
||||
<component @click="eventHandler"/>
|
||||
```
|
||||
|
||||
1. Shorthand `:` is preferable over `v-bind`
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
<component v-bind:class="btn"/>
|
||||
// bad
|
||||
<component v-bind:class="btn"/>
|
||||
|
||||
// good
|
||||
<component :class="btn"/>
|
||||
// good
|
||||
<component :class="btn"/>
|
||||
```
|
||||
|
||||
1. Shorthand `#` is preferable over `v-slot`
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
<template v-slot:header></template>
|
||||
// bad
|
||||
<template v-slot:header></template>
|
||||
|
||||
// good
|
||||
<template #header></template>
|
||||
// good
|
||||
<template #header></template>
|
||||
```
|
||||
|
||||
#### Closing tags
|
||||
|
@ -574,11 +574,11 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
|
|||
1. Prefer self closing component tags
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
<component></component>
|
||||
// bad
|
||||
<component></component>
|
||||
|
||||
// good
|
||||
<component />
|
||||
// good
|
||||
<component />
|
||||
```
|
||||
|
||||
#### Ordering
|
||||
|
@ -610,48 +610,48 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
|
|||
1. If the elements of the array being iterated have an unique `id` it is advised to use it:
|
||||
|
||||
```html
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
>
|
||||
<!-- content -->
|
||||
</div>
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
>
|
||||
<!-- content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
1. When the elements being iterated don't have a unique id, you can use the array index as the `:key` attribute
|
||||
|
||||
```html
|
||||
<div
|
||||
v-for="(item, index) in items"
|
||||
:key="index"
|
||||
>
|
||||
<!-- content -->
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in items"
|
||||
:key="index"
|
||||
>
|
||||
<!-- content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
1. When using `v-for` with `template` and there is more than one child element, the `:key` values must be unique. It's advised to use `kebab-case` namespaces.
|
||||
|
||||
```html
|
||||
<template v-for="(item, index) in items">
|
||||
<span :key="`span-${index}`"></span>
|
||||
<button :key="`button-${index}`"></button>
|
||||
</template>
|
||||
<template v-for="(item, index) in items">
|
||||
<span :key="`span-${index}`"></span>
|
||||
<button :key="`button-${index}`"></button>
|
||||
</template>
|
||||
```
|
||||
|
||||
1. When dealing with nested `v-for` use the same guidelines as above.
|
||||
|
||||
```html
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
>
|
||||
<span
|
||||
v-for="element in array"
|
||||
:key="element.id"
|
||||
>
|
||||
<span
|
||||
v-for="element in array"
|
||||
:key="element.id"
|
||||
>
|
||||
<!-- content -->
|
||||
</span>
|
||||
</div>
|
||||
<!-- content -->
|
||||
</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
Useful links:
|
||||
|
@ -664,19 +664,19 @@ Useful links:
|
|||
1. Tooltips: Do not rely on `has-tooltip` class name for Vue components
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
<span
|
||||
class="has-tooltip"
|
||||
title="Some tooltip text">
|
||||
Text
|
||||
</span>
|
||||
// bad
|
||||
<span
|
||||
class="has-tooltip"
|
||||
title="Some tooltip text">
|
||||
Text
|
||||
</span>
|
||||
|
||||
// good
|
||||
<span
|
||||
v-tooltip
|
||||
title="Some tooltip text">
|
||||
Text
|
||||
</span>
|
||||
// good
|
||||
<span
|
||||
v-tooltip
|
||||
title="Some tooltip text">
|
||||
Text
|
||||
</span>
|
||||
```
|
||||
|
||||
1. Tooltips: When using a tooltip, include the tooltip directive, `./app/assets/javascripts/vue_shared/directives/tooltip.js`
|
||||
|
@ -684,13 +684,13 @@ Useful links:
|
|||
1. Don't change `data-original-title`.
|
||||
|
||||
```javascript
|
||||
// bad
|
||||
<span data-original-title="tooltip text">Foo</span>
|
||||
// bad
|
||||
<span data-original-title="tooltip text">Foo</span>
|
||||
|
||||
// good
|
||||
<span title="tooltip text">Foo</span>
|
||||
// good
|
||||
<span title="tooltip text">Foo</span>
|
||||
|
||||
$('span').tooltip('_fixTitle');
|
||||
$('span').tooltip('_fixTitle');
|
||||
```
|
||||
|
||||
### The Javascript/Vue Accord
|
||||
|
|
|
@ -313,7 +313,7 @@ export default {
|
|||
|
||||
1. Do not call a mutation directly. Always use an action to commit a mutation. Doing so will keep consistency throughout the application. From Vuex docs:
|
||||
|
||||
> why don't we just call store.commit('action') directly? Well, remember that mutations must be synchronous? Actions aren't. We can perform asynchronous operations inside an action.
|
||||
> Why don't we just call store.commit('action') directly? Well, remember that mutations must be synchronous? Actions aren't. We can perform asynchronous operations inside an action.
|
||||
|
||||
```javascript
|
||||
// component.vue
|
||||
|
|
|
@ -9,8 +9,8 @@ when making _backend_ changes that might involve multiple features or [component
|
|||
|
||||
## Uploads
|
||||
|
||||
GitLab supports uploads to [object storage]. That means every feature and
|
||||
change that affects uploads should also be tested against [object storage],
|
||||
GitLab supports uploads to [object storage]. That means every feature and
|
||||
change that affects uploads should also be tested against [object storage],
|
||||
which is _not_ enabled by default in [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit).
|
||||
|
||||
When working on a related feature, make sure to enable and test it
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# Dirty Submit
|
||||
|
||||
> [Introduced][ce-21115] in GitLab 11.3.
|
||||
> [dirty_submit][dirty-submit]
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21115) in GitLab 11.3.
|
||||
|
||||
## Summary
|
||||
|
||||
|
@ -9,6 +8,9 @@ Prevent submitting forms with no changes.
|
|||
|
||||
Currently handles `input`, `textarea` and `select` elements.
|
||||
|
||||
Also, see [the code](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/dirty_submit/)
|
||||
within the GitLab project.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
|
@ -18,6 +20,3 @@ new DirtySubmitForm(document.querySelector('form'));
|
|||
// or
|
||||
new DirtySubmitForm(document.querySelectorAll('form'));
|
||||
```
|
||||
|
||||
[ce-21115]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21115
|
||||
[dirty-submit]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/dirty_submit/
|
|
@ -192,4 +192,4 @@ rules only if you are invoking/instantiating existing code modules.
|
|||
- [class-method-use-this](http://eslint.org/docs/rules/class-methods-use-this)
|
||||
|
||||
> Note: Disable these rules on a per line basis. This makes it easier to refactor
|
||||
in the future. E.g. use `eslint-disable-next-line` or `eslint-disable-line`.
|
||||
> in the future. E.g. use `eslint-disable-next-line` or `eslint-disable-line`.
|
||||
|
|
|
@ -24,7 +24,8 @@ Having said all of the above, we recommend staying away from shell scripts
|
|||
as much as possible. A language like Ruby or Python (if required for
|
||||
consistency with codebases that we leverage) is almost always a better choice.
|
||||
The high-level interpreted languages have more readable syntax, offer much more
|
||||
mature capabilities for unit-testing, linting, and error reporting.
|
||||
mature capabilities for unit-testing, linting, and error reporting.
|
||||
|
||||
Use shell scripts only if there's a strong restriction on project's
|
||||
dependencies size or any other requirements that are more important
|
||||
in a particular case.
|
||||
|
@ -48,12 +49,12 @@ that is:
|
|||
|
||||
This section describes the tools that should be made a mandatory part of
|
||||
a project's CI pipeline if it contains shell scripts. These tools
|
||||
automate shell code formatting, checking for errors or vulnerabilities, etc.
|
||||
automate shell code formatting, checking for errors or vulnerabilities, etc.
|
||||
|
||||
### Linting
|
||||
|
||||
We're using the [ShellCheck](https://www.shellcheck.net/) utility in its default configuration to lint our
|
||||
shell scripts.
|
||||
shell scripts.
|
||||
|
||||
All projects with shell scripts should use this GitLab CI/CD job:
|
||||
|
||||
|
@ -98,7 +99,7 @@ NOTE: **Note:**
|
|||
This is a work in progress.
|
||||
|
||||
It is an [ongoing effort](https://gitlab.com/gitlab-org/gitlab-ce/issues/64016) to evaluate different tools for the
|
||||
automated testing of shell scripts (like [BATS](https://github.com/sstephenson/bats)).
|
||||
automated testing of shell scripts (like [BATS](https://github.com/sstephenson/bats)).
|
||||
|
||||
## Code Review
|
||||
|
||||
|
|
|
@ -255,8 +255,8 @@ that a machine will hit the "too many mount points" problem in the future.
|
|||
thousands of unused Docker images.**
|
||||
|
||||
> We have to start somewhere and improve later. Also, we're using the
|
||||
CNG-mirror project to store these Docker images so that we can just wipe out
|
||||
the registry at some point, and use a new fresh, empty one.
|
||||
> CNG-mirror project to store these Docker images so that we can just wipe out
|
||||
> the registry at some point, and use a new fresh, empty one.
|
||||
|
||||
**How do we secure this from abuse? Apps are open to the world so we need to
|
||||
find a way to limit it to only us.**
|
||||
|
|
|
@ -46,8 +46,7 @@ In `config/gitlab.yml`:
|
|||
|
||||
## Storing LFS objects in remote object storage
|
||||
|
||||
> [Introduced][ee-2760] in [GitLab Premium][eep] 10.0. Brought to GitLab Core
|
||||
in 10.7.
|
||||
> [Introduced][ee-2760] in [GitLab Premium][eep] 10.0. Brought to GitLab Core in 10.7.
|
||||
|
||||
It is possible to store LFS objects in remote object storage which allows you
|
||||
to offload local hard disk R/W operations, and free up disk space significantly.
|
||||
|
@ -91,7 +90,7 @@ Here is a configuration example with S3.
|
|||
| `aws_access_key_id` | AWS credentials, or compatible | `ABC123DEF456` |
|
||||
| `aws_secret_access_key` | AWS credentials, or compatible | `ABC123DEF456ABC123DEF456ABC123DEF456` |
|
||||
| `aws_signature_version` | AWS signature version to use. 2 or 4 are valid options. Digital Ocean Spaces and other providers may need 2. | 4 |
|
||||
| `enable_signature_v4_streaming` | Set to true to enable HTTP chunked transfers with AWS v4 signatures (https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html). Oracle Cloud S3 needs this to be false | true
|
||||
| `enable_signature_v4_streaming` | Set to true to enable HTTP chunked transfers with [AWS v4 signatures](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html). Oracle Cloud S3 needs this to be false | true |
|
||||
| `region` | AWS region | us-east-1 |
|
||||
| `host` | S3 compatible host for when not using AWS, e.g. `localhost` or `storage.example.com` | s3.amazonaws.com |
|
||||
| `endpoint` | Can be used when configuring an S3 compatible service such as [Minio](https://www.minio.io), by entering a URL such as `http://127.0.0.1:9000` | (optional) |
|
||||
|
@ -107,7 +106,9 @@ Here is a configuration example with GCS.
|
|||
| `google_client_email` | The email address of the service account | `foo@gcp-project-12345.iam.gserviceaccount.com` |
|
||||
| `google_json_key_location` | The json key path | `/path/to/gcp-project-12345-abcde.json` |
|
||||
|
||||
_NOTE: The service account must have permission to access the bucket. [See more](https://cloud.google.com/storage/docs/authentication)_
|
||||
NOTE: **Note:**
|
||||
The service account must have permission to access the bucket.
|
||||
[See more](https://cloud.google.com/storage/docs/authentication)
|
||||
|
||||
Here is a configuration example with Rackspace Cloud Files.
|
||||
|
||||
|
@ -119,7 +120,13 @@ Here is a configuration example with Rackspace Cloud Files.
|
|||
| `rackspace_region` | The Rackspace storage region to use, a three letter code from the [list of service access endpoints](https://developer.rackspace.com/docs/cloud-files/v1/general-api-info/service-access/) | `iad` |
|
||||
| `rackspace_temp_url_key` | The private key you have set in the Rackspace API for temporary URLs. Read more [here](https://developer.rackspace.com/docs/cloud-files/v1/use-cases/public-access-to-your-cloud-files-account/#tempurl) | `ABC123DEF456ABC123DEF456ABC123DE` |
|
||||
|
||||
_NOTES: Regardless of whether the container has public access enabled or disabled, Fog will use the TempURL method to grant access to LFS objects. If you see errors in logs referencing instantiating storage with a temp-url-key, ensure that you have set they key properly on the Rackspace API and in gitlab.rb. You can verify the value of the key Rackspace has set by sending a GET request with token header to the service access endpoint URL and comparing the output of the returned headers._
|
||||
NOTE: **Note:**
|
||||
Regardless of whether the container has public access enabled or disabled, Fog will
|
||||
use the TempURL method to grant access to LFS objects. If you see errors in logs referencing
|
||||
instantiating storage with a temp-url-key, ensure that you have set they key properly
|
||||
on the Rackspace API and in gitlab.rb. You can verify the value of the key Rackspace
|
||||
has set by sending a GET request with token header to the service access endpoint URL
|
||||
and comparing the output of the returned headers.
|
||||
|
||||
### Manual uploading to an object storage
|
||||
|
||||
|
@ -167,13 +174,13 @@ On Omnibus installations, the settings are prefixed by `lfs_object_store_`:
|
|||
1. Save the file and [reconfigure GitLab]s for the changes to take effect.
|
||||
1. Migrate any existing local LFS objects to the object storage:
|
||||
|
||||
```bash
|
||||
gitlab-rake gitlab:lfs:migrate
|
||||
```
|
||||
```bash
|
||||
gitlab-rake gitlab:lfs:migrate
|
||||
```
|
||||
|
||||
This will migrate existing LFS objects to object storage. New LFS objects
|
||||
will be forwarded to object storage unless
|
||||
`gitlab_rails['lfs_object_store_background_upload']` is set to false.
|
||||
This will migrate existing LFS objects to object storage. New LFS objects
|
||||
will be forwarded to object storage unless
|
||||
`gitlab_rails['lfs_object_store_background_upload']` is set to false.
|
||||
|
||||
### S3 for installations from source
|
||||
|
||||
|
@ -203,13 +210,13 @@ For source installations the settings are nested under `lfs:` and then
|
|||
1. Save the file and [restart GitLab][] for the changes to take effect.
|
||||
1. Migrate any existing local LFS objects to the object storage:
|
||||
|
||||
```bash
|
||||
sudo -u git -H bundle exec rake gitlab:lfs:migrate RAILS_ENV=production
|
||||
```
|
||||
```bash
|
||||
sudo -u git -H bundle exec rake gitlab:lfs:migrate RAILS_ENV=production
|
||||
```
|
||||
|
||||
This will migrate existing LFS objects to object storage. New LFS objects
|
||||
will be forwarded to object storage unless `background_upload` is set to
|
||||
false.
|
||||
This will migrate existing LFS objects to object storage. New LFS objects
|
||||
will be forwarded to object storage unless `background_upload` is set to
|
||||
false.
|
||||
|
||||
## Storage statistics
|
||||
|
||||
|
|
|
@ -35,9 +35,10 @@ Documentation for GitLab instance administrators is under [LFS administration do
|
|||
- Git LFS always assumes HTTPS so if you have GitLab server on HTTP you will have
|
||||
to add the URL to Git config manually (see [troubleshooting](#troubleshooting))
|
||||
|
||||
>**Note**: With 8.12 GitLab added LFS support to SSH. The Git LFS communication
|
||||
still goes over HTTP, but now the SSH client passes the correct credentials
|
||||
to the Git LFS client, so no action is required by the user.
|
||||
NOTE: **Note:**
|
||||
With 8.12 GitLab added LFS support to SSH. The Git LFS communication
|
||||
still goes over HTTP, but now the SSH client passes the correct credentials
|
||||
to the Git LFS client, so no action is required by the user.
|
||||
|
||||
## Using Git LFS
|
||||
|
||||
|
@ -61,12 +62,13 @@ git commit -am "Added Debian iso" # commit the file meta data
|
|||
git push origin master # sync the git repo and large file to the GitLab server
|
||||
```
|
||||
|
||||
> **Note**: Make sure that `.gitattributes` is tracked by git. Otherwise Git
|
||||
> LFS will not be working properly for people cloning the project.
|
||||
>
|
||||
> ```bash
|
||||
> git add .gitattributes
|
||||
> ```
|
||||
NOTE: **Note:**
|
||||
**Make sure** that `.gitattributes` is tracked by Git. Otherwise Git
|
||||
LFS will not be working properly for people cloning the project.
|
||||
|
||||
```bash
|
||||
git add .gitattributes
|
||||
```
|
||||
|
||||
Cloning the repository works the same as before. Git automatically detects the
|
||||
LFS-tracked files and clones them via HTTP. If you performed the git clone
|
||||
|
@ -216,9 +218,10 @@ git config --add lfs.url "http://gitlab.example.com/group/project.git/info/lfs"
|
|||
|
||||
### Credentials are always required when pushing an object
|
||||
|
||||
>**Note**: With 8.12 GitLab added LFS support to SSH. The Git LFS communication
|
||||
still goes over HTTP, but now the SSH client passes the correct credentials
|
||||
to the Git LFS client, so no action is required by the user.
|
||||
NOTE: **Note:**
|
||||
With 8.12 GitLab added LFS support to SSH. The Git LFS communication
|
||||
still goes over HTTP, but now the SSH client passes the correct credentials
|
||||
to the Git LFS client, so no action is required by the user.
|
||||
|
||||
Given that Git LFS uses HTTP Basic Authentication to authenticate the user pushing
|
||||
the LFS object on every push for every object, user HTTPS credentials are required.
|
||||
|
|
|
@ -76,7 +76,7 @@ Here you'll find a guide on
|
|||
Since Annex files are stored as objects with symlinks and cannot be directly
|
||||
modified, we need to first remove those symlinks.
|
||||
|
||||
>**Note:**
|
||||
NOTE: **Note:**
|
||||
Make sure the you read about the [`direct` mode][annex-direct] as it contains
|
||||
useful information that may fit in your use case. Note that `annex direct` is
|
||||
deprecated in Git Annex version 6, so you may need to upgrade your repository
|
||||
|
|
|
@ -37,8 +37,7 @@ The following are some possible use cases for repository mirroring:
|
|||
|
||||
## Pushing to a remote repository **(CORE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/249) in GitLab Enterprise
|
||||
> Edition 8.7. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/249) in GitLab Enterprise Edition 8.7. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8.
|
||||
|
||||
For an existing project, you can set up push mirroring as follows:
|
||||
|
||||
|
@ -67,8 +66,7 @@ section.
|
|||
|
||||
### Push only protected branches **(CORE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3350) in
|
||||
> [GitLab Starter](https://about.gitlab.com/pricing/) 10.3. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3350) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8.
|
||||
|
||||
You can choose to only push your protected branches from GitLab to your remote repository.
|
||||
|
||||
|
@ -98,8 +96,7 @@ The repository will push soon. To force a push, click the appropriate button.
|
|||
|
||||
## Pulling from a remote repository **(STARTER)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/51) in GitLab Enterprise Edition 8.2.
|
||||
> [Added Git LFS support](https://gitlab.com/gitlab-org/gitlab-ee/issues/10871) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.11.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/51) in GitLab Enterprise Edition 8.2. [Added Git LFS support](https://gitlab.com/gitlab-org/gitlab-ee/issues/10871) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.11.
|
||||
|
||||
NOTE: **Note:** This feature [is available for free](https://gitlab.com/gitlab-org/gitlab-ee/issues/10361) to
|
||||
GitLab.com users until September 22nd, 2019.
|
||||
|
@ -157,8 +154,7 @@ Repository mirrors are updated as Sidekiq becomes available to process them. If
|
|||
|
||||
### SSH authentication
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2551) for Pull mirroring in [GitLab Starter](https://about.gitlab.com/pricing/) 9.5.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22982) for Push mirroring in [GitLab Core](https://about.gitlab.com/pricing/) 11.6
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2551) for Pull mirroring in [GitLab Starter](https://about.gitlab.com/pricing/) 9.5. [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22982) for Push mirroring in [GitLab Core](https://about.gitlab.com/pricing/) 11.6
|
||||
|
||||
SSH authentication is mutual:
|
||||
|
||||
|
@ -245,8 +241,7 @@ key to keep the mirror running.
|
|||
|
||||
### Overwrite diverged branches **(STARTER)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4559) in
|
||||
> [GitLab Starter](https://about.gitlab.com/pricing/) 10.6.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4559) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.6.
|
||||
|
||||
You can choose to always update your local branches with remote versions, even if they have
|
||||
diverged from the remote.
|
||||
|
@ -258,8 +253,7 @@ To use this option, check the **Overwrite diverged branches** box when creating
|
|||
|
||||
### Only mirror protected branches **(STARTER)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3326) in
|
||||
> [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3326) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
|
||||
|
||||
You can choose to pull mirror only the protected branches from your remote repository to GitLab.
|
||||
Non-protected branches are not mirrored and can diverge.
|
||||
|
@ -268,8 +262,7 @@ To use this option, check the **Only mirror protected branches** box when creati
|
|||
|
||||
### Hard failure **(STARTER)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3117) in
|
||||
> [GitLab Starter](https://about.gitlab.com/pricing/) 10.2.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3117) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.2.
|
||||
|
||||
Once the mirroring process is unsuccessfully retried 14 times in a row, it will get marked as hard
|
||||
failed. This will become visible in either the:
|
||||
|
@ -282,8 +275,7 @@ project mirroring again by [Forcing an update](#forcing-an-update-core).
|
|||
|
||||
### Trigger update using API **(STARTER)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3453) in
|
||||
[GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3453) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
|
||||
|
||||
Pull mirroring uses polling to detect new branches and commits added upstream, often minutes
|
||||
afterwards. If you notify GitLab by [API](../api/projects.md#start-the-pull-mirroring-process-for-a-project-starter),
|
||||
|
@ -325,9 +317,10 @@ protected branches.
|
|||
|
||||
### Preventing conflicts using a `pre-receive` hook
|
||||
|
||||
> **Warning:** The solution proposed will negatively impact the performance of
|
||||
> Git push operations because they will be proxied to the upstream Git
|
||||
> repository.
|
||||
CAUTION: **Warning:**
|
||||
The solution proposed will negatively impact the performance of
|
||||
Git push operations because they will be proxied to the upstream Git
|
||||
repository.
|
||||
|
||||
A server-side `pre-receive` hook can be used to prevent the race condition
|
||||
described above by only accepting the push after first pushing the commit to
|
||||
|
|
|
@ -35,8 +35,8 @@ A To Do displays on your To-Do List when:
|
|||
- You are `@mentioned` in a comment on a commit
|
||||
- A job in the CI pipeline running for your merge request failed, but this
|
||||
job is not allowed to fail
|
||||
- An open merge request becomes unmergeable due to conflict, and you are either:
|
||||
- The author
|
||||
- An open merge request becomes unmergeable due to conflict, and you are either:
|
||||
- The author
|
||||
- Have set it to automatically merge once the pipeline succeeds
|
||||
|
||||
To-do triggers are not affected by [GitLab Notification Email settings](notifications.md).
|
||||
|
|
Loading…
Reference in a new issue