Skip to content
Snippets Groups Projects
Commit b0be58a1 authored by Brett Walker's avatar Brett Walker Committed by Sean McGivern
Browse files

Resolve "CE documentation is not CommonMark compliant"

parent 2d16f479
No related branches found
No related tags found
1 merge request!10495Merge Requests - Assignee
Showing
with 669 additions and 617 deletions
Loading
@@ -297,10 +297,10 @@ avoid duplication, link to the special document that can be found in
Loading
@@ -297,10 +297,10 @@ avoid duplication, link to the special document that can be found in
[`doc/administration/restart_gitlab.md`][doc-restart]. Usually the text will [`doc/administration/restart_gitlab.md`][doc-restart]. Usually the text will
read like: read like:
   
``` ```
Save the file and [reconfigure GitLab](../../administration/restart_gitlab.md) Save the file and [reconfigure GitLab](../../administration/restart_gitlab.md)
for the changes to take effect. for the changes to take effect.
``` ```
   
If the document you are editing resides in a place other than the GitLab CE/EE If the document you are editing resides in a place other than the GitLab CE/EE
`doc/` directory, instead of the relative link, use the full path: `doc/` directory, instead of the relative link, use the full path:
Loading
Loading
Loading
@@ -166,47 +166,53 @@ There are a few gotchas with it:
Loading
@@ -166,47 +166,53 @@ There are a few gotchas with it:
to make it call the other method we want to extend, like a [template method to make it call the other method we want to extend, like a [template method
pattern](https://en.wikipedia.org/wiki/Template_method_pattern). pattern](https://en.wikipedia.org/wiki/Template_method_pattern).
For example, given this base: For example, given this base:
``` ruby
class Base
def execute
return unless enabled?
   
# ... ```ruby
# ... class Base
end def execute
end return unless enabled?
```
Instead of just overriding `Base#execute`, we should update it and extract # ...
the behaviour into another method: # ...
``` ruby end
class Base
def execute
return unless enabled?
do_something
end end
```
   
private Instead of just overriding `Base#execute`, we should update it and extract
the behaviour into another method:
   
def do_something ```ruby
# ... class Base
# ... def execute
return unless enabled?
do_something
end
private
def do_something
# ...
# ...
end
end end
end ```
```
Then we're free to override that `do_something` without worrying about the Then we're free to override that `do_something` without worrying about the
guards: guards:
``` ruby
module EE::Base ```ruby
extend ::Gitlab::Utils::Override module EE::Base
extend ::Gitlab::Utils::Override
override :do_something
def do_something override :do_something
# Follow the above pattern to call super and extend it def do_something
# Follow the above pattern to call super and extend it
end
end end
end ```
```
This would require updating CE first, or make sure this is back ported to CE. This would require updating CE first, or make sure this is back ported to CE.
   
When prepending, place them in the `ee/` specific sub-directory, and When prepending, place them in the `ee/` specific sub-directory, and
wrap class or module in `module EE` to avoid naming conflicts. wrap class or module in `module EE` to avoid naming conflicts.
Loading
@@ -469,7 +475,7 @@ Put the EE module files following
Loading
@@ -469,7 +475,7 @@ Put the EE module files following
   
For EE API routes, we put them in a `prepended` block: For EE API routes, we put them in a `prepended` block:
   
``` ruby ```ruby
module EE module EE
module API module API
module MergeRequests module MergeRequests
Loading
@@ -503,7 +509,7 @@ interface first here.
Loading
@@ -503,7 +509,7 @@ interface first here.
For example, suppose we have a few more optional params for EE, given this CE For example, suppose we have a few more optional params for EE, given this CE
API code: API code:
   
``` ruby ```ruby
module API module API
class MergeRequests < Grape::API class MergeRequests < Grape::API
# EE::API::MergeRequests would override the following helpers # EE::API::MergeRequests would override the following helpers
Loading
@@ -525,7 +531,7 @@ end
Loading
@@ -525,7 +531,7 @@ end
   
And then we could override it in EE module: And then we could override it in EE module:
   
``` ruby ```ruby
module EE module EE
module API module API
module MergeRequests module MergeRequests
Loading
@@ -552,7 +558,7 @@ To make it easy for an EE module to override the CE helpers, we need to define
Loading
@@ -552,7 +558,7 @@ To make it easy for an EE module to override the CE helpers, we need to define
those helpers we want to extend first. Try to do that immediately after the those helpers we want to extend first. Try to do that immediately after the
class definition to make it easy and clear: class definition to make it easy and clear:
   
``` ruby ```ruby
module API module API
class JobArtifacts < Grape::API class JobArtifacts < Grape::API
# EE::API::JobArtifacts would override the following helpers # EE::API::JobArtifacts would override the following helpers
Loading
@@ -569,7 +575,7 @@ end
Loading
@@ -569,7 +575,7 @@ end
   
And then we can follow regular object-oriented practices to override it: And then we can follow regular object-oriented practices to override it:
   
``` ruby ```ruby
module EE module EE
module API module API
module JobArtifacts module JobArtifacts
Loading
@@ -596,7 +602,7 @@ therefore can't be simply overridden. We need to extract them into a standalone
Loading
@@ -596,7 +602,7 @@ therefore can't be simply overridden. We need to extract them into a standalone
method, or introduce some "hooks" where we could inject behavior in the CE method, or introduce some "hooks" where we could inject behavior in the CE
route. Something like this: route. Something like this:
   
``` ruby ```ruby
module API module API
class MergeRequests < Grape::API class MergeRequests < Grape::API
helpers do helpers do
Loading
@@ -623,7 +629,7 @@ end
Loading
@@ -623,7 +629,7 @@ end
Note that `update_merge_request_ee` doesn't do anything in CE, but Note that `update_merge_request_ee` doesn't do anything in CE, but
then we could override it in EE: then we could override it in EE:
   
``` ruby ```ruby
module EE module EE
module API module API
module MergeRequests module MergeRequests
Loading
@@ -662,7 +668,7 @@ For example, in one place we need to pass an extra argument to
Loading
@@ -662,7 +668,7 @@ For example, in one place we need to pass an extra argument to
`at_least_one_of` so that the API could consider an EE-only argument as the `at_least_one_of` so that the API could consider an EE-only argument as the
least argument. This is not quite beautiful but it's working: least argument. This is not quite beautiful but it's working:
   
``` ruby ```ruby
module API module API
class MergeRequests < Grape::API class MergeRequests < Grape::API
def self.update_params_at_least_one_of def self.update_params_at_least_one_of
Loading
@@ -683,7 +689,7 @@ end
Loading
@@ -683,7 +689,7 @@ end
   
And then we could easily extend that argument in the EE class method: And then we could easily extend that argument in the EE class method:
   
``` ruby ```ruby
module EE module EE
module API module API
module MergeRequests module MergeRequests
Loading
Loading
Loading
@@ -74,7 +74,7 @@ bundle and included on the page.
Loading
@@ -74,7 +74,7 @@ bundle and included on the page.
> `content_for :page_specific_javascripts` within haml files, along with > `content_for :page_specific_javascripts` within haml files, along with
> manually generated webpack bundles. However under this new system you should > manually generated webpack bundles. However under this new system you should
> not ever need to manually add an entry point to the `webpack.config.js` file. > not ever need to manually add an entry point to the `webpack.config.js` file.
>
> **Tip:** > **Tip:**
> If you are unsure what controller and action corresponds to a given page, you > If you are unsure what controller and action corresponds to a given page, you
> can find this out by inspecting `document.body.dataset.page` within your > can find this out by inspecting `document.body.dataset.page` within your
Loading
@@ -109,7 +109,6 @@ bundle and included on the page.
Loading
@@ -109,7 +109,6 @@ bundle and included on the page.
`my_widget.js` is only imported within `pages/widget/show/index.js`, you `my_widget.js` is only imported within `pages/widget/show/index.js`, you
should place the module at `pages/widget/show/my_widget.js` and import it should place the module at `pages/widget/show/my_widget.js` and import it
with a relative path (e.g. `import initMyWidget from './my_widget';`). with a relative path (e.g. `import initMyWidget from './my_widget';`).
- If a class or module is _used by multiple routes_, place it within a - If a class or module is _used by multiple routes_, place it within a
shared directory at the closest common parent directory for the entry shared directory at the closest common parent directory for the entry
points that import it. For example, if `my_widget.js` is imported within points that import it. For example, if `my_widget.js` is imported within
Loading
Loading
This diff is collapsed.
Loading
@@ -290,23 +290,24 @@ export default {
Loading
@@ -290,23 +290,24 @@ export default {
``` ```
   
### Vuex Gotchas ### Vuex Gotchas
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.
   
```javascript 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:
// component.vue
// bad
created() {
this.$store.commit('mutation');
}
   
// good > 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.
created() {
this.$store.dispatch('action'); ```javascript
} // component.vue
```
// bad
created() {
this.$store.commit('mutation');
}
// good
created() {
this.$store.dispatch('action');
}
```
1. Use mutation types instead of hardcoding strings. It will be less error prone. 1. Use mutation types instead of hardcoding strings. It will be less error prone.
1. The State will be accessible in all components descending from the use where the store is instantiated. 1. The State will be accessible in all components descending from the use where the store is instantiated.
   
Loading
@@ -342,7 +343,7 @@ describe('component', () => {
Loading
@@ -342,7 +343,7 @@ describe('component', () => {
name: 'Foo', name: 'Foo',
age: '30', age: '30',
}; };
store = createStore(); store = createStore();
   
// populate the store // populate the store
Loading
Loading
Loading
@@ -101,8 +101,10 @@ end
Loading
@@ -101,8 +101,10 @@ end
in a prepended module, which is very likely the case in EE. We could see in a prepended module, which is very likely the case in EE. We could see
error like this: error like this:
   
1.1) Failure/Error: allow_any_instance_of(ApplicationSetting).to receive_messages(messages) ```
Using `any_instance` to stub a method (elasticsearch_indexing) that has been defined on a prepended module (EE::ApplicationSetting) is not supported. 1.1) Failure/Error: allow_any_instance_of(ApplicationSetting).to receive_messages(messages)
Using `any_instance` to stub a method (elasticsearch_indexing) that has been defined on a prepended module (EE::ApplicationSetting) is not supported.
```
   
### Alternative: `expect_next_instance_of` ### Alternative: `expect_next_instance_of`
   
Loading
Loading
Loading
@@ -65,7 +65,6 @@ are very appreciative of the work done by translators and proofreaders!
Loading
@@ -65,7 +65,6 @@ are very appreciative of the work done by translators and proofreaders!
   
Add your language in alphabetical order, and add yourself to the list Add your language in alphabetical order, and add yourself to the list
including: including:
- name - name
- link to your GitLab profile - link to your GitLab profile
- link to your CrowdIn profile - link to your CrowdIn profile
Loading
Loading
Loading
@@ -6,7 +6,7 @@
Loading
@@ -6,7 +6,7 @@
* **[Ruby unit tests](#ruby-unit-tests-spec-rb)** for models, controllers, helpers, etc. (`/spec/**/*.rb`) * **[Ruby unit tests](#ruby-unit-tests-spec-rb)** for models, controllers, helpers, etc. (`/spec/**/*.rb`)
* **[Full feature tests](#full-feature-tests-spec-features-rb)** (`/spec/features/**/*.rb`) * **[Full feature tests](#full-feature-tests-spec-features-rb)** (`/spec/features/**/*.rb`)
* **[Karma](#karma-tests-spec-javascripts-js)** (`/spec/javascripts/**/*.js`) * **[Karma](#karma-tests-spec-javascripts-js)** (`/spec/javascripts/**/*.js`)
* ~~Spinach~~ — These have been removed from our codebase in May 2018. (`/features/`) * <s>Spinach</s> — These have been removed from our codebase in May 2018. (`/features/`)
   
## RSpec: Ruby unit tests `/spec/**/*.rb` ## RSpec: Ruby unit tests `/spec/**/*.rb`
   
Loading
Loading
Loading
@@ -12,158 +12,157 @@ You can run eslint locally by running `yarn eslint`
Loading
@@ -12,158 +12,157 @@ You can run eslint locally by running `yarn eslint`
<a name="avoid-foreach"></a><a name="1.1"></a> <a name="avoid-foreach"></a><a name="1.1"></a>
- [1.1](#avoid-foreach) **Avoid ForEach when mutating data** Use `map`, `reduce` or `filter` instead of `forEach` when mutating data. This will minimize mutations in functions ([which is aligned with Airbnb's style guide][airbnb-minimize-mutations]) - [1.1](#avoid-foreach) **Avoid ForEach when mutating data** Use `map`, `reduce` or `filter` instead of `forEach` when mutating data. This will minimize mutations in functions ([which is aligned with Airbnb's style guide][airbnb-minimize-mutations])
   
``` ```
// bad // bad
users.forEach((user, index) => { users.forEach((user, index) => {
user.id = index; user.id = index;
}); });
// good // good
const usersWithId = users.map((user, index) => { const usersWithId = users.map((user, index) => {
return Object.assign({}, user, { id: index }); return Object.assign({}, user, { id: index });
}); });
``` ```
   
## Functions ## Functions
   
<a name="limit-params"></a><a name="2.1"></a> <a name="limit-params"></a><a name="2.1"></a>
- [2.1](#limit-params) **Limit number of parameters** If your function or method has more than 3 parameters, use an object as a parameter instead. - [2.1](#limit-params) **Limit number of parameters** If your function or method has more than 3 parameters, use an object as a parameter instead.
   
``` ```
// bad // bad
function a(p1, p2, p3) { function a(p1, p2, p3) {
// ... // ...
}; };
// good // good
function a(p) { function a(p) {
// ... // ...
}; };
``` ```
   
## Classes & constructors ## Classes & constructors
   
<a name="avoid-constructor-side-effects"></a><a name="3.1"></a> <a name="avoid-constructor-side-effects"></a><a name="3.1"></a>
- [3.1](#avoid-constructor-side-effects) **Avoid side effects in constructors** Avoid making some operations in the `constructor`, such as asynchronous calls, API requests and DOM manipulations. Prefer moving them into separate functions. This will make tests easier to write and code easier to maintain. - [3.1](#avoid-constructor-side-effects) **Avoid side effects in constructors** Avoid making some operations in the `constructor`, such as asynchronous calls, API requests and DOM manipulations. Prefer moving them into separate functions. This will make tests easier to write and code easier to maintain.
   
```javascript ```javascript
// bad // bad
class myClass { class myClass {
constructor(config) { constructor(config) {
this.config = config; this.config = config;
axios.get(this.config.endpoint) axios.get(this.config.endpoint)
}
} }
}
// good
// good class myClass {
class myClass { constructor(config) {
constructor(config) { this.config = config;
this.config = config; }
makeRequest() {
axios.get(this.config.endpoint)
}
} }
const instance = new myClass();
makeRequest() { instance.makeRequest();
axios.get(this.config.endpoint)
} ```
}
const instance = new myClass();
instance.makeRequest();
```
   
<a name="avoid-classes-to-handle-dom-events"></a><a name="3.2"></a> <a name="avoid-classes-to-handle-dom-events"></a><a name="3.2"></a>
- [3.2](#avoid-classes-to-handle-dom-events) **Avoid classes to handle DOM events** If the only purpose of the class is to bind a DOM event and handle the callback, prefer using a function. - [3.2](#avoid-classes-to-handle-dom-events) **Avoid classes to handle DOM events** If the only purpose of the class is to bind a DOM event and handle the callback, prefer using a function.
   
``` ```
// bad // bad
class myClass { class myClass {
constructor(config) { constructor(config) {
this.config = config; this.config = config;
} }
init() { init() {
document.addEventListener('click', () => {}); document.addEventListener('click', () => {});
} }
} }
// good // good
const myFunction = () => { const myFunction = () => {
document.addEventListener('click', () => { document.addEventListener('click', () => {
// handle callback here // handle callback here
}); });
} }
``` ```
   
<a name="element-container"></a><a name="3.3"></a> <a name="element-container"></a><a name="3.3"></a>
- [3.3](#element-container) **Pass element container to constructor** When your class manipulates the DOM, receive the element container as a parameter. - [3.3](#element-container) **Pass element container to constructor** When your class manipulates the DOM, receive the element container as a parameter.
This is more maintainable and performant. This is more maintainable and performant.
   
``` ```
// bad // bad
class a { class a {
constructor() { constructor() {
document.querySelector('.b'); document.querySelector('.b');
} }
} }
// good // good
class a { class a {
constructor(options) { constructor(options) {
options.container.querySelector('.b'); options.container.querySelector('.b');
} }
} }
``` ```
   
## Type Casting & Coercion ## Type Casting & Coercion
   
<a name="use-parseint"></a><a name="4.1"></a> <a name="use-parseint"></a><a name="4.1"></a>
- [4.1](#use-parseint) **Use ParseInt** Use `ParseInt` when converting a numeric string into a number. - [4.1](#use-parseint) **Use ParseInt** Use `ParseInt` when converting a numeric string into a number.
   
``` ```
// bad // bad
Number('10') Number('10')
// good
// good parseInt('10', 10);
parseInt('10', 10); ```
```
   
## CSS Selectors ## CSS Selectors
   
<a name="use-js-prefix"></a><a name="5.1"></a> <a name="use-js-prefix"></a><a name="5.1"></a>
- [5.1](#use-js-prefix) **Use js prefix** If a CSS class is only being used in JavaScript as a reference to the element, prefix the class name with `js-` - [5.1](#use-js-prefix) **Use js prefix** If a CSS class is only being used in JavaScript as a reference to the element, prefix the class name with `js-`
   
``` ```
// bad // bad
<button class="add-user"></button> <button class="add-user"></button>
// good // good
<button class="js-add-user"></button> <button class="js-add-user"></button>
``` ```
   
## Modules ## Modules
   
<a name="use-absolute-paths"></a><a name="6.1"></a> <a name="use-absolute-paths"></a><a name="6.1"></a>
- [6.1](#use-absolute-paths) **Use absolute paths for nearby modules** Use absolute paths if the module you are importing is less than two levels up. - [6.1](#use-absolute-paths) **Use absolute paths for nearby modules** Use absolute paths if the module you are importing is less than two levels up.
   
``` ```
// bad // bad
import GitLabStyleGuide from '~/guides/GitLabStyleGuide'; import GitLabStyleGuide from '~/guides/GitLabStyleGuide';
// good // good
import GitLabStyleGuide from '../GitLabStyleGuide'; import GitLabStyleGuide from '../GitLabStyleGuide';
``` ```
   
<a name="use-relative-paths"></a><a name="6.2"></a> <a name="use-relative-paths"></a><a name="6.2"></a>
- [6.2](#use-relative-paths) **Use relative paths for distant modules** If the module you are importing is two or more levels up, use a relative path instead of an absolute path. - [6.2](#use-relative-paths) **Use relative paths for distant modules** If the module you are importing is two or more levels up, use a relative path instead of an absolute path.
   
``` ```
// bad // bad
import GitLabStyleGuide from '../../../guides/GitLabStyleGuide'; import GitLabStyleGuide from '../../../guides/GitLabStyleGuide';
// good // good
import GitLabStyleGuide from '~/GitLabStyleGuide'; import GitLabStyleGuide from '~/GitLabStyleGuide';
``` ```
   
<a name="global-namespace"></a><a name="6.3"></a> <a name="global-namespace"></a><a name="6.3"></a>
- [6.3](#global-namespace) **Do not add to global namespace** - [6.3](#global-namespace) **Do not add to global namespace**
Loading
Loading
Loading
@@ -10,7 +10,7 @@ def method
Loading
@@ -10,7 +10,7 @@ def method
issue = Issue.new issue = Issue.new
   
issue.save issue.save
render json: issue render json: issue
end end
``` ```
Loading
@@ -20,7 +20,7 @@ end
Loading
@@ -20,7 +20,7 @@ end
def method def method
issue = Issue.new issue = Issue.new
issue.save issue.save
render json: issue render json: issue
end end
``` ```
Loading
Loading
Loading
@@ -3,8 +3,7 @@
Loading
@@ -3,8 +3,7 @@
## Log arguments to Sidekiq jobs ## Log arguments to Sidekiq jobs
   
If you want to see what arguments are being passed to Sidekiq jobs you can set If you want to see what arguments are being passed to Sidekiq jobs you can set
the `SIDEKIQ_LOG_ARGUMENTS` [environment variable] the `SIDEKIQ_LOG_ARGUMENTS` [environment variable](https://docs.gitlab.com/omnibus/settings/environment-variables.html) to `1` (true).
(https://docs.gitlab.com/omnibus/settings/environment-variables.html) to `1` (true).
   
Example: Example:
   
Loading
Loading
Loading
@@ -5,23 +5,23 @@
Loading
@@ -5,23 +5,23 @@
Our current CI parallelization setup is as follows: Our current CI parallelization setup is as follows:
   
1. The `knapsack` job in the prepare stage that is supposed to ensure we have a 1. The `knapsack` job in the prepare stage that is supposed to ensure we have a
`knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file: `knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file:
- The `knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file is fetched - The `knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file is fetched
from S3, if it's not here we initialize the file with `{}`. from S3, if it's not here we initialize the file with `{}`.
1. Each `rspec x y` job are run with `knapsack rspec` and should have an evenly 1. Each `rspec x y` job are run with `knapsack rspec` and should have an evenly
distributed share of tests: distributed share of tests:
- It works because the jobs have access to the - It works because the jobs have access to the
`knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` since the "artifacts `knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` since the "artifacts
from all previous stages are passed by default". [^1] from all previous stages are passed by default".
- the jobs set their own report path to - the jobs set their own report path to
`KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json`. `KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json`.
- if knapsack is doing its job, test files that are run should be listed under - if knapsack is doing its job, test files that are run should be listed under
`Report specs`, not under `Leftover specs`. `Report specs`, not under `Leftover specs`.
1. The `update-knapsack` job takes all the 1. The `update-knapsack` job takes all the
`knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json` `knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json`
files from the `rspec x y` jobs and merge them all together into a single files from the `rspec x y` jobs and merge them all together into a single
`knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file that is then `knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file that is then
uploaded to S3. uploaded to S3.
   
After that, the next pipeline will use the up-to-date After that, the next pipeline will use the up-to-date
`knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file. `knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file.
Loading
Loading
Loading
@@ -153,7 +153,7 @@ trade-off:
Loading
@@ -153,7 +153,7 @@ trade-off:
- Unit tests are usually cheap, and you should consider them like the basement - Unit tests are usually cheap, and you should consider them like the basement
of your house: you need them to be confident that your code is behaving of your house: you need them to be confident that your code is behaving
correctly. However if you run only unit tests without integration / system correctly. However if you run only unit tests without integration / system
tests, you might [miss] the [big] [picture]! tests, you might [miss] the [big] / [picture] !
- Integration tests are a bit more expensive, but don't abuse them. A system test - Integration tests are a bit more expensive, but don't abuse them. A system test
is often better than an integration test that is stubbing a lot of internals. is often better than an integration test that is stubbing a lot of internals.
- System tests are expensive (compared to unit tests), even more if they require - System tests are expensive (compared to unit tests), even more if they require
Loading
Loading
# How to create a project in GitLab # How to create a project in GitLab
   
>**Notes:** > **Notes:**
- For a list of words that are not allowed to be used as project names see the > - For a list of words that are not allowed to be used as project names see the
[reserved names][reserved]. > [reserved names][reserved].
   
1. In your dashboard, click the green **New project** button or use the plus 1. In your dashboard, click the green **New project** button or use the plus
icon in the upper right corner of the navigation bar. icon in the upper right corner of the navigation bar.
Loading
Loading
Loading
@@ -71,7 +71,7 @@ The first items we need to configure are the basic settings of the underlying vi
Loading
@@ -71,7 +71,7 @@ The first items we need to configure are the basic settings of the underlying vi
1. Enter a `User name` - e.g. **"gitlab-admin"** 1. Enter a `User name` - e.g. **"gitlab-admin"**
1. Select an `Authentication type`, either **SSH public key** or **Password**: 1. Select an `Authentication type`, either **SSH public key** or **Password**:
>**Note:** if you're unsure which authentication type to use, select **Password** > **Note:** if you're unsure which authentication type to use, select **Password**
   
1. If you chose **SSH public key** - enter your `SSH public key` into the field provided 1. If you chose **SSH public key** - enter your `SSH public key` into the field provided
_(read the [SSH documentation][GitLab-Docs-SSH] to learn more about how to setup SSH _(read the [SSH documentation][GitLab-Docs-SSH] to learn more about how to setup SSH
Loading
@@ -80,8 +80,10 @@ The first items we need to configure are the basic settings of the underlying vi
Loading
@@ -80,8 +80,10 @@ The first items we need to configure are the basic settings of the underlying vi
will use later in this tutorial to [SSH] into the VM, so make sure it's a strong password/passphrase)_ will use later in this tutorial to [SSH] into the VM, so make sure it's a strong password/passphrase)_
1. Choose the appropriate `Subscription` tier for your Azure account 1. Choose the appropriate `Subscription` tier for your Azure account
1. Choose an existing `Resource Group` or create a new one - e.g. **"GitLab-CE-Azure"** 1. Choose an existing `Resource Group` or create a new one - e.g. **"GitLab-CE-Azure"**
>**Note:** a "Resource group" is a way to group related resources together for easier administration.
We chose "GitLab-CE-Azure", but your resource group can have the same name as your VM. > **Note:** a "Resource group" is a way to group related resources together for easier administration.
> We chose "GitLab-CE-Azure", but your resource group can have the same name as your VM.
1. Choose a `Location` - if you're unsure, select the default location 1. Choose a `Location` - if you're unsure, select the default location
   
Here are the settings we've used: Here are the settings we've used:
Loading
@@ -95,7 +97,7 @@ Check the settings you have entered, and then click **"OK"** when you're ready t
Loading
@@ -95,7 +97,7 @@ Check the settings you have entered, and then click **"OK"** when you're ready t
Next, you need to choose the size of your VM - selecting features such as the number of CPU cores, Next, you need to choose the size of your VM - selecting features such as the number of CPU cores,
the amount of RAM, the size of storage (and its speed), etc. the amount of RAM, the size of storage (and its speed), etc.
   
>**Note:** in common with other cloud vendors, Azure operates a resource/usage pricing model, i.e. > **Note:** in common with other cloud vendors, Azure operates a resource/usage pricing model, i.e.
the more resources your VM consumes the more it will cost you to run, so make your selection the more resources your VM consumes the more it will cost you to run, so make your selection
carefully. You'll see that Azure provides an _estimated_ monthly cost beneath each VM Size to help carefully. You'll see that Azure provides an _estimated_ monthly cost beneath each VM Size to help
guide your selection. guide your selection.
Loading
@@ -106,7 +108,7 @@ ahead and select this one, but please choose the size which best meets your own
Loading
@@ -106,7 +108,7 @@ ahead and select this one, but please choose the size which best meets your own
   
![Azure - Create Virtual Machine - Size](img/azure-create-virtual-machine-size.png) ![Azure - Create Virtual Machine - Size](img/azure-create-virtual-machine-size.png)
   
>**Note:** be aware that whilst your VM is active (known as "allocated"), it will incur > **Note:** be aware that whilst your VM is active (known as "allocated"), it will incur
"compute charges" which, ultimately, you will be billed for. So, even if you're using the "compute charges" which, ultimately, you will be billed for. So, even if you're using the
free trial credits, you'll likely want to learn free trial credits, you'll likely want to learn
[how to properly shutdown an Azure VM to save money][Azure-Properly-Shutdown-VM]. [how to properly shutdown an Azure VM to save money][Azure-Properly-Shutdown-VM].
Loading
@@ -132,7 +134,7 @@ new VM. You'll be billed only for the VM itself (e.g. "Standard DS1 v2") because
Loading
@@ -132,7 +134,7 @@ new VM. You'll be billed only for the VM itself (e.g. "Standard DS1 v2") because
   
![Azure - Create Virtual Machine - Purchase](img/azure-create-virtual-machine-purchase.png) ![Azure - Create Virtual Machine - Purchase](img/azure-create-virtual-machine-purchase.png)
   
>**Note:** at this stage, you can review and modify the any of the settings you have made during all > **Note:** at this stage, you can review and modify the any of the settings you have made during all
previous steps, just click on any of the four steps to re-open them. previous steps, just click on any of the four steps to re-open them.
   
When you have read and agreed to the terms of use and are ready to proceed, click **"Purchase"**. When you have read and agreed to the terms of use and are ready to proceed, click **"Purchase"**.
Loading
@@ -174,7 +176,7 @@ _(the full domain name of your own VM will be different, of course)_.
Loading
@@ -174,7 +176,7 @@ _(the full domain name of your own VM will be different, of course)_.
   
Click **"Save"** for the changes to take effect. Click **"Save"** for the changes to take effect.
   
>**Note:** if you want to use your own domain name, you will need to add a DNS `A` record at your > **Note:** if you want to use your own domain name, you will need to add a DNS `A` record at your
domain registrar which points to the public IP address of your Azure VM. If you do this, you'll need domain registrar which points to the public IP address of your Azure VM. If you do this, you'll need
to make sure your VM is configured to use a _static_ public IP address (i.e. not a _dynamic_ one) to make sure your VM is configured to use a _static_ public IP address (i.e. not a _dynamic_ one)
or you will have to reconfigure the DNS `A` record each time Azure reassigns your VM a new public IP or you will have to reconfigure the DNS `A` record each time Azure reassigns your VM a new public IP
Loading
@@ -190,7 +192,7 @@ Ports are opened by adding _security rules_ to the **"Network security group"**
Loading
@@ -190,7 +192,7 @@ Ports are opened by adding _security rules_ to the **"Network security group"**
has been assigned to. If you followed the process above, then Azure will have automatically created has been assigned to. If you followed the process above, then Azure will have automatically created
an NSG named `GitLab-CE-nsg` and assigned the `GitLab-CE` VM to it. an NSG named `GitLab-CE-nsg` and assigned the `GitLab-CE` VM to it.
   
>**Note:** if you gave your VM a different name then the NSG automatically created by Azure will > **Note:** if you gave your VM a different name then the NSG automatically created by Azure will
also have a different name - the name you have your VM, with `-nsg` appended to it. also have a different name - the name you have your VM, with `-nsg` appended to it.
   
You can navigate to the NSG settings via many different routes in the Azure Portal, but one of the You can navigate to the NSG settings via many different routes in the Azure Portal, but one of the
Loading
@@ -321,7 +323,7 @@ Under the **"Components"** section, we can see that our VM is currently running
Loading
@@ -321,7 +323,7 @@ Under the **"Components"** section, we can see that our VM is currently running
GitLab. This is the version of GitLab which was contained in the Azure Marketplace GitLab. This is the version of GitLab which was contained in the Azure Marketplace
**"GitLab Community Edition"** offering we used to build the VM when we wrote this tutorial. **"GitLab Community Edition"** offering we used to build the VM when we wrote this tutorial.
   
>**Note:** The version of GitLab in your own VM instance may well be different, but the update > **Note:** The version of GitLab in your own VM instance may well be different, but the update
process will still be the same. process will still be the same.
   
### Connect via SSH ### Connect via SSH
Loading
@@ -333,11 +335,11 @@ connect to it using SSH ([Secure Shell][SSH]).
Loading
@@ -333,11 +335,11 @@ connect to it using SSH ([Secure Shell][SSH]).
If you're running Windows, you'll need to connect using [PuTTY] or an equivalent Windows SSH client. If you're running Windows, you'll need to connect using [PuTTY] or an equivalent Windows SSH client.
If you're running Linux or macOS, then you already have an SSH client installed. If you're running Linux or macOS, then you already have an SSH client installed.
   
>**Note:** > **Note:**
- Remember that you will need to login with the username and password you specified > - Remember that you will need to login with the username and password you specified
[when you created](#basics) your Azure VM > [when you created](#basics) your Azure VM
- If you need to reset your VM password, read > - If you need to reset your VM password, read
[how to reset SSH credentials for a user on an Azure VM][Azure-Troubleshoot-SSH-Connection]. > [how to reset SSH credentials for a user on an Azure VM][Azure-Troubleshoot-SSH-Connection].
   
#### SSH from the command-line #### SSH from the command-line
   
Loading
Loading
# Database MySQL # Database MySQL
   
>**Note:** > **Note:**
- We do not recommend using MySQL due to various issues. For example, case > - We do not recommend using MySQL due to various issues. For example, case
[(in)sensitivity](https://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html) [(in)sensitivity](https://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html)
and [problems](https://bugs.mysql.com/bug.php?id=65830) that and [problems](https://bugs.mysql.com/bug.php?id=65830) that
[suggested](https://bugs.mysql.com/bug.php?id=50909) [suggested](https://bugs.mysql.com/bug.php?id=50909)
[fixes](https://bugs.mysql.com/bug.php?id=65830) [have](https://bugs.mysql.com/bug.php?id=63164). [fixes](https://bugs.mysql.com/bug.php?id=65830) [have](https://bugs.mysql.com/bug.php?id=63164).
   
## Initial database setup ## Initial database setup
   
Loading
@@ -146,10 +146,12 @@ Congrats, your GitLab database uses the right InnoDB tablespace format.
Loading
@@ -146,10 +146,12 @@ Congrats, your GitLab database uses the right InnoDB tablespace format.
However, you must still ensure that any **future tables** created by GitLab will still use the right format: However, you must still ensure that any **future tables** created by GitLab will still use the right format:
   
- If `SELECT @@innodb_file_per_table` returned **1** previously, your server is running correctly. - If `SELECT @@innodb_file_per_table` returned **1** previously, your server is running correctly.
> It's however a requirement to check *now* that this setting is indeed persisted in your [my.cnf](https://dev.mysql.com/doc/refman/5.7/en/tablespace-enabling.html) file!
> It's however a requirement to check *now* that this setting is indeed persisted in your [my.cnf](https://dev.mysql.com/doc/refman/5.7/en/tablespace-enabling.html) file!
   
- If `SELECT @@innodb_file_per_table` returned **0** previously, your server is not running correctly. - If `SELECT @@innodb_file_per_table` returned **0** previously, your server is not running correctly.
> [Enable innodb_file_per_table](https://dev.mysql.com/doc/refman/5.7/en/tablespace-enabling.html) by running in a MySQL session as root the command `SET GLOBAL innodb_file_per_table=1, innodb_file_format=Barracuda;` and persist the two settings in your [my.cnf](https://dev.mysql.com/doc/refman/5.7/en/tablespace-enabling.html) file
> [Enable innodb_file_per_table](https://dev.mysql.com/doc/refman/5.7/en/tablespace-enabling.html) by running in a MySQL session as root the command `SET GLOBAL innodb_file_per_table=1, innodb_file_format=Barracuda;` and persist the two settings in your [my.cnf](https://dev.mysql.com/doc/refman/5.7/en/tablespace-enabling.html) file
   
Now, if you have a **different result** returned by the 2 commands above, it means you have a **mix of tables format** uses in your GitLab database. This can happen if your MySQL server had different values for `innodb_file_per_table` in its life and you updated GitLab at different moments with those inconsistent values. So keep reading. Now, if you have a **different result** returned by the 2 commands above, it means you have a **mix of tables format** uses in your GitLab database. This can happen if your MySQL server had different values for `innodb_file_per_table` in its life and you updated GitLab at different moments with those inconsistent values. So keep reading.
   
Loading
Loading
Loading
@@ -40,9 +40,9 @@ In order to deploy GitLab on Kubernetes, the following are required:
Loading
@@ -40,9 +40,9 @@ In order to deploy GitLab on Kubernetes, the following are required:
   
1. `helm` and `kubectl` [installed on your computer](preparation/tools_installation.md). 1. `helm` and `kubectl` [installed on your computer](preparation/tools_installation.md).
1. A Kubernetes cluster, version 1.8 or higher. 6vCPU and 16GB of RAM is recommended. 1. A Kubernetes cluster, version 1.8 or higher. 6vCPU and 16GB of RAM is recommended.
- [Google GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-container-cluster) - [Google GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-container-cluster)
- [Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) - [Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html)
- [Microsoft AKS](https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal) - [Microsoft AKS](https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal)
1. A [wildcard DNS entry and external IP address](preparation/networking.md) 1. A [wildcard DNS entry and external IP address](preparation/networking.md)
1. [Authenticate and connect](preparation/connect.md) to the cluster 1. [Authenticate and connect](preparation/connect.md) to the cluster
1. Configure and initialize [Helm Tiller](preparation/tiller.md). 1. Configure and initialize [Helm Tiller](preparation/tiller.md).
Loading
Loading
Loading
@@ -63,16 +63,18 @@ what we will use in this tutorial.
Loading
@@ -63,16 +63,18 @@ what we will use in this tutorial.
In short: In short:
   
1. Open a terminal and in a new directory run: 1. Open a terminal and in a new directory run:
```sh
vagrant init openshift/origin-all-in-one ```sh
``` vagrant init openshift/origin-all-in-one
```
1. This will generate a Vagrantfile based on the all-in-one VM image 1. This will generate a Vagrantfile based on the all-in-one VM image
1. In the same directory where you generated the Vagrantfile 1. In the same directory where you generated the Vagrantfile
enter: enter:
   
```sh ```sh
vagrant up vagrant up
``` ```
   
This will download the VirtualBox image and fire up the VM with some preconfigured This will download the VirtualBox image and fire up the VM with some preconfigured
values as you can see in the Vagrantfile. As you may have noticed, you need values as you can see in the Vagrantfile. As you may have noticed, you need
Loading
@@ -187,22 +189,22 @@ In that case, the OpenShift service might not be running, so in order to fix it:
Loading
@@ -187,22 +189,22 @@ In that case, the OpenShift service might not be running, so in order to fix it:
1. SSH into the VM by going to the directory where the Vagrantfile is and then 1. SSH into the VM by going to the directory where the Vagrantfile is and then
run: run:
   
```sh ```sh
vagrant ssh vagrant ssh
``` ```
   
1. Run `systemctl` and verify by the output that the `openshift` service is not 1. Run `systemctl` and verify by the output that the `openshift` service is not
running (it will be in red color). If that's the case start the service with: running (it will be in red color). If that's the case start the service with:
   
```sh ```sh
sudo systemctl start openshift sudo systemctl start openshift
``` ```
   
1. Verify the service is up with: 1. Verify the service is up with:
   
```sh ```sh
systemctl status openshift -l systemctl status openshift -l
``` ```
   
Now you will be able to login using `oc` (like we did before) and visit the web Now you will be able to login using `oc` (like we did before) and visit the web
console. console.
Loading
@@ -385,55 +387,55 @@ Let's see how to do that using the following steps.
Loading
@@ -385,55 +387,55 @@ Let's see how to do that using the following steps.
   
1. Make sure you are in the `gitlab` project: 1. Make sure you are in the `gitlab` project:
   
```sh ```sh
oc project gitlab oc project gitlab
``` ```
   
1. See what services are used for this project: 1. See what services are used for this project:
   
```sh ```sh
oc get svc oc get svc
``` ```
   
The output will be similar to: The output will be similar to:
   
``` ```
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
gitlab-ce 172.30.243.177 <none> 22/TCP,80/TCP 5d gitlab-ce 172.30.243.177 <none> 22/TCP,80/TCP 5d
gitlab-ce-postgresql 172.30.116.75 <none> 5432/TCP 5d gitlab-ce-postgresql 172.30.116.75 <none> 5432/TCP 5d
gitlab-ce-redis 172.30.105.88 <none> 6379/TCP 5d gitlab-ce-redis 172.30.105.88 <none> 6379/TCP 5d
``` ```
   
1. We need to see the replication controllers of the `gitlab-ce` service. 1. We need to see the replication controllers of the `gitlab-ce` service.
Get a detailed view of the current ones: Get a detailed view of the current ones:
   
```sh ```sh
oc describe rc gitlab-ce oc describe rc gitlab-ce
``` ```
   
This will return a large detailed list of the current replication controllers. This will return a large detailed list of the current replication controllers.
Search for the name of the GitLab controller, usually `gitlab-ce-1` or if Search for the name of the GitLab controller, usually `gitlab-ce-1` or if
that failed at some point and you spawned another one, it will be named that failed at some point and you spawned another one, it will be named
`gitlab-ce-2`. `gitlab-ce-2`.
   
1. Scale GitLab using the previous information: 1. Scale GitLab using the previous information:
   
```sh ```sh
oc scale --replicas=2 replicationcontrollers gitlab-ce-2 oc scale --replicas=2 replicationcontrollers gitlab-ce-2
``` ```
   
1. Get the new replicas number to make sure scaling worked: 1. Get the new replicas number to make sure scaling worked:
   
```sh ```sh
oc get rc gitlab-ce-2 oc get rc gitlab-ce-2
``` ```
   
which will return something like: which will return something like:
   
``` ```
NAME DESIRED CURRENT AGE NAME DESIRED CURRENT AGE
gitlab-ce-2 2 2 5d gitlab-ce-2 2 2 5d
``` ```
   
And that's it! We successfully scaled the replicas to 2 using the CLI. And that's it! We successfully scaled the replicas to 2 using the CLI.
   
Loading
@@ -469,9 +471,10 @@ GitLab service account to the `anyuid` [Security Context Constraints][scc].
Loading
@@ -469,9 +471,10 @@ GitLab service account to the `anyuid` [Security Context Constraints][scc].
For OpenShift v3.0, you will need to do this manually: For OpenShift v3.0, you will need to do this manually:
   
1. Edit the Security Context: 1. Edit the Security Context:
```sh
oc edit scc anyuid ```sh
``` oc edit scc anyuid
```
   
1. Add `system:serviceaccount:<project>:gitlab-ce-user` to the `users` section. 1. Add `system:serviceaccount:<project>:gitlab-ce-user` to the `users` section.
If you changed the Application Name from the default the user will If you changed the Application Name from the default the user will
Loading
Loading
Loading
@@ -2,7 +2,7 @@
Loading
@@ -2,7 +2,7 @@
   
To enable the Microsoft Azure OAuth2 OmniAuth provider you must register your application with Azure. Azure will generate a client ID and secret key for you to use. To enable the Microsoft Azure OAuth2 OmniAuth provider you must register your application with Azure. Azure will generate a client ID and secret key for you to use.
   
1. Sign in to the [Azure Management Portal](https://manage.windowsazure.com>). 1. Sign in to the [Azure Management Portal](https://manage.windowsazure.com).
   
1. Select "Active Directory" on the left and choose the directory you want to use to register GitLab. 1. Select "Active Directory" on the left and choose the directory you want to use to register GitLab.
   
Loading
Loading
Loading
@@ -24,11 +24,11 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
Loading
@@ -24,11 +24,11 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
   
1. Register your application in the OAuth2 provider you wish to authenticate with. 1. Register your application in the OAuth2 provider you wish to authenticate with.
   
The redirect URI you provide when registering the application should be: The redirect URI you provide when registering the application should be:
   
``` ```
http://your-gitlab.host.com/users/auth/oauth2_generic/callback http://your-gitlab.host.com/users/auth/oauth2_generic/callback
``` ```
   
1. You should now be able to get a Client ID and Client Secret. 1. You should now be able to get a Client ID and Client Secret.
Where this shows up will differ for each provider. Where this shows up will differ for each provider.
Loading
@@ -36,18 +36,18 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
Loading
@@ -36,18 +36,18 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
   
1. On your GitLab server, open the configuration file. 1. On your GitLab server, open the configuration file.
   
For Omnibus package: For Omnibus package:
   
```sh ```sh
sudo editor /etc/gitlab/gitlab.rb sudo editor /etc/gitlab/gitlab.rb
``` ```
   
For installations from source: For installations from source:
   
```sh ```sh
cd /home/git/gitlab cd /home/git/gitlab
sudo -u git -H editor config/gitlab.yml sudo -u git -H editor config/gitlab.yml
``` ```
   
1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings 1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings
   
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment