summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock12
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js2
-rw-r--r--app/assets/javascripts/blob_edit/edit_blob.js7
-rw-r--r--app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js18
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue6
-rw-r--r--app/assets/javascripts/ide/index.js1
-rw-r--r--app/assets/javascripts/ide/stores/state.js1
-rw-r--r--app/helpers/blob_helper.rb3
-rw-r--r--app/helpers/ide_helper.rb3
-rw-r--r--data/whats_new/202108190001_14_02.yml85
-rw-r--r--db/post_migrate/20210809123658_orphaned_invite_tokens_cleanup.rb35
-rw-r--r--db/post_migrate/20210819183128_reset_severity_levels_to_new_default.rb17
-rw-r--r--db/schema_migrations/202108191831281
-rw-r--r--lib/container_registry/client.rb3
-rw-r--r--spec/deprecation_toolkit_env.rb3
-rw-r--r--spec/frontend/blob_edit/edit_blob_spec.js11
-rw-r--r--spec/frontend/editor/source_editor_markdown_ext_spec.js32
-rw-r--r--spec/frontend/ide/components/repo_editor_spec.js7
-rw-r--r--spec/helpers/ide_helper_spec.rb6
-rw-r--r--spec/migrations/orphaned_invite_tokens_cleanup_spec.rb20
-rw-r--r--spec/migrations/reset_severity_levels_to_new_default_spec.rb33
22 files changed, 249 insertions, 61 deletions
diff --git a/Gemfile b/Gemfile
index 20ae89e60fb..ecb1e526e4d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -310,7 +310,7 @@ gem 'pg_query', '~> 2.1'
gem 'premailer-rails', '~> 1.10.3'
# LabKit: Tracing and Correlation
-gem 'gitlab-labkit', '~> 0.21.0'
+gem 'gitlab-labkit', '~> 0.21.1'
# Thrift is a dependency of gitlab-labkit, we want a version higher than 0.14.0
# because of https://gitlab.com/gitlab-org/gitlab/-/issues/321900
gem 'thrift', '>= 0.14.0'
@@ -479,7 +479,7 @@ gem 'gitaly', '~> 14.2.0.pre.rc2'
# KAS GRPC protocol definitions
gem 'kas-grpc', '~> 0.0.2'
-gem 'grpc', '~> 1.38.0'
+gem 'grpc', '~> 1.30.2'
gem 'google-protobuf', '~> 3.17.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index da82c2ee5c1..3ff3f6ca76f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -475,10 +475,10 @@ GEM
fog-json (~> 1.2.0)
mime-types
ms_rest_azure (~> 0.12.0)
- gitlab-labkit (0.21.0)
+ gitlab-labkit (0.21.1)
actionpack (>= 5.0.0, < 7.0.0)
activesupport (>= 5.0.0, < 7.0.0)
- grpc (~> 1.38)
+ grpc (~> 1.30.2)
jaeger-client (~> 1.1)
opentracing (~> 0.4)
pg_query (~> 2.1)
@@ -573,8 +573,8 @@ GEM
graphql (~> 1.6)
html-pipeline (~> 2.8)
sass (~> 3.4)
- grpc (1.38.0)
- google-protobuf (~> 3.15)
+ grpc (1.30.2)
+ google-protobuf (~> 3.12)
googleapis-common-protos-types (~> 1.0)
gssapi (1.2.0)
ffi (>= 1.0.1)
@@ -1477,7 +1477,7 @@ DEPENDENCIES
gitlab-dangerfiles (~> 2.3.0)
gitlab-experiment (~> 0.6.4)
gitlab-fog-azure-rm (~> 1.1.1)
- gitlab-labkit (~> 0.21.0)
+ gitlab-labkit (~> 0.21.1)
gitlab-license (~> 2.0)
gitlab-mail_room (~> 0.0.9)
gitlab-markup (~> 1.7.1)
@@ -1499,7 +1499,7 @@ DEPENDENCIES
graphlient (~> 0.4.0)
graphql (~> 1.11.8)
graphql-docs (~> 1.6.0)
- grpc (~> 1.38.0)
+ grpc (~> 1.30.2)
gssapi
guard-rspec
haml_lint (~> 0.36.0)
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index 76d9b18b777..2d9ffda06d0 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -69,6 +69,7 @@ export default () => {
const currentAction = $('.js-file-title').data('currentAction');
const projectId = editBlobForm.data('project-id');
const isMarkdown = editBlobForm.data('is-markdown');
+ const previewMarkdownPath = editBlobForm.data('previewMarkdownPath');
const commitButton = $('.js-commit-button');
const cancelLink = $('.btn.btn-cancel');
@@ -80,6 +81,7 @@ export default () => {
currentAction,
projectId,
isMarkdown,
+ previewMarkdownPath,
});
initPopovers();
initCodeQualityWalkthroughStep();
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index e068910c626..118cef59d5a 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -11,7 +11,7 @@ import { BLOB_EDITOR_ERROR, BLOB_PREVIEW_ERROR } from './constants';
export default class EditBlob {
// The options object has:
- // assetsPath, filePath, currentAction, projectId, isMarkdown
+ // assetsPath, filePath, currentAction, projectId, isMarkdown, previewMarkdownPath
constructor(options) {
this.options = options;
this.configureMonacoEditor();
@@ -30,7 +30,10 @@ export default class EditBlob {
import('~/editor/extensions/source_editor_markdown_ext')
.then(({ EditorMarkdownExtension: MarkdownExtension } = {}) => {
this.editor.use(
- new MarkdownExtension({ instance: this.editor, projectPath: this.options.projectPath }),
+ new MarkdownExtension({
+ instance: this.editor,
+ previewMarkdownPath: this.options.previewMarkdownPath,
+ }),
);
this.hasMarkdownExtension = true;
addEditorMarkdownListeners(this.editor);
diff --git a/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js b/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
index 76e009164f7..57de21c933e 100644
--- a/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
+++ b/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
@@ -14,17 +14,9 @@ import {
} from '../constants';
import { SourceEditorExtension } from './source_editor_extension_base';
-const getPreview = (text, projectPath = '') => {
- let url;
-
- if (projectPath) {
- url = `/${projectPath}/preview_markdown`;
- } else {
- const { group, project } = document.body.dataset;
- url = `/${group}/${project}/preview_markdown`;
- }
+const getPreview = (text, previewMarkdownPath) => {
return axios
- .post(url, {
+ .post(previewMarkdownPath, {
text,
})
.then(({ data }) => {
@@ -43,10 +35,10 @@ const setupDomElement = ({ injectToEl = null } = {}) => {
};
export class EditorMarkdownExtension extends SourceEditorExtension {
- constructor({ instance, projectPath, ...args } = {}) {
+ constructor({ instance, previewMarkdownPath, ...args } = {}) {
super({ instance, ...args });
Object.assign(instance, {
- projectPath,
+ previewMarkdownPath,
preview: {
el: undefined,
action: undefined,
@@ -112,7 +104,7 @@ export class EditorMarkdownExtension extends SourceEditorExtension {
fetchPreview() {
const { el: previewEl } = this.preview;
- getPreview(this.getValue(), this.projectPath)
+ getPreview(this.getValue(), this.previewMarkdownPath)
.then((data) => {
previewEl.innerHTML = sanitize(data);
syntaxHighlight(previewEl.querySelectorAll('.js-syntax-highlight'));
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index 2f990280367..2bf99550bf2 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -79,6 +79,7 @@ export default {
'editorTheme',
'entries',
'currentProjectId',
+ 'previewMarkdownPath',
]),
...mapGetters([
'getAlert',
@@ -314,14 +315,15 @@ export default {
if (
this.fileType === MARKDOWN_FILE_TYPE &&
- this.editor?.getEditorType() === EDITOR_TYPE_CODE
+ this.editor?.getEditorType() === EDITOR_TYPE_CODE &&
+ this.previewMarkdownPath
) {
import('~/editor/extensions/source_editor_markdown_ext')
.then(({ EditorMarkdownExtension: MarkdownExtension } = {}) => {
this.editor.use(
new MarkdownExtension({
instance: this.editor,
- projectPath: this.currentProjectId,
+ previewMarkdownPath: this.previewMarkdownPath,
}),
);
})
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index e8c726d6184..bdffed70882 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -63,6 +63,7 @@ export function initIde(el, options = {}) {
editorTheme: window.gon?.user_color_scheme || DEFAULT_THEME,
codesandboxBundlerUrl: el.dataset.codesandboxBundlerUrl,
environmentsGuidanceAlertDismissed: !parseBoolean(el.dataset.enableEnvironmentsGuidance),
+ previewMarkdownPath: el.dataset.previewMarkdownPath,
});
},
beforeDestroy() {
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 83551e87f09..526987c750a 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -32,4 +32,5 @@ export default () => ({
codesandboxBundlerUrl: null,
environmentsGuidanceAlertDismissed: false,
environmentsGuidanceAlertDetected: false,
+ previewMarkdownPath: '',
});
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index eccd0e7a34c..c1a33794b50 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -220,7 +220,8 @@ module BlobHelper
'assets-prefix' => Gitlab::Application.config.assets.prefix,
'blob-filename' => @blob && @blob.path,
'project-id' => project.id,
- 'is-markdown' => @blob && @blob.path && Gitlab::MarkupHelper.gitlab_markdown?(@blob.path)
+ 'is-markdown' => @blob && @blob.path && Gitlab::MarkupHelper.gitlab_markdown?(@blob.path),
+ 'preview-markdown-path' => preview_markdown_path(project)
}
end
diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb
index 41c7abbbabd..09ff57e2baf 100644
--- a/app/helpers/ide_helper.rb
+++ b/app/helpers/ide_helper.rb
@@ -19,7 +19,8 @@ module IdeHelper
'merge-request' => @merge_request,
'fork-info' => @fork_info&.to_json,
'project' => convert_to_project_entity_json(@project),
- 'enable-environments-guidance' => enable_environments_guidance?.to_s
+ 'enable-environments-guidance' => enable_environments_guidance?.to_s,
+ 'preview-markdown-path' => @project && preview_markdown_path(@project)
}
end
diff --git a/data/whats_new/202108190001_14_02.yml b/data/whats_new/202108190001_14_02.yml
new file mode 100644
index 00000000000..99ba097b60c
--- /dev/null
+++ b/data/whats_new/202108190001_14_02.yml
@@ -0,0 +1,85 @@
+- title: Add pronunciation to GitLab profile page
+ body: |
+ You can now add pronunciation to your user profile. In distributed teams where team members are from different countries, it can be difficult to determine how to say someone's name correctly. This will help others know how to pronounce your name.
+ stage: Manage
+ self-managed: true
+ gitlab-com: true
+ packages: [Free, Premium, Ultimate]
+ url: 'https://docs.gitlab.com/ee/user/profile/#add-your-pronunciation'
+ image_url: https://about.gitlab.com/images/14_2/pronounce.png
+ published_at: 2021-08-22
+ release: 14.2
+- title: View historical CI pipeline minute usage
+ body: |
+ Before GitLab 14.2, the CI pipeline minutes usage on the [Usage Quotas](https://docs.gitlab.com/ee/user/admin_area/settings/continuous_integration.html#shared-runners-pipeline-minutes-quota) page only showed the current month's usage. This data would reset every month and there was no way to view activity from the past months for analyzing historical usage.
+
+ Now there are two charts that show historical CI pipeline minutes usage by month or by project, so you can make informed decisions about your pipeline usage.
+ stage: Verify
+ self-managed: true
+ gitlab-com: true
+ packages: [Free, Premium, Ultimate]
+ url: 'https://docs.gitlab.com/ee/subscriptions/gitlab_com/index.html#ci-pipeline-minutes'
+ image_url: https://about.gitlab.com/images/14_2/CI_minutes_usage_graph.png
+ published_at: 2021-08-22
+ release: 14.2
+- title: Edit issue title from an issue board
+ body: |
+ Editing an issue in an issue board currently requires many steps and takes you out of your workflow. We've added an easy way to edit an issue's title right in the issue board, without navigating to another page. To edit the title, in the right sidebar, select the issue, then select **Edit**.
+ stage: Plan
+ self-managed: true
+ gitlab-com: true
+ packages: [Free, Premium, Ultimate]
+ url: 'https://docs.gitlab.com/ee/user/project/issue_board.html#edit-an-issue'
+ image_url: https://about.gitlab.com/images/14_2/issue-board-edit-title.gif
+ published_at: 2021-08-22
+ release: 14.2
+- title: Preview Markdown live while editing
+ body: |
+ Markdown is a fast and intuitive syntax for writing rich web content. Until it isn't. Luckily, it's easy to preview the rendered output of Markdown to ensure the accuracy of your markup from the **Preview** tab. Unfortunately, the context switch required to move between the raw source code and the preview can be tedious and disruptive to your flow.
+
+ Now, in both the Web IDE and single file editor, Markdown files have a new live preview option available. Right-click the editor and select **Preview Markdown** or use `Command/Control + Shift + P` to toggle a split-screen live preview of your Markdown content. The preview refreshes as you type, so you can be confident that your markup is valid and will render as you intended.
+ stage: Create
+ self-managed: true
+ gitlab-com: true
+ packages: [Free, Premium, Ultimate]
+ url: 'https://docs.gitlab.com/ee/user/project/web_ide/#markdown-editing'
+ image_url: https://about.gitlab.com/images/14_2/create-markdown-live-preview.png
+ published_at: 2021-08-22
+ release: 14.2
+- title: Stageless pipelines
+ body: |
+ Using the [`needs`](https://docs.gitlab.com/ee/ci/yaml/#needs) keyword in your pipeline configuration helps to reduce cycle times by ignoring stage ordering and running jobs without waiting for others to complete. Previously, `needs` could only be used between jobs on different stages.
+
+ In this release, we've removed this limitation so you can define a `needs` relationship between any job you want. As a result, you can now create a complete CI/CD pipeline without using stages by including `needs` in every job to implicitly configure the execution order. This lets you define a less verbose pipeline that takes less time to create and can run even faster.
+ stage: Verify
+ self-managed: true
+ gitlab-com: true
+ packages: [Free, Premium, Ultimate]
+ url: 'https://docs.gitlab.com/ee/ci/yaml/#needs'
+ image_url: https://about.gitlab.com/images/14_2/need.png
+ published_at: 2021-08-22
+ release: 14.2
+- title: New GitLab Kubernetes Agent UI
+ body: |
+ The GitLab Kubernetes Agent allows a secure bi-directional connection between GitLab and any Kubernetes cluster. Until now, registering a new Kubernetes Agent required writing GraphQL queries.
+
+ As of GitLab 14.2, GitLab ships with a user-friendly user interface and a registration form to help you get started with the Kubernetes Agent with ease.
+ stage: Configure
+ self-managed: true
+ gitlab-com: true
+ packages: [Premium, Ultimate]
+ url: 'https://docs.gitlab.com/ee/user/clusters/agent/'
+ image_url: https://about.gitlab.com/images/14_2/k8s-agent-registration.png
+ published_at: 2021-08-22
+ release: 14.2
+- title: Create a GitLab branch from a Jira issue
+ body: |
+ Users of the [GitLab.com for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud) application can now create GitLab branches directly from a Jira issue's [development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/). This enables developers to begin work on issues without having to switch tools and lose context.
+ stage: Create
+ self-managed: true
+ gitlab-com: true
+ packages: [Free, Premium, Ultimate]
+ url: 'https://docs.gitlab.com/ee/integration/jira/connect-app.html'
+ image_url: https://about.gitlab.com/images/14_2/jira_dev_panel_jira_setup_3.png
+ published_at: 2021-08-22
+ release: 14.2
diff --git a/db/post_migrate/20210809123658_orphaned_invite_tokens_cleanup.rb b/db/post_migrate/20210809123658_orphaned_invite_tokens_cleanup.rb
index f774db73eaa..ddbafaf32a9 100644
--- a/db/post_migrate/20210809123658_orphaned_invite_tokens_cleanup.rb
+++ b/db/post_migrate/20210809123658_orphaned_invite_tokens_cleanup.rb
@@ -6,15 +6,12 @@ class OrphanedInviteTokensCleanup < ActiveRecord::Migration[6.1]
disable_ddl_transaction!
TMP_INDEX_NAME = 'tmp_idx_orphaned_invite_tokens'
- QUERY_CONDITION = "invite_token IS NOT NULL and invite_accepted_at IS NOT NULL and invite_accepted_at < created_at"
def up
- membership = define_batchable_model('members')
+ add_concurrent_index('members', :id, where: query_condition, name: TMP_INDEX_NAME)
- add_concurrent_index('members', :id, where: QUERY_CONDITION, name: TMP_INDEX_NAME)
-
- membership.where(QUERY_CONDITION).pluck(:id).each_slice(10) do |group|
- membership.where(id: group).where(QUERY_CONDITION).update_all(invite_token: nil)
+ membership.where(query_condition).pluck(:id).each_slice(10) do |group|
+ membership.where(id: group).where(query_condition).update_all(invite_token: nil)
end
remove_concurrent_index_by_name('members', TMP_INDEX_NAME)
@@ -25,4 +22,30 @@ class OrphanedInviteTokensCleanup < ActiveRecord::Migration[6.1]
# This migration is irreversible
end
+
+ private
+
+ def membership
+ @membership ||= define_batchable_model('members')
+ end
+
+ # We need to ensure we're comparing timestamp with time zones across
+ # the board since that is an immutable comparison. Some database
+ # schemas have a mix of timestamp without time zones and and timestamp
+ # with time zones: https://gitlab.com/groups/gitlab-org/-/epics/2473
+ def query_condition
+ "invite_token IS NOT NULL and invite_accepted_at IS NOT NULL and #{timestamptz("invite_accepted_at")} < #{timestamptz("created_at")}"
+ end
+
+ def timestamptz(name)
+ if column_type(name) == "timestamp without time zone"
+ "TIMEZONE('UTC', #{name})"
+ else
+ name
+ end
+ end
+
+ def column_type(name)
+ membership.columns_hash[name].sql_type
+ end
end
diff --git a/db/post_migrate/20210819183128_reset_severity_levels_to_new_default.rb b/db/post_migrate/20210819183128_reset_severity_levels_to_new_default.rb
new file mode 100644
index 00000000000..cdfd92ac0d7
--- /dev/null
+++ b/db/post_migrate/20210819183128_reset_severity_levels_to_new_default.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class ResetSeverityLevelsToNewDefault < ActiveRecord::Migration[6.1]
+ ALL_SEVERITY_LEVELS = 6 # ::Enums::Vulnerability::SEVERITY_LEVELS.count
+
+ def up
+ execute(<<~SQL.squish)
+ UPDATE approval_project_rules
+ SET severity_levels = '{unknown, high, critical}'
+ WHERE array_length(severity_levels, 1) = #{ALL_SEVERITY_LEVELS};
+ SQL
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20210819183128 b/db/schema_migrations/20210819183128
new file mode 100644
index 00000000000..84b8b3780e3
--- /dev/null
+++ b/db/schema_migrations/20210819183128
@@ -0,0 +1 @@
+d57791945f0d21da90a5b1d75db9add6c7e916ad3c13df2522c7d71d572baa47 \ No newline at end of file
diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb
index 8dea765dd11..cc692140301 100644
--- a/lib/container_registry/client.rb
+++ b/lib/container_registry/client.rb
@@ -11,6 +11,7 @@ module ContainerRegistry
attr_accessor :uri
DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE = 'application/vnd.docker.distribution.manifest.v2+json'
+ DOCKER_DISTRIBUTION_MANIFEST_LIST_V2_TYPE = 'application/vnd.docker.distribution.manifest.list.v2+json'
OCI_MANIFEST_V1_TYPE = 'application/vnd.oci.image.manifest.v1+json'
CONTAINER_IMAGE_V1_TYPE = 'application/vnd.docker.container.image.v1+json'
REGISTRY_VERSION_HEADER = 'gitlab-container-registry-version'
@@ -19,6 +20,8 @@ module ContainerRegistry
ACCEPTED_TYPES = [DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE, OCI_MANIFEST_V1_TYPE].freeze
+ ACCEPTED_TYPES_RAW = [DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE, OCI_MANIFEST_V1_TYPE, DOCKER_DISTRIBUTION_MANIFEST_LIST_V2_TYPE].freeze
+
# Taken from: FaradayMiddleware::FollowRedirects
REDIRECT_CODES = Set.new [301, 302, 303, 307]
diff --git a/spec/deprecation_toolkit_env.rb b/spec/deprecation_toolkit_env.rb
index b95a8c599bf..f4db2c30094 100644
--- a/spec/deprecation_toolkit_env.rb
+++ b/spec/deprecation_toolkit_env.rb
@@ -56,9 +56,12 @@ module DeprecationToolkitEnv
# In this case, we recommend to add a silence together with an issue to patch or update
# the dependency causing the problem.
# See https://gitlab.com/gitlab-org/gitlab/-/commit/aea37f506bbe036378998916d374966c031bf347#note_647515736
+ #
+ # - ruby/lib/grpc/generic/interceptors.rb: https://gitlab.com/gitlab-org/gitlab/-/issues/339305
def self.allowed_kwarg_warning_paths
%w[
actionpack-6.1.3.2/lib/action_dispatch/routing/route_set.rb
+ ruby/lib/grpc/generic/interceptors.rb
]
end
diff --git a/spec/frontend/blob_edit/edit_blob_spec.js b/spec/frontend/blob_edit/edit_blob_spec.js
index 2be72ded0a2..ebef0656750 100644
--- a/spec/frontend/blob_edit/edit_blob_spec.js
+++ b/spec/frontend/blob_edit/edit_blob_spec.js
@@ -8,6 +8,8 @@ jest.mock('~/editor/source_editor');
jest.mock('~/editor/extensions/source_editor_markdown_ext');
jest.mock('~/editor/extensions/source_editor_file_template_ext');
+const PREVIEW_MARKDOWN_PATH = '/foo/bar/preview_markdown';
+
describe('Blob Editing', () => {
const useMock = jest.fn();
const mockInstance = {
@@ -34,6 +36,7 @@ describe('Blob Editing', () => {
const editorInst = (isMarkdown) => {
return new EditBlob({
isMarkdown,
+ previewMarkdownPath: PREVIEW_MARKDOWN_PATH,
});
};
@@ -44,6 +47,7 @@ describe('Blob Editing', () => {
it('loads FileTemplateExtension by default', async () => {
await initEditor();
+ expect(useMock).toHaveBeenCalledWith(expect.any(FileTemplateExtension));
expect(FileTemplateExtension).toHaveBeenCalledTimes(1);
});
@@ -55,9 +59,12 @@ describe('Blob Editing', () => {
it('loads MarkdownExtension only for the markdown files', async () => {
await initEditor(true);
- expect(useMock).toHaveBeenCalledTimes(2);
- expect(FileTemplateExtension).toHaveBeenCalledTimes(1);
+ expect(useMock).toHaveBeenCalledWith(expect.any(EditorMarkdownExtension));
expect(EditorMarkdownExtension).toHaveBeenCalledTimes(1);
+ expect(EditorMarkdownExtension).toHaveBeenCalledWith({
+ instance: mockInstance,
+ previewMarkdownPath: PREVIEW_MARKDOWN_PATH,
+ });
});
});
diff --git a/spec/frontend/editor/source_editor_markdown_ext_spec.js b/spec/frontend/editor/source_editor_markdown_ext_spec.js
index 48ccc10e486..245c6c28d31 100644
--- a/spec/frontend/editor/source_editor_markdown_ext_spec.js
+++ b/spec/frontend/editor/source_editor_markdown_ext_spec.js
@@ -23,7 +23,7 @@ describe('Markdown Extension for Source Editor', () => {
let editorEl;
let panelSpy;
let mockAxios;
- const projectPath = 'fooGroup/barProj';
+ const previewMarkdownPath = '/gitlab/fooGroup/barProj/preview_markdown';
const firstLine = 'This is a';
const secondLine = 'multiline';
const thirdLine = 'string with some **markup**';
@@ -57,7 +57,7 @@ describe('Markdown Extension for Source Editor', () => {
blobPath: markdownPath,
blobContent: text,
});
- editor.use(new EditorMarkdownExtension({ instance, projectPath }));
+ editor.use(new EditorMarkdownExtension({ instance, previewMarkdownPath }));
panelSpy = jest.spyOn(EditorMarkdownExtension, 'togglePreviewPanel');
});
@@ -74,7 +74,7 @@ describe('Markdown Extension for Source Editor', () => {
shown: false,
modelChangeListener: undefined,
});
- expect(instance.projectPath).toBe(projectPath);
+ expect(instance.previewMarkdownPath).toBe(previewMarkdownPath);
});
describe('model language changes listener', () => {
@@ -223,34 +223,24 @@ describe('Markdown Extension for Source Editor', () => {
});
describe('fetchPreview', () => {
- const group = 'foo';
- const project = 'bar';
- const setData = (path, g, p) => {
- instance.projectPath = path;
- document.body.setAttribute('data-group', g);
- document.body.setAttribute('data-project', p);
- };
const fetchPreview = async () => {
instance.fetchPreview();
await waitForPromises();
};
+ let previewMarkdownSpy;
+
beforeEach(() => {
- mockAxios.onPost().reply(200, { body: responseData });
+ previewMarkdownSpy = jest.fn().mockImplementation(() => [200, { body: responseData }]);
+ mockAxios.onPost(previewMarkdownPath).replyOnce((req) => previewMarkdownSpy(req));
});
- it('correctly fetches preview based on projectPath', async () => {
- setData(projectPath, group, project);
+ it('correctly fetches preview based on previewMarkdownPath', async () => {
await fetchPreview();
- expect(mockAxios.history.post[0].url).toBe(`/${projectPath}/preview_markdown`);
- expect(mockAxios.history.post[0].data).toEqual(JSON.stringify({ text }));
- });
- it('correctly fetches preview based on group and project data attributes', async () => {
- setData(undefined, group, project);
- await fetchPreview();
- expect(mockAxios.history.post[0].url).toBe(`/${group}/${project}/preview_markdown`);
- expect(mockAxios.history.post[0].data).toEqual(JSON.stringify({ text }));
+ expect(previewMarkdownSpy).toHaveBeenCalledWith(
+ expect.objectContaining({ data: JSON.stringify({ text }) }),
+ );
});
it('puts the fetched content into the preview DOM element', async () => {
diff --git a/spec/frontend/ide/components/repo_editor_spec.js b/spec/frontend/ide/components/repo_editor_spec.js
index b2254de706c..47bcfb59a5f 100644
--- a/spec/frontend/ide/components/repo_editor_spec.js
+++ b/spec/frontend/ide/components/repo_editor_spec.js
@@ -24,6 +24,8 @@ import axios from '~/lib/utils/axios_utils';
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
import { file } from '../helpers';
+const PREVIEW_MARKDOWN_PATH = '/foo/bar/preview_markdown';
+
const defaultFileProps = {
...file('file.txt'),
content: 'hello world',
@@ -77,6 +79,7 @@ const prepareStore = (state, activeFile) => {
entries: {
[activeFile.path]: activeFile,
},
+ previewMarkdownPath: PREVIEW_MARKDOWN_PATH,
};
const storeOptions = createStoreOptions();
return new Vuex.Store({
@@ -278,10 +281,10 @@ describe('RepoEditor', () => {
async ({ activeFile, viewer, shouldHaveMarkdownExtension } = {}) => {
await createComponent({ state: { viewer }, activeFile });
if (shouldHaveMarkdownExtension) {
- expect(vm.editor.projectPath).toBe(vm.currentProjectId);
+ expect(vm.editor.previewMarkdownPath).toBe(PREVIEW_MARKDOWN_PATH);
expect(vm.editor.togglePreview).toBeDefined();
} else {
- expect(vm.editor.projectPath).toBeUndefined();
+ expect(vm.editor.previewMarkdownPath).toBeUndefined();
expect(vm.editor.togglePreview).toBeUndefined();
}
},
diff --git a/spec/helpers/ide_helper_spec.rb b/spec/helpers/ide_helper_spec.rb
index d34358e49c0..503ad3ad66d 100644
--- a/spec/helpers/ide_helper_spec.rb
+++ b/spec/helpers/ide_helper_spec.rb
@@ -18,7 +18,8 @@ RSpec.describe IdeHelper do
'file-path' => nil,
'merge-request' => nil,
'fork-info' => nil,
- 'project' => nil
+ 'project' => nil,
+ 'preview-markdown-path' => nil
)
end
end
@@ -41,7 +42,8 @@ RSpec.describe IdeHelper do
'file-path' => 'foo/bar',
'merge-request' => '1',
'fork-info' => fork_info.to_json,
- 'project' => serialized_project
+ 'project' => serialized_project,
+ 'preview-markdown-path' => Gitlab::Routing.url_helpers.preview_markdown_project_path(project)
)
end
end
diff --git a/spec/migrations/orphaned_invite_tokens_cleanup_spec.rb b/spec/migrations/orphaned_invite_tokens_cleanup_spec.rb
index 889c04700c7..be5e7756514 100644
--- a/spec/migrations/orphaned_invite_tokens_cleanup_spec.rb
+++ b/spec/migrations/orphaned_invite_tokens_cleanup_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe OrphanedInviteTokensCleanup, :migration do
table(:members).create!(defaults.merge(extra_attributes))
end
- describe '#up', :aggregate_failures do
+ shared_examples 'removes orphaned invite tokens' do
it 'removes invite tokens for accepted records with invite_accepted_at < created_at' do
record1 = create_member(invite_token: 'foo', invite_accepted_at: 1.day.ago, created_at: 1.hour.ago)
record2 = create_member(invite_token: 'foo2', invite_accepted_at: nil, created_at: 1.hour.ago)
@@ -29,4 +29,22 @@ RSpec.describe OrphanedInviteTokensCleanup, :migration do
expect(table(:members).find(record3.id).invite_token).to eq 'foo3'
end
end
+
+ describe '#up', :aggregate_failures do
+ it_behaves_like 'removes orphaned invite tokens'
+ end
+
+ context 'when there is a mix of timestamptz and timestamp types' do
+ around do |example|
+ ActiveRecord::Base.connection.execute "ALTER TABLE members alter created_at type timestamp with time zone"
+
+ example.run
+
+ ActiveRecord::Base.connection.execute "ALTER TABLE members alter created_at type timestamp without time zone"
+ end
+
+ describe '#up', :aggregate_failures do
+ it_behaves_like 'removes orphaned invite tokens'
+ end
+ end
end
diff --git a/spec/migrations/reset_severity_levels_to_new_default_spec.rb b/spec/migrations/reset_severity_levels_to_new_default_spec.rb
new file mode 100644
index 00000000000..18dc001db16
--- /dev/null
+++ b/spec/migrations/reset_severity_levels_to_new_default_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe ResetSeverityLevelsToNewDefault do
+ let(:approval_project_rules) { table(:approval_project_rules) }
+ let(:projects) { table(:projects)}
+ let(:namespaces) { table(:namespaces)}
+ let(:namespace) { namespaces.create!(name: 'namespace', path: 'namespace')}
+ let(:project) { projects.create!(name: 'project', path: 'project', namespace_id: namespace.id)}
+ let(:approval_project_rule) { approval_project_rules.create!(name: 'rule', project_id: project.id, severity_levels: severity_levels) }
+
+ context 'without having all severity levels selected' do
+ let(:severity_levels) { ['high'] }
+
+ it 'does not change severity_levels' do
+ expect(approval_project_rule.severity_levels).to eq(severity_levels)
+ expect { migrate! }.not_to change { approval_project_rule.reload.severity_levels }
+ end
+ end
+
+ context 'with all scanners selected' do
+ let(:severity_levels) { ::Enums::Vulnerability::SEVERITY_LEVELS.keys }
+ let(:default_levels) { %w(unknown high critical) }
+
+ it 'changes severity_levels to the default value' do
+ expect(approval_project_rule.severity_levels).to eq(severity_levels)
+ expect { migrate! }.to change {approval_project_rule.reload.severity_levels}.from(severity_levels).to(default_levels)
+ end
+ end
+end