Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f505025346
commit
403678e004
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { mapState, mapGetters, mapActions } from 'vuex';
|
||||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
|
||||
import EditArea from './edit_area.vue';
|
||||
|
@ -10,7 +10,8 @@ export default {
|
|||
GlSkeletonLoader,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['content', 'isContentLoaded', 'isLoadingContent']),
|
||||
...mapState(['content', 'isLoadingContent']),
|
||||
...mapGetters(['isContentLoaded']),
|
||||
},
|
||||
mounted() {
|
||||
this.loadContent();
|
||||
|
|
|
@ -3,7 +3,11 @@ import StaticSiteEditor from './components/static_site_editor.vue';
|
|||
import createStore from './store';
|
||||
|
||||
const initStaticSiteEditor = el => {
|
||||
const store = createStore();
|
||||
const { projectId, path: sourcePath } = el.dataset;
|
||||
|
||||
const store = createStore({
|
||||
initialState: { projectId, sourcePath },
|
||||
});
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import createFlash from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
import * as mutationTypes from './mutation_types';
|
||||
import loadSourceContent from '~/static_site_editor/services/load_source_content';
|
||||
|
||||
export const loadContent = ({ commit, state: { sourcePath, projectId } }) => {
|
||||
commit(mutationTypes.LOAD_CONTENT);
|
||||
|
||||
return loadSourceContent({ sourcePath, projectId })
|
||||
.then(data => commit(mutationTypes.RECEIVE_CONTENT_SUCCESS, data))
|
||||
.catch(() => {
|
||||
commit(mutationTypes.RECEIVE_CONTENT_ERROR);
|
||||
createFlash(__('An error ocurred while loading your content. Please try again.'));
|
||||
});
|
||||
};
|
||||
|
||||
export default () => {};
|
|
@ -0,0 +1,2 @@
|
|||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const isContentLoaded = ({ content }) => Boolean(content);
|
|
@ -1,12 +1,18 @@
|
|||
import Vuex from 'vuex';
|
||||
import Vue from 'vue';
|
||||
import createState from './state';
|
||||
import * as getters from './getters';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
const createStore = ({ initialState } = {}) => {
|
||||
return new Vuex.Store({
|
||||
state: createState(initialState),
|
||||
getters,
|
||||
actions,
|
||||
mutations,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export const LOAD_CONTENT = 'loadContent';
|
||||
export const RECEIVE_CONTENT_SUCCESS = 'receiveContentSuccess';
|
||||
export const RECEIVE_CONTENT_ERROR = 'receiveContentError';
|
|
@ -0,0 +1,15 @@
|
|||
import * as types from './mutation_types';
|
||||
|
||||
export default {
|
||||
[types.LOAD_CONTENT](state) {
|
||||
state.isLoadingContent = true;
|
||||
},
|
||||
[types.RECEIVE_CONTENT_SUCCESS](state, { title, content }) {
|
||||
state.isLoadingContent = false;
|
||||
state.title = title;
|
||||
state.content = content;
|
||||
},
|
||||
[types.RECEIVE_CONTENT_ERROR](state) {
|
||||
state.isLoadingContent = false;
|
||||
},
|
||||
};
|
|
@ -1,8 +1,12 @@
|
|||
const createState = (initialState = {}) => ({
|
||||
projectId: null,
|
||||
sourcePath: null,
|
||||
|
||||
isLoadingContent: false,
|
||||
isContentLoaded: false,
|
||||
|
||||
content: '',
|
||||
title: '',
|
||||
|
||||
...initialState,
|
||||
});
|
||||
|
||||
|
|
|
@ -11,11 +11,12 @@ module Ci
|
|||
include StaticModel
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
attr_reader :stage, :name, :jobs
|
||||
attr_reader :project, :stage, :name, :jobs
|
||||
|
||||
delegate :size, to: :jobs
|
||||
|
||||
def initialize(stage, name:, jobs:)
|
||||
def initialize(project, stage, name:, jobs:)
|
||||
@project = project
|
||||
@stage = stage
|
||||
@name = name
|
||||
@jobs = jobs
|
||||
|
@ -23,7 +24,7 @@ module Ci
|
|||
|
||||
def status
|
||||
strong_memoize(:status) do
|
||||
if Feature.enabled?(:ci_composite_status, default_enabled: false)
|
||||
if Feature.enabled?(:ci_composite_status, project, default_enabled: false)
|
||||
Gitlab::Ci::Status::Composite
|
||||
.new(@jobs)
|
||||
.status
|
||||
|
@ -44,11 +45,11 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
def self.fabricate(stage)
|
||||
def self.fabricate(project, stage)
|
||||
stage.statuses.ordered.latest
|
||||
.sort_by(&:sortable_name).group_by(&:group_name)
|
||||
.map do |group_name, grouped_statuses|
|
||||
self.new(stage, name: group_name, jobs: grouped_statuses)
|
||||
self.new(project, stage, name: group_name, jobs: grouped_statuses)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ module Ci
|
|||
end
|
||||
|
||||
def groups
|
||||
@groups ||= Ci::Group.fabricate(self)
|
||||
@groups ||= Ci::Group.fabricate(project, self)
|
||||
end
|
||||
|
||||
def to_param
|
||||
|
|
|
@ -109,7 +109,7 @@ module Ci
|
|||
end
|
||||
|
||||
def groups
|
||||
@groups ||= Ci::Group.fabricate(self)
|
||||
@groups ||= Ci::Group.fabricate(project, self)
|
||||
end
|
||||
|
||||
def has_warnings?
|
||||
|
|
|
@ -9,9 +9,9 @@ module Ci
|
|||
# * No variables
|
||||
# * No spaces
|
||||
# * Minimal length of 8 characters
|
||||
# * Characters must be from the Base64 alphabet (RFC4648) with the addition of @ and :
|
||||
# * Characters must be from the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'
|
||||
# * Absolutely no fun is allowed
|
||||
REGEX = /\A[a-zA-Z0-9_+=\/@:-]{8,}\z/.freeze
|
||||
REGEX = /\A[a-zA-Z0-9_+=\/@:.-]{8,}\z/.freeze
|
||||
|
||||
included do
|
||||
validates :masked, inclusion: { in: [true, false] }
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
class AnalyticsSummaryEntity < Grape::Entity
|
||||
expose :value, safe: true
|
||||
expose :title
|
||||
expose :unit, if: { with_unit: true }
|
||||
end
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# This service is responsible for creating a pipeline for a given
|
||||
# ExternalPullRequest coming from other providers such as GitHub.
|
||||
|
||||
module Ci
|
||||
module ExternalPullRequests
|
||||
class CreatePipelineService < BaseService
|
||||
def execute(pull_request)
|
||||
return unless pull_request.open? && pull_request.actual_branch_head?
|
||||
|
||||
create_pipeline_for(pull_request)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_pipeline_for(pull_request)
|
||||
Ci::CreatePipelineService.new(project, current_user, create_params(pull_request))
|
||||
.execute(:external_pull_request_event, external_pull_request: pull_request)
|
||||
end
|
||||
|
||||
def create_params(pull_request)
|
||||
{
|
||||
ref: pull_request.source_ref,
|
||||
source_sha: pull_request.source_sha,
|
||||
target_sha: pull_request.target_sha
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,29 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# This service is responsible for creating a pipeline for a given
|
||||
# ExternalPullRequest coming from other providers such as GitHub.
|
||||
|
||||
module ExternalPullRequests
|
||||
class CreatePipelineService < BaseService
|
||||
def execute(pull_request)
|
||||
return unless pull_request.open? && pull_request.actual_branch_head?
|
||||
|
||||
create_pipeline_for(pull_request)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_pipeline_for(pull_request)
|
||||
Ci::CreatePipelineService.new(project, current_user, create_params(pull_request))
|
||||
.execute(:external_pull_request_event, external_pull_request: pull_request)
|
||||
end
|
||||
|
||||
def create_params(pull_request)
|
||||
{
|
||||
ref: pull_request.source_ref,
|
||||
source_sha: pull_request.source_sha,
|
||||
target_sha: pull_request.target_sha
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,4 +5,6 @@
|
|||
%i.fa.fa-rss
|
||||
|
||||
.content_list
|
||||
= spinner
|
||||
.loading
|
||||
.spinner.spinner-md
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
= f.text_field :tag_list, value: @project.tag_list.join(', '), maxlength: 2000, class: "form-control"
|
||||
%p.form-text.text-muted= _('Separate topics with commas.')
|
||||
|
||||
= render_if_exists 'compliance_management/compliance_framework/project_settings', f: f
|
||||
|
||||
.row
|
||||
.form-group.col-md-9
|
||||
= f.label :description, _('Project description (optional)'), class: 'label-bold'
|
||||
|
|
|
@ -21,7 +21,7 @@ class UpdateExternalPullRequestsWorker # rubocop:disable Scalability/IdempotentW
|
|||
.by_source_branch(branch)
|
||||
|
||||
external_pull_requests.find_each do |pull_request|
|
||||
ExternalPullRequests::CreatePipelineService.new(project, user)
|
||||
Ci::ExternalPullRequests::CreatePipelineService.new(project, user)
|
||||
.execute(pull_request)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add read_api scope to personal access tokens for granting read only API access
|
||||
merge_request: 28944
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Migrate .fa-spinner to .spinner for app/views/groups
|
||||
merge_request: 25053
|
||||
author: nuwe1
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Create operations_user_lists table
|
||||
merge_request: 28822
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add support for dot (.) in variables masking
|
||||
merge_request: 29022
|
||||
author:
|
||||
type: changed
|
|
@ -70,6 +70,8 @@ en:
|
|||
scope_desc:
|
||||
api:
|
||||
Grants complete read/write access to the API, including all groups and projects, the container registry, and the package registry.
|
||||
read_api:
|
||||
Grants read access to the API, including all groups and projects, the container registry, and the package registry.
|
||||
read_user:
|
||||
Grants read-only access to the authenticated user's profile through the /user API endpoint, which includes username, public email, and full name. Also grants access to read-only API endpoints under /users.
|
||||
read_repository:
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddProjectComplianceFrameworkSettingsTable < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
create_table :project_compliance_framework_settings, id: false do |t|
|
||||
t.references :project, primary_key: true, null: false, index: true, foreign_key: { on_delete: :cascade }
|
||||
t.integer :framework, null: false, limit: 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
drop_table :project_compliance_framework_settings
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateOperationsUserLists < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
def change
|
||||
create_table :operations_user_lists do |t|
|
||||
t.references :project, index: false, foreign_key: { on_delete: :cascade }, null: false
|
||||
t.timestamps_with_timezone
|
||||
t.integer :iid, null: false
|
||||
t.string :name, null: false, limit: 255
|
||||
t.text :user_xids, null: false, default: ''
|
||||
|
||||
t.index [:project_id, :iid], unique: true
|
||||
t.index [:project_id, :name], unique: true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4323,6 +4323,25 @@ CREATE SEQUENCE public.operations_strategies_id_seq
|
|||
|
||||
ALTER SEQUENCE public.operations_strategies_id_seq OWNED BY public.operations_strategies.id;
|
||||
|
||||
CREATE TABLE public.operations_user_lists (
|
||||
id bigint NOT NULL,
|
||||
project_id bigint NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
iid integer NOT NULL,
|
||||
name character varying(255) NOT NULL,
|
||||
user_xids text DEFAULT ''::text NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE public.operations_user_lists_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE public.operations_user_lists_id_seq OWNED BY public.operations_user_lists.id;
|
||||
|
||||
CREATE TABLE public.packages_build_infos (
|
||||
id bigint NOT NULL,
|
||||
package_id integer NOT NULL,
|
||||
|
@ -4722,6 +4741,20 @@ CREATE SEQUENCE public.project_ci_cd_settings_id_seq
|
|||
|
||||
ALTER SEQUENCE public.project_ci_cd_settings_id_seq OWNED BY public.project_ci_cd_settings.id;
|
||||
|
||||
CREATE TABLE public.project_compliance_framework_settings (
|
||||
project_id bigint NOT NULL,
|
||||
framework smallint NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE public.project_compliance_framework_settings_project_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE public.project_compliance_framework_settings_project_id_seq OWNED BY public.project_compliance_framework_settings.project_id;
|
||||
|
||||
CREATE TABLE public.project_custom_attributes (
|
||||
id integer NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
|
@ -7275,6 +7308,8 @@ ALTER TABLE ONLY public.operations_scopes ALTER COLUMN id SET DEFAULT nextval('p
|
|||
|
||||
ALTER TABLE ONLY public.operations_strategies ALTER COLUMN id SET DEFAULT nextval('public.operations_strategies_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY public.operations_user_lists ALTER COLUMN id SET DEFAULT nextval('public.operations_user_lists_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY public.packages_build_infos ALTER COLUMN id SET DEFAULT nextval('public.packages_build_infos_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY public.packages_conan_file_metadata ALTER COLUMN id SET DEFAULT nextval('public.packages_conan_file_metadata_id_seq'::regclass);
|
||||
|
@ -7315,6 +7350,8 @@ ALTER TABLE ONLY public.project_auto_devops ALTER COLUMN id SET DEFAULT nextval(
|
|||
|
||||
ALTER TABLE ONLY public.project_ci_cd_settings ALTER COLUMN id SET DEFAULT nextval('public.project_ci_cd_settings_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY public.project_compliance_framework_settings ALTER COLUMN project_id SET DEFAULT nextval('public.project_compliance_framework_settings_project_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY public.project_custom_attributes ALTER COLUMN id SET DEFAULT nextval('public.project_custom_attributes_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY public.project_daily_statistics ALTER COLUMN id SET DEFAULT nextval('public.project_daily_statistics_id_seq'::regclass);
|
||||
|
@ -8081,6 +8118,9 @@ ALTER TABLE ONLY public.operations_scopes
|
|||
ALTER TABLE ONLY public.operations_strategies
|
||||
ADD CONSTRAINT operations_strategies_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY public.operations_user_lists
|
||||
ADD CONSTRAINT operations_user_lists_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY public.packages_build_infos
|
||||
ADD CONSTRAINT packages_build_infos_pkey PRIMARY KEY (id);
|
||||
|
||||
|
@ -8144,6 +8184,9 @@ ALTER TABLE ONLY public.project_auto_devops
|
|||
ALTER TABLE ONLY public.project_ci_cd_settings
|
||||
ADD CONSTRAINT project_ci_cd_settings_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY public.project_compliance_framework_settings
|
||||
ADD CONSTRAINT project_compliance_framework_settings_pkey PRIMARY KEY (project_id);
|
||||
|
||||
ALTER TABLE ONLY public.project_custom_attributes
|
||||
ADD CONSTRAINT project_custom_attributes_pkey PRIMARY KEY (id);
|
||||
|
||||
|
@ -9644,6 +9687,10 @@ CREATE UNIQUE INDEX index_operations_scopes_on_strategy_id_and_environment_scope
|
|||
|
||||
CREATE INDEX index_operations_strategies_on_feature_flag_id ON public.operations_strategies USING btree (feature_flag_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_operations_user_lists_on_project_id_and_iid ON public.operations_user_lists USING btree (project_id, iid);
|
||||
|
||||
CREATE UNIQUE INDEX index_operations_user_lists_on_project_id_and_name ON public.operations_user_lists USING btree (project_id, name);
|
||||
|
||||
CREATE UNIQUE INDEX index_packages_build_infos_on_package_id ON public.packages_build_infos USING btree (package_id);
|
||||
|
||||
CREATE INDEX index_packages_build_infos_on_pipeline_id ON public.packages_build_infos USING btree (pipeline_id);
|
||||
|
@ -9736,6 +9783,8 @@ CREATE UNIQUE INDEX index_project_auto_devops_on_project_id ON public.project_au
|
|||
|
||||
CREATE UNIQUE INDEX index_project_ci_cd_settings_on_project_id ON public.project_ci_cd_settings USING btree (project_id);
|
||||
|
||||
CREATE INDEX index_project_compliance_framework_settings_on_project_id ON public.project_compliance_framework_settings USING btree (project_id);
|
||||
|
||||
CREATE INDEX index_project_custom_attributes_on_key_and_value ON public.project_custom_attributes USING btree (key, value);
|
||||
|
||||
CREATE UNIQUE INDEX index_project_custom_attributes_on_project_id_and_key ON public.project_custom_attributes USING btree (project_id, key);
|
||||
|
@ -10956,6 +11005,9 @@ ALTER TABLE ONLY public.project_deploy_tokens
|
|||
ALTER TABLE ONLY public.packages_conan_file_metadata
|
||||
ADD CONSTRAINT fk_rails_0afabd9328 FOREIGN KEY (package_file_id) REFERENCES public.packages_package_files(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY public.operations_user_lists
|
||||
ADD CONSTRAINT fk_rails_0c716e079b FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY public.geo_node_statuses
|
||||
ADD CONSTRAINT fk_rails_0ecc699c2a FOREIGN KEY (geo_node_id) REFERENCES public.geo_nodes(id) ON DELETE CASCADE;
|
||||
|
||||
|
@ -11391,6 +11443,9 @@ ALTER TABLE ONLY public.prometheus_alerts
|
|||
ALTER TABLE ONLY public.term_agreements
|
||||
ADD CONSTRAINT fk_rails_6ea6520e4a FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY public.project_compliance_framework_settings
|
||||
ADD CONSTRAINT fk_rails_6f5294f16c FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY public.users_security_dashboard_projects
|
||||
ADD CONSTRAINT fk_rails_6f6cf8e66e FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||
|
||||
|
@ -13002,8 +13057,10 @@ COPY "schema_migrations" (version) FROM STDIN;
|
|||
20200330121000
|
||||
20200330123739
|
||||
20200330132913
|
||||
20200331132103
|
||||
20200331195952
|
||||
20200331220930
|
||||
20200401211005
|
||||
20200402123926
|
||||
20200402135250
|
||||
20200402185044
|
||||
|
|
|
@ -43,6 +43,7 @@ the following table.
|
|||
| ------------------ | ------------- | ----------- |
|
||||
| `read_user` | [GitLab 8.15](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5951) | Allows access to the read-only endpoints under `/users`. Essentially, any of the `GET` requests in the [Users API][users] are allowed. |
|
||||
| `api` | [GitLab 8.15](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5951) | Grants complete read/write access to the API, including all groups and projects, the container registry, and the package registry. |
|
||||
| `read_api` | [GitLab 12.10](https://https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28944) | Grants read access to the API, including all groups and projects, the container registry, and the package registry. |
|
||||
| `read_registry` | [GitLab 9.3](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/11845) | Allows to read (pull) [container registry] images if a project is private and authorization is required. |
|
||||
| `sudo` | [GitLab 10.2](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14838) | Allows performing API actions as any user in the system (if the authenticated user is an admin). |
|
||||
| `read_repository` | [GitLab 10.7](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17894) | Allows read-only access (pull) to the repository through `git clone`. |
|
||||
|
|
|
@ -28,6 +28,7 @@ module API
|
|||
]
|
||||
|
||||
allow_access_with_scope :api
|
||||
allow_access_with_scope :read_api, if: -> (request) { request.get? }
|
||||
prefix :api
|
||||
|
||||
version 'v3', using: :path do
|
||||
|
|
|
@ -129,6 +129,7 @@ module API
|
|||
:avatar,
|
||||
:suggestion_commit_message,
|
||||
:repository_storage,
|
||||
:compliance_framework_setting,
|
||||
|
||||
# TODO: remove in API v5, replaced by *_access_level
|
||||
:issues_enabled,
|
||||
|
|
|
@ -6,7 +6,7 @@ module Gitlab
|
|||
IpBlacklisted = Class.new(StandardError)
|
||||
|
||||
# Scopes used for GitLab API access
|
||||
API_SCOPES = [:api, :read_user].freeze
|
||||
API_SCOPES = [:api, :read_user, :read_api].freeze
|
||||
|
||||
# Scopes used for GitLab Repository access
|
||||
REPOSITORY_SCOPES = [:read_repository, :write_repository].freeze
|
||||
|
@ -198,6 +198,7 @@ module Gitlab
|
|||
def abilities_for_scopes(scopes)
|
||||
abilities_by_scope = {
|
||||
api: full_authentication_abilities,
|
||||
read_api: read_only_authentication_abilities,
|
||||
read_registry: [:read_container_image],
|
||||
read_repository: [:download_code],
|
||||
write_repository: [:download_code, :push_code]
|
||||
|
|
|
@ -159,6 +159,7 @@ excluded_attributes:
|
|||
- :max_artifacts_size
|
||||
- :marked_for_deletion_at
|
||||
- :marked_for_deletion_by_user_id
|
||||
- :compliance_framework_setting
|
||||
namespaces:
|
||||
- :runners_token
|
||||
- :runners_token_encrypted
|
||||
|
|
|
@ -2090,6 +2090,9 @@ msgstr ""
|
|||
msgid "An error occurred. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "An error ocurred while loading your content. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "An instance-level serverless domain already exists."
|
||||
msgstr ""
|
||||
|
||||
|
@ -3830,6 +3833,9 @@ msgstr ""
|
|||
msgid "Choose which status most accurately reflects the current state of this issue:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Choose your framework"
|
||||
msgstr ""
|
||||
|
||||
msgid "CiStatusLabel|canceled"
|
||||
msgstr ""
|
||||
|
||||
|
@ -5236,6 +5242,24 @@ msgstr ""
|
|||
msgid "Compliance Dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance framework (optional)"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceFramework|GDPR - General Data Protection Regulation"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceFramework|HIPAA - Health Insurance Portability and Accountability Act"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceFramework|PCI-DSS - Payment Card Industry-Data Security Standard"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceFramework|SOC 2 - Service Organization Control 2"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceFramework|SOX - Sarbanes-Oxley"
|
||||
msgstr ""
|
||||
|
||||
msgid "Confidence: %{confidence}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -17967,6 +17991,9 @@ msgstr ""
|
|||
msgid "Select projects you want to import."
|
||||
msgstr ""
|
||||
|
||||
msgid "Select required regulatory standard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Select shards to replicate"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -17,11 +17,15 @@ describe('StaticSiteEditor', () => {
|
|||
let store;
|
||||
let loadContentActionMock;
|
||||
|
||||
const buildStore = (initialState = {}) => {
|
||||
const buildStore = ({ initialState, getters } = {}) => {
|
||||
loadContentActionMock = jest.fn();
|
||||
|
||||
store = new Vuex.Store({
|
||||
state: createState(initialState),
|
||||
getters: {
|
||||
isContentLoaded: () => false,
|
||||
...getters,
|
||||
},
|
||||
actions: {
|
||||
loadContent: loadContentActionMock,
|
||||
},
|
||||
|
@ -56,7 +60,7 @@ describe('StaticSiteEditor', () => {
|
|||
const content = 'edit area content';
|
||||
|
||||
beforeEach(() => {
|
||||
buildStore({ content, isContentLoaded: true });
|
||||
buildStore({ initialState: { content }, getters: { isContentLoaded: () => true } });
|
||||
buildWrapper();
|
||||
});
|
||||
|
||||
|
@ -70,7 +74,7 @@ describe('StaticSiteEditor', () => {
|
|||
});
|
||||
|
||||
it('displays skeleton loader while loading content', () => {
|
||||
buildStore({ isLoadingContent: true });
|
||||
buildStore({ initialState: { isLoadingContent: true } });
|
||||
buildWrapper();
|
||||
|
||||
expect(wrapper.find(GlSkeletonLoader).exists()).toBe(true);
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import testAction from 'helpers/vuex_action_helper';
|
||||
import createState from '~/static_site_editor/store/state';
|
||||
import * as actions from '~/static_site_editor/store/actions';
|
||||
import * as mutationTypes from '~/static_site_editor/store/mutation_types';
|
||||
import loadSourceContent from '~/static_site_editor/services/load_source_content';
|
||||
|
||||
import createFlash from '~/flash';
|
||||
|
||||
import {
|
||||
projectId,
|
||||
sourcePath,
|
||||
sourceContentTitle as title,
|
||||
sourceContent as content,
|
||||
} from '../mock_data';
|
||||
|
||||
jest.mock('~/flash');
|
||||
jest.mock('~/static_site_editor/services/load_source_content', () => jest.fn());
|
||||
|
||||
describe('Static Site Editor Store actions', () => {
|
||||
let state;
|
||||
|
||||
beforeEach(() => {
|
||||
state = createState({
|
||||
projectId,
|
||||
sourcePath,
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadContent', () => {
|
||||
describe('on success', () => {
|
||||
const payload = { title, content };
|
||||
|
||||
beforeEach(() => {
|
||||
loadSourceContent.mockResolvedValueOnce(payload);
|
||||
});
|
||||
|
||||
it('commits receiveContentSuccess', () => {
|
||||
testAction(
|
||||
actions.loadContent,
|
||||
null,
|
||||
state,
|
||||
[
|
||||
{ type: mutationTypes.LOAD_CONTENT },
|
||||
{ type: mutationTypes.RECEIVE_CONTENT_SUCCESS, payload },
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
expect(loadSourceContent).toHaveBeenCalledWith({ projectId, sourcePath });
|
||||
});
|
||||
});
|
||||
|
||||
describe('on error', () => {
|
||||
const expectedMutations = [
|
||||
{ type: mutationTypes.LOAD_CONTENT },
|
||||
{ type: mutationTypes.RECEIVE_CONTENT_ERROR },
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
loadSourceContent.mockRejectedValueOnce();
|
||||
});
|
||||
|
||||
it('commits receiveContentError', () => {
|
||||
testAction(actions.loadContent, null, state, expectedMutations);
|
||||
});
|
||||
|
||||
it('displays flash communicating error', () => {
|
||||
return testAction(actions.loadContent, null, state, expectedMutations).then(() => {
|
||||
expect(createFlash).toHaveBeenCalledWith(
|
||||
'An error ocurred while loading your content. Please try again.',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
import createState from '~/static_site_editor/store/state';
|
||||
import { isContentLoaded } from '~/static_site_editor/store/getters';
|
||||
import { sourceContent as content } from '../mock_data';
|
||||
|
||||
describe('Static Site Editor Store getters', () => {
|
||||
describe('isContentLoaded', () => {
|
||||
it('returns true when content is not empty', () => {
|
||||
expect(isContentLoaded(createState({ content }))).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when content is empty', () => {
|
||||
expect(isContentLoaded(createState({ content: '' }))).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,52 @@
|
|||
import createState from '~/static_site_editor/store/state';
|
||||
import mutations from '~/static_site_editor/store/mutations';
|
||||
import * as types from '~/static_site_editor/store/mutation_types';
|
||||
import { sourceContentTitle as title, sourceContent as content } from '../mock_data';
|
||||
|
||||
describe('Static Site Editor Store mutations', () => {
|
||||
let state;
|
||||
|
||||
beforeEach(() => {
|
||||
state = createState();
|
||||
});
|
||||
|
||||
describe('loadContent', () => {
|
||||
beforeEach(() => {
|
||||
mutations[types.LOAD_CONTENT](state);
|
||||
});
|
||||
|
||||
it('sets isLoadingContent to true', () => {
|
||||
expect(state.isLoadingContent).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('receiveContentSuccess', () => {
|
||||
const payload = { title, content };
|
||||
|
||||
beforeEach(() => {
|
||||
mutations[types.RECEIVE_CONTENT_SUCCESS](state, payload);
|
||||
});
|
||||
|
||||
it('sets current state to LOADING', () => {
|
||||
expect(state.isLoadingContent).toBe(false);
|
||||
});
|
||||
|
||||
it('sets title', () => {
|
||||
expect(state.title).toBe(payload.title);
|
||||
});
|
||||
|
||||
it('sets content', () => {
|
||||
expect(state.content).toBe(payload.content);
|
||||
});
|
||||
});
|
||||
|
||||
describe('receiveContentError', () => {
|
||||
beforeEach(() => {
|
||||
mutations[types.RECEIVE_CONTENT_ERROR](state);
|
||||
});
|
||||
|
||||
it('sets current state to LOADING_ERROR', () => {
|
||||
expect(state.isLoadingContent).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -224,7 +224,7 @@ describe('AjaxFormVariableList', () => {
|
|||
|
||||
describe('maskableRegex', () => {
|
||||
it('takes in the regex provided by the data attribute', () => {
|
||||
expect(container.dataset.maskableRegex).toBe('^[a-zA-Z0-9_+=/@:-]{8,}$');
|
||||
expect(container.dataset.maskableRegex).toBe('^[a-zA-Z0-9_+=/@:.-]{8,}$');
|
||||
expect(ajaxVariableList.maskableRegex).toBe(container.dataset.maskableRegex);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -162,7 +162,7 @@ describe('VariableList', () => {
|
|||
});
|
||||
|
||||
it('has a regex provided via a data attribute', () => {
|
||||
expect($wrapper.attr('data-maskable-regex')).toBe('^[a-zA-Z0-9_+=/@:-]{8,}$');
|
||||
expect($wrapper.attr('data-maskable-regex')).toBe('^[a-zA-Z0-9_+=/@:.-]{8,}$');
|
||||
});
|
||||
|
||||
it('allows values that are 8 characters long', done => {
|
||||
|
|
|
@ -8,7 +8,7 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
|
|||
|
||||
describe 'constants' do
|
||||
it 'API_SCOPES contains all scopes for API access' do
|
||||
expect(subject::API_SCOPES).to eq %i[api read_user]
|
||||
expect(subject::API_SCOPES).to eq %i[api read_user read_api]
|
||||
end
|
||||
|
||||
it 'ADMIN_SCOPES contains all scopes for ADMIN access' do
|
||||
|
@ -30,7 +30,7 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
|
|||
it 'optional_scopes contains all non-default scopes' do
|
||||
stub_container_registry_config(enabled: true)
|
||||
|
||||
expect(subject.optional_scopes).to eq %i[read_user read_repository write_repository read_registry sudo openid profile email]
|
||||
expect(subject.optional_scopes).to eq %i[read_user read_api read_repository write_repository read_registry sudo openid profile email]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -38,21 +38,21 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
|
|||
it 'contains all non-default scopes' do
|
||||
stub_container_registry_config(enabled: true)
|
||||
|
||||
expect(subject.all_available_scopes).to eq %i[api read_user read_repository write_repository read_registry sudo]
|
||||
expect(subject.all_available_scopes).to eq %i[api read_user read_api read_repository write_repository read_registry sudo]
|
||||
end
|
||||
|
||||
it 'contains for non-admin user all non-default scopes without ADMIN access' do
|
||||
stub_container_registry_config(enabled: true)
|
||||
user = create(:user, admin: false)
|
||||
|
||||
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_repository write_repository read_registry]
|
||||
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_api read_repository write_repository read_registry]
|
||||
end
|
||||
|
||||
it 'contains for admin user all non-default scopes with ADMIN access' do
|
||||
stub_container_registry_config(enabled: true)
|
||||
user = create(:user, admin: true)
|
||||
|
||||
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_repository write_repository read_registry sudo]
|
||||
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_api read_repository write_repository read_registry sudo]
|
||||
end
|
||||
|
||||
context 'registry_scopes' do
|
||||
|
|
|
@ -477,6 +477,7 @@ project:
|
|||
- export_jobs
|
||||
- daily_report_results
|
||||
- jira_imports
|
||||
- compliance_framework_setting
|
||||
award_emoji:
|
||||
- awardable
|
||||
- user
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Ci::Group do
|
||||
subject do
|
||||
described_class.new('test', name: 'rspec', jobs: jobs)
|
||||
end
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
let!(:jobs) { build_list(:ci_build, 1, :success) }
|
||||
let!(:jobs) { build_list(:ci_build, 1, :success, project: project) }
|
||||
|
||||
subject do
|
||||
described_class.new(project, 'test', name: 'rspec', jobs: jobs)
|
||||
end
|
||||
|
||||
it { is_expected.to include_module(StaticModel) }
|
||||
|
||||
|
|
|
@ -61,8 +61,12 @@ describe Ci::Maskable do
|
|||
expect(subject.match?(string)).to eq(false)
|
||||
end
|
||||
|
||||
it 'does not match strings using unsupported characters' do
|
||||
expect(subject.match?('HelloWorld%#^')).to eq(false)
|
||||
end
|
||||
|
||||
it 'matches valid strings' do
|
||||
expect(subject.match?('helloworld')).to eq(true)
|
||||
expect(subject.match?('Hello+World_123/@:-.')).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -3,15 +3,60 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe API::API do
|
||||
let(:user) { create(:user, last_activity_on: Date.yesterday) }
|
||||
include GroupAPIHelpers
|
||||
|
||||
describe 'Record user last activity in after hook' do
|
||||
# It does not matter which endpoint is used because last_activity_on should
|
||||
# be updated on every request. `/groups` is used as an example
|
||||
# to represent any API endpoint
|
||||
let(:user) { create(:user, last_activity_on: Date.yesterday) }
|
||||
|
||||
it 'updates the users last_activity_on date' do
|
||||
it 'updates the users last_activity_on to the current date' do
|
||||
expect { get api('/groups', user) }.to change { user.reload.last_activity_on }.to(Date.today)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'User with only read_api scope personal access token' do
|
||||
# It does not matter which endpoint is used because this should behave
|
||||
# in the same way for every request. `/groups` is used as an example
|
||||
# to represent any API endpoint
|
||||
|
||||
context 'when personal access token has only read_api scope' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:token) { create(:personal_access_token, user: user, scopes: [:read_api]) }
|
||||
|
||||
before_all do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'does authorize user for get request' do
|
||||
get api('/groups', personal_access_token: token)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
|
||||
it 'does not authorize user for post request' do
|
||||
params = attributes_for_group_api
|
||||
|
||||
post api("/groups", personal_access_token: token), params: params
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
end
|
||||
|
||||
it 'does not authorize user for put request' do
|
||||
group_param = { name: 'Test' }
|
||||
|
||||
put api("/groups/#{group.id}", personal_access_token: token), params: group_param
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
end
|
||||
|
||||
it 'does not authorize user for delete request' do
|
||||
delete api("/groups/#{group.id}", personal_access_token: token)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -180,7 +180,7 @@ describe 'OpenID Connect requests' do
|
|||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['issuer']).to eq('http://localhost')
|
||||
expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys')
|
||||
expect(json_response['scopes_supported']).to eq(%w[api read_user read_repository write_repository sudo openid profile email])
|
||||
expect(json_response['scopes_supported']).to eq(%w[api read_user read_api read_repository write_repository sudo openid profile email])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -28,4 +28,18 @@ describe AnalyticsSummarySerializer do
|
|||
it 'contains important elements of AnalyticsStage' do
|
||||
expect(subject).to include(:title, :value)
|
||||
end
|
||||
|
||||
it 'does not include unit' do
|
||||
expect(subject).not_to include(:unit)
|
||||
end
|
||||
|
||||
context 'when representing with unit' do
|
||||
let(:resource) { { title: 'frequency', value: 1.12, unit: 'per day' } }
|
||||
|
||||
subject { described_class.new.represent(resource, with_unit: true) }
|
||||
|
||||
it 'contains unit' do
|
||||
expect(subject).to include(:unit)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe ExternalPullRequests::CreatePipelineService do
|
||||
describe Ci::ExternalPullRequests::CreatePipelineService do
|
||||
describe '#execute' do
|
||||
let_it_be(:project) { create(:project, :auto_devops, :repository) }
|
||||
let_it_be(:user) { create(:user) }
|
|
@ -28,10 +28,10 @@ describe UpdateExternalPullRequestsWorker do
|
|||
|
||||
context 'when ref is a branch' do
|
||||
let(:ref) { 'refs/heads/feature-1' }
|
||||
let(:create_pipeline_service) { instance_double(ExternalPullRequests::CreatePipelineService) }
|
||||
let(:create_pipeline_service) { instance_double(Ci::ExternalPullRequests::CreatePipelineService) }
|
||||
|
||||
it 'runs CreatePipelineService for each pull request matching the source branch and repository' do
|
||||
expect(ExternalPullRequests::CreatePipelineService)
|
||||
expect(Ci::ExternalPullRequests::CreatePipelineService)
|
||||
.to receive(:new)
|
||||
.and_return(create_pipeline_service)
|
||||
.twice
|
||||
|
@ -45,7 +45,7 @@ describe UpdateExternalPullRequestsWorker do
|
|||
let(:ref) { 'refs/tags/v1.2.3' }
|
||||
|
||||
it 'does nothing' do
|
||||
expect(ExternalPullRequests::CreatePipelineService).not_to receive(:new)
|
||||
expect(Ci::ExternalPullRequests::CreatePipelineService).not_to receive(:new)
|
||||
|
||||
subject
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue