diff options
28 files changed, 262 insertions, 90 deletions
diff --git a/CHANGELOG-EE.md b/CHANGELOG-EE.md index 8bf716580a5..9226e23795b 100644 --- a/CHANGELOG-EE.md +++ b/CHANGELOG-EE.md @@ -1,5 +1,16 @@ Please view this file on the master branch, on stable branches it's out of date. +## 12.5.3 + +### Performance (1 change) + +- Geo - Improve query performance to determine job artifacts to sync when selective sync is enabled. !19583 + +### Other (1 change) + +- Geo - Does not schedule duplicated jobs while backfilling uploads, LFS objects and job artifacts. !20324 + + ## 12.5.1 ### Security (6 changes) diff --git a/CHANGELOG.md b/CHANGELOG.md index 806abf85e10..5c550c8c9db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,13 +16,6 @@ entry. - Flatten exception details in API and controller logs. !20434 -## 12.5.2 - -### Security (1 change) - -- Fix 500 error caused by invalid byte sequences in links. - - ## 12.5.1 ### Security (11 changes) diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 22d6771a47d..7c7053aa238 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -1.72.1 +1.75.0 diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js index db3ad0bb4c9..e25c9d90f60 100644 --- a/app/assets/javascripts/gfm_auto_complete.js +++ b/app/assets/javascripts/gfm_auto_complete.js @@ -3,11 +3,44 @@ import 'at.js'; import _ from 'underscore'; import glRegexp from './lib/utils/regexp'; import AjaxCache from './lib/utils/ajax_cache'; +import { spriteIcon } from './lib/utils/common_utils'; function sanitize(str) { return str.replace(/<(?:.|\n)*?>/gm, ''); } +export function membersBeforeSave(members) { + return _.map(members, member => { + const GROUP_TYPE = 'Group'; + + let title = ''; + if (member.username == null) { + return member; + } + title = member.name; + if (member.count && !member.mentionsDisabled) { + title += ` (${member.count})`; + } + + const autoCompleteAvatar = member.avatar_url || member.username.charAt(0).toUpperCase(); + + const rectAvatarClass = member.type === GROUP_TYPE ? 'rect-avatar' : ''; + const imgAvatar = `<img src="${member.avatar_url}" alt="${member.username}" class="avatar ${rectAvatarClass} avatar-inline center s26"/>`; + const txtAvatar = `<div class="avatar ${rectAvatarClass} center avatar-inline s26">${autoCompleteAvatar}</div>`; + const avatarIcon = member.mentionsDisabled + ? spriteIcon('notifications-off', 's16 vertical-align-middle prepend-left-5') + : ''; + + return { + username: member.username, + avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar, + title: sanitize(title), + search: sanitize(`${member.username} ${member.name}`), + icon: avatarIcon, + }; + }); +} + export const defaultAutocompleteConfig = { emojis: true, members: true, @@ -167,12 +200,13 @@ class GfmAutoComplete { alias: 'users', displayTpl(value) { let tmpl = GfmAutoComplete.Loading.template; - const { avatarTag, username, title } = value; + const { avatarTag, username, title, icon } = value; if (username != null) { tmpl = GfmAutoComplete.Members.templateFunction({ avatarTag, username, title, + icon, }); } return tmpl; @@ -185,33 +219,7 @@ class GfmAutoComplete { data: GfmAutoComplete.defaultLoadingData, callbacks: { ...this.getDefaultCallbacks(), - beforeSave(members) { - return $.map(members, m => { - let title = ''; - if (m.username == null) { - return m; - } - title = m.name; - if (m.count) { - title += ` (${m.count})`; - } - - const GROUP_TYPE = 'Group'; - - const autoCompleteAvatar = m.avatar_url || m.username.charAt(0).toUpperCase(); - - const rectAvatarClass = m.type === GROUP_TYPE ? 'rect-avatar' : ''; - const imgAvatar = `<img src="${m.avatar_url}" alt="${m.username}" class="avatar ${rectAvatarClass} avatar-inline center s26"/>`; - const txtAvatar = `<div class="avatar ${rectAvatarClass} center avatar-inline s26">${autoCompleteAvatar}</div>`; - - return { - username: m.username, - avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar, - title: sanitize(title), - search: sanitize(`${m.username} ${m.name}`), - }; - }); - }, + beforeSave: membersBeforeSave, }, }); } @@ -624,8 +632,8 @@ GfmAutoComplete.Emoji = { }; // Team Members GfmAutoComplete.Members = { - templateFunction({ avatarTag, username, title }) { - return `<li>${avatarTag} ${username} <small>${_.escape(title)}</small></li>`; + templateFunction({ avatarTag, username, title, icon }) { + return `<li>${avatarTag} ${username} <small>${_.escape(title)}</small> ${icon}</li>`; }, }; GfmAutoComplete.Labels = { diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index 2429da9c061..dac105d7243 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -182,6 +182,10 @@ const bindEvents = () => { text: s__('ProjectTemplates|Netlify/Hexo'), icon: '.template-option .icon-netlify', }, + salesforcedx: { + text: s__('ProjectTemplates|SalesforceDX'), + icon: '.template-option svg.icon-gitlab', + }, serverless_framework: { text: s__('ProjectTemplates|Serverless Framework/JS'), icon: '.template-option .icon-serverless_framework', diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 755d97b091c..0953ca96317 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -181,6 +181,7 @@ class GroupsController < Groups::ApplicationController :avatar, :description, :emails_disabled, + :mentions_disabled, :lfs_enabled, :name, :path, diff --git a/app/services/concerns/users/participable_service.rb b/app/services/concerns/users/participable_service.rb index 1c828234f1b..6fde9abfdb0 100644 --- a/app/services/concerns/users/participable_service.rb +++ b/app/services/concerns/users/participable_service.rb @@ -55,7 +55,8 @@ module Users username: group.full_path, name: group.full_name, avatar_url: group.avatar_url, - count: group_counts.fetch(group.id, 0) + count: group_counts.fetch(group.id, 0), + mentionsDisabled: group.mentions_disabled } end end diff --git a/app/services/issues/duplicate_service.rb b/app/services/issues/duplicate_service.rb index 82c226f601e..c936d75e277 100644 --- a/app/services/issues/duplicate_service.rb +++ b/app/services/issues/duplicate_service.rb @@ -25,3 +25,5 @@ module Issues end end end + +Issues::DuplicateService.prepend_if_ee('EE::Issues::DuplicateService') diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml index 4c88660ccb9..618cfe57be4 100644 --- a/app/views/groups/settings/_permissions.html.haml +++ b/app/views/groups/settings/_permissions.html.haml @@ -23,6 +23,13 @@ %span.d-block= s_('GroupSettings|Disable email notifications') %span.text-muted= s_('GroupSettings|This setting will override user notification preferences for all members of the group, subgroups, and projects.') + .form-group.append-bottom-default + .form-check + = f.check_box :mentions_disabled, checked: @group.mentions_disabled?, class: 'form-check-input' + = f.label :mentions_disabled, class: 'form-check-label' do + %span.d-block= s_('GroupSettings|Disable group mentions') + %span.text-muted= s_('GroupSettings|This setting will prevent group members from being notified if the group is mentioned.') + = render_if_exists 'groups/settings/ip_restriction', f: f, group: @group = render_if_exists 'groups/settings/allowed_email_domain', f: f, group: @group = render 'groups/settings/lfs', f: f diff --git a/changelogs/unreleased/3963-auto-related-duplicated-issues.yml b/changelogs/unreleased/3963-auto-related-duplicated-issues.yml new file mode 100644 index 00000000000..670f71d32dc --- /dev/null +++ b/changelogs/unreleased/3963-auto-related-duplicated-issues.yml @@ -0,0 +1,5 @@ +--- +title: Relate issues when they are marked as duplicated +merge_request: 20161 +author: minghuan lei +type: added diff --git a/changelogs/unreleased/feat-group-mentions-prevention.yml b/changelogs/unreleased/feat-group-mentions-prevention.yml new file mode 100644 index 00000000000..dd85a226111 --- /dev/null +++ b/changelogs/unreleased/feat-group-mentions-prevention.yml @@ -0,0 +1,5 @@ +--- +title: Allow groups to disable mentioning their members, if the group is mentioned +merge_request: 20184 +author: Fabio Huser +type: added diff --git a/changelogs/unreleased/gitaly-version-v1.75.0.yml b/changelogs/unreleased/gitaly-version-v1.75.0.yml new file mode 100644 index 00000000000..a4367d676e7 --- /dev/null +++ b/changelogs/unreleased/gitaly-version-v1.75.0.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade to Gitaly v1.75.0 +merge_request: 21045 +author: +type: changed diff --git a/changelogs/unreleased/salesforcedx_project_template.yml b/changelogs/unreleased/salesforcedx_project_template.yml new file mode 100644 index 00000000000..3cdf55ed85b --- /dev/null +++ b/changelogs/unreleased/salesforcedx_project_template.yml @@ -0,0 +1,5 @@ +--- +title: Add SalesforceDX project template +merge_request: 20831 +author: +type: added diff --git a/db/migrate/20191114132259_add_mentions_disabled_to_namespaces.rb b/db/migrate/20191114132259_add_mentions_disabled_to_namespaces.rb new file mode 100644 index 00000000000..dbd69568ef2 --- /dev/null +++ b/db/migrate/20191114132259_add_mentions_disabled_to_namespaces.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddMentionsDisabledToNamespaces < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def change + add_column :namespaces, :mentions_disabled, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 4be04185af5..2715c5717f7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -349,6 +349,7 @@ ActiveRecord::Schema.define(version: 2019_11_25_140458) do t.boolean "sourcegraph_enabled", default: false, null: false t.string "sourcegraph_url", limit: 255 t.boolean "sourcegraph_public_only", default: true, null: false + t.bigint "snippet_size_limit", default: 52428800, null: false t.text "encrypted_akismet_api_key" t.string "encrypted_akismet_api_key_iv", limit: 255 t.text "encrypted_elasticsearch_aws_secret_access_key" @@ -361,7 +362,6 @@ ActiveRecord::Schema.define(version: 2019_11_25_140458) do t.string "encrypted_slack_app_secret_iv", limit: 255 t.text "encrypted_slack_app_verification_token" t.string "encrypted_slack_app_verification_token_iv", limit: 255 - t.bigint "snippet_size_limit", default: 52428800, null: false t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id" t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id" t.index ["instance_administration_project_id"], name: "index_applicationsettings_on_instance_administration_project_id" @@ -2603,6 +2603,7 @@ ActiveRecord::Schema.define(version: 2019_11_25_140458) do t.boolean "emails_disabled" t.integer "max_pages_size" t.integer "max_artifacts_size" + t.boolean "mentions_disabled" t.index ["created_at"], name: "index_namespaces_on_created_at" t.index ["custom_project_templates_group_id", "type"], name: "index_namespaces_on_custom_project_templates_group_id_and_type", where: "(custom_project_templates_group_id IS NOT NULL)" t.index ["file_template_project_id"], name: "index_namespaces_on_file_template_project_id" diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 5f45a462f94..ad16aaa34ff 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -431,6 +431,23 @@ To enable this feature: 1. Expand the **Permissions, LFS, 2FA** section, and select **Disable email notifications**. 1. Click **Save changes**. +#### Disabling group mentions + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/21301) in GitLab 12.6. + +You can prevent users from being added to a conversation and getting notified when +anyone mentions a group in which those users are members. + +Groups with disabled mentions are visualized accordingly in the autocompletion dropdown. + +This is particularly helpful for groups with a large number of users. + +To enable this feature: + +1. Navigate to the group's **Settings > General** page. +1. Expand the **Permissions, LFS, 2FA** section, and select **Disable group mentions**. +1. Click **Save changes**. + ### Advanced settings - **Projects**: View all projects within that group, add members to each project, diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index 88dc8cbcabe..97ae429a33f 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -60,7 +60,7 @@ The following quick actions are applicable to descriptions, discussions and thre | `/remove_epic` | ✓ | | | Remove from epic **(ULTIMATE)** | | `/promote` | ✓ | | | Promote issue to epic **(ULTIMATE)** | | `/confidential` | ✓ | | | Make confidential | -| `/duplicate <#issue>` | ✓ | | | Mark this issue as a duplicate of another issue | +| `/duplicate <#issue>` | ✓ | | | Mark this issue as a duplicate of another issue and relate them for **(STARTER)** | | `/create_merge_request <branch name>` | ✓ | | | Create a new merge request starting from the current issue | | `/relate #issue1 #issue2` | ✓ | | | Mark issues as related **(STARTER)** | | `/move <path/to/project>` | ✓ | | | Move this issue to another project | diff --git a/lib/banzai/reference_parser/user_parser.rb b/lib/banzai/reference_parser/user_parser.rb index 067b06b7590..36c41c6615f 100644 --- a/lib/banzai/reference_parser/user_parser.rb +++ b/lib/banzai/reference_parser/user_parser.rb @@ -97,7 +97,9 @@ module Banzai def find_users_for_groups(ids) return [] if ids.empty? - User.joins(:group_members).where(members: { source_id: ids }).to_a + User.joins(:group_members).where(members: { + source_id: Namespace.where(id: ids).where('mentions_disabled IS NOT TRUE').select(:id) + }).to_a end def find_users_for_projects(ids) diff --git a/lib/gitlab/project_template.rb b/lib/gitlab/project_template.rb index 279fc4aa375..b4ee8818925 100644 --- a/lib/gitlab/project_template.rb +++ b/lib/gitlab/project_template.rb @@ -54,6 +54,7 @@ module Gitlab ProjectTemplate.new('nfplainhtml', 'Netlify/Plain HTML', _('A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfplain-html', 'illustrations/logos/netlify.svg'), ProjectTemplate.new('nfgitbook', 'Netlify/GitBook', _('A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfgitbook', 'illustrations/logos/netlify.svg'), ProjectTemplate.new('nfhexo', 'Netlify/Hexo', _('A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfhexo', 'illustrations/logos/netlify.svg'), + ProjectTemplate.new('salesforcedx', 'SalesforceDX', _('A project boilerplate for Salesforce App development with Salesforce Developer tools.'), 'https://gitlab.com/gitlab-org/project-templates/salesforcedx'), ProjectTemplate.new('serverless_framework', 'Serverless Framework/JS', _('A basic page and serverless function that uses AWS Lambda, AWS API Gateway, and GitLab Pages'), 'https://gitlab.com/gitlab-org/project-templates/serverless-framework', 'illustrations/logos/serverless_framework.svg') ].freeze diff --git a/lib/gitlab/tracking.rb b/lib/gitlab/tracking.rb index 91e2ff0b10d..37688d6e0e7 100644 --- a/lib/gitlab/tracking.rb +++ b/lib/gitlab/tracking.rb @@ -29,14 +29,14 @@ module Gitlab def event(category, action, label: nil, property: nil, value: nil, context: nil) return unless enabled? - snowplow.track_struct_event(category, action, label, property, value, context, Time.now.to_i) + snowplow.track_struct_event(category, action, label, property, value, context, (Time.now.to_f * 1000).to_i) end def self_describing_event(schema_url, event_data_json, context: nil) return unless enabled? event_json = SnowplowTracker::SelfDescribingJson.new(schema_url, event_data_json) - snowplow.track_self_describing_event(event_json, context, Time.now.to_i) + snowplow.track_self_describing_event(event_json, context, (Time.now.to_f * 1000).to_i) end def snowplow_options(group) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 405254c6278..68d3e795434 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -696,6 +696,9 @@ msgstr "" msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features." msgstr "" +msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools." +msgstr "" + msgid "A project is where you house your files (repository), plan your work (issues), and publish your documentation (wiki), %{among_other_things_link}." msgstr "" @@ -8860,6 +8863,9 @@ msgstr "" msgid "GroupSettings|Disable email notifications" msgstr "" +msgid "GroupSettings|Disable group mentions" +msgstr "" + msgid "GroupSettings|If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility." msgstr "" @@ -8908,6 +8914,9 @@ msgstr "" msgid "GroupSettings|This setting will override user notification preferences for all members of the group, subgroups, and projects." msgstr "" +msgid "GroupSettings|This setting will prevent group members from being notified if the group is mentioned." +msgstr "" + msgid "GroupSettings|Transfer group" msgstr "" @@ -13721,6 +13730,9 @@ msgstr "" msgid "ProjectTemplates|Ruby on Rails" msgstr "" +msgid "ProjectTemplates|SalesforceDX" +msgstr "" + msgid "ProjectTemplates|Serverless Framework/JS" msgstr "" diff --git a/spec/frontend/gfm_auto_complete_spec.js b/spec/frontend/gfm_auto_complete_spec.js index 8af49fd47a2..28ab2f2d6c4 100644 --- a/spec/frontend/gfm_auto_complete_spec.js +++ b/spec/frontend/gfm_auto_complete_spec.js @@ -1,6 +1,7 @@ /* eslint no-param-reassign: "off" */ import $ from 'jquery'; +import { membersBeforeSave } from '~/gfm_auto_complete'; import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete'; import 'jquery.caret'; @@ -262,6 +263,79 @@ describe('GfmAutoComplete', () => { }); }); + describe('membersBeforeSave', () => { + const mockGroup = { + username: 'my-group', + name: 'My Group', + count: 2, + avatar_url: './group.jpg', + type: 'Group', + mentionsDisabled: false, + }; + + it('should return the original object when username is null', () => { + expect(membersBeforeSave([{ ...mockGroup, username: null }])).toEqual([ + { ...mockGroup, username: null }, + ]); + }); + + it('should set the text avatar if avatar_url is null', () => { + expect(membersBeforeSave([{ ...mockGroup, avatar_url: null }])).toEqual([ + { + username: 'my-group', + avatarTag: '<div class="avatar rect-avatar center avatar-inline s26">M</div>', + title: 'My Group (2)', + search: 'my-group My Group', + icon: '', + }, + ]); + }); + + it('should set the image avatar if avatar_url is given', () => { + expect(membersBeforeSave([mockGroup])).toEqual([ + { + username: 'my-group', + avatarTag: + '<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline center s26"/>', + title: 'My Group (2)', + search: 'my-group My Group', + icon: '', + }, + ]); + }); + + it('should set mentions disabled icon if mentionsDisabled is set', () => { + expect(membersBeforeSave([{ ...mockGroup, mentionsDisabled: true }])).toEqual([ + { + username: 'my-group', + avatarTag: + '<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline center s26"/>', + title: 'My Group', + search: 'my-group My Group', + icon: + '<svg class="s16 vertical-align-middle prepend-left-5"><use xlink:href="undefined#notifications-off" /></svg>', + }, + ]); + }); + + it('should set the right image classes for User type members', () => { + expect( + membersBeforeSave([ + { username: 'my-user', name: 'My User', avatar_url: './users.jpg', type: 'User' }, + ]), + ).toEqual([ + { + username: 'my-user', + avatarTag: + '<img src="./users.jpg" alt="my-user" class="avatar avatar-inline center s26"/>', + title: 'My User', + search: 'my-user My User', + icon: '', + }, + ]); + }); + }); + describe('Issues.insertTemplateFunction', () => { it('should return default template', () => { expect(GfmAutoComplete.Issues.insertTemplateFunction({ id: 5, title: 'Some Issue' })).toBe( @@ -298,6 +372,41 @@ describe('GfmAutoComplete', () => { }); }); + describe('Members.templateFunction', () => { + it('should return html with avatarTag and username', () => { + expect( + GfmAutoComplete.Members.templateFunction({ + avatarTag: 'IMG', + username: 'my-group', + title: '', + icon: '', + }), + ).toBe('<li>IMG my-group <small></small> </li>'); + }); + + it('should add icon if icon is set', () => { + expect( + GfmAutoComplete.Members.templateFunction({ + avatarTag: 'IMG', + username: 'my-group', + title: '', + icon: '<i class="icon"/>', + }), + ).toBe('<li>IMG my-group <small></small> <i class="icon"/></li>'); + }); + + it('should add escaped title if title is set', () => { + expect( + GfmAutoComplete.Members.templateFunction({ + avatarTag: 'IMG', + username: 'my-group', + title: 'MyGroup+', + icon: '<i class="icon"/>', + }), + ).toBe('<li>IMG my-group <small>MyGroup+</small> <i class="icon"/></li>'); + }); + }); + describe('labels', () => { const dataSources = { labels: `${TEST_HOST}/autocomplete_sources/labels`, diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb index 931fb1e3953..71d2e1de3b6 100644 --- a/spec/lib/banzai/reference_parser/user_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb @@ -19,15 +19,23 @@ describe Banzai::ReferenceParser::UserParser do link['data-group'] = project.group.id.to_s end - it 'returns the users of the group' do - create(:group_member, group: group, user: user) - - expect(subject.referenced_by([link])).to eq([user]) - end - it 'returns an empty Array when the group has no users' do expect(subject.referenced_by([link])).to eq([]) end + + context 'when group has members' do + let!(:group_member) { create(:group_member, group: group, user: user) } + + it 'returns the users of the group' do + expect(subject.referenced_by([link])).to eq([user]) + end + + it 'returns an empty Array when the group has mentions disabled' do + group.update!(mentions_disabled: true) + + expect(subject.referenced_by([link])).to eq([]) + end + end end context 'using a non-existing group ID' do diff --git a/spec/lib/gitlab/project_template_spec.rb b/spec/lib/gitlab/project_template_spec.rb index 5559b1e4291..a2e3e2146f3 100644 --- a/spec/lib/gitlab/project_template_spec.rb +++ b/spec/lib/gitlab/project_template_spec.rb @@ -23,6 +23,7 @@ describe Gitlab::ProjectTemplate do described_class.new('nfplainhtml', 'Netlify/Plain HTML', _('A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfplain-html'), described_class.new('nfgitbook', 'Netlify/GitBook', _('A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfgitbook'), described_class.new('nfhexo', 'Netlify/Hexo', _('A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfhexo'), + described_class.new('salesforcedx', 'SalesforceDX', _('A project boilerplate for Salesforce App development with Salesforce Developer tools.'), 'https://gitlab.com/gitlab-org/project-templates/salesforcedx'), described_class.new('serverless_framework', 'Serverless Framework/JS', _('A basic page and serverless function that uses AWS Lambda, AWS API Gateway, and GitLab Pages'), 'https://gitlab.com/gitlab-org/project-templates/serverless-framework', 'illustrations/logos/serverless_framework.svg') ] diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb index dc877f20cae..efb07d9dc95 100644 --- a/spec/lib/gitlab/tracking_spec.rb +++ b/spec/lib/gitlab/tracking_spec.rb @@ -97,7 +97,7 @@ describe Gitlab::Tracking do '_property_', '_value_', nil, - timestamp.to_i + (timestamp.to_f * 1000).to_i ) track_event @@ -130,7 +130,7 @@ describe Gitlab::Tracking do expect(tracker).to receive(:track_self_describing_event).with( '_event_json_', nil, - timestamp.to_i + (timestamp.to_f * 1000).to_i ) track_event diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 604befd7225..b8a0e118479 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -689,8 +689,9 @@ describe Issues::UpdateService, :mailer do context 'valid canonical_issue_id' do it 'calls the duplicate service with both issues' do - expect_any_instance_of(Issues::DuplicateService) - .to receive(:execute).with(issue, canonical_issue) + expect_next_instance_of(Issues::DuplicateService) do |service| + expect(service).to receive(:execute).with(issue, canonical_issue) + end update_issue(canonical_issue_id: canonical_issue.id) end diff --git a/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb deleted file mode 100644 index 3834b8b2b87..00000000000 --- a/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -shared_examples 'duplicate quick action' do - context 'mark issue as duplicate' do - let(:original_issue) { create(:issue, project: project) } - - context 'when the current user can update issues' do - it 'does not create a note, and marks the issue as a duplicate' do - add_note("/duplicate ##{original_issue.to_reference}") - - expect(page).not_to have_content "/duplicate #{original_issue.to_reference}" - expect(page).to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" - - expect(issue.reload).to be_closed - end - end - - context 'when the current user cannot update the issue' do - let(:guest) { create(:user) } - before do - project.add_guest(guest) - gitlab_sign_out - sign_in(guest) - visit project_issue_path(project, issue) - end - - it 'does not create a note, and does not mark the issue as a duplicate' do - add_note("/duplicate ##{original_issue.to_reference}") - - expect(page).not_to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" - - expect(issue.reload).to be_open - end - end - end -end diff --git a/vendor/project_templates/salesforcedx.tar.gz b/vendor/project_templates/salesforcedx.tar.gz Binary files differnew file mode 100644 index 00000000000..f92721a453f --- /dev/null +++ b/vendor/project_templates/salesforcedx.tar.gz |