diff --git a/Gemfile b/Gemfile index ce3192a4743..cc7d59ef732 100644 --- a/Gemfile +++ b/Gemfile @@ -360,9 +360,9 @@ end group :development, :test do gem 'deprecation_toolkit', '~> 1.5.1', require: false gem 'bullet', '~> 6.1.3' - gem 'gitlab-pry-byebug', platform: :mri, require: ['pry-byebug', 'pry-byebug/pry_remote_ext'] + gem 'pry-byebug' gem 'pry-rails', '~> 0.3.9' - gem 'pry-remote' + gem 'pry-shell', '~> 0.4.0' gem 'awesome_print', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 34a0fe708a1..f6d6e07d3a3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -483,9 +483,6 @@ GEM addressable (~> 2.7) omniauth (~> 1.9) openid_connect (~> 1.2) - gitlab-pry-byebug (3.9.0) - byebug (~> 11.0) - pry (~> 0.13.0) gitlab-sidekiq-fetcher (0.5.6) sidekiq (~> 5) gitlab-styles (6.2.0) @@ -901,6 +898,8 @@ GEM parser (3.0.0.0) ast (~> 2.4.1) parslet (1.8.2) + pastel (0.8.0) + tty-color (~> 0.5) peek (1.1.0) railties (>= 4.0.0) pg (1.2.3) @@ -926,11 +925,15 @@ GEM pry (0.13.1) coderay (~> 1.1) method_source (~> 1.0) + pry-byebug (3.9.0) + byebug (~> 11.0) + pry (~> 0.13.0) pry-rails (0.3.9) pry (>= 0.10.4) - pry-remote (0.1.8) - pry (~> 0.9) - slop (~> 3.0) + pry-shell (0.4.0) + pry (~> 0.13.0) + tty-markdown + tty-prompt public_suffix (4.0.6) puma (5.1.1) nio4r (~> 2.0) @@ -1196,7 +1199,6 @@ GEM simplecov-html (0.12.2) sixarm_ruby_unaccent (1.2.0) slack-messenger (2.3.4) - slop (3.6.0) snowplow-tracker (0.6.1) contracts (~> 0.7, <= 0.11) solargraph (0.40.4) @@ -1236,6 +1238,11 @@ GEM state_machines-activerecord (0.8.0) activerecord (>= 5.1) state_machines-activemodel (>= 0.8.0) + strings (0.2.1) + strings-ansi (~> 0.2) + unicode-display_width (>= 1.5, < 3.0) + unicode_utils (~> 1.4) + strings-ansi (0.2.0) swd (1.2.0) activesupport (>= 3) attr_required (>= 0.0.5) @@ -1282,6 +1289,23 @@ GEM truncato (0.7.11) htmlentities (~> 4.3.1) nokogiri (>= 1.7.0, <= 2.0) + tty-color (0.6.0) + tty-cursor (0.7.1) + tty-markdown (0.7.0) + kramdown (>= 1.16.2, < 3.0) + pastel (~> 0.8) + rouge (~> 3.14) + strings (~> 0.2.0) + tty-color (~> 0.5) + tty-screen (~> 0.8) + tty-prompt (0.23.1) + pastel (~> 0.8) + tty-reader (~> 0.8) + tty-reader (0.9.0) + tty-cursor (~> 0.7) + tty-screen (~> 0.8) + wisper (~> 2.0) + tty-screen (0.8.1) tzinfo (1.2.9) thread_safe (~> 0.1) u2f (0.2.1) @@ -1350,6 +1374,7 @@ GEM builder expression_parser rinku + wisper (2.0.1) with_env (1.1.0) wmi-lite (1.0.5) xml-simple (1.1.5) @@ -1461,7 +1486,6 @@ DEPENDENCIES gitlab-markup (~> 1.7.1) gitlab-net-dns (~> 0.9.1) gitlab-omniauth-openid-connect (~> 0.4.0) - gitlab-pry-byebug gitlab-sidekiq-fetcher (= 0.5.6) gitlab-styles (~> 6.2.0) gitlab_chronic_duration (~> 0.10.6.2) @@ -1553,8 +1577,9 @@ DEPENDENCIES png_quantizator (~> 0.2.1) premailer-rails (~> 1.10.3) prometheus-client-mmap (~> 0.12.0) + pry-byebug pry-rails (~> 0.3.9) - pry-remote + pry-shell (~> 0.4.0) puma (~> 5.1.1) puma_worker_killer (~> 0.3.1) rack (~> 2.2.3) diff --git a/app/assets/javascripts/content_editor/constants.js b/app/assets/javascripts/content_editor/constants.js index d0d2102a999..45ebd87dac9 100644 --- a/app/assets/javascripts/content_editor/constants.js +++ b/app/assets/javascripts/content_editor/constants.js @@ -6,3 +6,5 @@ export const PROVIDE_SERIALIZER_OR_RENDERER_ERROR = s__( export const CONTENT_EDITOR_TRACKING_LABEL = 'content_editor'; export const TOOLBAR_CONTROL_TRACKING_ACTION = 'execute_toolbar_control'; +export const KEYBOARD_SHORTCUT_TRACKING_ACTION = 'execute_keyboard_shortcut'; +export const INPUT_RULE_TRACKING_ACTION = 'execute_input_rule'; diff --git a/app/assets/javascripts/content_editor/services/create_content_editor.js b/app/assets/javascripts/content_editor/services/create_content_editor.js index dbb0814e6c6..df45287e6cb 100644 --- a/app/assets/javascripts/content_editor/services/create_content_editor.js +++ b/app/assets/javascripts/content_editor/services/create_content_editor.js @@ -23,6 +23,7 @@ import * as Text from '../extensions/text'; import buildSerializerConfig from './build_serializer_config'; import { ContentEditor } from './content_editor'; import createMarkdownSerializer from './markdown_serializer'; +import trackInputRulesAndShortcuts from './track_input_rules_and_shortcuts'; const builtInContentEditorExtensions = [ Blockquote, @@ -66,7 +67,7 @@ export const createContentEditor = ({ renderMarkdown, extensions = [], tiptapOpt } const allExtensions = [...builtInContentEditorExtensions, ...extensions]; - const tiptapExtensions = collectTiptapExtensions(allExtensions); + const tiptapExtensions = collectTiptapExtensions(allExtensions).map(trackInputRulesAndShortcuts); const tiptapEditor = createTiptapEditor({ extensions: tiptapExtensions, ...tiptapOptions }); const serializerConfig = buildSerializerConfig(allExtensions); const serializer = createMarkdownSerializer({ render: renderMarkdown, serializerConfig }); diff --git a/app/assets/javascripts/content_editor/services/track_input_rules_and_shortcuts.js b/app/assets/javascripts/content_editor/services/track_input_rules_and_shortcuts.js new file mode 100644 index 00000000000..860e5372bc2 --- /dev/null +++ b/app/assets/javascripts/content_editor/services/track_input_rules_and_shortcuts.js @@ -0,0 +1,61 @@ +import { mapValues, omit } from 'lodash'; +import { InputRule } from 'prosemirror-inputrules'; +import { ENTER_KEY, BACKSPACE_KEY } from '~/lib/utils/keys'; +import Tracking from '~/tracking'; +import { + CONTENT_EDITOR_TRACKING_LABEL, + KEYBOARD_SHORTCUT_TRACKING_ACTION, + INPUT_RULE_TRACKING_ACTION, +} from '../constants'; + +const trackKeyboardShortcut = (contentType, commandFn, shortcut) => () => { + Tracking.event(undefined, KEYBOARD_SHORTCUT_TRACKING_ACTION, { + label: CONTENT_EDITOR_TRACKING_LABEL, + property: `${contentType}.${shortcut}`, + }); + return commandFn(); +}; + +const trackInputRule = (contentType, inputRule) => { + return new InputRule(inputRule.match, (...args) => { + const result = inputRule.handler(...args); + + if (result) { + Tracking.event(undefined, INPUT_RULE_TRACKING_ACTION, { + label: CONTENT_EDITOR_TRACKING_LABEL, + property: contentType, + }); + } + + return result; + }); +}; + +const trackInputRulesAndShortcuts = (tiptapExtension) => { + return tiptapExtension.extend({ + addKeyboardShortcuts() { + const shortcuts = this.parent?.() || {}; + const { name } = this; + + /** + * We don’t want to track keyboard shortcuts + * that are not deliberately executed to create + * new types of content + */ + const withoutEnterShortcut = omit(shortcuts, [ENTER_KEY, BACKSPACE_KEY]); + const decorated = mapValues(withoutEnterShortcut, (commandFn, shortcut) => + trackKeyboardShortcut(name, commandFn, shortcut), + ); + + return decorated; + }, + addInputRules() { + const inputRules = this.parent?.() || []; + const { name } = this; + + return inputRules.map((inputRule) => trackInputRule(name, inputRule)); + }, + }); +}; + +export default trackInputRulesAndShortcuts; diff --git a/app/assets/javascripts/lib/utils/keys.js b/app/assets/javascripts/lib/utils/keys.js index 2a8b1759e54..bd47f10b3ac 100644 --- a/app/assets/javascripts/lib/utils/keys.js +++ b/app/assets/javascripts/lib/utils/keys.js @@ -1,2 +1,3 @@ export const ESC_KEY = 'Escape'; export const ENTER_KEY = 'Enter'; +export const BACKSPACE_KEY = 'Backspace'; diff --git a/changelogs/unreleased/philipcunningham-investigate-secret-delivery-via-site-profile-328201.yml b/changelogs/unreleased/philipcunningham-investigate-secret-delivery-via-site-profile-328201.yml new file mode 100644 index 00000000000..89dddeab3a7 --- /dev/null +++ b/changelogs/unreleased/philipcunningham-investigate-secret-delivery-via-site-profile-328201.yml @@ -0,0 +1,5 @@ +--- +title: Create database table dast_site_profiles_pipelines +merge_request: 60090 +author: +type: added diff --git a/db/migrate/20210423054022_create_dast_site_profiles_pipelines.rb b/db/migrate/20210423054022_create_dast_site_profiles_pipelines.rb new file mode 100644 index 00000000000..bbdb4f02ab4 --- /dev/null +++ b/db/migrate/20210423054022_create_dast_site_profiles_pipelines.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class CreateDastSiteProfilesPipelines < ActiveRecord::Migration[6.0] + def up + table_comment = { owner: 'group::dynamic analysis', description: 'Join table between DAST Site Profiles and CI Pipelines' } + + create_table :dast_site_profiles_pipelines, primary_key: [:dast_site_profile_id, :ci_pipeline_id], comment: table_comment.to_json do |t| + t.bigint :dast_site_profile_id, null: false + t.bigint :ci_pipeline_id, null: false + + t.index :ci_pipeline_id, unique: true, name: :index_dast_site_profiles_pipelines_on_ci_pipeline_id + end + end + + def down + drop_table :dast_site_profiles_pipelines + end +end diff --git a/db/migrate/20210423054537_add_dast_site_profile_id_fk_to_dast_site_profiles_pipelines.rb b/db/migrate/20210423054537_add_dast_site_profile_id_fk_to_dast_site_profiles_pipelines.rb new file mode 100644 index 00000000000..eb3a5168609 --- /dev/null +++ b/db/migrate/20210423054537_add_dast_site_profile_id_fk_to_dast_site_profiles_pipelines.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AddDastSiteProfileIdFkToDastSiteProfilesPipelines < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :dast_site_profiles_pipelines, :dast_site_profiles, column: :dast_site_profile_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :dast_site_profiles_pipelines, column: :dast_site_profile_id + end + end +end diff --git a/db/migrate/20210423054846_add_ci_pipeline_id_fk_to_dast_site_profiles_pipelines.rb b/db/migrate/20210423054846_add_ci_pipeline_id_fk_to_dast_site_profiles_pipelines.rb new file mode 100644 index 00000000000..ed2a7ff859c --- /dev/null +++ b/db/migrate/20210423054846_add_ci_pipeline_id_fk_to_dast_site_profiles_pipelines.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AddCiPipelineIdFkToDastSiteProfilesPipelines < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :dast_site_profiles_pipelines, :ci_pipelines, column: :ci_pipeline_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :dast_site_profiles_pipelines, column: :ci_pipeline_id + end + end +end diff --git a/db/schema_migrations/20210423054022 b/db/schema_migrations/20210423054022 new file mode 100644 index 00000000000..4717a9e99b7 --- /dev/null +++ b/db/schema_migrations/20210423054022 @@ -0,0 +1 @@ +84f7b631c9017b286665beca42fb30e064c852d5a21c2f82a8bee6f0d5e62c25 \ No newline at end of file diff --git a/db/schema_migrations/20210423054537 b/db/schema_migrations/20210423054537 new file mode 100644 index 00000000000..a530190a32e --- /dev/null +++ b/db/schema_migrations/20210423054537 @@ -0,0 +1 @@ +0ea5c328f9d15d73744f8847c4b1071e2a360cd52ce0da1216ca6acc768050e5 \ No newline at end of file diff --git a/db/schema_migrations/20210423054846 b/db/schema_migrations/20210423054846 new file mode 100644 index 00000000000..08669e2427b --- /dev/null +++ b/db/schema_migrations/20210423054846 @@ -0,0 +1 @@ +013106237f73a94606f962f54c740af23deac637c8e075471ba03ef5d6c1b953 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 1ed5ca07ee9..5d33a61e942 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -12050,6 +12050,13 @@ CREATE SEQUENCE dast_site_profiles_id_seq ALTER SEQUENCE dast_site_profiles_id_seq OWNED BY dast_site_profiles.id; +CREATE TABLE dast_site_profiles_pipelines ( + dast_site_profile_id bigint NOT NULL, + ci_pipeline_id bigint NOT NULL +); + +COMMENT ON TABLE dast_site_profiles_pipelines IS '{"owner":"group::dynamic analysis","description":"Join table between DAST Site Profiles and CI Pipelines"}'; + CREATE TABLE dast_site_tokens ( id bigint NOT NULL, project_id bigint NOT NULL, @@ -20879,6 +20886,9 @@ ALTER TABLE ONLY dast_scanner_profiles ALTER TABLE ONLY dast_site_profile_secret_variables ADD CONSTRAINT dast_site_profile_secret_variables_pkey PRIMARY KEY (id); +ALTER TABLE ONLY dast_site_profiles_pipelines + ADD CONSTRAINT dast_site_profiles_pipelines_pkey PRIMARY KEY (dast_site_profile_id, ci_pipeline_id); + ALTER TABLE ONLY dast_site_profiles ADD CONSTRAINT dast_site_profiles_pkey PRIMARY KEY (id); @@ -22866,6 +22876,8 @@ CREATE INDEX index_dast_site_profiles_on_dast_site_id ON dast_site_profiles USIN CREATE UNIQUE INDEX index_dast_site_profiles_on_project_id_and_name ON dast_site_profiles USING btree (project_id, name); +CREATE UNIQUE INDEX index_dast_site_profiles_pipelines_on_ci_pipeline_id ON dast_site_profiles_pipelines USING btree (ci_pipeline_id); + CREATE INDEX index_dast_site_tokens_on_project_id ON dast_site_tokens USING btree (project_id); CREATE INDEX index_dast_site_validations_on_dast_site_token_id ON dast_site_validations USING btree (dast_site_token_id); @@ -25363,6 +25375,9 @@ ALTER TABLE ONLY alert_management_alerts ALTER TABLE ONLY path_locks ADD CONSTRAINT fk_5265c98f24 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; +ALTER TABLE ONLY dast_site_profiles_pipelines + ADD CONSTRAINT fk_53849b0ad5 FOREIGN KEY (ci_pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE; + ALTER TABLE ONLY clusters_applications_prometheus ADD CONSTRAINT fk_557e773639 FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE; @@ -25720,6 +25735,9 @@ ALTER TABLE ONLY experiment_subjects ALTER TABLE ONLY todos ADD CONSTRAINT fk_ccf0373936 FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE; +ALTER TABLE ONLY dast_site_profiles_pipelines + ADD CONSTRAINT fk_cf05cf8fe1 FOREIGN KEY (dast_site_profile_id) REFERENCES dast_site_profiles(id) ON DELETE CASCADE; + ALTER TABLE ONLY geo_event_log ADD CONSTRAINT fk_cff7185ad2 FOREIGN KEY (reset_checksum_event_id) REFERENCES geo_reset_checksum_events(id) ON DELETE CASCADE; diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md index 5c99a4d32b7..187e98e9b43 100644 --- a/doc/administration/job_artifacts.md +++ b/doc/administration/job_artifacts.md @@ -5,12 +5,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w type: reference, howto --- -# Jobs artifacts administration +# Jobs artifacts administration **(FREE SELF)** -> - Introduced in GitLab 8.2 and GitLab Runner 0.7.0. -> - Starting with GitLab 8.4 and GitLab Runner 1.0, the artifacts archive format changed to `ZIP`. -> - Starting with GitLab 8.17, builds are renamed to jobs. -> - This is the administration documentation. For the user guide see [pipelines/job_artifacts](../ci/pipelines/job_artifacts.md). +This is the administration documentation. For the user guide see [pipelines/job_artifacts](../ci/pipelines/job_artifacts.md). Artifacts is a list of files and directories which are attached to a job after it finishes. This feature is enabled by default in all GitLab installations. Keep reading @@ -87,12 +84,7 @@ _The artifacts are stored by default in ### Using object storage -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1762) in -> [GitLab Premium](https://about.gitlab.com/pricing/) 9.4. -> - Since version 9.5, artifacts are [browsable](../ci/pipelines/job_artifacts.md#download-job-artifacts), -> when object storage is enabled. 9.4 lacks this feature. -> - Since version 10.6, available in [GitLab Free](https://about.gitlab.com/pricing/). -> - Since version 11.0, we support `direct_upload` to S3. +> Introduced in GitLab 11.0: Support for `direct_upload` to S3. If you don't want to use the local disk where GitLab is installed to store the artifacts, you can use an object storage like AWS S3 instead. @@ -118,14 +110,14 @@ This section describes the earlier configuration format. For source installations the following settings are nested under `artifacts:` and then `object_store:`. On Omnibus GitLab installs they are prefixed by `artifacts_object_store_`. -| Setting | Default | Description | -|---------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `enabled` | `false` | Enable/disable object storage | -| `remote_directory` | | The bucket name where Artifacts are stored | -| `direct_upload` | `false` | Set to `true` to enable direct upload of Artifacts without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | -| `background_upload` | `true` | Set to `false` to disable automatic upload. Option may be removed once upload is direct to S3 | +| Setting | Default | Description | +|---------------------|---------|-------------| +| `enabled` | `false` | Enable or disable object storage. | +| `remote_directory` | | The bucket name where Artifacts are stored. | +| `direct_upload` | `false` | Set to `true` to enable direct upload of Artifacts without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | +| `background_upload` | `true` | Set to `false` to disable automatic upload. Option may be removed once upload is direct to S3. | | `proxy_download` | `false` | Set to `true` to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data. | -| `connection` | | Various connection options described below | +| `connection` | | Various connection options described below. | #### Connection settings diff --git a/doc/api/issues.md b/doc/api/issues.md index c62733e2d23..acfca50cb5e 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -27,7 +27,7 @@ When requested across groups or projects, it's expected to be the same as the `f ## List issues -> Moved `weight` to GitLab Premium in 13.9. +> The `weight` property moved to GitLab Premium in 13.9. Get all issues the authenticated user has access to. By default it returns only issues created by the current user. To get all issues, @@ -233,7 +233,7 @@ that closed the issue still exists. ## List group issues -> Moved `weight` to GitLab Premium in 13.9. +> The `weight` property moved to GitLab Premium in 13.9. Get a list of a group's issues. @@ -437,7 +437,7 @@ the issue still exists. ## List project issues -> Moved `weight` to GitLab Premium in 13.9. +> The `weight` property moved to GitLab Premium in 13.9. Get a list of a project's issues. @@ -972,7 +972,7 @@ the issue still exists. ## New issue -> Moved `weight` to GitLab Premium in 13.9. +> The `weight` property moved to GitLab Premium in 13.9. Creates a new project issue. @@ -1127,7 +1127,7 @@ See [Issues rate limits](../user/admin_area/settings/rate_limit_on_issues_creati ## Edit issue -> Moved `weight` to GitLab Premium in 13.9. +> The `weight` property moved to GitLab Premium in 13.9. Updates an existing project issue. This call is also used to mark an issue as closed. diff --git a/doc/api/packages/npm.md b/doc/api/packages/npm.md new file mode 100644 index 00000000000..3992a042915 --- /dev/null +++ b/doc/api/packages/npm.md @@ -0,0 +1,269 @@ +--- +stage: Package +group: Package +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.example/handbook/engineering/ux/technical-writing/#assignments +--- + +# npm API + +This is the API documentation for [npm Packages](../../user/packages/npm_registry/index.md). + +WARNING: +This API is used by the [npm package manager client](https://docs.npmjs.com/) +and is not meant for manual consumption. + +For instructions on how to upload and install npm packages from the GitLab +package registry, see the [npm package registry documentation](../../user/packages/npm_registry/index.md). + +NOTE: +These endpoints do not adhere to the standard API authentication methods. +See the [npm package registry documentation](../../user/packages/npm_registry/index.md) +for details on which headers and token types are supported. + +## Download a package + +> Introduced in GitLab 11.8. + +Downloads the npm package. This URL is provided by the [metadata endpoint](#metadata). + +```plaintext +GET projects/:id/packages/npm/:package_name/-/:file_name +``` + +| Attribute | Type | Required | Description | +| ----------------- | ------ | -------- | ----------- | +| `id` | string | yes | The ID or full path of the project. | +| `package_name` | string | yes | The name of the package. | +| `file_name` | string | yes | The name of the package file. | + +```shell +curl --header "Authorization: Bearer " "https://gitlab.example.com/api/v4/projects/1/packages/npm/@myscope/my-pkg/-/@my-scope/my-pkg-0.0.1.tgz" +``` + +Write the output to a file: + +```shell +curl --header "Authorization: Bearer " "https://gitlab.example.com/api/v4/projects/1/packages/npm/@myscope/my-pkg/-/@my-scope/my-pkg-0.0.1.tgz" >> @myscope/my-pkg-0.0.1.tgz +``` + +This writes the downloaded file to `@myscope/my-pkg-0.0.1.tgz` in the current directory. + +## Upload a package file + +> Introduced in GitLab 11.8. + +Upload a package. + +```plaintext +PUT projects/:id/packages/npm/:package_name +``` + +| Attribute | Type | Required | Description | +| ----------------- | ------ | -------- | ----------- | +| `id` | string | yes | The ID or full path of the project. | +| `package_name` | string | yes | The name of the package. | +| `versions` | string | yes | Package version info. | + +```shell +curl --request PUT + --header "Content-Type: application/json" + --data @./path/to/metadata/file.json + --header "Authorization: Bearer " \ + "https://gitlab.example.com/api/v4/projects/1/packages/npm/@myscope/my-pkg" +``` + +The metadata file content is generated by npm, but looks something like this: + +```json +{ + "_attachments": { + "@myscope/my-pkg-1.3.7.tgz": { + "content_type": "application/octet-stream", + "data": "H4sIAAAAAAAAE+1TQUvDMBjdeb/iI4edZEldV2dPwhARPIjiyXlI26zN1iYhSeeK7L+bNJtednMg4l4OKe+9PF7DF0XzNS0ZVmEfr4wUgxODEJLEMRzjPRJyCYPJNCFRlCTE+dzH1PvJqYscQ2ss1a7KT3PCv8DX/kfwMQRAgjYMpYBuIoIzKtwy6MILG6YNl8Jr0XgyvgpswUyuubJ75TGMDuSaUcsKyDooa1C6De6G8t7GRcG2br4CGxKME3wDR1hmrLexvJKwQLdaS52CkOAFMIrlfMlZsUAwGgHbcgsRcid3fdqade9SFz7u9a1naGsrqX3gHbcPNINDyydWcmN1By+W19x2oU7NcyZMfwn3z/PAqTaruanmUix5+V3UXVKq9yEoRZW1yqQYl9zWNBvnssFUcbyJsdJyxXJrcHQdz8gsTg6PzGChGty3H+6Gvz0BZ5xxxn/FJ1EDRNIACAAA", + "length": 354 + } + }, + "_id": "@myscope/my-pkg", + "description": "Package created by me", + "dist-tags": { + "latest": "1.3.7" + }, + "name": "@myscope/my-pkg", + "readme": "ERROR: No README data found!", + "versions": { + "1.3.7": { + "_id": "@myscope/my-pkg@1.3.7", + "_nodeVersion": "12.18.4", + "_npmVersion": "6.14.6", + "author": { + "name": "GitLab Package Registry Utility" + }, + "description": "Package created by me", + "dist": { + "integrity": "sha512-loy16p+Dtw2S43lBmD3Nye+t+Vwv7Tbhv143UN2mwcjaHJyBfGZdNCTXnma3gJCUSE/AR4FPGWEyCOOTJ+ev9g==", + "shasum": "4a9dbd94ca6093feda03d909f3d7e6bd89d9d4bf", + "tarball": "https://gitlab.example.com/api/v4/projects/1/packages/npm/@myscope/my-pkg/-/@myscope/my-pkg-1.3.7.tgz" + }, + "keywords": [], + "license": "ISC", + "main": "index.js", + "name": "@myscope/my-pkg", + "publishConfig": { + "@myscope:registry": "https://gitlab.example.com/api/v4/projects/1/packages/npm" + }, + "readme": "ERROR: No README data found!", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "version": "1.3.7" + } + } +} +``` + +## Route prefix + +For the remaining routes, there are two sets of identical routes that each make requests in +different scopes: + +- Use the instance-level prefix to make requests in the scope of the entire instance. +- Use the project-level prefix to make requests in a single project's scope. + +The examples in this document all use the project-level prefix. + +### Instance-level + +```plaintext + /packages/npm` +``` + +| Attribute | Type | Required | Description | +| --------- | ------ | -------- | ----------- | +| `id` | string | yes | The group ID or full group path. | + +### Project-level + +```plaintext + /projects/:id/packages/npm` +``` + +| Attribute | Type | Required | Description | +| --------- | ------ | -------- | ----------- | +| `id` | string | yes | The project ID or full project path. | + +## Metadata + +> Introduced in GitLab 11.8. + +Returns the metadata for a given package. + +```plaintext +GET /:package_name +``` + +| Attribute | Type | Required | Description | +| -------------- | ------ | -------- | ----------- | +| `package_name` | string | yes | The name of the package. | + +```shell +curl --header "Authorization: Bearer " "https://gitlab.example.com/api/v4/projects/1/packages/npm/@myscope/my-pkg" +``` + +Example response: + +```json +{ + "name": "@myscope/my-pkg", + "versions": { + "0.0.2": { + "name": "@myscope/my-pkg", + "version": "0.0.1", + "dist": { + "shasum": "93abb605b1110c0e3cca0a5b805e5cb01ac4ca9b", + "tarball": "https://gitlab.example.com/api/v4/projects/1/packages/npm/@myscope/my-pkg/-/@myscope/my-pkg-0.0.1.tgz" + } + } + }, + "dist-tags": { + "latest": "0.0.1" + } +} +``` + +The URLs in the response have the same route prefix used to request them. If you request them with +the instance-level route, the returned URLs contain `/api/v4/packages/npm`. + +## Dist-Tags + +### List tags + +> Introduced in GitLab 12.7. + +Lists the dist-tags for the package. + +```plaintext +GET /-/package/:package_name/dist-tags +``` + +| Attribute | Type | Required | Description | +| -------------- | ------ | -------- | ----------- | +| `package_name` | string | yes | The name of the package. | + +```shell +curl --header "Authorization: Bearer " "https://gitlab.example.com/api/v4/projects/1/packages/npm/-/package/@myscope/my-pkg/dist-tags" +``` + +Example response: + +```json +{ + "latest": "2.1.1", + "stable": "1.0.0" +} +``` + +The URLs in the response have the same route prefix used to request them. If you request them with +the instance-level route, the returned URLs contain `/api/v4/packages/npm`. + +### Create or update a tag + +> Introduced in GitLab 12.7. + +Create or update a dist-tag. + +```plaintext +PUT /-/package/:package_name/dist-tags/:tag +``` + +| Attribute | Type | Required | Description | +| -------------- | ------ | -------- | ----------- | +| `package_name` | string | yes | The name of the package. | +| `tag` | string | yes | The tag to be created or updated. | +| `version` | string | yes | The version to be tagged. | + +```shell +curl --request PUT --header "Authorization: Bearer " "https://gitlab.example.com/api/v4/projects/1/packages/npm/-/package/@myscope/my-pkg/dist-tags/stable" +``` + +This endpoint responds successfully with `204 No Content`. + +### Delete a tag + +> Introduced in GitLab 12.7. + +Delete a dist-tag. + +```plaintext +DELETE /-/package/:package_name/dist-tags/:tag +``` + +| Attribute | Type | Required | Description | +| -------------- | ------ | -------- | ----------- | +| `package_name` | string | yes | The name of the package. | +| `tag` | string | yes | The tag to be created or updated. | + +```shell +curl --request DELETE --header "Authorization: Bearer " "https://gitlab.example.com/api/v4/projects/1/packages/npm/-/package/@myscope/my-pkg/dist-tags/stable" +``` + +This endpoint responds successfully with `204 No Content`. diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 6cee893824e..7f2e502b94b 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -261,7 +261,7 @@ In GitLab 13.11, you can [replace this form with a modal window](#share-a-group- Similar to how you [share a project with a group](../project/members/share_project_with_groups.md), you can share a group with another group. Members get direct access -to the shared group. This is not valid for inherited members. +to the shared group. This includes members who inherited group membership from a parent group. To share a given group, for example, `Frontend` with another group, for example, `Engineering`: diff --git a/doc/user/packages/npm_registry/index.md b/doc/user/packages/npm_registry/index.md index c5f9d3dd47b..ace432b305f 100644 --- a/doc/user/packages/npm_registry/index.md +++ b/doc/user/packages/npm_registry/index.md @@ -14,6 +14,9 @@ packages whenever you need to use them as a dependency. Only [scoped](https://docs.npmjs.com/misc/scope/) packages are supported. +For documentation of the specific API endpoints that the npm package manager +client uses, see the [npm API documentation](../../../api/packages/npm.md). + ## Build an npm package This section covers how to install npm or Yarn and build a package for your diff --git a/package.json b/package.json index d2eddd5af0f..d90dccf2820 100644 --- a/package.json +++ b/package.json @@ -148,6 +148,7 @@ "popper.js": "^1.16.1", "portal-vue": "^2.1.7", "prismjs": "^1.21.0", + "prosemirror-inputrules": "^1.1.3", "prosemirror-markdown": "^1.5.1", "prosemirror-model": "^1.13.3", "raphael": "^2.2.7", diff --git a/spec/frontend/content_editor/services/track_input_rules_and_shortcuts_spec.js b/spec/frontend/content_editor/services/track_input_rules_and_shortcuts_spec.js new file mode 100644 index 00000000000..437714ba938 --- /dev/null +++ b/spec/frontend/content_editor/services/track_input_rules_and_shortcuts_spec.js @@ -0,0 +1,108 @@ +import { BulletList } from '@tiptap/extension-bullet-list'; +import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight'; +import { Document } from '@tiptap/extension-document'; +import { Heading } from '@tiptap/extension-heading'; +import { ListItem } from '@tiptap/extension-list-item'; +import { Paragraph } from '@tiptap/extension-paragraph'; +import { Text } from '@tiptap/extension-text'; +import { Editor, EditorContent } from '@tiptap/vue-2'; +import { mount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import { mockTracking } from 'helpers/tracking_helper'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import { + KEYBOARD_SHORTCUT_TRACKING_ACTION, + INPUT_RULE_TRACKING_ACTION, + CONTENT_EDITOR_TRACKING_LABEL, +} from '~/content_editor/constants'; +import trackInputRulesAndShortcuts from '~/content_editor/services/track_input_rules_and_shortcuts'; +import { ENTER_KEY, BACKSPACE_KEY } from '~/lib/utils/keys'; + +describe('content_editor/services/track_input_rules_and_shortcuts', () => { + let wrapper; + let trackingSpy; + let editor; + const HEADING_TEXT = 'Heading text'; + + const buildWrapper = () => { + wrapper = extendedWrapper( + mount(EditorContent, { + propsData: { + editor, + }, + }), + ); + }; + + beforeEach(() => { + trackingSpy = mockTracking(undefined, null, jest.spyOn); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('given the heading extension is instrumented', () => { + beforeEach(() => { + editor = new Editor({ + extensions: [ + Document, + Paragraph, + Text, + Heading, + CodeBlockLowlight, + BulletList, + ListItem, + ].map(trackInputRulesAndShortcuts), + }); + }); + + beforeEach(async () => { + buildWrapper(); + await nextTick(); + }); + + describe('when creating a heading using an keyboard shortcut', () => { + it('sends a tracking event indicating that a heading was created using an input rule', async () => { + const shortcuts = Heading.config.addKeyboardShortcuts.call(Heading); + const [firstShortcut] = Object.keys(shortcuts); + const nodeName = Heading.name; + + editor.chain().keyboardShortcut(firstShortcut).insertContent(HEADING_TEXT).run(); + + expect(trackingSpy).toHaveBeenCalledWith(undefined, KEYBOARD_SHORTCUT_TRACKING_ACTION, { + label: CONTENT_EDITOR_TRACKING_LABEL, + property: `${nodeName}.${firstShortcut}`, + }); + }); + }); + + it.each` + extension | shortcut + ${ListItem.name} | ${ENTER_KEY} + ${CodeBlockLowlight.name} | ${BACKSPACE_KEY} + `('does not track $shortcut shortcut for $extension extension', ({ shortcut }) => { + editor.chain().keyboardShortcut(shortcut).run(); + + expect(trackingSpy).not.toHaveBeenCalled(); + }); + + describe('when creating a heading using an input rule', () => { + it('sends a tracking event indicating that a heading was created using an input rule', async () => { + const nodeName = Heading.name; + const { view } = editor; + const { selection } = view.state; + + // Triggers the event handler that input rules listen to + view.someProp('handleTextInput', (f) => f(view, selection.from, selection.to, '## ')); + + editor.chain().insertContent(HEADING_TEXT).run(); + + expect(trackingSpy).toHaveBeenCalledWith(undefined, INPUT_RULE_TRACKING_ACTION, { + label: CONTENT_EDITOR_TRACKING_LABEL, + property: `${nodeName}`, + }); + }); + }); + }); +}); diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 84743e57594..f81db1413c2 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -260,6 +260,8 @@ ci_pipelines: - latest_statuses - dast_profile - dast_profiles_pipeline +- dast_site_profile +- dast_site_profiles_pipeline ci_refs: - project - ci_pipelines