diff options
20 files changed, 153 insertions, 14 deletions
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index 1e54d4d6b7d..ee889e0f7e0 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -256,7 +256,7 @@ export default { let toList; if (to) { const containerEl = to.closest('.js-board-list'); - toList = boardsStore.findList('id', Number(containerEl.dataset.board)); + toList = boardsStore.findList('id', Number(containerEl.dataset.board), ''); } /** diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue index 51a1ae50467..65cd2f044ae 100644 --- a/app/assets/javascripts/error_tracking/components/error_details.vue +++ b/app/assets/javascripts/error_tracking/components/error_details.vue @@ -251,8 +251,8 @@ export default { <li> <strong class="bold">{{ __('Sentry event') }}:</strong> <gl-link - class="d-inline-flex align-items-center" v-track-event="trackClickErrorLinkToSentryOptions(GQLerror.externalUrl)" + class="d-inline-flex align-items-center" :href="GQLerror.externalUrl" target="_blank" > @@ -264,7 +264,9 @@ export default { <strong class="bold">{{ __('First seen') }}:</strong> {{ formatDate(GQLerror.firstSeen) }} <gl-link :href="firstReleaseLink" target="_blank"> - <span>{{ __('Release') }}: {{ GQLerror.firstReleaseShortVersion.substr(0, 10) }}</span> + <span> + {{ __('Release') }}: {{ GQLerror.firstReleaseShortVersion.substr(0, 10) }} + </span> </gl-link> </li> <li v-if="GQLerror.lastReleaseShortVersion"> diff --git a/app/controllers/groups/group_links_controller.rb b/app/controllers/groups/group_links_controller.rb index 6796a862c00..d3360acd245 100644 --- a/app/controllers/groups/group_links_controller.rb +++ b/app/controllers/groups/group_links_controller.rb @@ -53,6 +53,6 @@ class Groups::GroupLinksController < Groups::ApplicationController end def check_feature_flag! - render_404 unless Feature.enabled?(:share_group_with_group) + render_404 unless Feature.enabled?(:share_group_with_group, default_enabled: true) end end diff --git a/app/models/group.rb b/app/models/group.rb index 186253619fe..51b4fe4c1ce 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -496,7 +496,7 @@ class Group < Namespace end def max_member_access_for_user_from_shared_groups(user) - return unless Feature.enabled?(:share_group_with_group) + return unless Feature.enabled?(:share_group_with_group, default_enabled: true) group_group_link_table = GroupGroupLink.arel_table group_member_table = GroupMember.arel_table diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index 6eb8a8947cc..048edb80d99 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -9,7 +9,7 @@ = _("Group members") %hr - if can_manage_members - - if Feature.enabled?(:share_group_with_group) + - if Feature.enabled?(:share_group_with_group, default_enabled: true) %ul.nav-links.nav.nav-tabs.gitlab-tabs{ role: 'tablist' } %li.nav-tab{ role: 'presentation' } %a.nav-link.active{ href: '#invite-member-pane', id: 'invite-member-tab', data: { toggle: 'tab' }, role: 'tab' }= _("Invite member") @@ -18,7 +18,7 @@ .tab-content.gitlab-tab-content .tab-pane.active{ id: 'invite-member-pane', role: 'tabpanel' } = render_invite_member_for_group(@group, @group_member.access_level) - - if Feature.enabled?(:share_group_with_group) + - if Feature.enabled?(:share_group_with_group, default_enabled: true) .tab-pane{ id: 'invite-group-pane', role: 'tabpanel' } = render 'shared/members/invite_group', submit_url: group_group_links_path(@group), access_levels: GroupMember.access_level_roles, default_access_level: @group_member.access_level, group_link_field: 'shared_with_group_id', group_access_field: 'shared_group_access' - else diff --git a/changelogs/unreleased/22986-share_group_with_group_ff_default_on.yml b/changelogs/unreleased/22986-share_group_with_group_ff_default_on.yml new file mode 100644 index 00000000000..f271c9c89ac --- /dev/null +++ b/changelogs/unreleased/22986-share_group_with_group_ff_default_on.yml @@ -0,0 +1,5 @@ +--- +title: Allow to share groups with other groups +merge_request: 23185 +author: +type: changed diff --git a/changelogs/unreleased/36753-dashes-not-supported-in-cn-for-ldap-group-sync-on-first-login.yml b/changelogs/unreleased/36753-dashes-not-supported-in-cn-for-ldap-group-sync-on-first-login.yml new file mode 100644 index 00000000000..93f3cce4376 --- /dev/null +++ b/changelogs/unreleased/36753-dashes-not-supported-in-cn-for-ldap-group-sync-on-first-login.yml @@ -0,0 +1,5 @@ +--- +title: Support dashes in LDAP group CN for sync on users first log in +merge_request: 20402 +author: +type: fixed diff --git a/changelogs/unreleased/sh-fix-issue-197300.yml b/changelogs/unreleased/sh-fix-issue-197300.yml new file mode 100644 index 00000000000..b54fcd24cc9 --- /dev/null +++ b/changelogs/unreleased/sh-fix-issue-197300.yml @@ -0,0 +1,5 @@ +--- +title: Fix issue CSV export failing for some projects +merge_request: 23223 +author: +type: fixed diff --git a/doc/administration/index.md b/doc/administration/index.md index 4cafb4eb87c..8172acd09b4 100644 --- a/doc/administration/index.md +++ b/doc/administration/index.md @@ -200,6 +200,7 @@ Learn how to install, configure, update, and maintain your GitLab instance. - [Log system](logs.md): Where to look for logs. - [Sidekiq Troubleshooting](troubleshooting/sidekiq.md): Debug when Sidekiq appears hung and is not processing jobs. - [Troubleshooting Elasticsearch](troubleshooting/elasticsearch.md) +- [GitLab application limits](instance_limits.md) ### Support Team Docs diff --git a/doc/ci/environments.md b/doc/ci/environments.md index 245a4d20e2d..55e93e19f66 100644 --- a/doc/ci/environments.md +++ b/doc/ci/environments.md @@ -232,6 +232,11 @@ declaring their names dynamically in `.gitlab-ci.yml`. Dynamic environments are a fundamental part of [Review apps](review_apps/index.md). +### Configuring incremental rollouts + +Learn how to release production changes to only a portion of your Kubernetes pods with +[incremental rollouts](environments/incremental_rollouts.md). + #### Allowed variables The `name` and `url` parameters for dynamic environments can use most available CI/CD variables, diff --git a/doc/ci/environments/img/incremental_rollouts_play_v12_7.png b/doc/ci/environments/img/incremental_rollouts_play_v12_7.png Binary files differnew file mode 100644 index 00000000000..314c4a07af0 --- /dev/null +++ b/doc/ci/environments/img/incremental_rollouts_play_v12_7.png diff --git a/doc/ci/environments/img/timed_rollout_v12_7.png b/doc/ci/environments/img/timed_rollout_v12_7.png Binary files differnew file mode 100644 index 00000000000..6b83bfc574e --- /dev/null +++ b/doc/ci/environments/img/timed_rollout_v12_7.png diff --git a/doc/ci/environments/incremental_rollouts.md b/doc/ci/environments/incremental_rollouts.md new file mode 100644 index 00000000000..0fa0af6a9fb --- /dev/null +++ b/doc/ci/environments/incremental_rollouts.md @@ -0,0 +1,113 @@ +--- +type: concepts, howto +--- + +# Incremental Rollouts with GitLab CI/CD + +When rolling out changes to your application, it is possible to release production changes +to only a portion of your Kubernetes pods as a risk mitigation strategy. By releasing +production changes gradually, error rates or performance degradation can be monitored, and +if there are no problems, all pods can be updated. + +GitLab supports both manually triggered and timed rollouts to a Kubernetes production system +using Incremental Rollouts. When using Manual Rollouts, the release of each tranche +of pods is manually triggered, while in Timed Rollouts, the release is performed in +tranches after a default pause of 5 minutes. +Timed rollouts can also be manually triggered before the pause period has expired. + +Manual and Timed rollouts are included automatically in projects controlled by +[AutoDevOps](../../topics/autodevops/index.md), but they are also configurable through +GitLab CI/CD in the `.gitlab-ci.yml` configuration file. + +Manually triggered rollouts can be implemented with your [Continuously Delivery](../introduction/index.md#continuous-delivery) +methodology, while timed rollouts do not require intervention and can be part of your +[Continuously Deployment](../introduction/index.md#continuous-deployment) strategy. +You can also combine both of them in a way that the app is deployed automatically +unless you eventually intervene manually if necessary. + +We created sample applications to demonstrate the three options, which you can +use as examples to build your own: + +- [Manual incremental rollouts](https://gitlab.com/gl-release/incremental-rollout-example/blob/master/.gitlab-ci.yml) +- [Timed incremental rollouts](https://gitlab.com/gl-release/timed-rollout-example/blob/master/.gitlab-ci.yml) +- [Both manual and timed rollouts](https://gitlab.com/gl-release/incremental-timed-rollout-example/blob/master/.gitlab-ci.yml) + +## Manual Rollouts + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/5415) in GitLab 10.8. + +It is possible to configure GitLab to do incremental rollouts manually through `.gitlab-ci.yml`. Manual configuration +allows more control over the this feature. The steps in an incremental rollout depend on the +number of pods that are defined for the deployment, which are configured when the Kubernetes +cluster is created. + +For example, if your application has 10 pods and a 10% rollout job is run, the new instance of the +application will be deployed to a single pod while the remaining 9 will present the previous instance. + +First we [define the template as manual](https://gitlab.com/gl-release/incremental-rollout-example/blob/master/.gitlab-ci.yml#L100-103): + +```yml +.manual_rollout_template: &manual_rollout_template + <<: *rollout_template + stage: production + when: manual +``` + +Then we [define the rollout amount for each step](https://gitlab.com/gl-release/incremental-rollout-example/blob/master/.gitlab-ci.yml#L152-155): + +```yml +rollout 10%: + <<: *manual_rollout_template + variables: + ROLLOUT_PERCENTAGE: 10 +``` + +When the jobs are built, a **play** button will appear next to the job's name. Click the **play** button +to release each stage of pods. You can also rollback by running a lower percentage job. Once 100% +is reached, you cannot roll back using this method. It is still possible to roll back by redeploying +the old version using the **Rollback** button on the environment page. + +![Play button](img/incremental_rollouts_play_v12_7.png) + +A [deployable application](https://gitlab.com/gl-release/incremental-rollout-example) is +available, demonstrating manually triggered incremental rollouts. + +## Timed Rollouts + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/7545) in GitLab 11.4. + +Timed rollouts behave in the same way as manual rollouts, except that each job is defined with a delay +in minutes before it will deploy. Clicking on the job will reveal the countdown. + +![Timed rollout](img/timed_rollout_v12_7.png) + +It is possible to combine this functionality with manual incremental rollouts so that the job will +countdown and then deploy. + +First we [define the template as timed](https://gitlab.com/gl-release/timed-rollout-example/blob/master/.gitlab-ci.yml#L86-89): + +```yml +.timed_rollout_template: &timed_rollout_template + <<: *rollout_template + when: delayed + start_in: 1 minutes +``` + +We can define the delay period using the `start_in` key: + +```yml +start_in: 1 minutes +``` + +Then we [define the rollout amount for each step](https://gitlab.com/gl-release/timed-rollout-example/blob/master/.gitlab-ci.yml#L97-101): + +```yml +timed rollout 30%: + <<: *timed_rollout_template + stage: timed rollout 30% + variables: + ROLLOUT_PERCENTAGE: 30 +``` + +A [deployable application](https://gitlab.com/gl-release/timed-rollout-example) is +available, [demonstrating configuration of timed rollouts](https://gitlab.com/gl-release/timed-rollout-example/blob/master/.gitlab-ci.yml#L86-95). diff --git a/lib/gitlab/project_authorizations.rb b/lib/gitlab/project_authorizations.rb index 4e5e2d4a6a9..e2271b1492c 100644 --- a/lib/gitlab/project_authorizations.rb +++ b/lib/gitlab/project_authorizations.rb @@ -68,7 +68,7 @@ module Gitlab .select([namespaces[:id], members[:access_level]]) .except(:order) - if Feature.enabled?(:share_group_with_group) + if Feature.enabled?(:share_group_with_group, default_enabled: true) # Namespaces shared with any of the group cte << Group.select([namespaces[:id], 'group_group_links.group_access AS access_level']) .joins(join_group_group_links) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 5f1f9c0d49f..06b9faec354 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -10227,6 +10227,9 @@ msgstr "" msgid "Invalid server response" msgstr "" +msgid "Invalid start or end time format" +msgstr "" + msgid "Invalid two-factor code." msgstr "" diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js index e19cb1fd3c1..378ef50f706 100644 --- a/spec/frontend/error_tracking/components/error_details_spec.js +++ b/spec/frontend/error_tracking/components/error_details_spec.js @@ -266,7 +266,7 @@ describe('ErrorDetails', () => { }); }); - it('should display a link', () => { + it('should not display a link', () => { mocks.$apollo.queries.GQLerror.loading = false; wrapper.setData({ GQLerror: { diff --git a/spec/frontend/registry/list/components/app_spec.js b/spec/frontend/registry/list/components/app_spec.js index 7797f41a4b5..c2c220b2cd2 100644 --- a/spec/frontend/registry/list/components/app_spec.js +++ b/spec/frontend/registry/list/components/app_spec.js @@ -35,7 +35,6 @@ describe('Registry List', () => { beforeEach(() => { wrapper = mount(registry, { - attachToDocument: true, propsData, computed: { repos() { @@ -61,7 +60,6 @@ describe('Registry List', () => { describe('without data', () => { beforeEach(() => { wrapper = mount(registry, { - attachToDocument: true, propsData, computed: { repos() { diff --git a/spec/frontend/registry/list/components/collapsible_container_spec.js b/spec/frontend/registry/list/components/collapsible_container_spec.js index dda35b55af8..f969f0ba9ba 100644 --- a/spec/frontend/registry/list/components/collapsible_container_spec.js +++ b/spec/frontend/registry/list/components/collapsible_container_spec.js @@ -26,7 +26,6 @@ describe('collapsible registry container', () => { ...config, store, localVue, - attachToDocument: true, }); beforeEach(() => { diff --git a/spec/frontend/registry/list/components/project_empty_state_spec.js b/spec/frontend/registry/list/components/project_empty_state_spec.js index 0194abe6642..d29b9e47233 100644 --- a/spec/frontend/registry/list/components/project_empty_state_spec.js +++ b/spec/frontend/registry/list/components/project_empty_state_spec.js @@ -6,7 +6,6 @@ describe('Registry Project Empty state', () => { beforeEach(() => { wrapper = mount(projectEmptyState, { - attachToDocument: true, propsData: { noContainersImage: 'imageUrl', helpPagePath: 'help', diff --git a/spec/frontend/registry/list/components/table_registry_spec.js b/spec/frontend/registry/list/components/table_registry_spec.js index 935f93db883..b13797929dd 100644 --- a/spec/frontend/registry/list/components/table_registry_spec.js +++ b/spec/frontend/registry/list/components/table_registry_spec.js @@ -28,7 +28,11 @@ describe('table registry', () => { const bulkDeletePath = 'path'; const mountWithStore = config => - mount(tableRegistry, { ...config, store, localVue, attachToDocument: true }); + mount(tableRegistry, { + ...config, + store, + localVue, + }); beforeEach(() => { store = new Vuex.Store({ |