Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
830a1f59e2
commit
75d101a1c2
|
|
@ -1 +1 @@
|
|||
684af7592d733edf7a16a817cd7900f03755cfb7
|
||||
d47724f6e9e18fd7c7c73ec68d89ed874c841502
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
import { GlButton, GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
|
||||
import NewIssueDropdown from '~/vue_shared/components/new_issue_dropdown/new_issue_dropdown.vue';
|
||||
import { i18n } from '../constants';
|
||||
import NewIssueDropdown from './new_issue_dropdown.vue';
|
||||
import { hasNewIssueDropdown } from '../has_new_issue_dropdown_mixin';
|
||||
|
||||
export default {
|
||||
i18n,
|
||||
|
|
@ -16,6 +17,7 @@ export default {
|
|||
GlSprintf,
|
||||
NewIssueDropdown,
|
||||
},
|
||||
mixins: [hasNewIssueDropdown()],
|
||||
inject: [
|
||||
'canCreateProjects',
|
||||
'emptyStateSvgPath',
|
||||
|
|
@ -75,7 +77,13 @@ export default {
|
|||
:export-csv-path="exportCsvPathWithQuery"
|
||||
:issuable-count="currentTabCount"
|
||||
/>
|
||||
<new-issue-dropdown v-if="showNewIssueDropdown" class="gl-align-self-center" />
|
||||
<new-issue-dropdown
|
||||
v-if="showNewIssueDropdown"
|
||||
class="gl-align-self-center"
|
||||
:query="$options.searchProjectsQuery"
|
||||
:query-variables="newIssueDropdownQueryVariables"
|
||||
:extract-projects="extractProjects"
|
||||
/>
|
||||
</template>
|
||||
</gl-empty-state>
|
||||
<hr />
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ import {
|
|||
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
|
||||
import { IssuableListTabs, IssuableStates } from '~/vue_shared/issuable/list/constants';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import NewIssueDropdown from '~/vue_shared/components/new_issue_dropdown/new_issue_dropdown.vue';
|
||||
import {
|
||||
CREATED_DESC,
|
||||
defaultTypeTokenOptions,
|
||||
|
|
@ -82,9 +83,9 @@ import {
|
|||
getSortOptions,
|
||||
isSortKey,
|
||||
} from '../utils';
|
||||
import { hasNewIssueDropdown } from '../has_new_issue_dropdown_mixin';
|
||||
import EmptyStateWithAnyIssues from './empty_state_with_any_issues.vue';
|
||||
import EmptyStateWithoutAnyIssues from './empty_state_without_any_issues.vue';
|
||||
import NewIssueDropdown from './new_issue_dropdown.vue';
|
||||
|
||||
const UserToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/user_token.vue');
|
||||
const EmojiToken = () =>
|
||||
|
|
@ -117,7 +118,7 @@ export default {
|
|||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
mixins: [glFeatureFlagMixin(), hasNewIssueDropdown()],
|
||||
inject: [
|
||||
'autocompleteAwardEmojisPath',
|
||||
'calendarPath',
|
||||
|
|
@ -831,7 +832,12 @@ export default {
|
|||
{{ $options.i18n.newIssueLabel }}
|
||||
</gl-button>
|
||||
<slot name="new-objective-button"></slot>
|
||||
<new-issue-dropdown v-if="showNewIssueDropdown" />
|
||||
<new-issue-dropdown
|
||||
v-if="showNewIssueDropdown"
|
||||
:query="$options.searchProjectsQuery"
|
||||
:query-variables="newIssueDropdownQueryVariables"
|
||||
:extract-projects="extractProjects"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #timeframe="{ issuable = {} }">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
import searchProjectsQuery from './queries/search_projects.query.graphql';
|
||||
|
||||
export const hasNewIssueDropdown = () => ({
|
||||
inject: ['fullPath'],
|
||||
computed: {
|
||||
newIssueDropdownQueryVariables() {
|
||||
return {
|
||||
fullPath: this.fullPath,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
extractProjects(data) {
|
||||
return data?.group?.projects?.nodes;
|
||||
},
|
||||
},
|
||||
searchProjectsQuery,
|
||||
});
|
||||
|
|
@ -9,16 +9,17 @@ export const HTTP_STATUS_PARTIAL_CONTENT = 206;
|
|||
export const HTTP_STATUS_MULTI_STATUS = 207;
|
||||
export const HTTP_STATUS_ALREADY_REPORTED = 208;
|
||||
export const HTTP_STATUS_IM_USED = 226;
|
||||
export const HTTP_STATUS_METHOD_NOT_ALLOWED = 405;
|
||||
export const HTTP_STATUS_CONFLICT = 409;
|
||||
export const HTTP_STATUS_GONE = 410;
|
||||
export const HTTP_STATUS_PAYLOAD_TOO_LARGE = 413;
|
||||
export const HTTP_STATUS_UNPROCESSABLE_ENTITY = 422;
|
||||
export const HTTP_STATUS_TOO_MANY_REQUESTS = 429;
|
||||
export const HTTP_STATUS_BAD_REQUEST = 400;
|
||||
export const HTTP_STATUS_UNAUTHORIZED = 401;
|
||||
export const HTTP_STATUS_FORBIDDEN = 403;
|
||||
export const HTTP_STATUS_NOT_FOUND = 404;
|
||||
export const HTTP_STATUS_METHOD_NOT_ALLOWED = 405;
|
||||
export const HTTP_STATUS_CONFLICT = 409;
|
||||
export const HTTP_STATUS_GONE = 410;
|
||||
export const HTTP_STATUS_PAYLOAD_TOO_LARGE = 413;
|
||||
export const HTTP_STATUS_IM_A_TEAPOT = 418;
|
||||
export const HTTP_STATUS_UNPROCESSABLE_ENTITY = 422;
|
||||
export const HTTP_STATUS_TOO_MANY_REQUESTS = 429;
|
||||
export const HTTP_STATUS_INTERNAL_SERVER_ERROR = 500;
|
||||
export const HTTP_STATUS_SERVICE_UNAVAILABLE = 503;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
query searchUserProjects($search: String) {
|
||||
projects(search: $search, membership: true, sort: "latest_activity_desc") {
|
||||
nodes {
|
||||
id
|
||||
issuesEnabled
|
||||
name
|
||||
nameWithNamespace
|
||||
webUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import { createAlert } from '~/flash';
|
|||
import { DASH_SCOPE, joinPaths } from '~/lib/utils/url_utility';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import searchProjectsQuery from '../queries/search_projects.query.graphql';
|
||||
import searchUserProjects from './graphql/search_user_projects.query.graphql';
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
|
|
@ -25,7 +25,23 @@ export default {
|
|||
GlLoadingIcon,
|
||||
GlSearchBoxByType,
|
||||
},
|
||||
inject: ['fullPath'],
|
||||
props: {
|
||||
query: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => searchUserProjects,
|
||||
},
|
||||
queryVariables: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
extractProjects: {
|
||||
type: Function,
|
||||
required: false,
|
||||
default: (data) => data?.projects?.nodes,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
projects: [],
|
||||
|
|
@ -36,14 +52,18 @@ export default {
|
|||
},
|
||||
apollo: {
|
||||
projects: {
|
||||
query: searchProjectsQuery,
|
||||
query() {
|
||||
return this.query;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.fullPath,
|
||||
search: this.search,
|
||||
...this.queryVariables,
|
||||
};
|
||||
},
|
||||
update: ({ group }) => group.projects.nodes ?? [],
|
||||
update(data) {
|
||||
return this.extractProjects(data) || [];
|
||||
},
|
||||
error(error) {
|
||||
createAlert({
|
||||
message: __('An error occurred while loading projects.'),
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ZuoraCSP
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
ZUORA_URL = 'https://*.zuora.com'
|
||||
|
||||
included do
|
||||
content_security_policy do |policy|
|
||||
next if policy.directives.blank?
|
||||
|
||||
default_script_src = policy.directives['script-src'] || policy.directives['default-src']
|
||||
script_src_values = Array.wrap(default_script_src) | ["'self'", "'unsafe-eval'", ZUORA_URL]
|
||||
|
||||
default_frame_src = policy.directives['frame-src'] || policy.directives['default-src']
|
||||
frame_src_values = Array.wrap(default_frame_src) | ["'self'", ZUORA_URL]
|
||||
|
||||
default_child_src = policy.directives['child-src'] || policy.directives['default-src']
|
||||
child_src_values = Array.wrap(default_child_src) | ["'self'", ZUORA_URL]
|
||||
|
||||
policy.script_src(*script_src_values)
|
||||
policy.frame_src(*frame_src_values)
|
||||
policy.child_src(*child_src_values)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,7 +5,6 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
include RedisTracking
|
||||
include ProductAnalyticsTracking
|
||||
include ProjectStatsRefreshConflictsGuard
|
||||
include ZuoraCSP
|
||||
|
||||
urgency :low, [
|
||||
:index, :new, :builds, :show, :failures, :create,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ module Projects
|
|||
module Settings
|
||||
class CiCdController < Projects::ApplicationController
|
||||
include RunnerSetupScripts
|
||||
include ZuoraCSP
|
||||
|
||||
NUMBER_OF_RUNNERS_PER_PAGE = 20
|
||||
|
||||
|
|
|
|||
|
|
@ -394,6 +394,7 @@ class MergeRequest < ApplicationRecord
|
|||
scope :order_closed_at_desc, -> { order_by_metric(:latest_closed_at, 'DESC') }
|
||||
scope :preload_source_project, -> { preload(:source_project) }
|
||||
scope :preload_target_project, -> { preload(:target_project) }
|
||||
scope :preload_target_project_with_namespace, -> { preload(target_project: [:namespace]) }
|
||||
scope :preload_routables, -> do
|
||||
preload(target_project: [:route, { namespace: :route }],
|
||||
source_project: [:route, { namespace: :route }])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddNotNullConstraintToOAuthAccessTokensExpiresIn < Gitlab::Database::Migration[2.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
# validate: false ensures that existing records are not affected
|
||||
# https://docs.gitlab.com/ee/development/database/not_null_constraints.html#prevent-new-invalid-records-current-release
|
||||
add_not_null_constraint :oauth_access_tokens, :expires_in, validate: false
|
||||
change_column_default :oauth_access_tokens, :expires_in, 7200
|
||||
end
|
||||
|
||||
def down
|
||||
remove_not_null_constraint :oauth_access_tokens, :expires_in
|
||||
change_column_default :oauth_access_tokens, :expires_in, nil
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
16e7446f8fba7fe0b76559432ac6ecc30261a5775b9f914c77425ceab3b92315
|
||||
|
|
@ -18479,7 +18479,7 @@ CREATE TABLE oauth_access_tokens (
|
|||
application_id integer,
|
||||
token character varying NOT NULL,
|
||||
refresh_token character varying,
|
||||
expires_in integer,
|
||||
expires_in integer DEFAULT 7200,
|
||||
revoked_at timestamp without time zone,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
scopes character varying
|
||||
|
|
@ -25632,6 +25632,9 @@ ALTER TABLE ONLY chat_teams
|
|||
ALTER TABLE vulnerability_scanners
|
||||
ADD CONSTRAINT check_37608c9db5 CHECK ((char_length(vendor) <= 255)) NOT VALID;
|
||||
|
||||
ALTER TABLE oauth_access_tokens
|
||||
ADD CONSTRAINT check_70f294ef54 CHECK ((expires_in IS NOT NULL)) NOT VALID;
|
||||
|
||||
ALTER TABLE sprints
|
||||
ADD CONSTRAINT check_ccd8a1eae0 CHECK ((start_date IS NOT NULL)) NOT VALID;
|
||||
|
||||
|
|
|
|||
|
|
@ -397,14 +397,15 @@ Example response:
|
|||
Download a release asset file by making a request with the following format:
|
||||
|
||||
```plaintext
|
||||
GET /projects/:id/releases/:tag_name/downloads/:filepath
|
||||
GET /projects/:id/releases/:tag_name/downloads/:direct_asset_path
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|----------------------------| -------------- | -------- | ----------------------------------------------------------------------------------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../rest/index.md#namespaced-path-encoding). |
|
||||
| `tag_name` | string | yes | The Git tag the release is associated with. |
|
||||
| `filepath` | string | yes | Path to the release asset file as specified when [creating](links.md#create-a-release-link) or [updating](links.md#update-a-release-link) its link. |
|
||||
| `filepath` | string | yes | Deprecated: Use `direct_asset_path` instead. |
|
||||
| `direct_asset_path` | string | yes | Path to the release asset file as specified when [creating](links.md#create-a-release-link) or [updating](links.md#update-a-release-link) its link. |
|
||||
|
||||
Example request:
|
||||
|
||||
|
|
@ -463,15 +464,16 @@ POST /projects/:id/releases
|
|||
| `assets:links` | array of hash | no | An array of assets links. |
|
||||
| `assets:links:name`| string | required by: `assets:links` | The name of the link. Link names must be unique within the release. |
|
||||
| `assets:links:url` | string | required by: `assets:links` | The URL of the link. Link URLs must be unique within the release. |
|
||||
| `assets:links:filepath` | string | no | Optional path for a [Direct Asset link](../../user/project/releases/release_fields.md#permanent-links-to-release-assets).
|
||||
| `assets:links:link_type` | string | no | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`.
|
||||
| `assets:links:filepath` | string | no | Deprecated: Use `direct_asset_path` instead. |
|
||||
| `assets:links:direct_asset_path` | string | no | Optional path for a [direct asset link](../../user/project/releases/release_fields.md#permanent-links-to-release-assets). |
|
||||
| `assets:links:link_type` | string | no | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`. |
|
||||
| `released_at` | datetime | no | Date and time for the release. Defaults to the current time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). Only provide this field if creating an [upcoming](../../user/project/releases/index.md#upcoming-releases) or [historical](../../user/project/releases/index.md#historical-releases) release. |
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl --header 'Content-Type: application/json' --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--data '{ "name": "New release", "tag_name": "v0.3", "description": "Super nice release", "milestones": ["v1.0", "v1.0-rc"], "assets": { "links": [{ "name": "hoge", "url": "https://google.com", "filepath": "/binaries/linux-amd64", "link_type":"other" }] } }' \
|
||||
--data '{ "name": "New release", "tag_name": "v0.3", "description": "Super nice release", "milestones": ["v1.0", "v1.0-rc"], "assets": { "links": [{ "name": "hoge", "url": "https://google.com", "direct_asset_path": "/binaries/linux-amd64", "link_type":"other" }] } }' \
|
||||
--request POST "https://gitlab.example.com/api/v4/projects/24/releases"
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -93,14 +93,15 @@ Creates an asset as a link from a release.
|
|||
POST /projects/:id/releases/:tag_name/assets/links
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|-------------|----------------|----------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../rest/index.md#namespaced-path-encoding). |
|
||||
| `tag_name` | string | yes | The tag associated with the Release. |
|
||||
| `name` | string | yes | The name of the link. Link names must be unique in the release. |
|
||||
| `url` | string | yes | The URL of the link. Link URLs must be unique in the release. |
|
||||
| `filepath` | string | no | Optional path for a [Direct Asset link](../../user/project/releases/release_fields.md#permanent-links-to-release-assets). |
|
||||
| `link_type` | string | no | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`. |
|
||||
| Attribute | Type | Required | Description |
|
||||
|----------------------|----------------|----------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../rest/index.md#namespaced-path-encoding). |
|
||||
| `tag_name` | string | yes | The tag associated with the Release. |
|
||||
| `name` | string | yes | The name of the link. Link names must be unique in the release. |
|
||||
| `url` | string | yes | The URL of the link. Link URLs must be unique in the release. |
|
||||
| `filepath` | string | no | Deprecated: Use `direct_asset_path` instead. |
|
||||
| `direct_asset_path` | string | no | Optional path for a [direct asset link](../../user/project/releases/release_fields.md#permanent-links-to-release-assets). |
|
||||
| `link_type` | string | no | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`. |
|
||||
|
||||
Example request:
|
||||
|
||||
|
|
@ -109,7 +110,7 @@ curl --request POST \
|
|||
--header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--data name="hellodarwin-amd64" \
|
||||
--data url="https://gitlab.example.com/mynamespace/hello/-/jobs/688/artifacts/raw/bin/hello-darwin-amd64" \
|
||||
--data filepath="/bin/hellodarwin-amd64" \
|
||||
--data direct_asset_path="/bin/hellodarwin-amd64" \
|
||||
"https://gitlab.example.com/api/v4/projects/20/releases/v1.7.0/assets/links"
|
||||
```
|
||||
|
||||
|
|
@ -134,15 +135,16 @@ Updates an asset as a link from a release.
|
|||
PUT /projects/:id/releases/:tag_name/assets/links/:link_id
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| ------------- | -------------- | -------- | --------------------------------------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../rest/index.md#namespaced-path-encoding). |
|
||||
| `tag_name` | string | yes | The tag associated with the Release. |
|
||||
| `link_id` | integer | yes | The ID of the link. |
|
||||
| `name` | string | no | The name of the link. |
|
||||
| `url` | string | no | The URL of the link. |
|
||||
| `filepath` | string | no | Optional path for a [Direct Asset link](../../user/project/releases/release_fields.md#permanent-links-to-release-assets).
|
||||
| `link_type` | string | no | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`. |
|
||||
| Attribute | Type | Required | Description |
|
||||
| -------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../rest/index.md#namespaced-path-encoding). |
|
||||
| `tag_name` | string | yes | The tag associated with the Release. |
|
||||
| `link_id` | integer | yes | The ID of the link. |
|
||||
| `name` | string | no | The name of the link. |
|
||||
| `url` | string | no | The URL of the link. |
|
||||
| `filepath` | string | no | Deprecated: Use `direct_asset_path` instead. |
|
||||
| `direct_asset_path` | string | no | Optional path for a [direct asset link](../../user/project/releases/release_fields.md#permanent-links-to-release-assets). |
|
||||
| `link_type` | string | no | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`. |
|
||||
|
||||
NOTE:
|
||||
You have to specify at least one of `name` or `url`
|
||||
|
|
|
|||
|
|
@ -214,15 +214,6 @@ In order to disable the warning use `RSPEC_WARN_MISSING_FEATURE_CATEGORY=false`
|
|||
RSPEC_WARN_MISSING_FEATURE_CATEGORY=false bin/rspec spec/<test_file>
|
||||
```
|
||||
|
||||
### Excluding specs from feature categorization
|
||||
|
||||
In the rare case an action cannot be tied to a feature category this
|
||||
can be done using the `not_owned` feature category.
|
||||
|
||||
```ruby
|
||||
RSpec.describe Utils, feature_category: :not_owned do
|
||||
```
|
||||
|
||||
### Tooling feature category
|
||||
|
||||
For Engineering Productivity internal tooling we use `feature_category: :tooling`.
|
||||
|
|
|
|||
|
|
@ -61,6 +61,38 @@ To enable Arkose Protect:
|
|||
Feature.enable(:arkose_labs_prevent_login)
|
||||
```
|
||||
|
||||
## Triage and debug ArkoseLabs issues
|
||||
|
||||
You can triage and debug issues raised by ArkoseLabs with:
|
||||
|
||||
- The [GitLab production logs](https://log.gprd.gitlab.net).
|
||||
- The [Arkose logging service](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/arkose/logger.rb).
|
||||
|
||||
### View ArkoseLabs Verify API response for a user session
|
||||
|
||||
To view an ArkoseLabs Verify API response for a user, [query the GitLab production logs](https://log.gprd.gitlab.net/goto/54b82f50-935a-11ed-9f43-e3784d7fe3ca) with the following KQL:
|
||||
|
||||
```plaintext
|
||||
KQL: json.message:"Arkose verify response" AND json.username:replace_username_here
|
||||
```
|
||||
|
||||
If the query is valid, the result contains debug information about the user's session:
|
||||
|
||||
| Response | Description |
|
||||
|---------|-------------|
|
||||
| `json.response.session_details.suppressed` | Value is `true` if the challenge was not shown to the user. Always `true` if the user is allowlisted. |
|
||||
| `json.arkose.risk_band` | Can be `low`, `medium`, or `high`. Ignored on sign in. Use to debug identity verification issues. |
|
||||
| `json.response.session_details.solved` | Indicates whether the user solved the challenge. Always `true` if the user is allowlisted. |
|
||||
| `json.response.session_details.previously_verified` | Indicates whether the token has been reused. Default is `false`. If `true`, it might indicate malicious activity. |
|
||||
|
||||
### Check if a user failed an ArkoseLabs challenge
|
||||
|
||||
To check if a user failed to sign in because the ArkoseLabs challenge was not solved, [query the GitLab production logs](https://log.gprd.gitlab.net/goto/b97c8a80-935a-11ed-85ed-e7557b0a598c) with the following KQL:
|
||||
|
||||
```plaintext
|
||||
KQL: json.message:"Challenge was not solved" AND json.username:replace_username_here`
|
||||
```
|
||||
|
||||
## QA tests caveat
|
||||
|
||||
Several GitLab QA test suites need to sign in to the app to test its features. This can conflict
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
type: reference, howto
|
||||
stage: Manage
|
||||
group: Authentication and Authorization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Configure SCIM for self-managed GitLab instances **(PREMIUM SELF)**
|
||||
|
||||
You can use the open standard System for Cross-domain Identity Management (SCIM) to automatically:
|
||||
|
||||
- Create users.
|
||||
- Remove users (deactivate SCIM identity).
|
||||
|
||||
The [internal GitLab SCIM API](../../../development/internal_api/index.md#instance-scim-api) implements part of [the RFC7644 protocol](https://www.rfc-editor.org/rfc/rfc7644).
|
||||
|
||||
If you are a GitLab.com user, see [configuring SCIM for GitLab.com groups](../../../user/group/saml_sso/scim_setup.md).
|
||||
|
||||
## Configure GitLab
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Configure [SAML single sign-on](../../../integration/saml.md).
|
||||
|
||||
To configure GitLab SCIM:
|
||||
|
||||
1. On the top bar, select **Main menu > Admin area**.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Expand the **SCIM Token** section and select **Generate a SCIM token**.
|
||||
1. For configuration of your identity provider, save the:
|
||||
- Token from the **Your SCIM token** field.
|
||||
- URL from the **SCIM API endpoint URL** field.
|
||||
|
|
@ -95,12 +95,35 @@ Our criteria for the separation of duties is as follows:
|
|||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213364) in GitLab 13.3.
|
||||
> - Chain of Custody reports sent using email [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342594) in GitLab 15.3 with a flag named `async_chain_of_custody_report`. Disabled by default.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/370100) in GitLab 15.5. Feature flag `async_chain_of_custody_report` removed.
|
||||
> - Chain of Custody report includes all commits (instead of just merge commits) [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267601) in GitLab 15.8 with a flag named `all_commits_compliance_report`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default the Chain of Custody report only contains information on merge commits. To make the report contain information on all commits to projects within a group, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `all_commits_compliance_report`. On GitLab.com, this feature is not available.
|
||||
|
||||
The Chain of Custody report allows customers to export a list of merge commits within the group.
|
||||
The data provides a comprehensive view with respect to merge commits. It includes the merge commit SHA,
|
||||
merge request author, merge request ID, merge user, date merged, pipeline ID, group name, project name, and merge request approvers.
|
||||
Depending on the merge strategy, the merge commit SHA can be a merge commit, squash commit, or a diff head commit.
|
||||
|
||||
With the `all_commits_compliance_report` flag enabled, the Chain of Custody report provides a 1 month trailing window of any commit into a project under the group.
|
||||
|
||||
To generate the report for all commits, GitLab:
|
||||
|
||||
1. Fetches all projects under the group.
|
||||
1. For each project, fetches the last 1 month of commits. Each project is capped at 1024 commits. If there are more than 1024 commits in the 1-month window, they
|
||||
are truncated.
|
||||
1. Writes the commits to a CSV file. The file is truncated at 15 MB because the report is emailed as an attachment.
|
||||
|
||||
The expanded report includes the commit SHA, commit author, committer, date committed, the group, and the project.
|
||||
If the commit has a related merge commit, then the following are also included:
|
||||
|
||||
- Merge commit SHA.
|
||||
- Merge request ID.
|
||||
- User who merged the merge request.
|
||||
- Merge date.
|
||||
- Pipeline ID.
|
||||
- Merge request approvers.
|
||||
|
||||
To generate the Chain of Custody report:
|
||||
|
||||
1. On the top bar, select **Main menu > Groups** and find your group.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ module Gitlab
|
|||
'manifest_src' => "'self'",
|
||||
'media_src' => "'self' data: http: https:",
|
||||
'script_src' => ContentSecurityPolicy::Directives.script_src,
|
||||
'style_src' => "'self' 'unsafe-inline'",
|
||||
'style_src' => ContentSecurityPolicy::Directives.style_src,
|
||||
'worker_src' => "#{Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'assets/')} blob: data:",
|
||||
'object_src' => "'none'",
|
||||
'report_uri' => nil
|
||||
|
|
@ -43,6 +43,7 @@ module Gitlab
|
|||
|
||||
allow_websocket_connections(directives)
|
||||
allow_cdn(directives, Settings.gitlab.cdn_host) if Settings.gitlab.cdn_host.present?
|
||||
allow_zuora(directives) if Gitlab.com?
|
||||
# Support for Sentry setup via configuration files will be removed in 16.0
|
||||
# in favor of Gitlab::CurrentSettings.
|
||||
allow_legacy_sentry(directives) if Gitlab.config.sentry&.enabled && Gitlab.config.sentry&.clientside_dsn
|
||||
|
|
@ -128,6 +129,14 @@ module Gitlab
|
|||
append_to_directive(directives, 'frame_src', cdn_host)
|
||||
end
|
||||
|
||||
def self.zuora_host
|
||||
"https://*.zuora.com/apps/PublicHostedPageLite.do"
|
||||
end
|
||||
|
||||
def self.allow_zuora(directives)
|
||||
append_to_directive(directives, 'frame_src', zuora_host)
|
||||
end
|
||||
|
||||
def self.append_to_directive(directives, directive, text)
|
||||
directives[directive] = "#{directives[directive]} #{text}".strip
|
||||
end
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ module Gitlab
|
|||
def self.script_src
|
||||
"'strict-dynamic' 'self' 'unsafe-inline' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.recaptcha.net https://apis.google.com"
|
||||
end
|
||||
|
||||
def self.style_src
|
||||
"'self' 'unsafe-inline'"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25137,6 +25137,9 @@ msgstr ""
|
|||
msgid "List available repositories"
|
||||
msgstr ""
|
||||
|
||||
msgid "List of all commits"
|
||||
msgstr ""
|
||||
|
||||
msgid "List of all merge commits"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ module Gitlab
|
|||
div :project
|
||||
div :storage_type_legend
|
||||
span :container_registry_size
|
||||
div :purchased_usage_total_free # Different UI for free namespace
|
||||
span :purchased_usage_total
|
||||
div :purchased_usage_total
|
||||
div :storage_purchase_successful_alert, text: /You have successfully purchased a storage/
|
||||
div :additional_storage_alert, text: /purchase additional storage/
|
||||
|
||||
|
|
@ -66,14 +65,10 @@ module Gitlab
|
|||
# Returns total purchased storage value once it's ready on page
|
||||
#
|
||||
# @return [Float] Total purchased storage value in GiB
|
||||
def total_purchased_storage(free_name_space = true)
|
||||
def total_purchased_storage
|
||||
additional_storage_alert_element.wait_until(&:present?)
|
||||
|
||||
if free_name_space
|
||||
purchased_usage_total_free.split('/').last.match(/\d+\.\d+/)[0].to_f
|
||||
else
|
||||
purchased_usage_total.to_f
|
||||
end
|
||||
purchased_usage_total[/(\d+){2}.\d+/].to_f
|
||||
end
|
||||
|
||||
def additional_ci_minutes_added?
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe DashboardController do
|
||||
RSpec.describe DashboardController, feature_category: :code_review_workflow do
|
||||
context 'signed in' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
|
|||
end
|
||||
|
||||
before do
|
||||
stub_feature_flags(refactor_security_extension: false)
|
||||
project.add_maintainer(user)
|
||||
project_only_mwps.add_maintainer(user)
|
||||
sign_in(user)
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Zuora content security policy', feature_category: :purchase do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
let(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
|
||||
before do
|
||||
project.add_developer(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
it 'has proper Content Security Policy headers' do
|
||||
visit pipeline_path(pipeline)
|
||||
|
||||
expect(response_headers['Content-Security-Policy']).to include('https://*.zuora.com')
|
||||
end
|
||||
end
|
||||
|
|
@ -8,6 +8,7 @@ import statisticsLabels from '~/admin/statistics_panel/constants';
|
|||
import createStore from '~/admin/statistics_panel/store';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import mockStatistics from '../mock_data';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
|
@ -25,7 +26,7 @@ describe('Admin statistics app', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
axiosMock = new AxiosMockAdapter(axios);
|
||||
axiosMock.onGet(/api\/(.*)\/application\/statistics/).reply(200);
|
||||
axiosMock.onGet(/api\/(.*)\/application\/statistics/).reply(HTTP_STATUS_OK);
|
||||
store = createStore();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import testAction from 'helpers/vuex_action_helper';
|
|||
import service from '~/batch_comments/services/drafts_service';
|
||||
import * as actions from '~/batch_comments/stores/modules/batch_comments/actions';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
describe('Batch comments store actions', () => {
|
||||
let res = {};
|
||||
|
|
@ -31,7 +32,7 @@ describe('Batch comments store actions', () => {
|
|||
describe('addDraftToDiscussion', () => {
|
||||
it('commits ADD_NEW_DRAFT if no errors returned', () => {
|
||||
res = { id: 1 };
|
||||
mock.onAny().reply(200, res);
|
||||
mock.onAny().reply(HTTP_STATUS_OK, res);
|
||||
|
||||
return testAction(
|
||||
actions.addDraftToDiscussion,
|
||||
|
|
@ -58,7 +59,7 @@ describe('Batch comments store actions', () => {
|
|||
describe('createNewDraft', () => {
|
||||
it('commits ADD_NEW_DRAFT if no errors returned', () => {
|
||||
res = { id: 1 };
|
||||
mock.onAny().reply(200, res);
|
||||
mock.onAny().reply(HTTP_STATUS_OK, res);
|
||||
|
||||
return testAction(
|
||||
actions.createNewDraft,
|
||||
|
|
@ -100,7 +101,7 @@ describe('Batch comments store actions', () => {
|
|||
commit,
|
||||
};
|
||||
res = { id: 1 };
|
||||
mock.onAny().reply(200);
|
||||
mock.onAny().reply(HTTP_STATUS_OK);
|
||||
|
||||
return actions.deleteDraft(context, { id: 1 }).then(() => {
|
||||
expect(commit).toHaveBeenCalledWith('DELETE_DRAFT', 1);
|
||||
|
|
@ -144,7 +145,7 @@ describe('Batch comments store actions', () => {
|
|||
},
|
||||
};
|
||||
res = { id: 1 };
|
||||
mock.onAny().reply(200, res);
|
||||
mock.onAny().reply(HTTP_STATUS_OK, res);
|
||||
|
||||
return actions.fetchDrafts(context).then(() => {
|
||||
expect(commit).toHaveBeenCalledWith('SET_BATCH_COMMENTS_DRAFTS', { id: 1 });
|
||||
|
|
@ -169,7 +170,7 @@ describe('Batch comments store actions', () => {
|
|||
});
|
||||
|
||||
it('dispatches actions & commits', () => {
|
||||
mock.onAny().reply(200);
|
||||
mock.onAny().reply(HTTP_STATUS_OK);
|
||||
|
||||
return actions.publishReview({ dispatch, commit, getters, rootGetters }).then(() => {
|
||||
expect(commit.mock.calls[0]).toEqual(['REQUEST_PUBLISH_REVIEW']);
|
||||
|
|
@ -180,7 +181,7 @@ describe('Batch comments store actions', () => {
|
|||
});
|
||||
|
||||
it('calls service with notes data', () => {
|
||||
mock.onAny().reply(200);
|
||||
mock.onAny().reply(HTTP_STATUS_OK);
|
||||
jest.spyOn(axios, 'post');
|
||||
|
||||
return actions
|
||||
|
|
@ -221,7 +222,7 @@ describe('Batch comments store actions', () => {
|
|||
commit,
|
||||
};
|
||||
res = { id: 1 };
|
||||
mock.onAny().reply(200, res);
|
||||
mock.onAny().reply(HTTP_STATUS_OK, res);
|
||||
params = { note: { id: 1 }, noteText: 'test' };
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import axios from 'axios';
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
||||
import renderOpenApi from '~/blob/openapi';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
describe('OpenAPI blob viewer', () => {
|
||||
const id = 'js-openapi-viewer';
|
||||
|
|
@ -10,7 +11,7 @@ describe('OpenAPI blob viewer', () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
setHTMLFixture(`<div id="${id}" data-endpoint="${mockEndpoint}"></div>`);
|
||||
mock = new MockAdapter(axios).onGet().reply(200);
|
||||
mock = new MockAdapter(axios).onGet().reply(HTTP_STATUS_OK);
|
||||
await renderOpenApi();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
|||
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
|
||||
import Clusters from '~/clusters/clusters_bundle';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import initProjectSelectDropdown from '~/project_select';
|
||||
|
||||
jest.mock('~/lib/utils/poll');
|
||||
|
|
@ -19,7 +20,7 @@ describe('Clusters', () => {
|
|||
|
||||
mock = new MockAdapter(axios);
|
||||
|
||||
mock.onGet(statusPath).reply(200);
|
||||
mock.onGet(statusPath).reply(HTTP_STATUS_OK);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import MockAdapter from 'axios-mock-adapter';
|
|||
import testAction from 'helpers/vuex_action_helper';
|
||||
import * as actions from '~/emoji/awards_app/store/actions';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
jest.mock('@sentry/browser');
|
||||
jest.mock('~/vue_shared/plugins/global_toast');
|
||||
|
|
@ -152,7 +153,7 @@ describe('Awards app actions', () => {
|
|||
|
||||
describe('success', () => {
|
||||
beforeEach(() => {
|
||||
mock.onDelete(`${relativeRootUrl || ''}/awards/1`).reply(200);
|
||||
mock.onDelete(`${relativeRootUrl || ''}/awards/1`).reply(HTTP_STATUS_OK);
|
||||
});
|
||||
|
||||
it('commits REMOVE_AWARD', async () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { s__ } from '~/locale';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { resolvers } from '~/environments/graphql/resolvers';
|
||||
import environmentToRollback from '~/environments/graphql/queries/environment_to_rollback.query.graphql';
|
||||
import environmentToDelete from '~/environments/graphql/queries/environment_to_delete.query.graphql';
|
||||
|
|
@ -44,7 +45,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
const search = '';
|
||||
mock
|
||||
.onGet(ENDPOINT, { params: { nested: true, scope, page: 1, search } })
|
||||
.reply(200, environmentsApp, {});
|
||||
.reply(HTTP_STATUS_OK, environmentsApp, {});
|
||||
|
||||
const app = await mockResolvers.Query.environmentApp(
|
||||
null,
|
||||
|
|
@ -63,7 +64,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
const interval = 3000;
|
||||
mock
|
||||
.onGet(ENDPOINT, { params: { nested: true, scope, page: 1, search: '' } })
|
||||
.reply(200, environmentsApp, {
|
||||
.reply(HTTP_STATUS_OK, environmentsApp, {
|
||||
'poll-interval': interval,
|
||||
});
|
||||
|
||||
|
|
@ -78,7 +79,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
const scope = 'stopped';
|
||||
mock
|
||||
.onGet(ENDPOINT, { params: { nested: true, scope, page: 1, search: '' } })
|
||||
.reply(200, environmentsApp, {
|
||||
.reply(HTTP_STATUS_OK, environmentsApp, {
|
||||
'x-next-page': '2',
|
||||
'x-page': '1',
|
||||
'X-Per-Page': '2',
|
||||
|
|
@ -108,7 +109,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
const scope = 'stopped';
|
||||
mock
|
||||
.onGet(ENDPOINT, { params: { nested: true, scope, page: 1, search: '' } })
|
||||
.reply(200, environmentsApp, {});
|
||||
.reply(HTTP_STATUS_OK, environmentsApp, {});
|
||||
|
||||
await mockResolvers.Query.environmentApp(null, { scope, page: 1, search: '' }, { cache });
|
||||
expect(cache.writeQuery).toHaveBeenCalledWith({
|
||||
|
|
@ -131,7 +132,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
it('should fetch the folder url passed to it', async () => {
|
||||
mock
|
||||
.onGet(ENDPOINT, { params: { per_page: 3, scope: 'available', search: '' } })
|
||||
.reply(200, folder);
|
||||
.reply(HTTP_STATUS_OK, folder);
|
||||
|
||||
const environmentFolder = await mockResolvers.Query.folder(null, {
|
||||
environment: { folderPath: ENDPOINT },
|
||||
|
|
@ -144,7 +145,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
});
|
||||
describe('stopEnvironment', () => {
|
||||
it('should post to the stop environment path', async () => {
|
||||
mock.onPost(ENDPOINT).reply(200);
|
||||
mock.onPost(ENDPOINT).reply(HTTP_STATUS_OK);
|
||||
|
||||
const client = { writeQuery: jest.fn() };
|
||||
const environment = { stopPath: ENDPOINT };
|
||||
|
|
@ -180,7 +181,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
});
|
||||
describe('rollbackEnvironment', () => {
|
||||
it('should post to the retry environment path', async () => {
|
||||
mock.onPost(ENDPOINT).reply(200);
|
||||
mock.onPost(ENDPOINT).reply(HTTP_STATUS_OK);
|
||||
|
||||
await mockResolvers.Mutation.rollbackEnvironment(null, {
|
||||
environment: { retryUrl: ENDPOINT },
|
||||
|
|
@ -193,7 +194,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
});
|
||||
describe('deleteEnvironment', () => {
|
||||
it('should DELETE to the delete environment path', async () => {
|
||||
mock.onDelete(ENDPOINT).reply(200);
|
||||
mock.onDelete(ENDPOINT).reply(HTTP_STATUS_OK);
|
||||
|
||||
await mockResolvers.Mutation.deleteEnvironment(null, {
|
||||
environment: { deletePath: ENDPOINT },
|
||||
|
|
@ -206,7 +207,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
});
|
||||
describe('cancelAutoStop', () => {
|
||||
it('should post to the auto stop path', async () => {
|
||||
mock.onPost(ENDPOINT).reply(200);
|
||||
mock.onPost(ENDPOINT).reply(HTTP_STATUS_OK);
|
||||
|
||||
await mockResolvers.Mutation.cancelAutoStop(null, { autoStopUrl: ENDPOINT });
|
||||
|
||||
|
|
@ -262,7 +263,7 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
|||
});
|
||||
describe('action', () => {
|
||||
it('should POST to the given path', async () => {
|
||||
mock.onPost(ENDPOINT).reply(200);
|
||||
mock.onPost(ENDPOINT).reply(HTTP_STATUS_OK);
|
||||
const errors = await mockResolvers.Mutation.action(null, { action: { playPath: ENDPOINT } });
|
||||
|
||||
expect(errors).toEqual({ __typename: 'LocalEnvironmentErrors', errors: [] });
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import * as types from '~/error_tracking_settings/store/mutation_types';
|
|||
import defaultState from '~/error_tracking_settings/store/state';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { refreshCurrentPage } from '~/lib/utils/url_utility';
|
||||
import { projectList } from '../mock';
|
||||
|
||||
|
|
@ -118,7 +119,7 @@ describe('error tracking settings actions', () => {
|
|||
});
|
||||
|
||||
it('should save the page', async () => {
|
||||
mock.onPatch(TEST_HOST).reply(200);
|
||||
mock.onPatch(TEST_HOST).reply(HTTP_STATUS_OK);
|
||||
await testAction(actions.updateSettings, null, state, [], [{ type: 'requestSettings' }]);
|
||||
expect(mock.history.patch.length).toBe(1);
|
||||
expect(refreshCurrentPage).toHaveBeenCalled();
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ import axios from 'axios';
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
||||
import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dropdown_manager';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
describe('Filtered Search Dropdown Manager', () => {
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
mock.onGet().reply(200);
|
||||
mock.onGet().reply(HTTP_STATUS_OK);
|
||||
});
|
||||
|
||||
describe('addWordToInput', () => {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
|||
import FilteredSearchSpecHelper from 'helpers/filtered_search_spec_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
|
||||
describe('Filtered Search Visual Tokens', () => {
|
||||
|
|
@ -24,7 +25,7 @@ describe('Filtered Search Visual Tokens', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
mock.onGet().reply(200);
|
||||
mock.onGet().reply(HTTP_STATUS_OK);
|
||||
|
||||
setHTMLFixture(`
|
||||
<ul class="tokens-container">
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import Api from '~/api';
|
|||
import dismissUserCallout from '~/graphql_shared/mutations/dismiss_user_callout.mutation.graphql';
|
||||
import services from '~/ide/services';
|
||||
import { query, mutate } from '~/ide/services/gql';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { escapeFileUrl } from '~/lib/utils/url_utility';
|
||||
import ciConfig from '~/ci/pipeline_editor/graphql/queries/ci_config.query.graphql';
|
||||
import { projectData } from '../mock_data';
|
||||
|
|
@ -271,7 +272,7 @@ describe('IDE services', () => {
|
|||
const TEST_PROJECT_PATH = 'foo/bar';
|
||||
const axiosURL = `${TEST_RELATIVE_URL_ROOT}/${TEST_PROJECT_PATH}/service_ping/web_ide_pipelines_count`;
|
||||
|
||||
mock.onPost(axiosURL).reply(200);
|
||||
mock.onPost(axiosURL).reply(HTTP_STATUS_OK);
|
||||
|
||||
return services.pingUsage(TEST_PROJECT_PATH).then(() => {
|
||||
expect(axios.post).toHaveBeenCalledWith(axiosURL);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import {
|
|||
} from '~/ide/stores/actions';
|
||||
import * as types from '~/ide/stores/mutation_types';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_IM_A_TEAPOT } from '~/lib/utils/http_status';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { file, createTriggerRenameAction, createTriggerChangeAction } from '../helpers';
|
||||
|
||||
|
|
@ -927,7 +928,7 @@ describe('Multi-file store actions', () => {
|
|||
});
|
||||
|
||||
it('does not pass the error further and flashes an alert if error is not 404', async () => {
|
||||
mock.onGet(/(.*)/).replyOnce(418);
|
||||
mock.onGet(/(.*)/).replyOnce(HTTP_STATUS_IM_A_TEAPOT);
|
||||
|
||||
await expect(getBranchData(...callParams)).rejects.toEqual(
|
||||
new Error('Branch not loaded - <strong>abc/def/main-testing</strong>'),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
|
|||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { createAlert } from '~/flash';
|
||||
import { HTTP_STATUS_BAD_REQUEST } from '~/lib/utils/http_status';
|
||||
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { STATUSES } from '~/import_entities/constants';
|
||||
import { i18n, ROOT_NAMESPACE } from '~/import_entities/import_groups/constants';
|
||||
|
|
@ -113,7 +113,7 @@ describe('import table', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
axiosMock = new MockAdapter(axios);
|
||||
axiosMock.onGet(/.*\/exists$/, () => []).reply(200);
|
||||
axiosMock.onGet(/.*\/exists$/, () => []).reply(HTTP_STATUS_OK);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {
|
|||
import state from '~/import_entities/import_projects/store/state';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
||||
|
|
@ -433,7 +434,7 @@ describe('import_projects store actions', () => {
|
|||
afterEach(() => mock.restore());
|
||||
|
||||
it('commits CANCEL_IMPORT_SUCCESS on success', async () => {
|
||||
mock.onPost(MOCK_ENDPOINT).reply(200);
|
||||
mock.onPost(MOCK_ENDPOINT).reply(HTTP_STATUS_OK);
|
||||
|
||||
await testAction(
|
||||
cancelImport,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { GlEmptyState, GlLink } from '@gitlab/ui';
|
|||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
|
||||
import EmptyStateWithoutAnyIssues from '~/issues/list/components/empty_state_without_any_issues.vue';
|
||||
import NewIssueDropdown from '~/issues/list/components/new_issue_dropdown.vue';
|
||||
import NewIssueDropdown from '~/vue_shared/components/new_issue_dropdown/new_issue_dropdown.vue';
|
||||
import { i18n } from '~/issues/list/constants';
|
||||
|
||||
describe('EmptyStateWithoutAnyIssues component', () => {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import { IssuableListTabs, IssuableStates } from '~/vue_shared/issuable/list/con
|
|||
import EmptyStateWithAnyIssues from '~/issues/list/components/empty_state_with_any_issues.vue';
|
||||
import EmptyStateWithoutAnyIssues from '~/issues/list/components/empty_state_without_any_issues.vue';
|
||||
import IssuesListApp from '~/issues/list/components/issues_list_app.vue';
|
||||
import NewIssueDropdown from '~/issues/list/components/new_issue_dropdown.vue';
|
||||
import NewIssueDropdown from '~/vue_shared/components/new_issue_dropdown/new_issue_dropdown.vue';
|
||||
import {
|
||||
CREATED_DESC,
|
||||
RELATIVE_POSITION,
|
||||
|
|
|
|||
|
|
@ -1,133 +0,0 @@
|
|||
import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
|
||||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import NewIssueDropdown from '~/issues/list/components/new_issue_dropdown.vue';
|
||||
import searchProjectsQuery from '~/issues/list/queries/search_projects.query.graphql';
|
||||
import { DASH_SCOPE, joinPaths } from '~/lib/utils/url_utility';
|
||||
import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import {
|
||||
emptySearchProjectsQueryResponse,
|
||||
project1,
|
||||
project3,
|
||||
searchProjectsQueryResponse,
|
||||
} from '../mock_data';
|
||||
|
||||
describe('NewIssueDropdown component', () => {
|
||||
let wrapper;
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
const mountComponent = ({
|
||||
search = '',
|
||||
queryResponse = searchProjectsQueryResponse,
|
||||
mountFn = shallowMount,
|
||||
} = {}) => {
|
||||
const requestHandlers = [[searchProjectsQuery, jest.fn().mockResolvedValue(queryResponse)]];
|
||||
const apolloProvider = createMockApollo(requestHandlers);
|
||||
|
||||
return mountFn(NewIssueDropdown, {
|
||||
apolloProvider,
|
||||
provide: {
|
||||
fullPath: 'mushroom-kingdom',
|
||||
},
|
||||
data() {
|
||||
return { search };
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findInput = () => wrapper.findComponent(GlSearchBoxByType);
|
||||
const showDropdown = async () => {
|
||||
findDropdown().vm.$emit('shown');
|
||||
await waitForPromises();
|
||||
jest.advanceTimersByTime(DEBOUNCE_DELAY);
|
||||
await waitForPromises();
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders a split dropdown', () => {
|
||||
wrapper = mountComponent();
|
||||
|
||||
expect(findDropdown().props('split')).toBe(true);
|
||||
});
|
||||
|
||||
it('renders a label for the dropdown toggle button', () => {
|
||||
wrapper = mountComponent();
|
||||
|
||||
expect(findDropdown().attributes('toggle-text')).toBe(NewIssueDropdown.i18n.toggleButtonLabel);
|
||||
});
|
||||
|
||||
it('focuses on input when dropdown is shown', async () => {
|
||||
wrapper = mountComponent({ mountFn: mount });
|
||||
|
||||
const inputSpy = jest.spyOn(findInput().vm, 'focusInput');
|
||||
|
||||
await showDropdown();
|
||||
|
||||
expect(inputSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('renders projects with issues enabled', async () => {
|
||||
wrapper = mountComponent({ mountFn: mount });
|
||||
await showDropdown();
|
||||
|
||||
const listItems = wrapper.findAll('li');
|
||||
|
||||
expect(listItems.at(0).text()).toBe(project1.nameWithNamespace);
|
||||
expect(listItems.at(1).text()).toBe(project3.nameWithNamespace);
|
||||
});
|
||||
|
||||
it('renders `No matches found` when there are no matches', async () => {
|
||||
wrapper = mountComponent({
|
||||
search: 'no matches',
|
||||
queryResponse: emptySearchProjectsQueryResponse,
|
||||
mountFn: mount,
|
||||
});
|
||||
|
||||
await showDropdown();
|
||||
|
||||
expect(wrapper.find('li').text()).toBe(NewIssueDropdown.i18n.noMatchesFound);
|
||||
});
|
||||
|
||||
describe('when no project is selected', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = mountComponent();
|
||||
});
|
||||
|
||||
it('dropdown button is not a link', () => {
|
||||
expect(findDropdown().attributes('split-href')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('displays default text on the dropdown button', () => {
|
||||
expect(findDropdown().props('text')).toBe(NewIssueDropdown.i18n.defaultDropdownText);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a project is selected', () => {
|
||||
beforeEach(async () => {
|
||||
wrapper = mountComponent({ mountFn: mount });
|
||||
await waitForPromises();
|
||||
await showDropdown();
|
||||
|
||||
wrapper.findComponent(GlDropdownItem).vm.$emit('click', project1);
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
it('dropdown button is a link', () => {
|
||||
const href = joinPaths(project1.webUrl, DASH_SCOPE, 'issues/new');
|
||||
|
||||
expect(findDropdown().attributes('split-href')).toBe(href);
|
||||
});
|
||||
|
||||
it('displays project name on the dropdown button', () => {
|
||||
expect(findDropdown().props('text')).toBe(`New issue in ${project1.name}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -343,49 +343,3 @@ export const urlParamsWithSpecialValues = {
|
|||
weight: 'None',
|
||||
health_status: 'None',
|
||||
};
|
||||
|
||||
export const project1 = {
|
||||
id: 'gid://gitlab/Group/26',
|
||||
issuesEnabled: true,
|
||||
name: 'Super Mario Project',
|
||||
nameWithNamespace: 'Mushroom Kingdom / Super Mario Project',
|
||||
webUrl: 'https://127.0.0.1:3000/mushroom-kingdom/super-mario-project',
|
||||
};
|
||||
|
||||
export const project2 = {
|
||||
id: 'gid://gitlab/Group/59',
|
||||
issuesEnabled: false,
|
||||
name: 'Mario Kart Project',
|
||||
nameWithNamespace: 'Mushroom Kingdom / Mario Kart Project',
|
||||
webUrl: 'https://127.0.0.1:3000/mushroom-kingdom/mario-kart-project',
|
||||
};
|
||||
|
||||
export const project3 = {
|
||||
id: 'gid://gitlab/Group/103',
|
||||
issuesEnabled: true,
|
||||
name: 'Mario Party Project',
|
||||
nameWithNamespace: 'Mushroom Kingdom / Mario Party Project',
|
||||
webUrl: 'https://127.0.0.1:3000/mushroom-kingdom/mario-party-project',
|
||||
};
|
||||
|
||||
export const searchProjectsQueryResponse = {
|
||||
data: {
|
||||
group: {
|
||||
id: '1',
|
||||
projects: {
|
||||
nodes: [project1, project2, project3],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const emptySearchProjectsQueryResponse = {
|
||||
data: {
|
||||
group: {
|
||||
id: '1',
|
||||
projects: {
|
||||
nodes: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ import waitForPromises from 'helpers/wait_for_promises';
|
|||
import { initIssueApp } from '~/issues/show';
|
||||
import * as parseData from '~/issues/show/utils/parse_data';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import createStore from '~/notes/stores';
|
||||
import { appProps } from './mock_data/mock_data';
|
||||
|
||||
const mock = new MockAdapter(axios);
|
||||
mock.onGet().reply(200);
|
||||
mock.onGet().reply(HTTP_STATUS_OK);
|
||||
|
||||
jest.mock('~/lib/utils/poll');
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@
|
|||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
describe('axios_utils', () => {
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mock = new AxiosMockAdapter(axios);
|
||||
mock.onAny('/ok').reply(200);
|
||||
mock.onAny('/err').reply(500);
|
||||
mock.onAny('/ok').reply(HTTP_STATUS_OK);
|
||||
mock.onAny('/err').reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(axios.countActiveRequests()).toBe(0);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { TEST_HOST } from 'helpers/test_constants';
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import DeleteMilestoneModal from '~/milestones/components/delete_milestone_modal.vue';
|
||||
import eventHub from '~/milestones/event_hub';
|
||||
import { HTTP_STATUS_IM_A_TEAPOT, HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
|
||||
import { redirectTo } from '~/lib/utils/url_utility';
|
||||
import { createAlert } from '~/flash';
|
||||
|
||||
|
|
@ -71,9 +72,9 @@ describe('Delete milestone modal', () => {
|
|||
});
|
||||
|
||||
it.each`
|
||||
statusCode | alertMessage
|
||||
${418} | ${`Failed to delete milestone ${mockProps.milestoneTitle}`}
|
||||
${404} | ${`Milestone ${mockProps.milestoneTitle} was not found`}
|
||||
statusCode | alertMessage
|
||||
${HTTP_STATUS_IM_A_TEAPOT} | ${`Failed to delete milestone ${mockProps.milestoneTitle}`}
|
||||
${HTTP_STATUS_NOT_FOUND} | ${`Milestone ${mockProps.milestoneTitle} was not found`}
|
||||
`(
|
||||
'displays error if deleting milestone failed with code $statusCode',
|
||||
async ({ statusCode, alertMessage }) => {
|
||||
|
|
|
|||
|
|
@ -918,7 +918,7 @@ describe('Monitoring store actions', () => {
|
|||
|
||||
it('stars dashboard if it is not starred', () => {
|
||||
state.selectedDashboard = unstarredDashboard;
|
||||
mock.onPost(unstarredDashboard.user_starred_path).reply(200);
|
||||
mock.onPost(unstarredDashboard.user_starred_path).reply(HTTP_STATUS_OK);
|
||||
|
||||
return testAction(toggleStarredValue, null, state, [
|
||||
{ type: types.REQUEST_DASHBOARD_STARRING },
|
||||
|
|
@ -934,7 +934,7 @@ describe('Monitoring store actions', () => {
|
|||
|
||||
it('unstars dashboard if it is starred', () => {
|
||||
state.selectedDashboard = starredDashboard;
|
||||
mock.onPost(starredDashboard.user_starred_path).reply(200);
|
||||
mock.onPost(starredDashboard.user_starred_path).reply(HTTP_STATUS_OK);
|
||||
|
||||
return testAction(toggleStarredValue, null, state, [
|
||||
{ type: types.REQUEST_DASHBOARD_STARRING },
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import MockAdapter from 'axios-mock-adapter';
|
|||
import { getByText as getByTextHelper } from '@testing-library/dom';
|
||||
import { GlToggle } from '@gitlab/ui';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
|
||||
import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
|
|
@ -74,7 +75,7 @@ describe('NewNavToggle', () => {
|
|||
});
|
||||
|
||||
it('reloads the page on success', async () => {
|
||||
mock.onPut(TEST_ENDPONT).reply(200);
|
||||
mock.onPut(TEST_ENDPONT).reply(HTTP_STATUS_OK);
|
||||
|
||||
actFn();
|
||||
await waitForPromises();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { mount } from '@vue/test-utils';
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import CiIcon from '~/vue_shared/components/ci_icon.vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import PipelineStage from '~/pipelines/components/pipeline_mini_graph/pipeline_stage.vue';
|
||||
import eventHub from '~/pipelines/event_hub';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
|
|
@ -188,8 +189,8 @@ describe('Pipelines stage component', () => {
|
|||
|
||||
describe('job update in dropdown', () => {
|
||||
beforeEach(async () => {
|
||||
mock.onGet(dropdownPath).reply(200, stageReply);
|
||||
mock.onPost(`${stageReply.latest_statuses[0].status.action.path}.json`).reply(200);
|
||||
mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
|
||||
mock.onPost(`${stageReply.latest_statuses[0].status.action.path}.json`).reply(HTTP_STATUS_OK);
|
||||
|
||||
createComponent();
|
||||
await waitForPromises();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import MockAdapter from 'axios-mock-adapter';
|
|||
import { nextTick } from 'vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import ActionComponent from '~/pipelines/components/jobs_shared/action_component.vue';
|
||||
|
||||
describe('pipeline graph action component', () => {
|
||||
|
|
@ -15,7 +16,7 @@ describe('pipeline graph action component', () => {
|
|||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
|
||||
mock.onPost('foo.json').reply(200);
|
||||
mock.onPost('foo.json').reply(HTTP_STATUS_OK);
|
||||
|
||||
wrapper = mount(ActionComponent, {
|
||||
propsData: {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import waitForPromises from 'helpers/wait_for_promises';
|
|||
import { TEST_HOST } from 'spec/test_constants';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
|
||||
import PipelinesManualActions from '~/pipelines/components/pipelines_list/pipelines_manual_actions.vue';
|
||||
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
|
||||
|
|
@ -70,7 +71,7 @@ describe('Pipelines Actions dropdown', () => {
|
|||
|
||||
describe('on click', () => {
|
||||
it('makes a request and toggles the loading state', async () => {
|
||||
mock.onPost(mockActions.path).reply(200);
|
||||
mock.onPost(mockActions.path).reply(HTTP_STATUS_OK);
|
||||
|
||||
findAllDropdownItems().at(0).vm.$emit('click');
|
||||
|
||||
|
|
@ -132,7 +133,7 @@ describe('Pipelines Actions dropdown', () => {
|
|||
});
|
||||
|
||||
it('makes post request after confirming', async () => {
|
||||
mock.onPost(scheduledJobAction.path).reply(200);
|
||||
mock.onPost(scheduledJobAction.path).reply(HTTP_STATUS_OK);
|
||||
confirmAction.mockResolvedValueOnce(true);
|
||||
|
||||
findAllDropdownItems().at(0).vm.$emit('click');
|
||||
|
|
@ -145,7 +146,7 @@ describe('Pipelines Actions dropdown', () => {
|
|||
});
|
||||
|
||||
it('does not make post request if confirmation is cancelled', async () => {
|
||||
mock.onPost(scheduledJobAction.path).reply(200);
|
||||
mock.onPost(scheduledJobAction.path).reply(HTTP_STATUS_OK);
|
||||
confirmAction.mockResolvedValueOnce(false);
|
||||
|
||||
findAllDropdownItems().at(0).vm.$emit('click');
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import MockAxiosAdapter from 'axios-mock-adapter';
|
|||
import { nextTick } from 'vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import SharedRunnersToggleComponent from '~/projects/settings/components/shared_runners_toggle.vue';
|
||||
|
||||
const TEST_UPDATE_PATH = '/test/update_shared_runners';
|
||||
|
|
@ -36,7 +37,7 @@ describe('projects/settings/components/shared_runners', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
mockAxios = new MockAxiosAdapter(axios);
|
||||
mockAxios.onPost(TEST_UPDATE_PATH).reply(200);
|
||||
mockAxios.onPost(TEST_UPDATE_PATH).reply(HTTP_STATUS_OK);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import axios from 'axios';
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import MemoryUsage from '~/vue_merge_request_widget/components/deployment/memory_usage.vue';
|
||||
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ describe('MemoryUsage', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
mock.onGet(`${url}.json`).reply(200);
|
||||
mock.onGet(`${url}.json`).reply(HTTP_STATUS_OK);
|
||||
|
||||
vm = createComponent();
|
||||
el = vm.$el;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import waitForPromises from 'helpers/wait_for_promises';
|
|||
import { securityReportMergeRequestDownloadPathsQueryResponse } from 'jest/vue_shared/security_reports/mock_data';
|
||||
import api from '~/api';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import Poll from '~/lib/utils/poll';
|
||||
import { setFaviconOverlay } from '~/lib/utils/favicon';
|
||||
import notify from '~/lib/utils/notify';
|
||||
|
|
@ -837,7 +838,7 @@ describe('MrWidgetOptions', () => {
|
|||
|
||||
describe('suggestPipeline', () => {
|
||||
beforeEach(() => {
|
||||
mock.onAny().reply(200);
|
||||
mock.onAny().reply(HTTP_STATUS_OK);
|
||||
});
|
||||
|
||||
describe('given feature flag is enabled', () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
export const emptySearchProjectsQueryResponse = {
|
||||
data: {
|
||||
projects: {
|
||||
nodes: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const emptySearchProjectsWithinGroupQueryResponse = {
|
||||
data: {
|
||||
group: {
|
||||
id: '1',
|
||||
projects: emptySearchProjectsQueryResponse.data.projects,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const project1 = {
|
||||
id: 'gid://gitlab/Group/26',
|
||||
issuesEnabled: true,
|
||||
name: 'Super Mario Project',
|
||||
nameWithNamespace: 'Mushroom Kingdom / Super Mario Project',
|
||||
webUrl: 'https://127.0.0.1:3000/mushroom-kingdom/super-mario-project',
|
||||
};
|
||||
|
||||
export const project2 = {
|
||||
id: 'gid://gitlab/Group/59',
|
||||
issuesEnabled: false,
|
||||
name: 'Mario Kart Project',
|
||||
nameWithNamespace: 'Mushroom Kingdom / Mario Kart Project',
|
||||
webUrl: 'https://127.0.0.1:3000/mushroom-kingdom/mario-kart-project',
|
||||
};
|
||||
|
||||
export const project3 = {
|
||||
id: 'gid://gitlab/Group/103',
|
||||
issuesEnabled: true,
|
||||
name: 'Mario Party Project',
|
||||
nameWithNamespace: 'Mushroom Kingdom / Mario Party Project',
|
||||
webUrl: 'https://127.0.0.1:3000/mushroom-kingdom/mario-party-project',
|
||||
};
|
||||
|
||||
export const searchProjectsQueryResponse = {
|
||||
data: {
|
||||
projects: {
|
||||
nodes: [project1, project2, project3],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const searchProjectsWithinGroupQueryResponse = {
|
||||
data: {
|
||||
group: {
|
||||
id: '1',
|
||||
projects: searchProjectsQueryResponse.data.projects,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
|
||||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import NewIssueDropdown from '~/vue_shared/components/new_issue_dropdown/new_issue_dropdown.vue';
|
||||
import searchUserProjectsQuery from '~/vue_shared/components/new_issue_dropdown/graphql/search_user_projects.query.graphql';
|
||||
import searchProjectsWithinGroupQuery from '~/issues/list/queries/search_projects.query.graphql';
|
||||
import { DASH_SCOPE, joinPaths } from '~/lib/utils/url_utility';
|
||||
import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import {
|
||||
emptySearchProjectsQueryResponse,
|
||||
emptySearchProjectsWithinGroupQueryResponse,
|
||||
project1,
|
||||
project3,
|
||||
searchProjectsQueryResponse,
|
||||
searchProjectsWithinGroupQueryResponse,
|
||||
} from './mock_data';
|
||||
|
||||
describe('NewIssueDropdown component', () => {
|
||||
let wrapper;
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
// Props
|
||||
const withinGroupProps = {
|
||||
query: searchProjectsWithinGroupQuery,
|
||||
queryVariables: { fullPath: 'mushroom-kingdom' },
|
||||
extractProjects: (data) => data.group.projects.nodes,
|
||||
};
|
||||
|
||||
const mountComponent = ({
|
||||
search = '',
|
||||
query = searchUserProjectsQuery,
|
||||
queryResponse = searchProjectsQueryResponse,
|
||||
mountFn = shallowMount,
|
||||
propsData = {},
|
||||
} = {}) => {
|
||||
const requestHandlers = [[query, jest.fn().mockResolvedValue(queryResponse)]];
|
||||
const apolloProvider = createMockApollo(requestHandlers);
|
||||
|
||||
return mountFn(NewIssueDropdown, {
|
||||
apolloProvider,
|
||||
propsData,
|
||||
data() {
|
||||
return { search };
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findInput = () => wrapper.findComponent(GlSearchBoxByType);
|
||||
const showDropdown = async () => {
|
||||
findDropdown().vm.$emit('shown');
|
||||
await waitForPromises();
|
||||
jest.advanceTimersByTime(DEBOUNCE_DELAY);
|
||||
await waitForPromises();
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders a split dropdown', () => {
|
||||
wrapper = mountComponent();
|
||||
|
||||
expect(findDropdown().props('split')).toBe(true);
|
||||
});
|
||||
|
||||
it('renders a label for the dropdown toggle button', () => {
|
||||
wrapper = mountComponent();
|
||||
|
||||
expect(findDropdown().attributes('toggle-text')).toBe(NewIssueDropdown.i18n.toggleButtonLabel);
|
||||
});
|
||||
|
||||
it('focuses on input when dropdown is shown', async () => {
|
||||
wrapper = mountComponent({ mountFn: mount });
|
||||
|
||||
const inputSpy = jest.spyOn(findInput().vm, 'focusInput');
|
||||
|
||||
await showDropdown();
|
||||
|
||||
expect(inputSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
describe.each`
|
||||
description | propsData | query | queryResponse | emptyResponse
|
||||
${'by default'} | ${undefined} | ${searchUserProjectsQuery} | ${searchProjectsQueryResponse} | ${emptySearchProjectsQueryResponse}
|
||||
${'within a group'} | ${withinGroupProps} | ${searchProjectsWithinGroupQuery} | ${searchProjectsWithinGroupQueryResponse} | ${emptySearchProjectsWithinGroupQueryResponse}
|
||||
`('$description', ({ propsData, query, queryResponse, emptyResponse }) => {
|
||||
it('renders projects with issues enabled', async () => {
|
||||
wrapper = mountComponent({ mountFn: mount, query, queryResponse, propsData });
|
||||
await showDropdown();
|
||||
|
||||
const listItems = wrapper.findAll('li');
|
||||
|
||||
expect(listItems.at(0).text()).toBe(project1.nameWithNamespace);
|
||||
expect(listItems.at(1).text()).toBe(project3.nameWithNamespace);
|
||||
});
|
||||
|
||||
it('renders `No matches found` when there are no matches', async () => {
|
||||
wrapper = mountComponent({
|
||||
search: 'no matches',
|
||||
query,
|
||||
queryResponse: emptyResponse,
|
||||
mountFn: mount,
|
||||
propsData,
|
||||
});
|
||||
|
||||
await showDropdown();
|
||||
|
||||
expect(wrapper.find('li').text()).toBe(NewIssueDropdown.i18n.noMatchesFound);
|
||||
});
|
||||
|
||||
describe('when no project is selected', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = mountComponent({ query, queryResponse, propsData });
|
||||
});
|
||||
|
||||
it('dropdown button is not a link', () => {
|
||||
expect(findDropdown().attributes('split-href')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('displays default text on the dropdown button', () => {
|
||||
expect(findDropdown().props('text')).toBe(NewIssueDropdown.i18n.defaultDropdownText);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a project is selected', () => {
|
||||
beforeEach(async () => {
|
||||
wrapper = mountComponent({ mountFn: mount, query, queryResponse, propsData });
|
||||
await showDropdown();
|
||||
|
||||
wrapper.findComponent(GlDropdownItem).vm.$emit('click', project1);
|
||||
});
|
||||
|
||||
it('dropdown button is a link', () => {
|
||||
const href = joinPaths(project1.webUrl, DASH_SCOPE, 'issues/new');
|
||||
|
||||
expect(findDropdown().attributes('split-href')).toBe(href);
|
||||
});
|
||||
|
||||
it('displays project name on the dropdown button', () => {
|
||||
expect(findDropdown().props('text')).toBe(`New issue in ${project1.name}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -6,6 +6,7 @@ import Mousetrap from 'mousetrap';
|
|||
import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
||||
import GLForm from '~/gl_form';
|
||||
import * as utils from '~/lib/utils/common_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import ZenMode from '~/zen_mode';
|
||||
|
||||
describe('ZenMode', () => {
|
||||
|
|
@ -32,7 +33,7 @@ describe('ZenMode', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
mock.onGet().reply(200);
|
||||
mock.onGet().reply(HTTP_STATUS_OK);
|
||||
|
||||
loadHTMLFixture(fixtureName);
|
||||
|
||||
|
|
|
|||
|
|
@ -94,13 +94,31 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
|
|||
|
||||
it 'adds CDN host to CSP' do
|
||||
expect(directives['script_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.script_src + " https://cdn.example.com")
|
||||
expect(directives['style_src']).to eq("'self' 'unsafe-inline' https://cdn.example.com")
|
||||
expect(directives['style_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.style_src + " https://cdn.example.com")
|
||||
expect(directives['font_src']).to eq("'self' https://cdn.example.com")
|
||||
expect(directives['worker_src']).to eq('http://localhost/assets/ blob: data: https://cdn.example.com')
|
||||
expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " https://cdn.example.com http://localhost/admin/ http://localhost/assets/ http://localhost/-/speedscope/index.html http://localhost/-/sandbox/")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Zuora directives' do
|
||||
context 'when is Gitlab.com?' do
|
||||
before do
|
||||
allow(::Gitlab).to receive(:com?).and_return(true)
|
||||
end
|
||||
|
||||
it 'adds Zuora host to CSP' do
|
||||
expect(directives['frame_src']).to include('https://*.zuora.com/apps/PublicHostedPageLite.do')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when is not Gitlab.com?' do
|
||||
it 'does not add Zuora host to CSP' do
|
||||
expect(directives['frame_src']).not_to include('https://*.zuora.com/apps/PublicHostedPageLite.do')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when sentry is configured' do
|
||||
let(:legacy_dsn) { 'dummy://abc@legacy-sentry.example.com/1' }
|
||||
let(:dsn) { 'dummy://def@sentry.example.com/2' }
|
||||
|
|
|
|||
|
|
@ -135,6 +135,15 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
let_it_be(:merge_request3) { create(:merge_request, :unique_branches, reviewers: []) }
|
||||
let_it_be(:merge_request4) { create(:merge_request, :draft_merge_request) }
|
||||
|
||||
describe '.preload_target_project_with_namespace' do
|
||||
subject(:mr) { described_class.preload_target_project_with_namespace.first }
|
||||
|
||||
it 'returns MR with the target project\'s namespace preloaded' do
|
||||
expect(mr.association(:target_project)).to be_loaded
|
||||
expect(mr.target_project.association(:namespace)).to be_loaded
|
||||
end
|
||||
end
|
||||
|
||||
describe '.review_requested' do
|
||||
it 'returns MRs that have any review requests' do
|
||||
expect(described_class.review_requested).to eq([merge_request1, merge_request2])
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module gitlab.com/gitlab-org/gitlab/workhorse
|
|||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.6.1
|
||||
github.com/BurntSushi/toml v1.2.1
|
||||
github.com/FZambia/sentinel v1.1.1
|
||||
github.com/alecthomas/chroma/v2 v2.4.0
|
||||
|
|
@ -29,39 +29,40 @@ require (
|
|||
gitlab.com/gitlab-org/gitaly/v15 v15.7.0
|
||||
gitlab.com/gitlab-org/golang-archive-zip v0.1.1
|
||||
gitlab.com/gitlab-org/labkit v1.17.0
|
||||
gocloud.dev v0.27.0
|
||||
gocloud.dev v0.28.0
|
||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
|
||||
golang.org/x/net v0.1.0
|
||||
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
|
||||
golang.org/x/tools v0.1.12
|
||||
golang.org/x/net v0.4.0
|
||||
golang.org/x/oauth2 v0.2.0
|
||||
golang.org/x/tools v0.2.0
|
||||
google.golang.org/grpc v1.51.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
honnef.co/go/tools v0.3.3
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.103.0 // indirect
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
cloud.google.com/go/iam v0.3.0 // indirect
|
||||
cloud.google.com/go/monitoring v1.5.0 // indirect
|
||||
cloud.google.com/go v0.107.0 // indirect
|
||||
cloud.google.com/go/compute v1.13.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.2 // indirect
|
||||
cloud.google.com/go/iam v0.7.0 // indirect
|
||||
cloud.google.com/go/monitoring v1.9.0 // indirect
|
||||
cloud.google.com/go/profiler v0.1.0 // indirect
|
||||
cloud.google.com/go/storage v1.24.0 // indirect
|
||||
cloud.google.com/go/trace v1.2.0 // indirect
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.13.13 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
|
||||
cloud.google.com/go/storage v1.28.0 // indirect
|
||||
cloud.google.com/go/trace v1.4.0 // indirect
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.13.14 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 // indirect
|
||||
github.com/DataDog/datadog-go v4.4.0+incompatible // indirect
|
||||
github.com/DataDog/sketches-go v1.0.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||
github.com/beevik/ntp v0.3.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/client9/reopen v1.0.0 // indirect
|
||||
|
|
@ -69,14 +70,13 @@ require (
|
|||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/pprof v0.0.0-20220608213341-c488b8fa1db3 // indirect
|
||||
github.com/google/pprof v0.0.0-20221102093814-76f304f74e5e // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/wire v0.5.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
|
|
@ -89,13 +89,13 @@ require (
|
|||
github.com/oklog/ulid/v2 v2.0.2 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/philhofer/fwd v1.1.1 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/prometheus/prometheus v0.37.0 // indirect
|
||||
github.com/prometheus/prometheus v0.40.5 // indirect
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
|
||||
github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.21.2 // indirect
|
||||
|
|
@ -105,19 +105,19 @@ require (
|
|||
github.com/tklauser/numcpus v0.2.1 // indirect
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
golang.org/x/crypto v0.3.0 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/mod v0.6.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.2.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/text v0.5.0 // indirect
|
||||
golang.org/x/time v0.2.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
||||
google.golang.org/api v0.91.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/api v0.103.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78 // indirect
|
||||
google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3 // indirect
|
||||
gopkg.in/DataDog/dd-trace-go.v1 v1.32.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
|||
756
workhorse/go.sum
756
workhorse/go.sum
File diff suppressed because it is too large
Load Diff
|
|
@ -11,6 +11,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
|
||||
"github.com/BurntSushi/toml"
|
||||
"gocloud.dev/blob"
|
||||
"gocloud.dev/blob/azureblob"
|
||||
|
|
@ -178,12 +179,13 @@ func (creds *AzureCredentials) getURLOpener() (*azureblob.URLOpener, error) {
|
|||
AccountName: creds.AccountName,
|
||||
}
|
||||
|
||||
clientFunc := func(svcURL azureblob.ServiceURL) (*azblob.ServiceClient, error) {
|
||||
clientFunc := func(svcURL azureblob.ServiceURL, containerName azureblob.ContainerName) (*container.Client, error) {
|
||||
sharedKeyCred, err := azblob.NewSharedKeyCredential(creds.AccountName, creds.AccountKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Azure credentials: %w", err)
|
||||
}
|
||||
return azblob.NewServiceClientWithSharedKey(string(svcURL), sharedKeyCred, &azblob.ClientOptions{})
|
||||
containerURL := fmt.Sprintf("%s/%s", svcURL, containerName)
|
||||
return container.NewClientWithSharedKeyCredential(containerURL, sharedKeyCred, &container.ClientOptions{})
|
||||
}
|
||||
|
||||
return &azureblob.URLOpener{
|
||||
|
|
|
|||
Loading…
Reference in New Issue