summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/build_test_package.md35
-rw-r--r--doc/development/code_review.md41
-rw-r--r--doc/development/fe_guide/style_guide_js.md602
-rw-r--r--doc/development/fe_guide/vue.md15
-rw-r--r--doc/update/9.0-to-9.1.md1
-rw-r--r--doc/update/patch_versions.md1
-rw-r--r--doc/update/upgrader.md2
8 files changed, 410 insertions, 288 deletions
diff --git a/doc/development/README.md b/doc/development/README.md
index 77bb0263374..d04380e5b33 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -41,6 +41,7 @@
- [Shell commands](shell_commands.md) in the GitLab codebase
- [Sidekiq debugging](sidekiq_debugging.md)
- [Object state models](object_state_models.md)
+- [Building a package for testing purposes](build_test_package.md)
## Databases
diff --git a/doc/development/build_test_package.md b/doc/development/build_test_package.md
new file mode 100644
index 00000000000..2bc1a700844
--- /dev/null
+++ b/doc/development/build_test_package.md
@@ -0,0 +1,35 @@
+# Building a package for testing
+
+While developing a new feature or modifying an existing one, it is helpful if an
+installable package (or a docker image) containing those changes is available
+for testing. For this very purpose, a manual job is provided in the GitLab CI/CD
+pipeline that can be used to trigger a pipeline in the omnibus-gitlab repository
+that will create
+1. A deb package for Ubuntu 16.04, available as a build artifact, and
+2. A docker image, which is pushed to [Omnibus GitLab's container
+registry](https://gitlab.com/gitlab-org/omnibus-gitlab/container_registry)
+(images titled `gitlab-ce` and `gitlab-ee` respectively and image tag is the
+commit which triggered the pipeline).
+
+When you push a commit to either the gitlab-ce or gitlab-ee project, the
+pipeline for that commit will have a `build-package` manual action you can
+trigger.
+
+## Specifying versions of components
+
+If you want to create a package from a specific branch, commit or tag of any of
+the GitLab components (like GitLab Workhorse, Gitaly, GitLab Pages, etc.), you
+can specify the branch name, commit sha or tag in the component's respective
+`*_VERSION` file. For example, if you want to build a package that uses the
+branch `0-1-stable`, modify the content of `GITALY_SERVER_VERSION` to
+`0-1-stable` and push the commit. This will create a manual job that can be
+used to trigger the build.
+
+## Specifying the branch in omnibus-gitlab repository
+
+In scenarios where a configuration change is to be introduced and omnibus-gitlab
+repository already has the necessary changes in a specific branch, you can build
+a package against that branch through an environment variable named
+`OMNIBUS_BRANCH`. To do this, specify that environment variable with the name of
+the branch as value in `.gitlab-ci.yml` and push a commit. This will create a
+manual job that can be used to trigger the build.
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 819578404b6..be3dd1e2cc6 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -1,5 +1,25 @@
# Code Review Guidelines
+## Getting your merge request reviewed, approved, and merged
+
+There are a few rules to get your merge request accepted:
+
+1. Your merge request should only be **merged by a [maintainer][team]**.
+ 1. If your merge request includes only backend changes [^1], it must be
+ **approved by a [backend maintainer][team]**.
+ 1. If your merge request includes only frontend changes [^1], it must be
+ **approved by a [frontend maintainer][team]**.
+ 1. If your merge request includes frontend and backend changes [^1], it must
+ be **approved by a [frontend and a backend maintainer][team]**.
+1. To lower the amount of merge requests maintainers need to review, you can
+ ask or assign any [reviewers][team] for a first review.
+ 1. If you need some guidance (e.g. it's your first merge request), feel free
+ to ask one of the [Merge request coaches][team].
+ 1. The reviewer will assign the merge request to a maintainer once the
+ reviewer is satisfied with the state of the merge request.
+
+## Best practices
+
This guide contains advice and best practices for performing code review, and
having your code reviewed.
@@ -12,7 +32,7 @@ of colleagues and contributors. However, the final decision to accept a merge
request is up to one the project's maintainers, denoted on the
[team page](https://about.gitlab.com/team).
-## Everyone
+### Everyone
- Accept that many programming decisions are opinions. Discuss tradeoffs, which
you prefer, and reach a resolution quickly.
@@ -31,8 +51,11 @@ request is up to one the project's maintainers, denoted on the
- Consider one-on-one chats or video calls if there are too many "I didn't
understand" or "Alternative solution:" comments. Post a follow-up comment
summarizing one-on-one discussion.
+- If you ask a question to a specific person, always start the comment by
+ mentioning them; this will ensure they see it if their notification level is
+ set to "mentioned" and other people will understand they don't have to respond.
-## Having your code reviewed
+### Having your code reviewed
Please keep in mind that code review is a process that can take multiple
iterations, and reviewers may spot things later that they may not have seen the
@@ -50,11 +73,12 @@ first time.
- Extract unrelated changes and refactorings into future merge requests/issues.
- Seek to understand the reviewer's perspective.
- Try to respond to every comment.
+- Let the reviewer select the "Resolve discussion" buttons.
- Push commits based on earlier rounds of feedback as isolated commits to the
branch. Do not squash until the branch is ready to merge. Reviewers should be
able to read individual updates based on their earlier feedback.
-## Reviewing code
+### Reviewing code
Understand why the change is necessary (fixes a bug, improves the user
experience, refactors the existing code). Then:
@@ -69,12 +93,19 @@ experience, refactors the existing code). Then:
someone else would be confused by it as well.
- After a round of line notes, it can be helpful to post a summary note such as
"LGTM :thumbsup:", or "Just a couple things to address."
+- Assign the merge request to the author if changes are required following your
+ review.
+- Set the milestone before merging a merge request.
- Avoid accepting a merge request before the job succeeds. Of course, "Merge
When Pipeline Succeeds" (MWPS) is fine.
- If you set the MR to "Merge When Pipeline Succeeds", you should take over
subsequent revisions for anything that would be spotted after that.
+- Consider using the [Squash and
+ merge][squash-and-merge] feature when the merge request has a lot of commits.
+
+[squash-and-merge]: https://docs.gitlab.com/ee/user/project/merge_requests/squash_and_merge.html#squash-and-merge
-## The right balance
+### The right balance
One of the most difficult things during code review is finding the right
balance in how deep the reviewer can interfere with the code created by a
@@ -100,7 +131,7 @@ reviewee.
tomorrow. When you are not able to find the right balance, ask other people
about their opinion.
-## Credits
+### Credits
Largely based on the [thoughtbot code review guide].
diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md
index 1d2b0558948..d2d89517241 100644
--- a/doc/development/fe_guide/style_guide_js.md
+++ b/doc/development/fe_guide/style_guide_js.md
@@ -11,207 +11,205 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns.
#### ESlint
-- **Never** disable eslint rules unless you have a good reason. You may see a lot of legacy files with `/* eslint-disable some-rule, some-other-rule */` at the top, but legacy files are a special case. Any time you develop a new feature or refactor an existing one, you should abide by the eslint rules.
-
-- **Never Ever EVER** disable eslint globally for a file
+1. **Never** disable eslint rules unless you have a good reason.
+You may see a lot of legacy files with `/* eslint-disable some-rule, some-other-rule */`
+at the top, but legacy files are a special case. Any time you develop a new feature or
+refactor an existing one, you should abide by the eslint rules.
+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 :)
```
-- If you do need to disable a rule for a single violation, try to do it as locally as possible
-
+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:
+ 1. [no-new][eslint-new]
+ 1. [class-methods-use-this][eslint-this]
-- When they are needed _always_ place ESlint directive comment blocks on the first line of a script, followed by any global declarations, then a blank newline prior to any imports or code.
-
+1. When they are needed _always_ place ESlint directive comment blocks on the first line of a script,
+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';
```
-- **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead.
-
-- When declaring multiple globals, always use one `/* global [name] */` line per variable.
+1. **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead.
+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 */
```
-
-- Use up to 3 parameters for a function or class. If you need more accept an Object instead.
+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
-- Use ES module syntax to import modules
-
+1. Use ES module syntax to import modules
```javascript
- // bad
- require('foo');
+ // bad
+ require('foo');
- // good
- import Foo from 'foo';
+ // good
+ import Foo from 'foo';
- // bad
- module.exports = Foo;
+ // bad
+ module.exports = Foo;
- // good
- export default Foo;
+ // good
+ export default Foo;
```
-- Relative paths
-
- Unless you are writing a test, always reference other scripts using relative paths instead of `~`
+1. Relative paths: Unless you are writing a test, always reference other scripts using
+relative paths instead of `~`
+ * In **app/assets/javascripts**:
- In **app/assets/javascripts**:
- ```javascript
- // bad
- import Foo from '~/foo'
-
- // good
- import Foo from '../foo';
- ```
+ ```javascript
+ // bad
+ import Foo from '~/foo'
- In **spec/javascripts**:
- ```javascript
- // bad
- import Foo from '../../app/assets/javascripts/foo'
+ // good
+ import Foo from '../foo';
+ ```
+ * In **spec/javascripts**:
- // good
- import Foo from '~/foo';
- ```
+ ```javascript
+ // bad
+ import Foo from '../../app/assets/javascripts/foo'
-- Avoid using IIFE. Although we have a lot of examples of files which wrap their contents in IIFEs (immediately-invoked function expressions), this is no longer necessary after the transition from Sprockets to webpack. Do not use them anymore and feel free to remove them when refactoring legacy code.
+ // good
+ import Foo from '~/foo';
+ ```
-- Avoid adding to the global namespace.
+1. Avoid using IIFE. Although we have a lot of examples of files which wrap their
+contents in IIFEs (immediately-invoked function expressions),
+this is no longer necessary after the transition from Sprockets to webpack.
+Do not use them anymore and feel free to remove them when refactoring legacy code.
+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 { /* ... */ }
```
-- Side effects are forbidden in any script which contains exports
-
+1. Side effects are forbidden in any script which contains exports
```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
-- Strive to write many small pure functions, and minimize where mutations occur.
-
+1. Strive to write many small pure functions, and minimize where mutations occur.
```javascript
- // bad
- const values = {foo: 1};
+ // bad
+ const values = {foo: 1};
- function impureFunction(items) {
- const bar = 1;
+ function impureFunction(items) {
+ const bar = 1;
- items.foo = items.a * bar + 2;
+ items.foo = items.a * bar + 2;
- return items.a;
- }
+ return items.a;
+ }
- const c = impureFunction(values);
+ const c = impureFunction(values);
- // good
- var values = {foo: 1};
+ // good
+ var values = {foo: 1};
- function pureFunction (foo) {
- var bar = 1;
+ function pureFunction (foo) {
+ var bar = 1;
- foo = foo * bar + 2;
+ foo = foo * bar + 2;
- return foo;
- }
+ return foo;
+ }
- var c = pureFunction(values.foo);
+ var c = pureFunction(values.foo);
```
-- Avoid constructors with side-effects
+1. Avoid constructors with side-effects
-- Prefer `.map`, `.reduce` or `.filter` over `.forEach`
+1. Prefer `.map`, `.reduce` or `.filter` over `.forEach`
A forEach will cause side effects, it will be mutating the array being iterated. Prefer using `.map`,
`.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
-- `parseInt()` is preferable over `Number()` or `+`
-
+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
-- If the class is being used in Javascript it needs to be prepend with `js-`
+1. If the class is being used in Javascript it needs to be prepend with `js-`
```html
// bad
<button class="add-user">
@@ -226,234 +224,270 @@ A forEach will cause side effects, it will be mutating the array being iterated.
### Vue.js
-
#### Basic Rules
-- Only include one Vue.js component per file.
-- Export components as plain objects:
-
+1. The service has it's own file
+1. The store has it's own file
+1. Use a function in the bundle file to instantiate the Vue component:
```javascript
- export default {
- template: `<h1>I'm a component</h1>
- }
- ```
+ // bad
+ class {
+ init() {
+ new Component({})
+ }
+ }
-#### Naming
-- **Extensions**: Use `.vue` extension for Vue components.
-- **Reference Naming**: Use PascalCase for Vue components and camelCase for their instances:
+ // good
+ document.addEventListener('DOMContentLoaded', () => new Vue({
+ el: '#element',
+ components: {
+ componentName
+ },
+ render: createElement => createElement('component-name'),
+ }));
+ ```
+1. Don not use a singleton for the service or the store
```javascript
- // bad
- import cardBoard from 'cardBoard';
+ // bad
+ class Store {
+ constructor() {
+ if (!this.prototype.singleton) {
+ // do something
+ }
+ }
+ }
- // good
- import CardBoard from 'cardBoard'
+ // good
+ class Store {
+ constructor() {
+ // do something
+ }
+ }
+ ```
- // bad
- components: {
- CardBoard: CardBoard
- };
+#### Naming
+1. **Extensions**: Use `.vue` extension for Vue components.
+1. **Reference Naming**: Use camelCase for their instances:
+ ```javascript
+ // good
+ import cardBoard from 'cardBoard'
- // good
- components: {
- cardBoard: CardBoard
- };
+ components: {
+ cardBoard:
+ };
```
-- **Props Naming:**
-- Avoid using DOM component prop names.
-- Use kebab-case instead of camelCase to provide props in templates.
-
+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" />
+ ```
#### Alignment
-- Follow these alignment styles for the template method:
-
+1. Follow these alignment styles for the template method:
```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>
- // if props fit in one line then keep it on the same line
- <component bar="bar" />
+ // if props fit in one line then keep it on the same line
+ <component bar="bar" />
```
#### Quotes
-- Always use double quotes `"` inside templates and single quotes `'` for all other JS.
-
+1. Always use double quotes `"` inside templates and single quotes `'` for all other JS.
```javascript
- // bad
- template: `
- <button :class='style'>Button</button>
- `
-
- // good
- template: `
- <button :class="style">Button</button>
- `
+ // bad
+ template: `
+ <button :class='style'>Button</button>
+ `
+
+ // good
+ template: `
+ <button :class="style">Button</button>
+ `
```
#### Props
-- Props should be declared as an object
-
+1. Props should be declared as an object
```javascript
- // bad
- props: ['foo']
-
- // good
- props: {
- foo: {
- type: String,
- required: false,
- default: 'bar'
+ // bad
+ props: ['foo']
+
+ // good
+ props: {
+ foo: {
+ type: String,
+ required: false,
+ default: 'bar'
+ }
}
- }
```
-- Required key should always be provided when declaring a prop
-
+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'
+ }
}
- }
```
-- Default key should always be provided if the prop is not required:
-
+1. Default key should always be provided if the prop is not required:
```javascript
- // bad
- props: {
- foo: {
- type: String,
- required: false,
+ // bad
+ 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
-- `data` method should always be a function
+1. `data` method should always be a function
```javascript
- // bad
- data: {
- foo: 'foo'
- }
-
- // good
- data() {
- return {
+ // bad
+ data: {
foo: 'foo'
- };
- }
+ }
+
+ // good
+ data() {
+ return {
+ foo: 'foo'
+ };
+ }
```
#### Directives
-- Shorthand `@` is preferable over `v-on`
-
+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"/>
```
-- Shorthand `:` is preferable over `v-bind`
-
+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"/>
```
#### Closing tags
-- Prefer self closing component tags
-
+1. Prefer self closing component tags
```javascript
- // bad
- <component></component>
+ // bad
+ <component></component>
- // good
- <component />
+ // good
+ <component />
```
#### Ordering
-- Order for a Vue Component:
+1. Order for a Vue Component:
1. `name`
- 2. `props`
- 3. `data`
- 4. `components`
- 5. `computedProps`
- 6. `methods`
- 7. lifecycle methods
- 1. `beforeCreate`
- 2. `created`
- 3. `beforeMount`
- 4. `mounted`
- 5. `beforeUpdate`
- 6. `updated`
- 7. `activated`
- 8. `deactivated`
- 9. `beforeDestroy`
- 10. `destroyed`
- 8. `template`
+ 1. `props`
+ 1. `mixins`
+ 1. `data`
+ 1. `components`
+ 1. `computedProps`
+ 1. `methods`
+ 1. `beforeCreate`
+ 1. `created`
+ 1. `beforeMount`
+ 1. `mounted`
+ 1. `beforeUpdate`
+ 1. `updated`
+ 1. `activated`
+ 1. `deactivated`
+ 1. `beforeDestroy`
+ 1. `destroyed`
+
+#### Vue and Boostrap
+1. Tooltips: Do not rely on `has-tooltip` class name for vue components
+ ```javascript
+ // bad
+ <span class="has-tooltip">
+ Text
+ </span>
+
+ // good
+ <span data-toggle="tooltip">
+ Text
+ </span>
+ ```
+
+1. Tooltips: When using a tooltip, include the tooltip mixin
+
+1. Don't change `data-original-title`.
+ ```javascript
+ // bad
+ <span data-original-title="tooltip text">Foo</span>
+
+ // good
+ <span title="tooltip text">Foo</span>
+
+ $('span').tooltip('fixTitle');
+ ```
## SCSS
@@ -461,3 +495,5 @@ A forEach will cause side effects, it will be mutating the array being iterated.
[airbnb-js-style-guide]: https://github.com/airbnb/javascript
[eslintrc]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.eslintrc
+[eslint-this]: http://eslint.org/docs/rules/class-methods-use-this
+[eslint-new]: http://eslint.org/docs/rules/no-new
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index 73d2ffc1bdc..a984bb6c94c 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -387,6 +387,10 @@ describe('Todos App', () => {
});
});
```
+#### Test the component's output
+The main return value of a Vue component is the rendered output. In order to test the component we
+need to test the rendered output. [Vue][vue-test] guide's to unit test show us exactly that:
+
### Stubbing API responses
[Vue Resource Interceptors][vue-resource-interceptor] allow us to add a interceptor with
@@ -419,6 +423,16 @@ the response we need:
});
```
+1. Use `$.mount()` to mount the component
+```javascript
+ // bad
+ new Component({
+ el: document.createElement('div')
+ });
+
+ // good
+ new Component().$mount();
+```
[vue-docs]: http://vuejs.org/guide/index.html
[issue-boards]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/boards
@@ -429,5 +443,6 @@ the response we need:
[one-way-data-flow]: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow
[vue-resource-repo]: https://github.com/pagekit/vue-resource
[vue-resource-interceptor]: https://github.com/pagekit/vue-resource/blob/develop/docs/http.md#interceptors
+[vue-test]: https://vuejs.org/v2/guide/unit-testing.html
[issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6
[flux]: https://facebook.github.io/flux
diff --git a/doc/update/9.0-to-9.1.md b/doc/update/9.0-to-9.1.md
index 2d597894517..2b582d4eefd 100644
--- a/doc/update/9.0-to-9.1.md
+++ b/doc/update/9.0-to-9.1.md
@@ -104,6 +104,7 @@ cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags
sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_SHELL_VERSION)
+sudo -u git -H bin/compile
```
### 7. Update gitlab-workhorse
diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md
index f69d567eeb7..ac1bcb8f241 100644
--- a/doc/update/patch_versions.md
+++ b/doc/update/patch_versions.md
@@ -75,6 +75,7 @@ cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags
sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION` -b v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`
+sudo -u git -H sh -c 'if [ -x bin/compile ]; then bin/compile; fi'
```
### 6. Start application
diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md
index 5fa39ef1b0a..eb7f14a96d5 100644
--- a/doc/update/upgrader.md
+++ b/doc/update/upgrader.md
@@ -60,6 +60,7 @@ GitLab Shell might be outdated, running the commands below ensures you're using
cd /home/git/gitlab-shell
sudo -u git -H git fetch
sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`
+sudo -u git -H sh -c 'if [ -x bin/compile ] ; then bin/compile ; fi'
```
## One line upgrade command
@@ -78,6 +79,7 @@ cd /home/git/gitlab; \
cd /home/git/gitlab-shell; \
sudo -u git -H git fetch; \
sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`; \
+ sudo -u git -H sh -c 'if [ -x bin/compile ] ; then bin/compile ; fi'; \
cd /home/git/gitlab; \
sudo service gitlab start; \
sudo service nginx restart; \