@@ -135,15 +135,15 @@ created in snippets, wikis, and repos.
...
@@ -135,15 +135,15 @@ created in snippets, wikis, and repos.
-[Monitoring GitLab](monitoring/index.md):
-[Monitoring GitLab](monitoring/index.md):
-[Monitoring uptime](../user/admin_area/monitoring/health_check.md): Check the server status using the health check endpoint.
-[Monitoring uptime](../user/admin_area/monitoring/health_check.md): Check the server status using the health check endpoint.
-[IP whitelist](monitoring/ip_whitelist.md): Monitor endpoints that provide health check information when probed.
-[IP whitelist](monitoring/ip_whitelist.md): Monitor endpoints that provide health check information when probed.
-[Monitoring GitHub imports](monitoring/github_imports.md): GitLab's GitHub Importer displays Prometheus metrics to monitor the health and progress of the importer.
-[Monitoring GitHub imports](monitoring/github_imports.md): GitLab's GitHub Importer displays Prometheus metrics to monitor the health and progress of the importer.
-[GitLab performance monitoring with InfluxDB](monitoring/performance/influxdb_configuration.md): Configure GitLab and InfluxDB for measuring performance metrics.
-[GitLab performance monitoring with InfluxDB](monitoring/performance/influxdb_configuration.md): Configure GitLab and InfluxDB for measuring performance metrics.
-[InfluxDB Schema](monitoring/performance/influxdb_schema.md): Measurements stored in InfluxDB.
-[InfluxDB Schema](monitoring/performance/influxdb_schema.md): Measurements stored in InfluxDB.
-[GitLab performance monitoring with Prometheus](monitoring/prometheus/index.md): Configure GitLab and Prometheus for measuring performance metrics.
-[GitLab performance monitoring with Prometheus](monitoring/prometheus/index.md): Configure GitLab and Prometheus for measuring performance metrics.
-[GitLab performance monitoring with Grafana](monitoring/performance/grafana_configuration.md): Configure GitLab to visualize time series metrics through graphs and dashboards.
-[GitLab performance monitoring with Grafana](monitoring/performance/grafana_configuration.md): Configure GitLab to visualize time series metrics through graphs and dashboards.
-[Request Profiling](monitoring/performance/request_profiling.md): Get a detailed profile on slow requests.
-[Request Profiling](monitoring/performance/request_profiling.md): Get a detailed profile on slow requests.
You can also use the `uml::` directive for compatibility with [sphinxcontrib-plantuml](https://pypi.python.org/pypi/sphinxcontrib-plantuml), but please note that we currently only support the `caption` option.
You can also use the `uml::` directive for compatibility with [sphinxcontrib-plantuml](https://pypi.python.org/pypi/sphinxcontrib-plantuml), but please note that we currently only support the `caption` option.
- Prometheus and the various exporters listed in this page are bundled in the
> - Prometheus and the various exporters listed in this page are bundled in the
Omnibus GitLab package. Check each exporter's documentation for the timeline
> Omnibus GitLab package. Check each exporter's documentation for the timeline
they got added. For installations from source you will have to install them
> they got added. For installations from source you will have to install them
yourself. Over subsequent releases additional GitLab metrics will be captured.
> yourself. Over subsequent releases additional GitLab metrics will be captured.
- Prometheus services are on by default with GitLab 9.0.
> - Prometheus services are on by default with GitLab 9.0.
- Prometheus and its exporters do not authenticate users, and will be available
> - Prometheus and its exporters do not authenticate users, and will be available
to anyone who can access them.
> to anyone who can access them.
[Prometheus] is a powerful time-series monitoring service, providing a flexible
[Prometheus] is a powerful time-series monitoring service, providing a flexible
platform for monitoring GitLab and other software products.
platform for monitoring GitLab and other software products.
...
@@ -107,7 +107,7 @@ Sample Prometheus queries:
...
@@ -107,7 +107,7 @@ Sample Prometheus queries:
> Introduced in GitLab 9.0.
> Introduced in GitLab 9.0.
> Pod monitoring introduced in GitLab 9.4.
> Pod monitoring introduced in GitLab 9.4.
If your GitLab server is running within Kubernetes, Prometheus will collect metrics from the Nodes and [annotated Pods](https://prometheus.io/docs/operating/configuration/#<kubernetes_sd_config>) in the cluster, including performance data on each container. This is particularly helpful if your CI/CD environments run in the same cluster, as you can use the [Prometheus project integration][] to monitor them.
If your GitLab server is running within Kubernetes, Prometheus will collect metrics from the Nodes and [annotated Pods](https://prometheus.io/docs/operating/configuration/#kubernetes_sd_config) in the cluster, including performance data on each container. This is particularly helpful if your CI/CD environments run in the same cluster, as you can use the [Prometheus project integration][] to monitor them.
@@ -119,28 +120,28 @@ If you are using AWS IAM profiles, be sure to omit the AWS access key and secret
...
@@ -119,28 +120,28 @@ If you are using AWS IAM profiles, be sure to omit the AWS access key and secret
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
1. Migrate any existing local uploads to the object storage:
1. Migrate any existing local uploads to the object storage:
>**Notes:**
> **Notes:**
These task complies with the `BATCH` environment variable to process uploads in batch (200 by default). All of the processing will be done in a background worker and requires **no downtime**.
> These task complies with the `BATCH` environment variable to process uploads in batch (200 by default). All of the processing will be done in a background worker and requires **no downtime**.
@@ -167,32 +168,30 @@ _The uploads are stored by default in
...
@@ -167,32 +168,30 @@ _The uploads are stored by default in
1. Save the file and [restart GitLab][] for the changes to take effect.
1. Save the file and [restart GitLab][] for the changes to take effect.
1. Migrate any existing local uploads to the object storage:
1. Migrate any existing local uploads to the object storage:
>**Notes:**
> **Notes:**
> - These task comply with the `BATCH` environment variable to process uploads in batch (200 by default). All of the processing will be done in a background worker and requires **no downtime**.
- These task comply with the `BATCH` environment variable to process uploads in batch (200 by default). All of the processing will be done in a background worker and requires **no downtime**.
> - To migrate in production use `RAILS_ENV=production` environment variable.
- To migrate in production use `RAILS_ENV=production` environment variable.
@@ -76,8 +76,8 @@ Below are the changes made between V3 and V4.
...
@@ -76,8 +76,8 @@ Below are the changes made between V3 and V4.
- Simplify project payload exposed on Environment endpoints [!9675](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9675)
- Simplify project payload exposed on Environment endpoints [!9675](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9675)
- API uses merge request `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the merge requests, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530)
- API uses merge request `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the merge requests, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530)
- API uses issue `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the issues, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530)
- API uses issue `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the issues, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530)
- Change initial page from `0` to `1` on `GET /projects/:id/repository/commits` (like on the rest of the API) [!9679](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
- Change initial page from `0` to `1` on `GET /projects/:id/repository/commits` (like on the rest of the API) [!9679](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
- Return correct `Link` header data for `GET /projects/:id/repository/commits` [!9679](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
- Return correct `Link` header data for `GET /projects/:id/repository/commits`[!9679](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
- Update endpoints for repository files [!9637](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9637)
- Update endpoints for repository files [!9637](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9637)
- Moved `GET /projects/:id/repository/files?file_path=:file_path` to `GET /projects/:id/repository/files/:file_path` (`:file_path` should be URL-encoded)
- Moved `GET /projects/:id/repository/files?file_path=:file_path` to `GET /projects/:id/repository/files/:file_path` (`:file_path` should be URL-encoded)
-`GET /projects/:id/repository/blobs/:sha` now returns JSON attributes for the blob identified by `:sha`, instead of finding the commit identified by `:sha` and returning the raw content of the blob in that commit identified by the required `?filepath=:filepath`
-`GET /projects/:id/repository/blobs/:sha` now returns JSON attributes for the blob identified by `:sha`, instead of finding the commit identified by `:sha` and returning the raw content of the blob in that commit identified by the required `?filepath=:filepath`
@@ -87,18 +87,18 @@ will later see, is exposed in various places within GitLab. Each time a job that
...
@@ -87,18 +87,18 @@ will later see, is exposed in various places within GitLab. Each time a job that
has an environment specified and succeeds, a deployment is recorded, remembering
has an environment specified and succeeds, a deployment is recorded, remembering
the Git SHA and environment name.
the Git SHA and environment name.
>**Note:**
>**Note:**
Starting with GitLab 8.15, the environment name is exposed to the Runner in
> Starting with GitLab 8.15, the environment name is exposed to the Runner in
two forms: `$CI_ENVIRONMENT_NAME`, and `$CI_ENVIRONMENT_SLUG`. The first is
> two forms: `$CI_ENVIRONMENT_NAME`, and `$CI_ENVIRONMENT_SLUG`. The first is
the name given in `.gitlab-ci.yml` (with any variables expanded), while the
> the name given in `.gitlab-ci.yml` (with any variables expanded), while the
second is a "cleaned-up" version of the name, suitable for use in URLs, DNS,
> second is a "cleaned-up" version of the name, suitable for use in URLs, DNS,
etc.
> etc.
>
>**Note:**
>**Note:**
Starting with GitLab 9.3, the environment URL is exposed to the Runner via
> Starting with GitLab 9.3, the environment URL is exposed to the Runner via
`$CI_ENVIRONMENT_URL`. The URL would be expanded from `.gitlab-ci.yml`, or if
> `$CI_ENVIRONMENT_URL`. The URL would be expanded from `.gitlab-ci.yml`, or if
the URL was not defined there, the external URL from the environment would be
> the URL was not defined there, the external URL from the environment would be
used.
> used.
To sum up, with the above `.gitlab-ci.yml` we have achieved that:
To sum up, with the above `.gitlab-ci.yml` we have achieved that:
...
@@ -134,14 +134,15 @@ There's a bunch of information there, specifically you can see:
...
@@ -134,14 +134,15 @@ There's a bunch of information there, specifically you can see:
- A button that re-deploys the latest deployment, meaning it runs the job
- A button that re-deploys the latest deployment, meaning it runs the job
defined by the environment name for that specific commit
defined by the environment name for that specific commit
>**Notes:**
> **Notes:**
- While you can create environments manually in the web interface, we recommend
>
that you define your environments in `.gitlab-ci.yml` first. They will
> - While you can create environments manually in the web interface, we recommend
be automatically created for you after the first deploy.
> that you define your environments in `.gitlab-ci.yml` first. They will
- The environments page can only be viewed by Reporters and above. For more
> be automatically created for you after the first deploy.
information on the permissions, see the [permissions documentation][permissions].
> - The environments page can only be viewed by Reporters and above. For more
- Only deploys that happen after your `.gitlab-ci.yml` is properly configured
> information on the permissions, see the [permissions documentation][permissions].
will show up in the "Environment" and "Last deployment" lists.
> - Only deploys that happen after your `.gitlab-ci.yml` is properly configured
> will show up in the "Environment" and "Last deployment" lists.
The information shown in the Environments page is limited to the latest
The information shown in the Environments page is limited to the latest
deployments, but as you may have guessed an environment can have multiple
deployments, but as you may have guessed an environment can have multiple
...
@@ -563,13 +564,13 @@ exist, you should see something like:
...
@@ -563,13 +564,13 @@ exist, you should see something like:
## Monitoring environments
## Monitoring environments
>**Notes:**
>**Notes:**
>
>
- For the monitoring dashboard to appear, you need to:
> - For the monitoring dashboard to appear, you need to:
- Have enabled the [Prometheus integration][prom]
> - Have enabled the [Prometheus integration][prom]
- Configured Prometheus to collect at least one [supported metric](../user/project/integrations/prometheus_library/metrics.md)
> - Configured Prometheus to collect at least one [supported metric](../user/project/integrations/prometheus_library/metrics.md)
- With GitLab 9.2, all deployments to an environment are shown directly on the
> - With GitLab 9.2, all deployments to an environment are shown directly on the
monitoring dashboard
> monitoring dashboard
If you have enabled [Prometheus for monitoring system and response metrics](https://docs.gitlab.com/ee/user/project/integrations/prometheus.html), you can monitor the performance behavior of your app running in each environment.
If you have enabled [Prometheus for monitoring system and response metrics](https://docs.gitlab.com/ee/user/project/integrations/prometheus.html), you can monitor the performance behavior of your app running in each environment.
There are a few rules to get your merge request accepted:
There are a few rules to get your merge request accepted:
1. Your merge request should only be **merged by a [maintainer][team]**.
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
1. If your merge request includes only backend changes [^1], it must be
**approved by a [backend maintainer][projects]**.
**approved by a [backend maintainer][projects]**.
1. If your merge request includes only frontend changes [^1], it must be
1. If your merge request includes only frontend changes [^1], it must be
**approved by a [frontend maintainer][projects]**.
**approved by a [frontend maintainer][projects]**.
1. If your merge request includes UX changes [^1], it must
1. If your merge request includes UX changes [^1], it must
be **approved by a [UX team member][team]**.
be **approved by a [UX team member][team]**.
1. If your merge request includes adding a new JavaScript library [^1], it must be
1. If your merge request includes adding a new JavaScript library [^1], it must be
**approved by a [frontend lead][team]**.
**approved by a [frontend lead][team]**.
1. If your merge request includes adding a new UI/UX paradigm [^1], it must be
1. If your merge request includes adding a new UI/UX paradigm [^1], it must be
**approved by a [UX lead][team]**.
**approved by a [UX lead][team]**.
1. If your merge request includes frontend and backend changes [^1], it must
1. If your merge request includes frontend and backend changes [^1], it must
be **approved by a [frontend and a backend maintainer][projects]**.
be **approved by a [frontend and a backend maintainer][projects]**.
1. If your merge request includes UX and frontend changes [^1], it must
1. If your merge request includes UX and frontend changes [^1], it must
be **approved by a [UX team member and a frontend maintainer][team]**.
be **approved by a [UX team member and a frontend maintainer][team]**.
1. If your merge request includes UX, frontend and backend changes [^1], it must
1. If your merge request includes UX, frontend and backend changes [^1], it must
be **approved by a [UX team member, a frontend and a backend maintainer][team]**.
be **approved by a [UX team member, a frontend and a backend maintainer][team]**.
1. If your merge request includes a new dependency or a filesystem change, it must
1. If your merge request includes a new dependency or a filesystem change, it must
be *approved by a [Distribution team member][team]*. See how to work with the [Distribution team for more details.](https://about.gitlab.com/handbook/engineering/dev-backend/distribution/)
be *approved by a [Distribution team member][team]*. See how to work with the [Distribution team for more details.](https://about.gitlab.com/handbook/engineering/dev-backend/distribution/)
1. To lower the amount of merge requests maintainers need to review, you can
1. To lower the amount of merge requests maintainers need to review, you can
ask or assign any [reviewers][projects] for a first review.
ask or assign any [reviewers][projects] for a first review.
1. If you need some guidance (e.g. it's your first merge request), feel free
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].
to ask one of the [Merge request coaches][team].
1. The reviewer will assign the merge request to a maintainer once the
1. The reviewer will assign the merge request to a maintainer once the
reviewer is satisfied with the state of the merge request.
reviewer is satisfied with the state of the merge request.
1. Keep in mind that maintainers are also going to perform a final code review.
1. Keep in mind that maintainers are also going to perform a final code review.
The ideal scenario is that the reviewer has already addressed any concerns
The ideal scenario is that the reviewer has already addressed any concerns
the maintainer would have found, and the maintainer only has to perform the
the maintainer would have found, and the maintainer only has to perform the
...
@@ -160,41 +160,41 @@ Enterprise Edition instance. This has some implications:
...
@@ -160,41 +160,41 @@ Enterprise Edition instance. This has some implications:
1.**Query changes** should be tested to ensure that they don't result in worse
1.**Query changes** should be tested to ensure that they don't result in worse
performance at the scale of GitLab.com:
performance at the scale of GitLab.com:
1. Generating large quantities of data locally can help.
1. Generating large quantities of data locally can help.
2. Asking for query plans from GitLab.com is the most reliable way to validate
2. Asking for query plans from GitLab.com is the most reliable way to validate
these.
these.
2.**Database migrations** must be:
2.**Database migrations** must be:
1. Reversible.
1. Reversible.
2. Performant at the scale of GitLab.com - ask a maintainer to test the
2. Performant at the scale of GitLab.com - ask a maintainer to test the
migration on the staging environment if you aren't sure.
migration on the staging environment if you aren't sure.
3. Categorised correctly:
3. Categorised correctly:
- Regular migrations run before the new code is running on the instance.
- Regular migrations run before the new code is running on the instance.
-[Post-deployment migrations](post_deployment_migrations.md) run _after_
-[Post-deployment migrations](post_deployment_migrations.md) run _after_
the new code is deployed, when the instance is configured to do that.
the new code is deployed, when the instance is configured to do that.
-[Background migrations](background_migrations.md) run in Sidekiq, and
-[Background migrations](background_migrations.md) run in Sidekiq, and
should only be done for migrations that would take an extreme amount of
should only be done for migrations that would take an extreme amount of
time at GitLab.com scale.
time at GitLab.com scale.
3.**Sidekiq workers**
3.**Sidekiq workers**
[cannot change in a backwards-incompatible way](sidekiq_style_guide.md#removing-or-renaming-queues):
[cannot change in a backwards-incompatible way](sidekiq_style_guide.md#removing-or-renaming-queues):
1. Sidekiq queues are not drained before a deploy happens, so there will be
1. Sidekiq queues are not drained before a deploy happens, so there will be
workers in the queue from the previous version of GitLab.
workers in the queue from the previous version of GitLab.
2. If you need to change a method signature, try to do so across two releases,
2. If you need to change a method signature, try to do so across two releases,
and accept both the old and new arguments in the first of those.
and accept both the old and new arguments in the first of those.
3. Similarly, if you need to remove a worker, stop it from being scheduled in
3. Similarly, if you need to remove a worker, stop it from being scheduled in
one release, then remove it in the next. This will allow existing jobs to
one release, then remove it in the next. This will allow existing jobs to
execute.
execute.
4. Don't forget, not every instance will upgrade to every intermediate version
4. Don't forget, not every instance will upgrade to every intermediate version
(some people may go from X.1.0 to X.10.0, or even try bigger upgrades!), so
(some people may go from X.1.0 to X.10.0, or even try bigger upgrades!), so
try to be liberal in accepting the old format if it is cheap to do so.
try to be liberal in accepting the old format if it is cheap to do so.
4.**Cached values** may persist across releases. If you are changing the type a
4.**Cached values** may persist across releases. If you are changing the type a
cached value returns (say, from a string or nil to an array), change the
cached value returns (say, from a string or nil to an array), change the
-[Label for community contributors](#label-for-community-contributors)
-[Label for community contributors](#label-for-community-contributors)
-[Issue triaging](#issue-triaging)
-[Issue triaging](#issue-triaging)
-[Feature proposals](#feature-proposals)
-[Feature proposals](#feature-proposals)
...
@@ -250,7 +250,7 @@ code snippet right after your description in a new line: `~"feature proposal"`.
...
@@ -250,7 +250,7 @@ code snippet right after your description in a new line: `~"feature proposal"`.
Please keep feature proposals as small and simple as possible, complex ones
Please keep feature proposals as small and simple as possible, complex ones
might be edited to make them small and simple.
might be edited to make them small and simple.
Please submit Feature Proposals using the ['Feature Proposal' issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/FeatureProposal.md) provided on the issue tracker.
Please submit Feature Proposals using the ['Feature Proposal' issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Feature%20Proposal.md) provided on the issue tracker.
For changes in the interface, it is helpful to include a mockup. Issues that add to, or change, the interface should
For changes in the interface, it is helpful to include a mockup. Issues that add to, or change, the interface should
be given the ~"UX" label. This will allow the UX team to provide input and guidance. You may
be given the ~"UX" label. This will allow the UX team to provide input and guidance. You may
@@ -17,74 +17,81 @@ at the top, but legacy files are a special case. Any time you develop a new fea
...
@@ -17,74 +17,81 @@ at the top, but legacy files are a special case. Any time you develop a new fea
refactor an existing one, you should abide by the eslint rules.
refactor an existing one, you should abide by the eslint rules.
1.**Never Ever EVER** disable eslint globally for a file
1.**Never Ever EVER** disable eslint globally for a file
```javascript
// bad
/* eslint-disable */
// better
/* eslint-disable some-rule, some-other-rule */
// best
```javascript
// nothing :)
// bad
```
/* eslint-disable */
// better
/* eslint-disable some-rule, some-other-rule */
// best
// nothing :)
```
1. 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 */
importFoofrom'foo';
newFoo();
// better
```javascript
importFoofrom'foo';
// bad
/* eslint-disable no-new */
import Foo from 'foo';
new Foo();
// better
import Foo from 'foo';
// eslint-disable-next-line no-new
new Foo();
```
// eslint-disable-next-line no-new
newFoo();
```
1. There are few rules that we need to disable due to technical debt. Which are:
1. There are few rules that we need to disable due to technical debt. Which are:
1.[no-new][eslint-new]
1. [no-new][eslint-new]
1.[class-methods-use-this][eslint-this]
1. [class-methods-use-this][eslint-this]
1. When they are needed _always_ place ESlint directive comment blocks on the first line of a script,
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.
followed by any global declarations, then a blank newline prior to any imports or code.
```javascript
// bad
/* global Foo */
/* eslint-disable no-new */
importBarfrom'./bar';
// good
/* eslint-disable no-new */
/* global Foo */
importBarfrom'./bar';
```javascript
```
// bad
/* global Foo */
/* eslint-disable no-new */
import Bar from './bar';
// good
/* eslint-disable no-new */
/* global Foo */
import Bar from './bar';
```
1. **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead.
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.
1. When declaring multiple globals, always use one `/* global [name] */` line per variable.
```javascript
// bad
/* globals Flash, Cookies, jQuery */
// good
```javascript
/* global Flash */
// bad
/* global Cookies */
/* globals Flash, Cookies, jQuery */
/* 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.
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){}
// good
```javascript
fn(options){}
// bad
```
fn(p1, p2, p3, p4) {}
// good
fn(options) {}
```
#### Modules, Imports, and Exports
#### Modules, Imports, and Exports
1. Use ES module syntax to import modules
1. Use ES module syntax to import modules
```javascript
```javascript
// bad
// bad
...
@@ -178,109 +185,116 @@ Do not use them anymore and feel free to remove them when refactoring legacy cod
...
@@ -178,109 +185,116 @@ Do not use them anymore and feel free to remove them when refactoring legacy cod
```
```
#### Data Mutation and Pure functions
#### Data Mutation and Pure functions
1. 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
```javascript
// bad
// bad
const values = {foo: 1};
const values = {foo: 1};
function impureFunction(items) {
function impureFunction(items) {
const bar = 1;
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
// good
var values = {foo: 1};
var values = {foo: 1};
function pureFunction (foo) {
function pureFunction (foo) {
var bar = 1;
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);
```
```
1. Avoid constructors with side-effects.
1. Avoid constructors with side-effects.
Although we aim for code without side-effects we need some side-effects for our code to run.
Although we aim for code without side-effects we need some side-effects for our code to run.
If the class won't do anything if we only instantiate it, it's ok to add side effects into the constructor (_Note:_ The following is just an example. If the only purpose of the class is to add an event listener and handle the callback a function will be more suitable.)
On the other hand, if a class only needs to extend a third party/add event listeners in some specific cases, they should be initialized outside of the constructor.
1. Prefer `.map`, `.reduce` or `.filter` over `.forEach`
If the class won't do anything if we only instantiate it, it's ok to add side effects into the constructor (_Note:_ The following is just an example. If the only purpose of the class is to add an event listener and handle the callback a function will be more suitable.)
A forEach will most likely cause side effects, it will be mutating the array being iterated. Prefer using `.map`,
On the other hand, if a class only needs to extend a third party/add event listeners in some specific cases, they should be initialized outside of the constructor.
constusersWithId=users.map((user,index)=>{
returnObject.assign({},user,{id:index});
1. Prefer `.map`, `.reduce` or `.filter` over `.forEach`
});
A forEach will most likely cause side effects, it will be mutating the array being iterated. Prefer using `.map`,
1. Follow these alignment styles for the template method:
1. Follow these alignment styles for the template method:
1. With more than one attribute, all attributes should be on a new line:
```javascript
// bad
<componentv-if="bar"
param="baz"/>
<buttonclass="btn">Clickme</button>
// good
<component
v-if="bar"
param="baz"
/>
<buttonclass="btn">
Clickme
</button>
```
1. The tag can be inline if there is only one attribute:
```javascript
// good
<componentbar="bar"/>
// good
<component
bar="bar"
/>
// bad
1. With more than one attribute, all attributes should be on a new line:
<component
bar="bar"/>
```javascript
```
// bad
<component v-if="bar"
param="baz" />
<button class="btn">Click me</button>
// good
<component
v-if="bar"
param="baz"
/>
<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"
/>
// bad
<component
bar="bar" />
```
#### Quotes
#### Quotes
1. 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
```javascript
template:`
// bad
<button :class="style">Button</button>
template: `
`
<button :class='style'>Button</button>
```
`
// good
template: `
<button :class="style">Button</button>
`
```
#### Props
#### Props
1. Props should be declared as an object
```javascript
// bad
props:['foo']
// good
1. Props should be declared as an object
props:{
```javascript
foo:{
// bad
type:String,
props: ['foo']
required:false,
default:'bar'
// good
props: {
foo: {
type: String,
required: false,
default: 'bar'
}
}
}
}
```
```
1. 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,
}
}
// good
```javascript
props:{
// bad
foo:{
props: {
type:String,
foo: {
required:false,
type: String,
default:'bar'
}
}
}
}
```
// good
props: {
foo: {
type: String,
required: false,
default: 'bar'
}
}
```
1. Default key should be provided if the prop is not required.
1. Default key should be provided if the prop is not required.
_Note:_ There are some scenarios where we need to check for the existence of the property.
_Note:_ There are some scenarios where we need to check for the existence of the property.
On those a default key should not be provided.
On those a default key should not be provided.
```javascript
// good
props:{
foo:{
type:String,
required:false,
}
}
// good
```javascript
props:{
// good
foo:{
props: {
type:String,
foo: {
required:false,
type: String,
default:'bar'
required: false,
}
}
}
}
// good
// good
props: {
props:{
foo: {
foo:{
type: String,
type:String,
required: false,
required:true
default: 'bar'
}
}
}
}
```
// good
props: {
foo: {
type: String,
required: true
}
}
```
#### Data
#### Data
1. `data` method should always be a function
1. `data` method should always be a function
```javascript
```javascript
...
@@ -502,38 +530,41 @@ On those a default key should not be provided.
...
@@ -502,38 +530,41 @@ On those a default key should not be provided.
#### Directives
#### Directives
1. Shorthand `@` is preferable over `v-on`
1. Shorthand `@` is preferable over `v-on`
```javascript
// bad
<componentv-on:click="eventHandler"/>
// good
```javascript
<component@click="eventHandler"/>
// bad
```
<component v-on:click="eventHandler"/>
// good
<component@click="eventHandler"/>
```
1. Shorthand `:` is preferable over `v-bind`
1. Shorthand `:` is preferable over `v-bind`
```javascript
// bad
<componentv-bind:class="btn"/>
// good
```javascript
<component:class="btn"/>
// bad
```
<componentv-bind:class="btn"/>
// good
<component:class="btsn"/>
```
#### Closing tags
#### Closing tags
1. Prefer self closing component tags
1. Prefer self closing component tags
```javascript
// bad
<component></component>
// good
```javascript
<component/>
// bad
```
<component></component>
// good
<component/>
```
#### Ordering
#### Ordering
1. Tag order in `.vue` file
1. Tag order in `.vue` file
```
```
<script>
<script>
// ...
// ...
...
@@ -550,12 +581,14 @@ On those a default key should not be provided.
...
@@ -550,12 +581,14 @@ On those a default key should not be provided.
```
```
1. Properties in a Vue Component:
1. Properties in a Vue Component:
Check [order of properties in components rule][vue-order].
Check [order of properties in components rule][vue-order].
#### `:key`
#### `:key`
When using `v-for` you need to provide a *unique*`:key` attribute for each item.
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:
1. If the elements of the array being iterated have an unique `id` it is advised to use it:
```html
```html
<div
<div
v-for="item in items"
v-for="item in items"
...
@@ -566,6 +599,7 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
...
@@ -566,6 +599,7 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
```
```
1. When the elements being iterated don't have a unique id, you can use the array index as the `:key` attribute
1. When the elements being iterated don't have a unique id, you can use the array index as the `:key` attribute
```html
```html
<div
<div
v-for="(item, index) in items"
v-for="(item, index) in items"
...
@@ -575,8 +609,8 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
...
@@ -575,8 +609,8 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
</div>
</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.
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
```html
<template v-for="(item, index) in items">
<template v-for="(item, index) in items">
<span :key="`span-${index}`"></span>
<span :key="`span-${index}`"></span>
...
@@ -585,64 +619,69 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
...
@@ -585,64 +619,69 @@ When using `v-for` you need to provide a *unique* `:key` attribute for each item
```
```
1. When dealing with nested `v-for` use the same guidelines as above.
1. When dealing with nested `v-for` use the same guidelines as above.
The goal of this accord is to make sure we are all on the same page.
The goal of this accord is to make sure we are all on the same page.
1. When writing Vue, you may not use jQuery in your application.
1. When writing Vue, you may not use jQuery in your application.
1. If you need to grab data from the DOM, you may query the DOM 1 time while bootstrapping your application to grab data attributes using `dataset`. You can do this without jQuery.
1. If you need to grab data from the DOM, you may query the DOM 1 time while bootstrapping your application to grab data attributes using `dataset`. You can do this without jQuery.
1. You may use a jQuery dependency in Vue.js following [this example from the docs](https://vuejs.org/v2/examples/select2.html).
1. You may use a jQuery dependency in Vue.js following [this example from the docs](https://vuejs.org/v2/examples/select2.html).
1. If an outside jQuery Event needs to be listen to inside the Vue application, you may use jQuery event listeners.
1. If an outside jQuery Event needs to be listen to inside the Vue application, you may use jQuery event listeners.
1. We will avoid adding new jQuery events when they are not required. Instead of adding new jQuery events take a look at [different methods to do the same task](https://vuejs.org/v2/api/#vm-emit).
1. We will avoid adding new jQuery events when they are not required. Instead of adding new jQuery events take a look at [different methods to do the same task](https://vuejs.org/v2/api/#vm-emit).
1. You may query the `window` object 1 time, while bootstrapping your application for application specific data (e.g. `scrollTo` is ok to access anytime). Do this access during the bootstrapping of your application.
1. You may query the `window` object 1 time, while bootstrapping your application for application specific data (e.g. `scrollTo` is ok to access anytime). Do this access during the bootstrapping of your application.
1. You may have a temporary but immediate need to create technical debt by writing code that does not follow our standards, to be refactored later. Maintainers need to be ok with the tech debt in the first place. An issue should be created for that tech debt to evaluate it further and discuss. In the coming months you should fix that tech debt, with it's priority to be determined by maintainers.
1. You may have a temporary but immediate need to create technical debt by writing code that does not follow our standards, to be refactored later. Maintainers need to be ok with the tech debt in the first place. An issue should be created for that tech debt to evaluate it further and discuss. In the coming months you should fix that tech debt, with it's priority to be determined by maintainers.
1. When creating tech debt you must write the tests for that code before hand and those tests may not be rewritten. e.g. jQuery tests rewritten to Vue tests.
1. When creating tech debt you must write the tests for that code before hand and those tests may not be rewritten. e.g. jQuery tests rewritten to Vue tests.
...
@@ -650,6 +689,7 @@ The goal of this accord is to make sure we are all on the same page.
...
@@ -650,6 +689,7 @@ The goal of this accord is to make sure we are all on the same page.
1. Once you have chosen a centralized state management solution you must use it for your entire application. i.e. Don't mix and match your state management solutions.
1. Once you have chosen a centralized state management solution you must use it for your entire application. i.e. Don't mix and match your state management solutions.
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.
@@ -12,158 +12,157 @@ You can run eslint locally by running `yarn eslint`
...
@@ -12,158 +12,157 @@ You can run eslint locally by running `yarn eslint`
<aname="avoid-foreach"></a><aname="1.1"></a>
<aname="avoid-foreach"></a><aname="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
<aname="limit-params"></a><aname="2.1"></a>
<aname="limit-params"></a><aname="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.
-[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.
- [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.
- [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-`
- [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**
@@ -146,10 +146,12 @@ Congrats, your GitLab database uses the right InnoDB tablespace format.
...
@@ -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.
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.
@@ -43,9 +43,9 @@ From the left side bar, hover over `Operations` and select `Kubernetes`, then cl
...
@@ -43,9 +43,9 @@ From the left side bar, hover over `Operations` and select `Kubernetes`, then cl
A few details from the EKS cluster will be required to connect it to GitLab.
A few details from the EKS cluster will be required to connect it to GitLab.
1. A valid Kubernetes certificate and token are needed to authenticate to the EKS cluster. A pair is created by default, which can be used. Open a shell and use `kubectl` to retrieve them:
1. A valid Kubernetes certificate and token are needed to authenticate to the EKS cluster. A pair is created by default, which can be used. Open a shell and use `kubectl` to retrieve them:
* List the secrets with `kubectl get secrets`, and one should named similar to `default-token-xxxxx`. Copy that token name for use below.
* List the secrets with `kubectl get secrets`, and one should named similar to `default-token-xxxxx`. Copy that token name for use below.
* Get the certificate with `kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 -D`
* Get the certificate with `kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 -D`
* Retrieve the token with `kubectl get secret <secret name> -o jsonpath="{['data']['token']}" | base64 -D`.
* Retrieve the token with `kubectl get secret <secret name> -o jsonpath="{['data']['token']}" | base64 -D`.
1. The API server endpoint is also required, so GitLab can connect to the cluster. This is displayed on the AWS EKS console, when viewing the EKS cluster details.
1. The API server endpoint is also required, so GitLab can connect to the cluster. This is displayed on the AWS EKS console, when viewing the EKS cluster details.
You now have all the information needed to connect the EKS cluster:
You now have all the information needed to connect the EKS cluster: