diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-07 12:09:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-07 12:09:51 +0300 |
commit | d8803c7e40bd35d883ef007ddc56907bd837a748 (patch) | |
tree | e65de9306d46d111222b03ef29aafbe57adf86ac /doc | |
parent | b6a92c969b16549683ef276f1db7ba9a41dc85bb (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'doc')
-rw-r--r-- | doc/api/graphql/reference/gitlab_schema.graphql | 42 | ||||
-rw-r--r-- | doc/api/graphql/reference/gitlab_schema.json | 104 | ||||
-rw-r--r-- | doc/development/README.md | 1 | ||||
-rw-r--r-- | doc/development/fe_guide/vue.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/vuex.md | 79 | ||||
-rw-r--r-- | doc/development/multi_version_compatibility.md | 62 | ||||
-rw-r--r-- | doc/development/pipelines.md | 3 |
7 files changed, 247 insertions, 46 deletions
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index c483743a303..9f08e8ebf58 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -4157,6 +4157,11 @@ type Group { first: Int """ + Returns only the projects which have vulnerabilities + """ + hasVulnerabilities: Boolean = false + + """ Include also subgroup projects """ includeSubgroups: Boolean = false @@ -4319,6 +4324,33 @@ enum HealthStatus { onTrack } +type InstanceSecurityDashboard { + """ + Projects selected in Instance Security Dashboard + """ + projects( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: String + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the last _n_ elements from the list. + """ + last: Int + ): ProjectConnection! +} + """ State of a GitLab issue or merge request """ @@ -6295,6 +6327,11 @@ type Namespace { first: Int """ + Returns only the projects which have vulnerabilities + """ + hasVulnerabilities: Boolean = false + + """ Include also subgroup projects """ includeSubgroups: Boolean = false @@ -8022,6 +8059,11 @@ type Query { ): Group """ + Fields related to Instance Security Dashboard + """ + instanceSecurityDashboard: InstanceSecurityDashboard + + """ Metadata about GitLab """ metadata: Metadata diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 661a7cec50c..1b6d719acd6 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -11539,6 +11539,16 @@ "defaultValue": "false" }, { + "name": "hasVulnerabilities", + "description": "Returns only the projects which have vulnerabilities", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + }, + { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { @@ -12026,6 +12036,76 @@ "possibleTypes": null }, { + "kind": "OBJECT", + "name": "InstanceSecurityDashboard", + "description": null, + "fields": [ + { + "name": "projects", + "description": "Projects selected in Instance Security Dashboard", + "args": [ + { + "name": "after", + "description": "Returns the elements in the list that come after the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "before", + "description": "Returns the elements in the list that come before the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": "Returns the first _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "last", + "description": "Returns the last _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "ProjectConnection", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { "kind": "SCALAR", "name": "Int", "description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", @@ -18704,6 +18784,16 @@ "defaultValue": "false" }, { + "name": "hasVulnerabilities", + "description": "Returns only the projects which have vulnerabilities", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + }, + { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { @@ -23716,6 +23806,20 @@ "deprecationReason": null }, { + "name": "instanceSecurityDashboard", + "description": "Fields related to Instance Security Dashboard", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "InstanceSecurityDashboard", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { "name": "metadata", "description": "Metadata about GitLab", "args": [ diff --git a/doc/development/README.md b/doc/development/README.md index 0dd00525e0c..22644b77c06 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -218,6 +218,7 @@ Complementary reads: - [Defining relations between files using projections](projections.md) - [Reference processing](./reference_processing.md) +- [Compatibility with multiple versions of the application running at the same time](multi_version_compatibility.md) ## Other GitLab Development Kit (GDK) guides diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index 83871f5c98e..ce5e14bfe87 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -321,7 +321,7 @@ One should apply to be a Vue.js expert by opening an MR when the Merge Request's - Deep understanding of Vue and Vuex reactivity - Vue and Vuex code are structured according to both official and our guidelines - Full understanding of testing a Vue and Vuex application -- Vuex code follows the [documented pattern](vuex.md#actions-pattern-request-and-receive-namespaces) +- Vuex code follows the [documented pattern](vuex.md#naming-pattern-request-and-receive-namespaces) - Knowledge about the existing Vue and Vuex applications and existing reusable components ## Vue 2 -> Vue 3 Migration diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md index ea59c3c7a2b..e7be67b8da5 100644 --- a/doc/development/fe_guide/vuex.md +++ b/doc/development/fe_guide/vuex.md @@ -86,71 +86,35 @@ You can use `mapState` to access state properties in the components. An action is a payload of information to send data from our application to our store. -An action is usually composed by a `type` and a `payload` and they describe what happened. -Enforcing that every change is described as an action lets us have a clear understanding of what is going on in the app. +An action is usually composed by a `type` and a `payload` and they describe what happened. Unlike [mutations](#mutationsjs), actions can contain asynchronous operations - that's why we always need to handle asynchronous logic in actions. -In this file, we will write the actions that will call the respective mutations: +In this file, we will write the actions that will call mutations for handling a list of users: ```javascript import * as types from './mutation_types'; import axios from '~/lib/utils/axios_utils'; import createFlash from '~/flash'; - export const requestUsers = ({ commit }) => commit(types.REQUEST_USERS); - export const receiveUsersSuccess = ({ commit }, data) => commit(types.RECEIVE_USERS_SUCCESS, data); - export const receiveUsersError = ({ commit }, error) => commit(types.RECEIVE_USERS_ERROR, error); - export const fetchUsers = ({ state, dispatch }) => { - dispatch('requestUsers'); + commit(types.REQUEST_USERS); axios.get(state.endpoint) - .then(({ data }) => dispatch('receiveUsersSuccess', data)) + .then(({ data }) => commit(types.RECEIVE_USERS_SUCCESS, data)) .catch((error) => { - dispatch('receiveUsersError', error) + commit(types.RECEIVE_USERS_ERROR, error) createFlash('There was an error') }); } - export const requestAddUser = ({ commit }) => commit(types.REQUEST_ADD_USER); - export const receiveAddUserSuccess = ({ commit }, data) => commit(types.RECEIVE_ADD_USER_SUCCESS, data); - export const receiveAddUserError = ({ commit }, error) => commit(types.REQUEST_ADD_USER_ERROR, error); - export const addUser = ({ state, dispatch }, user) => { - dispatch('requestAddUser'); + commit(types.REQUEST_ADD_USER); axios.post(state.endpoint, user) - .then(({ data }) => dispatch('receiveAddUserSuccess', data)) - .catch((error) => dispatch('receiveAddUserError', error)); + .then(({ data }) => commit(types.RECEIVE_ADD_USER_SUCCESS, data)) + .catch((error) => commit(types.REQUEST_ADD_USER_ERROR, error)); } ``` -#### Actions Pattern: `request` and `receive` namespaces - -When a request is made we often want to show a loading state to the user. - -Instead of creating an action to toggle the loading state and dispatch it in the component, -create: - -1. An action `requestSomething`, to toggle the loading state -1. An action `receiveSomethingSuccess`, to handle the success callback -1. An action `receiveSomethingError`, to handle the error callback -1. An action `fetchSomething` to make the request. - 1. In case your application does more than a `GET` request you can use these as examples: - - `POST`: `createSomething` - - `PUT`: `updateSomething` - - `DELETE`: `deleteSomething` - -The component MUST only dispatch the `fetchNamespace` action. Actions namespaced with `request` or `receive` should not be called from the component -The `fetch` action will be responsible to dispatch `requestNamespace`, `receiveNamespaceSuccess` and `receiveNamespaceError` - -By following this pattern we guarantee: - -1. All applications follow the same pattern, making it easier for anyone to maintain the code -1. All data in the application follows the same lifecycle pattern -1. Actions are contained and human friendly -1. Unit tests are easier -1. Actions are simple and straightforward - #### Dispatching actions To dispatch an action from a component, use the `mapActions` helper: @@ -181,6 +145,8 @@ Remember that actions only describe that something happened, they don't describe **Never commit a mutation directly from a component** +Instead, you should create an action that will commit a mutation. + ```javascript import * as types from './mutation_types'; @@ -210,6 +176,31 @@ Remember that actions only describe that something happened, they don't describe }; ``` +#### Naming Pattern: `REQUEST` and `RECEIVE` namespaces + +When a request is made we often want to show a loading state to the user. + +Instead of creating an mutation to toggle the loading state, we should: + +1. A mutation with type `REQUEST_SOMETHING`, to toggle the loading state +1. A mutation with type `RECEIVE_SOMETHING_SUCCESS`, to handle the success callback +1. A mutation with type `RECEIVE_SOMETHING_ERROR`, to handle the error callback +1. An action `fetchSomething` to make the request and commit mutations on mentioned cases + 1. In case your application does more than a `GET` request you can use these as examples: + - `POST`: `createSomething` + - `PUT`: `updateSomething` + - `DELETE`: `deleteSomething` + +As a result, we can dispatch the `fetchNamespace` action from the component and it will be responsible to commit `REQUEST_NAMESPACE`, `RECEIVE_NAMESPACE_SUCCESS` and `RECEIVE_NAMESPACE_ERROR` mutations. + +> Previously, we were dispatching actions from the `fetchNamespace` action instead of committing mutation, so please don't be confused if you find a different pattern in the older parts of the codebase. However, we encourage leveraging a new pattern whenever you write new Vuex stores + +By following this pattern we guarantee: + +1. All applications follow the same pattern, making it easier for anyone to maintain the code +1. All data in the application follows the same lifecycle pattern +1. Unit tests are easier + ### `getters.js` Sometimes we may need to get derived state based on store state, like filtering for a specific prop. diff --git a/doc/development/multi_version_compatibility.md b/doc/development/multi_version_compatibility.md new file mode 100644 index 00000000000..aedd5c1ffb7 --- /dev/null +++ b/doc/development/multi_version_compatibility.md @@ -0,0 +1,62 @@ +# Compatibility with multiple versions of the application running at the same time + +When adding or changing features, we must be aware that there may be multiple versions of the application running +at the same time and connected to the same PostgreSQL and Redis databases. This could happen during a rolling deploy +when the servers are updated one by one. + +During a rolling deploy, post-deployment DB migrations are run after all the servers have been updated. This means the +servers could be in these intermediate states: + +1. Old application code running with new DB migrations already executed +1. New application code running with new DB migrations but without new post-deployment DB migrations + +We must make sure that the application works properly in these states. + +For GitLab.com, we also run a set of canary servers which run a more recent version of the application. Users with +the canary cookie set would be handled by these servers. Some URL patterns may also be forced to the canary servers, +even without the cookie being set. This also means that some pages may match the pattern and get handled by canary servers, +but AJAX requests to URLs (like the GraphQL endpoint) won't match the pattern. + +With this canary setup, we'd be in this mixed-versions state for an extended period of time until canary is promoted to +production and post-deployment migrations run. + +## Examples of previous incidents + +### Some links to issues and MRs were broken + +When we moved MR routes, users on the new servers were redirected to the new URLs. When these users shared these new URLs in +Markdown (or anywhere else), they were broken links for users on the old servers. + +For more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/118840). + +### Stale cache in issue or merge request descriptions and comments + +We bumped the Markdown cache version and found a bug when a user edited a description or comment which was generated from a different Markdown +cache version. The cached HTML wasn't generated properly after saving. In most cases, this wouldn't have happened because users would have +viewed the Markdown before clicking **Edit** and that would mean the Markdown cache is refreshed. But because we run mixed versions, this is +more likely to happen. Another user on a different version could view the same page and refresh the cache to the other version behind the scenes. + +For more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/208255). + +### Project service templates incorrectly copied + +We changed the column which indicates whether a service is a template. When we create services, we copy attributes from the template +and set this column to `false`. The old servers were still updating the old column, but that was fine because we had a DB trigger +that updated the new column from the old one. For the new servers though, they were only updating the new column and that same trigger +was now working against us and setting it back to the wrong value. + +For more information, see [the relevant issue](https://gitlab.com/gitlab-com/gl-infra/infrastructure/-/issues/9176). + +### Sidebar wasn't loading for some users + +We changed the data type of one GraphQL field. When a user opened an issue page from the new servers and the GraphQL AJAX request went +to the old servers, a type mismatch happened, which resulted in a JavaScript error that prevented the sidebar from loading. + +For more information, see [the relevant issue](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/1772). + +### CI artifact uploads were failing + +We added a `NOT NULL` constraint to a column and marked it as a `NOT VALID` constraint so that it is not enforced on existing rows. +But even with that, this was still a problem because the old servers were still inserting new rows with null values. + +For more information, see [the relevant issue](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/1944). diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md index 701262dbf1f..d15ac8d5320 100644 --- a/doc/development/pipelines.md +++ b/doc/development/pipelines.md @@ -132,6 +132,7 @@ and included in `rules` definitions via [YAML anchors](../ci/yaml/README.md#anch | `changes:` patterns | Description | |------------------------------|--------------------------------------------------------------------------| +| `ci-patterns` | Only create job for CI config-related changes. | | `yaml-patterns` | Only create job for YAML-related changes. | | `docs-patterns` | Only create job for docs-related changes. | | `frontend-dependency-patterns` | Only create job when frontend dependencies are updated (i.e. `package.json`, and `yarn.lock`). changes. | @@ -384,7 +385,7 @@ graph RL; subgraph "Needs `gitlab:assets:compile`"; 2_3-1 --> 1-5 end - + subgraph "Needs `build-qa-image` & `build-assets-image`"; 2_4-1["package-and-qa (manual)"] --> 1-2 & 2_3-1; click 2_4-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914305&udv=0" |