diff options
35 files changed, 705 insertions, 450 deletions
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index 529a0de696b..6551f47d3be 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -139,7 +139,7 @@ setup-test-env: rspec unit pg: <<: *rspec-metadata-pg - parallel: 20 + parallel: 25 rspec integration pg: <<: *rspec-metadata-pg @@ -152,7 +152,7 @@ rspec system pg: rspec unit pg-10: <<: *rspec-metadata-pg-10 <<: *only-schedules-master - parallel: 20 + parallel: 25 rspec integration pg-10: <<: *rspec-metadata-pg-10 diff --git a/.gitlab/issue_templates/Database Reviewer.md b/.gitlab/issue_templates/Database Reviewer.md deleted file mode 100644 index acbaf5c1965..00000000000 --- a/.gitlab/issue_templates/Database Reviewer.md +++ /dev/null @@ -1,34 +0,0 @@ -#### Database Reviewer Checklist - -Thank you for becoming a ~database reviewer! Please work on the list -below to complete your setup. For any question, reach out to #database -an mention `@abrandl`. - -- [ ] Change issue title to include your name: `Database Reviewer Checklist: Your Name` -- [ ] Review general [code review guide](https://docs.gitlab.com/ee/development/code_review.html) -- [ ] Review [database review documentation](https://about.gitlab.com/handbook/engineering/workflow/code-review/database.html) -- [ ] Familiarize with [migration helpers](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/database/migration_helpers.rb) and review usage in existing migrations -- [ ] Read [database migration style guide](https://docs.gitlab.com/ee/development/migration_style_guide.html) -- [ ] Familiarize with best practices in [database guides](https://docs.gitlab.com/ee/development/#database-guides) -- [ ] Watch [Optimising Rails Database Queries: Episode 1](https://www.youtube.com/watch?v=79GurlaxhsI) -- [ ] Read [Understanding EXPLAIN plans](https://docs.gitlab.com/ee/development/understanding_explain_plans.html) -- [ ] Review [database best practices](https://docs.gitlab.com/ee/development/#best-practices) -- [ ] Review how we use [database instances restored from a backup](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd) for testing and make sure you're set up to execute pipelines (check [README.md](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd/blob/master/README.md) and reach out to @abrandl since this is currently subject to being changed) -- [ ] Get yourself added to [`@gl-database`](https://gitlab.com/groups/gl-database/-/group_members) group and respond to @-mentions to the group (reach out to any maintainer on the group to get added). You will get TODOs on gitlab.com for group mentions. -- [ ] Make sure you have proper access to at least a read-only replica in staging and production -- [ ] Indicate in `data/team.yml` your role as a database reviewer ([example MR](https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/19600/diffs)). Assign MR to your manager for merge. -- [ ] Send one MR to improve the [review documentation](https://about.gitlab.com/handbook/engineering/workflow/code-review/database.html) or the [issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Database%20Reviewer.md) - -Note that *approving and accepting* merge requests is *restricted* to -Database Maintainers only. As a reviewer, pass the MR to a maintainer -for approval. - -You're all set! Watch out for TODOs on GitLab.com. - -###### Where to go for questions? - -Reach out to `#database` on Slack and mention `@abrandl` for any questions. - -cc @abrandl - -/label ~meta ~database diff --git a/Dangerfile b/Dangerfile index d0a605f8d8e..094d55e8652 100644 --- a/Dangerfile +++ b/Dangerfile @@ -19,4 +19,5 @@ unless helper.release_automation? danger.import_dangerfile(path: 'danger/single_codebase') danger.import_dangerfile(path: 'danger/gitlab_ui_wg') danger.import_dangerfile(path: 'danger/ce_ee_vue_templates') + danger.import_dangerfile(path: 'danger/only_documentation') end diff --git a/PROCESS.md b/PROCESS.md index 07b150ea463..22b68b0aaca 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -84,43 +84,28 @@ star, smile, etc.). Some good tips about code reviews can be found in our [Code Review Guidelines]: https://docs.gitlab.com/ce/development/code_review.html -## Feature freeze on the 7th for the release on the 22nd - -The feature freeze on the 7th has been discontinued. The [transition period overview](https://gitlab.com/gitlab-org/release/docs/blob/21cbd409dd5f157fe252f254f3e897f01908abe2/general/deploy/auto-deploy-transition.md#transition) -describes the change to this process. During the transition period, the only guarantee that -a change will be included in the release on the 22nd is if the change has been -deployed to GitLab.com prior to this date. +## Feature flags -### Feature flags +Overview and details of feature flag processes in development of GitLab itself is described in [feature flags process documentation](https://docs.gitlab.com/ee/development/feature_flags/process.html). -Merge requests that make changes hidden behind a feature flag, or remove an -existing feature flag because a feature is deemed stable, may be merged (and -picked into the stable branches) up to the 19th of the month. Such merge -requests should have the ~"feature flag" label assigned, and don't require a -corresponding exception request to be created. +Guides on how to include feature flags in your backend/frontend code while developing GitLab are described in [developing with feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags/developing.html). -A level of common sense should be applied when deciding whether to have a feature -behind a feature flag off or on by default. +Getting access and how to expose the feature to users is detailed in [controlling feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags/controls.html). -The following guidelines can be applied to help make this decision: +## Feature proposals from the 22nd to the 1st -* If the feature is not fully ready or functioning, the feature flag should be disabled by default. -* If the feature is ready but there are concerns about performance or impact, the feature flag should be enabled by default, but -disabled via chatops before deployment on GitLab.com environments. If the performance concern is confirmed, the final release should have the feature flag disabled by default. -* In most other cases, the feature flag can be enabled by default. +To allow the Product and Engineering teams time to discuss issues that will be placed into an upcoming milestone, +Product Managers must have their proposal for that milestone ready by the 22nd of each month. -For more information on rolling out changes using feature flags, read [through the documentation](https://docs.gitlab.com/ee/development/rolling_out_changes_using_feature_flags.html). +This proposal will be shared with Engineering for discussion, feedback, and planning. +The plan for the upcoming milestone must be finalized by the 1st of the month, one week before kickoff on the 8th. -In order to build the final package and present the feature for self-hosted -customers, the feature flag should be removed. This should happen before the -22nd, ideally _at least_ 2 days before. That means MRs with feature -flags being picked at the 19th would have quite a tight schedule, so picking -these _earlier_ is preferable. +## Feature freeze on the 7th for the release on the 22nd -While rare, release managers may decide to reject picking a change into a stable -branch, even when feature flags are used. This might be necessary if the changes -are deemed problematic, too invasive, or there simply isn't enough time to -properly test how the changes behave on GitLab.com. +The feature freeze on the 7th has been discontinued. [Transition period overview](https://gitlab.com/gitlab-org/release/docs/blob/21cbd409dd5f157fe252f254f3e897f01908abe2/general/deploy/auto-deploy-transition.md#transition) +describes the change to this process. During the transition period, the only guarantee that +a change will be included in the release on the 22nd is if the change has been +deployed to GitLab.com prior to this date. ### Between the 1st and the 7th diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue index 9a3ce5174db..81773bd140e 100644 --- a/app/assets/javascripts/monitoring/components/charts/area.vue +++ b/app/assets/javascripts/monitoring/components/charts/area.vue @@ -1,5 +1,6 @@ <script> import { __ } from '~/locale'; +import { GlLink } from '@gitlab/ui'; import { GlAreaChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts'; import dateFormat from 'dateformat'; import { debounceByAnimationFrame, roundOffFloat } from '~/lib/utils/common_utils'; @@ -14,6 +15,7 @@ export default { components: { GlAreaChart, GlChartSeriesLabel, + GlLink, Icon, }, inheritAttrs: false, @@ -44,6 +46,10 @@ export default { required: false, default: () => [], }, + projectPath: { + type: String, + required: true, + }, thresholds: { type: Array, required: false, @@ -55,6 +61,7 @@ export default { tooltip: { title: '', content: [], + commitUrl: '', isDeployment: false, sha: '', }, @@ -195,12 +202,13 @@ export default { this.tooltip.title = dateFormat(params.value, 'dd mmm yyyy, h:MMTT'); this.tooltip.content = []; params.seriesData.forEach(seriesData => { - if (seriesData.componentSubType === graphTypes.deploymentData) { - this.tooltip.isDeployment = true; + this.tooltip.isDeployment = seriesData.componentSubType === graphTypes.deploymentData; + if (this.tooltip.isDeployment) { const [deploy] = this.recentDeployments.filter( deployment => deployment.createdAt === seriesData.value[0], ); this.tooltip.sha = deploy.sha.substring(0, 8); + this.tooltip.commitUrl = deploy.commitUrl; } else { const { seriesName, color } = seriesData; // seriesData.value contains the chart's [x, y] value pair @@ -259,7 +267,7 @@ export default { </template> <div slot="tooltipContent" class="d-flex align-items-center"> <icon name="commit" class="mr-2" /> - {{ tooltip.sha }} + <gl-link :href="tooltip.commitUrl">{{ tooltip.sha }}</gl-link> </div> </template> <template v-else> diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 23687c54fd3..2cbda8ea05d 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -359,6 +359,7 @@ export default { <monitor-area-chart v-for="(graphData, graphIndex) in chartsWithData(groupData.metrics)" :key="graphIndex" + :project-path="projectPath" :graph-data="graphData" :deployment-data="deploymentData" :thresholds="getGraphAlertValues(graphData.queries)" diff --git a/app/assets/javascripts/notes/components/discussion_notes.vue b/app/assets/javascripts/notes/components/discussion_notes.vue index 228bb652597..30971ad5227 100644 --- a/app/assets/javascripts/notes/components/discussion_notes.vue +++ b/app/assets/javascripts/notes/components/discussion_notes.vue @@ -105,8 +105,8 @@ export default { :commit="commit" :help-page-path="helpPagePath" :show-reply-button="userCanReply" - @handle-delete-note="$emit('deleteNote')" - @start-replying="$emit('startReplying')" + @handleDeleteNote="$emit('deleteNote')" + @startReplying="$emit('startReplying')" > <note-edited-text v-if="discussion.resolved" @@ -132,7 +132,7 @@ export default { :note="componentData(note)" :help-page-path="helpPagePath" :line="line" - @handle-delete-note="$emit('deleteNote')" + @handleDeleteNote="$emit('deleteNote')" /> </template> </template> @@ -144,7 +144,7 @@ export default { :note="componentData(note)" :help-page-path="helpPagePath" :line="diffLine" - @handle-delete-note="$emit('deleteNote')" + @handleDeleteNote="$emit('deleteNote')" > <slot v-if="index === 0" slot="avatar-badge" name="avatar-badge"></slot> </component> diff --git a/app/assets/javascripts/reports/components/report_item.vue b/app/assets/javascripts/reports/components/report_item.vue index 01a30809e1a..2be9c37b00a 100644 --- a/app/assets/javascripts/reports/components/report_item.vue +++ b/app/assets/javascripts/reports/components/report_item.vue @@ -1,6 +1,6 @@ <script> import IssueStatusIcon from '~/reports/components/issue_status_icon.vue'; -import { components, componentNames } from '~/reports/components/issue_body'; +import { components, componentNames } from 'ee_else_ce/reports/components/issue_body'; export default { name: 'ReportItem', diff --git a/app/models/postgresql/replication_slot.rb b/app/models/postgresql/replication_slot.rb index 74ccf23cf69..7a123deb719 100644 --- a/app/models/postgresql/replication_slot.rb +++ b/app/models/postgresql/replication_slot.rb @@ -28,7 +28,7 @@ module Postgresql # We force the use of a transaction here so the query always goes to the # primary, even when using the EE DB load balancer. sizes = transaction { pluck(lag_function) } - too_great = sizes.count { |size| size >= max } + too_great = sizes.compact.count { |size| size >= max } # If too many replicas are falling behind too much, the availability of a # GitLab instance might suffer. To prevent this from happening we require diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml index 13847cd9be1..576ec3e1782 100644 --- a/app/views/shared/projects/_list.html.haml +++ b/app/views/shared/projects/_list.html.haml @@ -28,7 +28,7 @@ .js-projects-list-holder - if any_projects?(projects) - - load_pipeline_status(projects) + - load_pipeline_status(projects) if pipeline_status %ul.projects-list{ class: css_classes } - projects.each_with_index do |project, i| - css_class = (i >= projects_limit) || project.pending_delete? ? 'hide' : nil diff --git a/changelogs/unreleased/11888-regression-deploy-correlation-markers-on-monitoring-graphs-not-clickable.yml b/changelogs/unreleased/11888-regression-deploy-correlation-markers-on-monitoring-graphs-not-clickable.yml new file mode 100644 index 00000000000..606abe818b4 --- /dev/null +++ b/changelogs/unreleased/11888-regression-deploy-correlation-markers-on-monitoring-graphs-not-clickable.yml @@ -0,0 +1,5 @@ +--- +title: Turn commit sha in monitor charts popover to link +merge_request: 29914 +author: +type: fixed diff --git a/changelogs/unreleased/63200-reply-button-broken.yml b/changelogs/unreleased/63200-reply-button-broken.yml new file mode 100644 index 00000000000..11f81dbd925 --- /dev/null +++ b/changelogs/unreleased/63200-reply-button-broken.yml @@ -0,0 +1,5 @@ +--- +title: Fix unresponsive reply button in discussions +merge_request: 29936 +author: +type: fixed diff --git a/changelogs/unreleased/po-raw-changes-encoding.yml b/changelogs/unreleased/po-raw-changes-encoding.yml new file mode 100644 index 00000000000..051d18f50c7 --- /dev/null +++ b/changelogs/unreleased/po-raw-changes-encoding.yml @@ -0,0 +1,5 @@ +--- +title: Expect bytes from Gitaly RPC GetRawChanges +merge_request: 28164 +author: +type: fixed diff --git a/changelogs/unreleased/sh-avoid-loading-pipeline-status.yml b/changelogs/unreleased/sh-avoid-loading-pipeline-status.yml new file mode 100644 index 00000000000..2dead948786 --- /dev/null +++ b/changelogs/unreleased/sh-avoid-loading-pipeline-status.yml @@ -0,0 +1,5 @@ +--- +title: Avoid loading pipeline status in search results +merge_request: 30111 +author: +type: performance diff --git a/changelogs/unreleased/sh-handle-nil-replication-lag.yml b/changelogs/unreleased/sh-handle-nil-replication-lag.yml new file mode 100644 index 00000000000..5638d7e79e3 --- /dev/null +++ b/changelogs/unreleased/sh-handle-nil-replication-lag.yml @@ -0,0 +1,5 @@ +--- +title: Fix background migrations failing with unused replication slot +merge_request: 30042 +author: +type: fixed diff --git a/danger/only_documentation/Dangerfile b/danger/only_documentation/Dangerfile new file mode 100644 index 00000000000..8e4564f22b6 --- /dev/null +++ b/danger/only_documentation/Dangerfile @@ -0,0 +1,24 @@ +# rubocop:disable Style/SignalException +# frozen_string_literal: true + +has_only_docs_changes = helper.all_changed_files.all? { |file| file.start_with?('doc/') } +is_docs_only_branch = gitlab.branch_for_head =~ /(^docs[\/-].*|.*-docs$)/ + +if is_docs_only_branch && !has_only_docs_changes + fail "It seems like your branch name has a `docs` prefix or suffix. "\ + "The CI won't run the full pipeline, but you also have changed non-docs files. "\ + "Please recreate this MR with a new branch name." +end + +if has_only_docs_changes && !is_docs_only_branch + markdown(<<~MARKDOWN) + + ## Documentation only changes + + Hey! Seems your merge request contains only docs changes. + Tired of waiting 2 hours for the pipeline to finish? + Next time, prepend `docs-` to [your branch name](https://docs.gitlab.com/ee/development/documentation/#branch-naming) + and the pipeline will finish before you say GitLab (x300)! + + MARKDOWN +end diff --git a/doc/development/chatops_on_gitlabcom.md b/doc/development/chatops_on_gitlabcom.md index c63ec53414c..a7b402c3fb0 100644 --- a/doc/development/chatops_on_gitlabcom.md +++ b/doc/development/chatops_on_gitlabcom.md @@ -1,12 +1,13 @@ # Chatops on GitLab.com -Chatops on GitLab.com allows GitLabbers to run various automation tasks on GitLab.com using Slack. +ChatOps on GitLab.com allows GitLab team members to run various automation tasks on GitLab.com using Slack. ## Requesting access -GitLabbers may need access to Chatops on GitLab.com for administration tasks such as: +GitLab team-members may need access to Chatops on GitLab.com for administration +tasks such as: -- Configuring feature flags on staging. +- Configuring feature flags. - Running `EXPLAIN` queries against the GitLab.com production replica. To request access to Chatops on GitLab.com: @@ -18,4 +19,4 @@ To request access to Chatops on GitLab.com: - [Chatops Usage](https://docs.gitlab.com/ee/ci/chatops/README.html) - [Understanding EXPLAIN plans](understanding_explain_plans.md) - - [Feature Groups](feature_flags.md#feature-groups) + - [Feature Groups](feature_flags/development.md#feature-groups) diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md index ff6dc16d1a0..7cd3d82ec4e 100644 --- a/doc/development/documentation/styleguide.md +++ b/doc/development/documentation/styleguide.md @@ -100,6 +100,13 @@ use regular Markdown markup, following the rules in the linked style guide. Note that Kramdown-specific markup (e.g., `{:.class}`) will not render properly on GitLab instances under [`/help`](index.md#gitlab-help). +Hard-coded HTML is valid, although it's discouraged to be used while we have `/help`. HTML is permitted as long as: + +- There's no equivalent markup in markdown. +- Advanced tables are necessary. +- Special styling is required. +- Reviewed and approved by a technical writer. + ## Structure ### Organize by topic, not by type @@ -143,7 +150,8 @@ The table below shows what kind of documentation goes where. a proper naming would be `import_projects_from_github.md`. The same rule applies to images. 1. For image files, do not exceed 100KB. -1. We do not yet support embedded videos. Please link out. +1. Do not upload video files to the product repositories. +[Link or embed videos](#videos) instead. 1. There are four main directories, `user`, `administration`, `api` and `development`. 1. The `doc/user/` directory has five main subdirectories: `project/`, `group/`, `profile/`, `dashboard/` and `admin_area/`. @@ -207,6 +215,7 @@ Do not include the same information in multiple places. [Link to a SSOT instead. ## Text +- [Write in markdown](#markdown). - Splitting long lines (preferably up to 100 characters) can make it easier to provide feedback on small chunks of text. - Insert an empty line for new paragraphs. - Use sentence case for titles, headings, labels, menu items, and buttons. @@ -430,7 +439,7 @@ To indicate the steps of navigation through the UI: - Images should be used (only when necessary) to _illustrate_ the description of a process, not to _replace_ it. - Max image size: 100KB (gifs included). -- The GitLab docs do not support videos yet. +- See also how to link and embed [videos](#videos) to illustrate the docs. Inside the document: @@ -455,6 +464,85 @@ directly to an HTML `img` tag: <img src="path/to/image.jpg" alt="Alt text (required)" class="image-noshadow"> ``` +## Videos + +Adding GitLab's existing YouTube video tutorials to the documentation is +highly encouraged, unless the video is outdated. Videos should not +replace documentation, but complement or illustrate it. If content in a video is +fundamental to a feature and its key use cases, but this is not adequately covered in the documentation, +add this detail to the documentation text or create an issue to review the video and do so. + +Do not upload videos to the product repositories. [Link](#link-to-video) or [embed](#embed-videos) them instead. + +### Link to video + +To link out to a video, include a YouTube icon so that readers can +quickly and easily scan the page for videos before reading: + +```md +<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> +For an overview, see [Video Title](link-to-video). +``` + +You can link any up-to-date video that is useful to the GitLab user. + +### Embed videos + +> [Introduced](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/472) in GitLab 12.1. + +GitLab docs (docs.gitlab.com) support embedded videos. + +You can only embed videos from +[GitLab's official YouTube account](https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg). +For videos from other sources, [link](#link-to-video) them instead. + +In most cases, it is better to [link to video](#link-to-video) instead, +because an embed takes up a lot of space on the page and can be distracting +to readers. + +To embed a video, follow the instructions below and make sure +you have your MR reviewed and approved by a technical writer. + +1. Copy the code below and paste it into your markdown file. + Leave a blank line above and below it. Do NOT edit the code + (don't remove or add any spaces, etc). +1. On YouTube, visit the video URL you want to display. Copy + the regular URL from your browser (`https://www.youtube.com/watch?v=VIDEO-ID`) + and replace the video title and link in the line under `<div class="video-fallback">`. +1. On YouTube, click **Share**, then **Embed**. +1. Copy the `<iframe>` source (`src`) **URL only** + (`https://www.youtube.com/embed/VIDEO-ID`), + and paste it, replacing the content of the `src` field in the + `iframe` tag. + +```html +leave a blank line here +<div class="video-fallback"> + See the video: [Video title](https://www.youtube.com/watch?v=MqL6BMOySIQ). +</div> +<figure class="video-container"> + <iframe src="https://www.youtube.com/embed/MqL6BMOySIQ" frameborder="0" allowfullscreen="true"> </iframe> +</figure> +leave a blank line here +``` + +This is how it renders on docs.gitlab.com: + +<div class="video-fallback"> + See the video: [What is GitLab](https://www.youtube.com/watch?v=enMumwvLAug). +</div> +<figure class="video-container"> + <iframe src="https://www.youtube.com/embed/MqL6BMOySIQ" frameborder="0" allowfullscreen="true"> </iframe> +</figure> + +> Notes: +> +> - The `figure` tag is required for semantic SEO and the `video_container` +class is necessary to make sure the video is responsive and displays +nicely on different mobile devices. +> - The `<div class="video-fallback">` is a fallback necessary for GitLab's +`/help`, as GitLab's markdown processor does not support iframes. It's hidden on the docs site but will be displayed on GitLab's `/help`. + ## Code blocks - Always wrap code added to a sentence in inline code blocks (``` ` ```). diff --git a/doc/development/fe_guide/accessibility.md b/doc/development/fe_guide/accessibility.md index df32242a522..64c793cfd64 100644 --- a/doc/development/fe_guide/accessibility.md +++ b/doc/development/fe_guide/accessibility.md @@ -5,8 +5,16 @@ [Chrome Accessibility Developer Tools][chrome-accessibility-developer-tools] are useful for testing for potential accessibility problems in GitLab. -Accessibility best-practices and more in-depth information is available on -[the Audit Rules page][audit-rules] for the Chrome Accessibility Developer Tools. +The [axe][axe-website] browser extension (available for [Firefox][axe-firefox-extension] and [Chrome][axe-chrome-extension]) is +also a handy tool for running audits and getting feedback on markup, CSS and even potentially problematic color usages. + +Accessibility best-practices and more in-depth information are available on +[the Audit Rules page][audit-rules] for the Chrome Accessibility Developer Tools. The "[awesome a11y][awesome-a11y]" list is also a +useful compilation of accessibility-related material. [chrome-accessibility-developer-tools]: https://github.com/GoogleChrome/accessibility-developer-tools [audit-rules]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules +[axe-website]: https://www.deque.com/axe/ +[axe-firefox-extension]: https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/ +[axe-chrome-extension]: https://chrome.google.com/webstore/detail/axe/lhdoppojpmngadmnindnejefpokejbdd +[awesome-a11y]: https://github.com/brunopulis/awesome-a11y diff --git a/doc/development/feature_flags.md b/doc/development/feature_flags.md index 13f0c5cc33e..6bad91d6287 100644 --- a/doc/development/feature_flags.md +++ b/doc/development/feature_flags.md @@ -1,127 +1 @@ -# Manage feature flags - -Starting from GitLab 9.3 we support feature flags for features in GitLab via -[Flipper](https://github.com/jnunemaker/flipper/). You should use the `Feature` -class (defined in `lib/feature.rb`) in your code to get, set and list feature -flags. - -During runtime you can set the values for the gates via the -[features API](../api/features.md) (accessible to admins only). - -## Feature groups - -Starting from GitLab 9.4 we support feature groups via -[Flipper groups](https://github.com/jnunemaker/flipper/blob/v0.10.2/docs/Gates.md#2-group). - -Feature groups must be defined statically in `lib/feature.rb` (in the -`.register_feature_groups` method), but their implementation can obviously be -dynamic (querying the DB etc.). - -Once defined in `lib/feature.rb`, you will be able to activate a -feature for a given feature group via the [`feature_group` param of the features API](../api/features.md#set-or-create-a-feature) - -For GitLab.com, [team members have access to feature flags through Chatops](chatops_on_gitlabcom.md). Only -percentage gates are supported at this time. Setting a feature to be used 50% of -the time, you should execute `/chatops run feature set my_feature_flag 50`. - -## Feature flags for user applications - -This document only covers feature flags used in the development of GitLab -itself. Feature flags in deployed user applications can be found at -[Feature Flags](../user/project/operations/feature_flags.md) - -## Developing with feature flags - -In general, it's better to have a group- or user-based gate, and you should prefer -it over the use of percentage gates. This would make debugging easier, as you -filter for example logs and errors based on actors too. Furthermore, this allows -for enabling for the `gitlab-org` group first, while the rest of the users -aren't impacted. - -```ruby -# Good -Feature.enabled?(:feature_flag, project) - -# Avoid, if possible -Feature.enabled?(:feature_flag) -``` - -To use feature gates based on actors, the model needs to respond to -`flipper_id`. For example, to enable for the Foo model: - -```ruby -class Foo < ActiveRecord::Base - include FeatureGate -end -``` - -Features that are developed and are intended to be merged behind a feature flag -should not include a changelog entry. The entry should be added in the merge -request removing the feature flags. - -In the rare case that you need the feature flag to be on automatically, use -`default_enabled: true` when checking: - -```ruby -Feature.enabled?(:feature_flag, project, default_enabled: true) -``` - -For more information about rolling out changes using feature flags, refer to the -[Rolling out changes using feature flags](rolling_out_changes_using_feature_flags.md) -guide. - -### Frontend - -For frontend code you can use the method `push_frontend_feature_flag`, which is -available to all controllers that inherit from `ApplicationController`. Using -this method you can expose the state of a feature flag as follows: - -```ruby -before_action do - push_frontend_feature_flag(:vim_bindings) -end - -def index - # ... -end - -def edit - # ... -end -``` - -You can then check for the state of the feature flag in JavaScript as follows: - -```javascript -if ( gon.features.vimBindings ) { - // ... -} -``` - -The name of the feature flag in JavaScript will always be camelCased, meaning -that checking for `gon.features.vim_bindings` would not work. - -### Specs - -In the test environment `Feature.enabled?` is stubbed to always respond to `true`, -so we make sure behavior under feature flag doesn't go untested in some non-specific -contexts. - -Whenever a feature flag is present, make sure to test _both_ states of the -feature flag. - -See the -[testing guide](testing_guide/best_practices.md#feature-flags-in-tests) -for information and examples on how to stub feature flags in tests. - -## Enabling a feature flag (in development) - -In the rails console (`rails c`), enter the following command to enable your feature flag - -```ruby -Feature.enable(:feature_flag_name) -``` - -## Enabling a feature flag (in production) - -Check how to [roll out changes using feature flags](rolling_out_changes_using_feature_flags.md). +This document was moved to [another location](feature_flags/index.md). diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md new file mode 100644 index 00000000000..c67467b7c11 --- /dev/null +++ b/doc/development/feature_flags/controls.md @@ -0,0 +1,123 @@ +# Access for enabling a feature flag in production + +In order to be able to turn on/off features behind feature flags in any of the +GitLab Inc. provided environments such as staging and production, you need to +have access to the chatops bot. Chatops bot is currently running on the ops instance, +which is different from GitLab.com or dev.gitlab.org. + +Follow the Chatops document to [request access](https://docs.gitlab.com/ee/development/chatops_on_gitlabcom.html#requesting-access). + +Once you are added to the project test if your access propagated, +run: + +``` +/chatops run feature --help +``` + +## Rolling out changes + +When the changes are deployed to the environments it is time to start +rolling out the feature to our users. The exact procedure of rolling out a +change is unspecified, as this can vary from change to change. However, in +general we recommend rolling out changes incrementally, instead of enabling them +for everybody right away. We also recommend you to _not_ enable a feature +_before_ the code is being deployed. +This allows you to separate rolling out a feature from a deploy, making it +easier to measure the impact of both separately. + +GitLab's feature library (using +[Flipper](https://github.com/jnunemaker/flipper), and covered in the [Feature +Flags process](process.md) guide) supports rolling out changes to a percentage of +users. This in turn can be controlled using [GitLab chatops](../../ci/chatops/README.md). + +For an up to date list of feature flag commands please see [the source +code](https://gitlab.com/gitlab-com/chatops/blob/master/lib/chatops/commands/feature.rb). +Note that all the examples in that file must be preceded by +`/chatops run`. + +If you get an error "Whoops! This action is not allowed. This incident +will be reported." that means your Slack account is not allowed to +change feature flags or you do not [have access](#access-for-enabling-a-feature-flag-in-production). + +### Enabling feature for staging and dev.gitlab.org + +As a first step in a feature rollout, you should enable the feature on <https://staging.gitlab.com> +and <https://dev.gitlab.org>. + +For example, to enable a feature for 25% of all users, run the following in +Slack: + +``` +/chatops run feature set new_navigation_bar 25 --dev +/chatops run feature set new_navigation_bar 25 --staging +``` + +These two environments have different scopes. +`dev.gitlab.org` is a production CE environment that has internal GitLab Inc. +traffic and is used for some development and other related work. +`staging.gitlab.com` has a smaller subset of GitLab.com database and repositories +and does not have regular traffic. Staging is an EE instance and can give you +a (very) rough estimate of how your feature will look/behave on GitLab.com. +Both of these instances are connected to Sentry so make sure you check the projects +there for any exceptions while testing your feature after enabling the feature flag. + +Once you are confident enough that these environments are in a good state with your +feature enabled, you can roll out the change to GitLab.com. + +## Enabling feature for GitLab.com + +Similar to above, to enable a feature for 25% of all users, run the following in +Slack: + +``` +/chatops run feature set new_navigation_bar 25 +``` + +This will enable the feature for GitLab.com, with `new_navigation_bar` being the +name of the feature. + +If you are not certain what percentages to use, simply use the following steps: + +1. 25% +1. 50% +1. 75% +1. 100% + +Between every step you'll want to wait a little while and monitor the +appropriate graphs on <https://dashboards.gitlab.net>. The exact time to wait +may differ. For some features a few minutes is enough, while for others you may +want to wait several hours or even days. This is entirely up to you, just make +sure it is clearly communicated to your team, and the Production team if you +anticipate any potential problems. + +Feature gates can also be actor based, for example a feature could first be +enabled for only the `gitlab-ce` project. The project is passed by supplying a +`--project` flag: + +``` +/chatops run feature set --project=gitlab-org/gitlab-ce some_feature true +``` + +For groups the `--group` flag is available: + +``` +/chatops run feature set --group=gitlab-org some_feature true +``` + +## Cleaning up + +Once the change is deemed stable, submit a new merge request to remove the +feature flag. This ensures the change is available to all users and self-hosted +instances. Make sure to add the ~"feature flag" label to this merge request so +release managers are aware the changes are hidden behind a feature flag. If the +merge request has to be picked into a stable branch, make sure to also add the +appropriate "Pick into X" label (e.g. "Pick into XX.X"). +See [the process document](https://docs.gitlab.com/ee/development/feature_flags/process.html#including-a-feature-behind-feature-flag-in-the-final-release) for further details. + +When a feature gate has been removed from the code base, the value still exists +in the database. +This can be removed through ChatOps: + +``` +/chatops run feature delete some_feature +``` diff --git a/doc/development/feature_flags/development.md b/doc/development/feature_flags/development.md new file mode 100644 index 00000000000..238052529d9 --- /dev/null +++ b/doc/development/feature_flags/development.md @@ -0,0 +1,131 @@ +# Developing with feature flags + +In general, it's better to have a group- or user-based gate, and you should prefer +it over the use of percentage gates. This would make debugging easier, as you +filter for example logs and errors based on actors too. Furthermore, this allows +for enabling for the `gitlab-org` or `gitlab-com` group first, while the rest of +the users aren't impacted. + +```ruby +# Good +Feature.enabled?(:feature_flag, project) + +# Avoid, if possible +Feature.enabled?(:feature_flag) +``` + +To use feature gates based on actors, the model needs to respond to +`flipper_id`. For example, to enable for the Foo model: + +```ruby +class Foo < ActiveRecord::Base + include FeatureGate +end +``` + +Features that are developed and are intended to be merged behind a feature flag +should not include a changelog entry. The entry should be added in the merge +request removing the feature flags. + +In the rare case that you need the feature flag to be on automatically, use +`default_enabled: true` when checking: + +```ruby +Feature.enabled?(:feature_flag, project, default_enabled: true) +``` + +The [`Project#feature_available?`][project-fa], +[`Namespace#feature_available?`][namespace-fa] (EE), and +[`License.feature_available?`][license-fa] (EE) methods all implicitly check for +a feature flag by the same name as the provided argument. + +For example if a feature is license-gated, there's no need to add an additional +explicit feature flag check since the flag will be checked as part of the +`License.feature_available?` call. Similarly, there's no need to "clean up" a +feature flag once the feature has reached general availability. + +You'd still want to use an explicit `Feature.enabled?` check if your new feature +isn't gated by a License or Plan. + +[project-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/app/models/project_feature.rb#L63-68 +[namespace-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/ee/namespace.rb#L71-85 +[license-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/license.rb#L293-300 + +An important side-effect of the implicit feature flags mentioned above is that +unless the feature is explicitly disabled or limited to a percentage of users, +the feature flag check will default to `true`. + +As an example, if you were to ship the backend half of a feature behind a flag, +you'd want to explicitly disable that flag until the frontend half is also ready +to be shipped. [You can do this via Chatops](https://docs.gitlab.com/ee/development/feature_flags/controls.html): + +``` +/chatops run feature set some_feature 0 +``` + +Note that you can do this at any time, even before the merge request using the +flag has been merged! + +## Feature groups + +Starting from GitLab 9.4 we support feature groups via +[Flipper groups](https://github.com/jnunemaker/flipper/blob/v0.10.2/docs/Gates.md#2-group). + +Feature groups must be defined statically in `lib/feature.rb` (in the +`.register_feature_groups` method), but their implementation can obviously be +dynamic (querying the DB etc.). + +Once defined in `lib/feature.rb`, you will be able to activate a +feature for a given feature group via the [`feature_group` param of the features API](../../api/features.md#set-or-create-a-feature) + +### Frontend + +For frontend code you can use the method `push_frontend_feature_flag`, which is +available to all controllers that inherit from `ApplicationController`. Using +this method you can expose the state of a feature flag as follows: + +```ruby +before_action do + push_frontend_feature_flag(:vim_bindings) +end + +def index + # ... +end + +def edit + # ... +end +``` + +You can then check for the state of the feature flag in JavaScript as follows: + +```javascript +if ( gon.features.vimBindings ) { + // ... +} +``` + +The name of the feature flag in JavaScript will always be camelCased, meaning +that checking for `gon.features.vim_bindings` would not work. + +### Specs + +In the test environment `Feature.enabled?` is stubbed to always respond to `true`, +so we make sure behavior under feature flag doesn't go untested in some non-specific +contexts. + +Whenever a feature flag is present, make sure to test _both_ states of the +feature flag. + +See the +[testing guide](../testing_guide/best_practices.md#feature-flags-in-tests) +for information and examples on how to stub feature flags in tests. + +### Enabling a feature flag (in development) + +In the rails console (`rails c`), enter the following command to enable your feature flag + +```ruby +Feature.enable(:feature_flag_name) +``` diff --git a/doc/development/feature_flags/index.md b/doc/development/feature_flags/index.md new file mode 100644 index 00000000000..56872f8c075 --- /dev/null +++ b/doc/development/feature_flags/index.md @@ -0,0 +1,12 @@ +# Feature flags in development of GitLab + +Feature flags can be used to gradually roll out changes, be +it a new feature, or a performance improvement. By using feature flags, we can +comfortably measure the impact of our changes, while still being able to easily +disable those changes, without having to revert an entire release. + +Before using feature flags for GitLab's development, read through the following: + +- [Process for using features flags](process.md). +- [Developing with feature flags documentation](development.md). +- [Controlling feature flags documentation](controls.md). diff --git a/doc/development/feature_flags/process.md b/doc/development/feature_flags/process.md new file mode 100644 index 00000000000..ee142b0da66 --- /dev/null +++ b/doc/development/feature_flags/process.md @@ -0,0 +1,130 @@ +# Feature flags process +## Feature flags for user applications + +This document only covers feature flags used in the development of GitLab +itself. Feature flags in deployed user applications can be found at +[Feature Flags feature documentation](../../user/project/operations/feature_flags.md). + +## Feature flags in GitLab development + +The following highlights should be considered when deciding if feature flags +should be leveraged: + +- By default, the feature flags should be **off**. +- Feature flags should remain in the codebase for as short period as possible +to reduce the need for feature flag accounting. +- The person operating with feature flags is responsible for clearly communicating +the status of a feature behind the feature flag with responsible stakeholders. +- Merge requests that make changes hidden behind a feature flag, or remove an +existing feature flag because a feature is deemed stable must have the +~"feature flag" label assigned. + +One might be tempted to think that feature flags will delay the release of a +feature by at least one month (= one release). This is not the case. A feature +flag does not have to stick around for a specific amount of time +(e.g. at least one release), instead they should stick around until the feature +is deemed stable. Stable means it works on GitLab.com without causing any +problems, such as outages. + +### When to use feature flags + +Starting with GitLab 11.4, developers are required to use feature flags for +non-trivial changes. Such changes include: + +- New features (e.g. a new merge request widget, epics, etc). +- Complex performance improvements that may require additional testing in + production, such as rewriting complex queries. +- Invasive changes to the user interface, such as a new navigation bar or the + removal of a sidebar. +- Adding support for importing projects from a third-party service. + +In all cases, those working on the changes can best decide if a feature flag is +necessary. For example, changing the color of a button doesn't need a feature +flag, while changing the navigation bar definitely needs one. In case you are +uncertain if a feature flag is necessary, simply ask about this in the merge +request, and those reviewing the changes will likely provide you with an answer. + +When using a feature flag for UI elements, make sure to _also_ use a feature +flag for the underlying backend code, if there is any. This ensures there is +absolutely no way to use the feature until it is enabled. + +### Including a feature behind feature flag in the final release + +In order to build a final release and present the feature for self-hosted +users, the feature flag should be at least defaulted to **on**. If the feature +is deemed stable and there is confidence that removing the feature flag is safe, +consider removing the feature flag altogether. Take into consideration that such +action can make the feature available on GitLab.com shortly after the change to +the feature flag is merged. + +Changing the default state or removing the feature flag has to be done before +the 22nd of the month, _at least_ 2 working days before, in order for the change +to be included in the final self-managed release. + +In addition to this, the feature behind feature flag should: + +- Run in all GitLab.com environments for a sufficient period of time. This time +period depends on the feature behind the feature flag, but as a general rule of +thumb 2-4 working days should be sufficient to gather enough feedback. +- The feature should be exposed to all users within the GitLab.com plan during +the above mentioned period of time. Exposing the feature to a smaller percentage +or only a group of users might not expose a sufficient amount of information to aid in +making a decision on feature stability. + +While rare, release managers may decide to reject picking or revert a change in +a stable branch, even when feature flags are used. This might be necessary if +the changes are deemed problematic, too invasive, or there simply isn't enough +time to properly measure how the changes behave on GitLab.com. + +### The cost of feature flags + +When reading the above, one might be tempted to think this procedure is going to +add a lot of work. Fortunately, this is not the case, and we'll show why. For +this example we'll specify the cost of the work to do as a number, ranging from +0 to infinity. The greater the number, the more expensive the work is. The cost +does _not_ translate to time, it's just a way of measuring complexity of one +change relative to another. + +Let's say we are building a new feature, and we have determined that the cost of +this is 10. We have also determined that the cost of adding a feature flag check +in a variety of places is 1. If we do not use feature flags, and our feature +works as intended, our total cost is 10. This however is the best case scenario. +Optimizing for the best case scenario is guaranteed to lead to trouble, whereas +optimizing for the worst case scenario is almost always better. + +To illustrate this, let's say our feature causes an outage, and there's no +immediate way to resolve it. This means we'd have to take the following steps to +resolve the outage: + +1. Revert the release. +1. Perform any cleanups that might be necessary, depending on the changes that + were made. +1. Revert the commit, ensuring the "master" branch remains stable. This is + especially necessary if solving the problem can take days or even weeks. +1. Pick the revert commit into the appropriate stable branches, ensuring we + don't block any future releases until the problem is resolved. + +As history has shown, these steps are time consuming, complex, often involve +many developers, and worst of all: our users will have a bad experience using +GitLab.com until the problem is resolved. + +Now let's say that all of this has an associated cost of 10. This means that in +the worst case scenario, which we should optimize for, our total cost is now 20. + +If we had used a feature flag, things would have been very different. We don't +need to revert a release, and because feature flags are disabled by default we +don't need to revert and pick any Git commits. In fact, all we have to do is +disable the feature, and in the worst case, perform cleanup. Let's say that +the cost of this is 2. In this case, our best case cost is 11: 10 to build the +feature, and 1 to add the feature flag. The worst case cost is now 13: 10 to +build the feature, 1 to add the feature flag, and 2 to disable and clean up. + +Here we can see that in the best case scenario the work necessary is only a tiny +bit more compared to not using a feature flag. Meanwhile, the process of +reverting our changes has been made significantly and reliably cheaper. + +In other words, feature flags do not slow down the development process. Instead, +they speed up the process as managing incidents now becomes _much_ easier. Once +continuous deployments are easier to perform, the time to iterate on a feature +is reduced even further, as you no longer need to wait weeks before your changes +are available on GitLab.com. diff --git a/doc/development/new_fe_guide/tips.md b/doc/development/new_fe_guide/tips.md index 4564f678ec0..879b54bd93c 100644 --- a/doc/development/new_fe_guide/tips.md +++ b/doc/development/new_fe_guide/tips.md @@ -10,16 +10,16 @@ yarn clean ## Creating feature flags in development -The process for creating a feature flag is the same as [enabling a feature flag in development](../feature_flags.md#enabling-a-feature-flag-in-development). +The process for creating a feature flag is the same as [enabling a feature flag in development](../feature_flags/development.md#enabling-a-feature-flag-in-development). Your feature flag can now be: -- [made available to the frontend](../feature_flags.md#frontend) via the `gon` -- queried in [tests](../feature_flags.md#specs) -- queried in HAML templates and ruby files via the `Feature.enabled?(:my_shiny_new_feature_flag)` method +- [Made available to the frontend](../feature_flags/development.md#frontend) via the `gon` +- Queried in [tests](../feature_flags/development.md#specs) +- Queried in HAML templates and ruby files via the `Feature.enabled?(:my_shiny_new_feature_flag)` method ### More on feature flags - [Deleting a feature flag](../../api/features.md#delete-a-feature) -- [Manage feature flags](../feature_flags.md) +- [Manage feature flags](../feature_flags/process.md) - [Feature flags API](../../api/features.md) diff --git a/doc/development/rolling_out_changes_using_feature_flags.md b/doc/development/rolling_out_changes_using_feature_flags.md index 84028b1b342..6bad91d6287 100644 --- a/doc/development/rolling_out_changes_using_feature_flags.md +++ b/doc/development/rolling_out_changes_using_feature_flags.md @@ -1,225 +1 @@ -# Rolling out changes using feature flags - -[Feature flags](feature_flags.md) can be used to gradually roll out changes, be -it a new feature, or a performance improvement. By using feature flags, we can -comfortably measure the impact of our changes, while still being able to easily -disable those changes, without having to revert an entire release. - -## When to use feature flags - -Starting with GitLab 11.4, developers are required to use feature flags for -non-trivial changes. Such changes include: - -- New features (e.g. a new merge request widget, epics, etc). -- Complex performance improvements that may require additional testing in - production, such as rewriting complex queries. -- Invasive changes to the user interface, such as a new navigation bar or the - removal of a sidebar. -- Adding support for importing projects from a third-party service. - -In all cases, those working on the changes can best decide if a feature flag is -necessary. For example, changing the color of a button doesn't need a feature -flag, while changing the navigation bar definitely needs one. In case you are -uncertain if a feature flag is necessary, simply ask about this in the merge -request, and those reviewing the changes will likely provide you with an answer. - -When using a feature flag for UI elements, make sure to _also_ use a feature -flag for the underlying backend code, if there is any. This ensures there is -absolutely no way to use the feature until it is enabled. - -## The cost of feature flags - -When reading the above, one might be tempted to think this procedure is going to -add a lot of work. Fortunately, this is not the case, and we'll show why. For -this example we'll specify the cost of the work to do as a number, ranging from -0 to infinity. The greater the number, the more expensive the work is. The cost -does _not_ translate to time, it's just a way of measuring complexity of one -change relative to another. - -Let's say we are building a new feature, and we have determined that the cost of -this is 10. We have also determined that the cost of adding a feature flag check -in a variety of places is 1. If we do not use feature flags, and our feature -works as intended, our total cost is 10. This however is the best case scenario. -Optimising for the best case scenario is guaranteed to lead to trouble, whereas -optimising for the worst case scenario is almost always better. - -To illustrate this, let's say our feature causes an outage, and there's no -immediate way to resolve it. This means we'd have to take the following steps to -resolve the outage: - -1. Revert the release. -1. Perform any cleanups that might be necessary, depending on the changes that - were made. -1. Revert the commit, ensuring the "master" branch remains stable. This is - especially necessary if solving the problem can take days or even weeks. -1. Pick the revert commit into the appropriate stable branches, ensuring we - don't block any future releases until the problem is resolved. - -As history has shown, these steps are time consuming, complex, often involve -many developers, and worst of all: our users will have a bad experience using -GitLab.com until the problem is resolved. - -Now let's say that all of this has an associated cost of 10. This means that in -the worst case scenario, which we should optimise for, our total cost is now 20. - -If we had used a feature flag, things would have been very different. We don't -need to revert a release, and because feature flags are disabled by default we -don't need to revert and pick any Git commits. In fact, all we have to do is -disable the feature, and in the worst case, perform cleanup. Let's say that -the cost of this is 2. In this case, our best case cost is 11: 10 to build the -feature, and 1 to add the feature flag. The worst case cost is now 13: 10 to -build the feature, 1 to add the feature flag, and 2 to disable and clean up. - -Here we can see that in the best case scenario the work necessary is only a tiny -bit more compared to not using a feature flag. Meanwhile, the process of -reverting our changes has been made significantly and reliably cheaper. - -In other words, feature flags do not slow down the development process. Instead, -they speed up the process as managing incidents now becomes _much_ easier. Once -continuous deployments are easier to perform, the time to iterate on a feature -is reduced even further, as you no longer need to wait weeks before your changes -are available on GitLab.com. - -## Rolling out changes - -The procedure of using feature flags is straightforward, and similar to not -using them. You add the necessary tests (make sure to test both the on and off -states of your feature flag(s)), make sure they all pass, have the code -reviewed, etc. You then submit your merge request, and add the ~"feature flag" -label. This label is used to signal to release managers that your changes are -hidden behind a feature flag and that it is safe to pick the MR into a stable -branch, without the need for an exception request. - -When the changes are deployed it is time to start rolling out the feature to our -users. The exact procedure of rolling out a change is unspecified, as this can -vary from change to change. However, in general we recommend rolling out changes -incrementally, instead of enabling them for everybody right away. We also -recommend you to _not_ enable a feature _before_ the code is being deployed. -This allows you to separate rolling out a feature from a deploy, making it -easier to measure the impact of both separately. - -GitLab's feature library (using -[Flipper](https://github.com/jnunemaker/flipper), and covered in the [Feature -Flags](feature_flags.md) guide) supports rolling out changes to a percentage of -users. This in turn can be controlled using [GitLab -chatops](../ci/chatops/README.md). - -For an up to date list of feature flag commands please see [the source -code](https://gitlab.com/gitlab-com/chatops/blob/master/lib/chatops/commands/feature.rb). -Note that all the examples in that file must be preceded by -`/chatops run`. - -If you get an error "Whoops! This action is not allowed. This incident -will be reported." that means your Slack account is not allowed to -change feature flags. To test if you are allowed to do anything at all, -run: - -``` -/chatops run feature --help -``` - -For example, to enable a feature for 25% of all users, run the following in -Slack: - -``` -/chatops run feature set new_navigation_bar 25 -``` - -This will enable the feature for GitLab.com, with `new_navigation_bar` being the -name of the feature. We can also enable the feature for <https://dev.gitlab.org> -or <https://staging.gitlab.com>: - -``` -/chatops run feature set new_navigation_bar 25 --dev -/chatops run feature set new_navigation_bar 25 --staging -``` - -If you are not certain what percentages to use, simply use the following steps: - -1. 25% -1. 50% -1. 75% -1. 100% - -Between every step you'll want to wait a little while and monitor the -appropriate graphs on <https://dashboards.gitlab.net>. The exact time to wait -may differ. For some features a few minutes is enough, while for others you may -want to wait several hours or even days. This is entirely up to you, just make -sure it is clearly communicated to your team, and the Production team if you -anticipate any potential problems. - -Feature gates can also be actor based, for example a feature could first be -enabled for only the `gitlab-ce` project. The project is passed by supplying a -`--project` flag: - -``` -/chatops run feature set --project=gitlab-org/gitlab-ce some_feature true -``` - -For groups the `--group` flag is available: - -``` -/chatops run feature set --group=gitlab-org some_feature true -``` - -Once a change is deemed stable, submit a new merge request to remove the -feature flag. This ensures the change is available to all users and self-hosted -instances. Make sure to add the ~"feature flag" label to this merge request so -release managers are aware the changes are hidden behind a feature flag. If the -merge request has to be picked into a stable branch (e.g. after the 7th), make -sure to also add the appropriate "Pick into X" label (e.g. "Pick into 11.4"). - -One might be tempted to think this will delay the release of a feature by at -least one month (= one release). This is not the case. A feature flag does not -have to stick around for a specific amount of time (e.g. at least one release), -instead they should stick around until the feature is deemed stable. Stable -means it works on GitLab.com without causing any problems, such as outages. In -most cases this will translate to a feature (with a feature flag) being shipped -in RC1, followed by the feature flag being removed in RC2. This in turn means -the feature will be stable by the time we publish a stable package around the -22nd of the month. - -## Implicit feature flags - -The [`Project#feature_available?`][project-fa], -[`Namespace#feature_available?`][namespace-fa] (EE), and -[`License.feature_available?`][license-fa] (EE) methods all implicitly check for -a feature flag by the same name as the provided argument. - -For example if a feature is license-gated, there's no need to add an additional -explicit feature flag check since the flag will be checked as part of the -`License.feature_available?` call. Similarly, there's no need to "clean up" a -feature flag once the feature has reached general availability. - -You'd still want to use an explicit `Feature.enabled?` check if your new feature -isn't gated by a License or Plan. - -[project-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/app/models/project_feature.rb#L63-68 -[namespace-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/ee/namespace.rb#L71-85 -[license-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/license.rb#L293-300 - -### Undefined feature flags default to "on" - -An important side-effect of the [implicit feature flags](#implicit-feature-flags) -mentioned above is that unless the feature is explicitly disabled or limited to a -percentage of users, the feature flag check will default to `true`. - -As an example, if you were to ship the backend half of a feature behind a flag, -you'd want to explicitly disable that flag until the frontend half is also ready -to be shipped. You can do this via ChatOps: - -``` -/chatops run feature set some_feature 0 -``` - -Note that you can do this at any time, even before the merge request using the -flag has been merged! - -### Cleaning up - -When a feature gate has been removed from the code base, the value still exists -in the database. This can be removed through ChatOps: - -``` -/chatops run feature delete some_feature -``` +This document was moved to [another location](feature_flags/index.md). diff --git a/doc/development/testing_guide/end_to_end/quick_start_guide.md b/doc/development/testing_guide/end_to_end/quick_start_guide.md index f96c85be1ba..041bdf716b3 100644 --- a/doc/development/testing_guide/end_to_end/quick_start_guide.md +++ b/doc/development/testing_guide/end_to_end/quick_start_guide.md @@ -242,7 +242,7 @@ module QA issue = Resource::Issue.fabricate_via_api! do |issue| issue.title = 'Issue to test the scoped labels' - issue.labels = @initial_label + issue.labels = [@initial_label] end [@new_label_same_scope, @new_label_different_scope].each do |label| @@ -365,6 +365,14 @@ Add the following `attribute :id` and `attribute :labels` right above the [`attr > We add the attributes above the existing attribute to keep them alphabetically organized. +Then, let's initialize an instance variable for labels to allow an empty array as default value when such information is not passed during the resource fabrication, since this optional. [Between the attributes and the `fabricate!` method](https://gitlab.com/gitlab-org/gitlab-ee/blob/1a1f1408728f19b2aa15887cd20bddab7e70c8bd/qa/qa/resource/issue.rb#L18), add the following: + +```ruby +def initialize + @labels = [] +end +``` + Next, add the following code right below the [`fabricate!`](https://gitlab.com/gitlab-org/gitlab-ee/blob/d3584e80b4236acdf393d815d604801573af72cc/qa/qa/resource/issue.rb#L27) method. ```ruby @@ -378,7 +386,7 @@ end def api_post_body { - labels: [labels], + labels: labels, title: title } end diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md index 1cf883679d7..b7e6844f43a 100644 --- a/doc/gitlab-basics/command-line-commands.md +++ b/doc/gitlab-basics/command-line-commands.md @@ -29,7 +29,9 @@ git clone PASTE HTTPS OR SSH HERE A clone of the project will be created in your computer. ->**Note:** If you clone your project via a URL that contains special characters, make sure that characters are URL-encoded. +NOTE: **Note:** +If you clone your project via a URL that contains special characters, make sure +that characters are URL-encoded. ### Go into a project directory to work in it @@ -86,12 +88,18 @@ cat README.md ### Remove a file +DANGER: **Danger:** +This will permanently delete the file. + ``` rm NAME-OF-FILE ``` ### Remove a directory and all of its contents +DANGER: **Danger:** +This will permanently delete the directory and all of its contents. + ``` rm -r NAME-OF-DIRECTORY ``` @@ -113,9 +121,13 @@ history You will be asked for an administrator’s password. ``` -sudo +sudo COMMAND ``` +CAUTION: **Caution:** +Be careful of the commands you run with `sudo`. Certain commands may cause +damage to your data and system. + ### Show which directory I am in ``` diff --git a/lib/gitlab/git/raw_diff_change.rb b/lib/gitlab/git/raw_diff_change.rb index e1002af40f6..9a41f04a4db 100644 --- a/lib/gitlab/git/raw_diff_change.rb +++ b/lib/gitlab/git/raw_diff_change.rb @@ -11,8 +11,8 @@ module Gitlab if raw_change.is_a?(Gitaly::GetRawChangesResponse::RawChange) @blob_id = raw_change.blob_id @blob_size = raw_change.size - @old_path = raw_change.old_path.presence - @new_path = raw_change.new_path.presence + @old_path = raw_change.old_path_bytes.presence + @new_path = raw_change.new_path_bytes.presence @operation = raw_change.operation&.downcase || :unknown else parse(raw_change) diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index fd36ff812ff..5a5c0a1f6ac 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -39,6 +39,19 @@ describe SearchController do end end + context 'global search' do + render_views + + it 'omits pipeline status from load' do + project = create(:project, :public) + expect(Gitlab::Cache::Ci::ProjectPipelineStatus).not_to receive(:load_in_batch_for_projects) + + get :show, params: { scope: 'projects', search: project.name } + + expect(assigns[:search_objects].first).to eq project + end + end + it 'finds issue comments' do project = create(:project, :public) note = create(:note_on_issue, project: project) diff --git a/spec/frontend/notes/components/discussion_notes_spec.js b/spec/frontend/notes/components/discussion_notes_spec.js index c3204b3aaa0..394666403ee 100644 --- a/spec/frontend/notes/components/discussion_notes_spec.js +++ b/spec/frontend/notes/components/discussion_notes_spec.js @@ -112,6 +112,44 @@ describe('DiscussionNotes', () => { }); }); + describe('events', () => { + describe('with groupped notes and replies expanded', () => { + const findNoteAtIndex = index => wrapper.find(`.note:nth-of-type(${index + 1}`); + + beforeEach(() => { + createComponent({ shouldGroupReplies: true, isExpanded: true }); + }); + + it('emits deleteNote when first note emits handleDeleteNote', () => { + findNoteAtIndex(0).vm.$emit('handleDeleteNote'); + expect(wrapper.emitted().deleteNote).toBeTruthy(); + }); + + it('emits startReplying when first note emits startReplying', () => { + findNoteAtIndex(0).vm.$emit('startReplying'); + expect(wrapper.emitted().startReplying).toBeTruthy(); + }); + + it('emits deleteNote when second note emits handleDeleteNote', () => { + findNoteAtIndex(1).vm.$emit('handleDeleteNote'); + expect(wrapper.emitted().deleteNote).toBeTruthy(); + }); + }); + + describe('with ungroupped notes', () => { + let note; + beforeEach(() => { + createComponent(); + note = wrapper.find('.note'); + }); + + it('emits deleteNote when first note emits handleDeleteNote', () => { + note.vm.$emit('handleDeleteNote'); + expect(wrapper.emitted().deleteNote).toBeTruthy(); + }); + }); + }); + describe('componentData', () => { beforeEach(() => { createComponent(); diff --git a/spec/javascripts/monitoring/charts/area_spec.js b/spec/javascripts/monitoring/charts/area_spec.js index ac7e0bb12a1..d3a76f33679 100644 --- a/spec/javascripts/monitoring/charts/area_spec.js +++ b/spec/javascripts/monitoring/charts/area_spec.js @@ -1,14 +1,19 @@ import { shallowMount } from '@vue/test-utils'; +import { GlLink } from '@gitlab/ui'; import { GlAreaChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts'; import { shallowWrapperContainsSlotText } from 'spec/helpers/vue_test_utils_helper'; import Area from '~/monitoring/components/charts/area.vue'; import { createStore } from '~/monitoring/stores'; import * as types from '~/monitoring/stores/mutation_types'; +import { TEST_HOST } from 'spec/test_constants'; import MonitoringMock, { deploymentData } from '../mock_data'; describe('Area component', () => { + const mockSha = 'mockSha'; const mockWidgets = 'mockWidgets'; const mockSvgPathContent = 'mockSvgPathContent'; + const projectPath = `${TEST_HOST}/path/to/project`; + const commitUrl = `${projectPath}/commit/${mockSha}`; let mockGraphData; let areaChart; let spriteSpy; @@ -26,6 +31,7 @@ describe('Area component', () => { graphData: mockGraphData, containerWidth: 0, deploymentData: store.state.monitoringDashboard.deploymentData, + projectPath, }, slots: { default: mockWidgets, @@ -88,11 +94,14 @@ describe('Area component', () => { ); }); - it('renders commit sha in tooltip content', () => { - const mockSha = 'mockSha'; + it('renders clickable commit sha in tooltip content', () => { areaChart.vm.tooltip.sha = mockSha; + areaChart.vm.tooltip.commitUrl = commitUrl; - expect(shallowWrapperContainsSlotText(glAreaChart, 'tooltipContent', mockSha)).toBe(true); + const commitLink = areaChart.find(GlLink); + + expect(shallowWrapperContainsSlotText(commitLink, 'default', mockSha)).toBe(true); + expect(commitLink.attributes('href')).toEqual(commitUrl); }); }); }); diff --git a/spec/models/postgresql/replication_slot_spec.rb b/spec/models/postgresql/replication_slot_spec.rb index e100af7ddc7..95ae204a8a8 100644 --- a/spec/models/postgresql/replication_slot_spec.rb +++ b/spec/models/postgresql/replication_slot_spec.rb @@ -47,5 +47,13 @@ describe Postgresql::ReplicationSlot, :postgresql do expect(described_class.lag_too_great?).to eq(false) end + + it 'returns false when there is a nil replication lag' do + expect(described_class) + .to receive(:pluck) + .and_return([0.megabytes, nil]) + + expect(described_class.lag_too_great?).to eq(false) + end end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index c5ab7e57272..0bd17dbacd7 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -844,6 +844,19 @@ describe Repository do end end + describe '#get_raw_changes' do + context `with non-UTF8 bytes in paths` do + let(:old_rev) { 'd0888d297eadcd7a345427915c309413b1231e65' } + let(:new_rev) { '19950f03c765f7ac8723a73a0599764095f52fc0' } + let(:changes) { repository.raw_changes_between(old_rev, new_rev) } + + it 'returns the changes' do + expect { changes }.not_to raise_error + expect(changes.first.new_path.bytes).to eq("hello\x80world".bytes) + end + end + end + describe '#create_ref' do it 'redirects the call to write_ref' do ref, ref_path = '1', '2' diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index 77f22d9dd24..e63099d89b7 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -64,7 +64,8 @@ module TestEnv 'with-codeowners' => '219560e', 'submodule_inside_folder' => 'b491b92', 'png-lfs' => 'fe42f41', - 'sha-starting-with-large-number' => '8426165' + 'sha-starting-with-large-number' => '8426165', + 'invalid-utf8-diff-paths' => '99e4853' }.freeze # gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily |