Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
14846d722e
commit
e99d2e196c
2
Gemfile
2
Gemfile
|
@ -165,7 +165,7 @@ gem 'html-pipeline', '~> 2.13.2'
|
|||
gem 'deckar01-task_list', '2.3.1'
|
||||
gem 'gitlab-markup', '~> 1.8.0'
|
||||
gem 'github-markup', '~> 1.7.0', require: 'github/markup'
|
||||
gem 'commonmarker', '~> 0.23.4'
|
||||
gem 'commonmarker', '~> 0.23.6'
|
||||
gem 'kramdown', '~> 2.3.1'
|
||||
gem 'RedCloth', '~> 4.3.2'
|
||||
gem 'rdoc', '~> 6.3.2'
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
{"name":"claide-plugins","version":"0.9.2","platform":"ruby","checksum":"c7ea78bc067ab23bce8515497cdcdcb8f01c86dadfbe13c44644e382922c1c2e"},
|
||||
{"name":"coderay","version":"1.1.3","platform":"ruby","checksum":"dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b"},
|
||||
{"name":"colored2","version":"3.1.2","platform":"ruby","checksum":"b13c2bd7eeae2cf7356a62501d398e72fde78780bd26aec6a979578293c28b4a"},
|
||||
{"name":"commonmarker","version":"0.23.4","platform":"ruby","checksum":"95d9cb050576376374a66d71a4feab3562e0955aab9d80a3e8606a5cf5e9c7ce"},
|
||||
{"name":"commonmarker","version":"0.23.6","platform":"ruby","checksum":"c8aeaaaff4ba497bf180f762db63a0069794fafb6eff221224c9c8199d337b38"},
|
||||
{"name":"concurrent-ruby","version":"1.1.10","platform":"ruby","checksum":"244cb1ca0d91ec2c15ca2209507c39fb163336994428e16fbd3f465c87bd8e68"},
|
||||
{"name":"connection_pool","version":"2.2.5","platform":"ruby","checksum":"13a8fc3921ce4df8e04fb65f1037251decb08d74757b41163688bd1c1feccd39"},
|
||||
{"name":"contracts","version":"0.11.0","platform":"ruby","checksum":"df6e438efa89c31dd3095851c3f7a25dfdae36b35ff1d4547f1d92941b3c7286"},
|
||||
|
|
|
@ -282,7 +282,7 @@ GEM
|
|||
open4 (~> 1.3)
|
||||
coderay (1.1.3)
|
||||
colored2 (3.1.2)
|
||||
commonmarker (0.23.4)
|
||||
commonmarker (0.23.6)
|
||||
concurrent-ruby (1.1.10)
|
||||
connection_pool (2.2.5)
|
||||
contracts (0.11.0)
|
||||
|
@ -1557,7 +1557,7 @@ DEPENDENCIES
|
|||
capybara-screenshot (~> 1.0.22)
|
||||
carrierwave (~> 1.3)
|
||||
charlock_holmes (~> 0.7.7)
|
||||
commonmarker (~> 0.23.4)
|
||||
commonmarker (~> 0.23.6)
|
||||
concurrent-ruby (~> 1.1)
|
||||
connection_pool (~> 2.0)
|
||||
countries (~> 3.0)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { DEFAULT_PER_PAGE } from '~/api';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import axios from '../lib/utils/axios_utils';
|
||||
import { buildApiUrl } from './api_utils';
|
||||
|
@ -55,7 +55,7 @@ export function getUserProjects(userId, query, options, callback) {
|
|||
})
|
||||
.then(({ data }) => callback(data))
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('Something went wrong while fetching projects'),
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -7,7 +7,7 @@ import { getEmojiScoreWithIntent } from '~/emoji/utils';
|
|||
import { getCookie, setCookie, scrollToElement } from '~/lib/utils/common_utils';
|
||||
import * as Emoji from '~/emoji';
|
||||
import { dispose, fixTitle } from '~/tooltips';
|
||||
import createFlash from './flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { isInVueNoteablePage } from './lib/utils/dom_utils';
|
||||
import { __ } from './locale';
|
||||
|
@ -491,7 +491,7 @@ export class AwardsHandler {
|
|||
}
|
||||
})
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('Something went wrong on our end.'),
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { GlLoadingIcon, GlFormInput, GlFormGroup, GlButton, GlSafeHtmlDirective } from '@gitlab/ui';
|
||||
import { escape, debounce } from 'lodash';
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert, VARIANT_INFO } from '~/flash';
|
||||
import { s__, sprintf } from '~/locale';
|
||||
import createEmptyBadge from '../empty_badge';
|
||||
import Badge from './badge.vue';
|
||||
|
@ -136,14 +136,14 @@ export default {
|
|||
if (this.isEditing) {
|
||||
return this.saveBadge()
|
||||
.then(() => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__('Badges|Badge saved.'),
|
||||
type: 'notice',
|
||||
variant: VARIANT_INFO,
|
||||
});
|
||||
this.wasValidated = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__(
|
||||
'Badges|Saving the badge failed, please check the entered URLs and try again.',
|
||||
),
|
||||
|
@ -154,14 +154,14 @@ export default {
|
|||
|
||||
return this.addBadge()
|
||||
.then(() => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__('Badges|New badge added.'),
|
||||
type: 'notice',
|
||||
variant: VARIANT_INFO,
|
||||
});
|
||||
this.wasValidated = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__(
|
||||
'Badges|Adding the badge failed, please check the entered URLs and try again.',
|
||||
),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlSprintf, GlModal } from '@gitlab/ui';
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert, VARIANT_INFO } from '~/flash';
|
||||
import { __, s__ } from '~/locale';
|
||||
import Badge from './badge.vue';
|
||||
import BadgeForm from './badge_form.vue';
|
||||
|
@ -40,13 +40,13 @@ export default {
|
|||
onSubmitModal() {
|
||||
this.deleteBadge(this.badgeInModal)
|
||||
.then(() => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__('Badges|The badge was deleted.'),
|
||||
type: 'notice',
|
||||
variant: VARIANT_INFO,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__('Badges|Deleting the badge failed, please try again.'),
|
||||
});
|
||||
throw error;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { isEmpty } from 'lodash';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { scrollToElement } from '~/lib/utils/common_utils';
|
||||
import { __ } from '~/locale';
|
||||
import { CHANGES_TAB, DISCUSSION_TAB, SHOW_TAB } from '../../../constants';
|
||||
|
@ -18,7 +18,7 @@ export const addDraftToDiscussion = ({ commit }, { endpoint, data }) =>
|
|||
return res;
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('An error occurred adding a draft to the thread.'),
|
||||
});
|
||||
});
|
||||
|
@ -32,7 +32,7 @@ export const createNewDraft = ({ commit }, { endpoint, data }) =>
|
|||
return res;
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('An error occurred adding a new draft.'),
|
||||
});
|
||||
});
|
||||
|
@ -44,7 +44,7 @@ export const deleteDraft = ({ commit, getters }, draft) =>
|
|||
commit(types.DELETE_DRAFT, draft.id);
|
||||
})
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('An error occurred while deleting the comment'),
|
||||
}),
|
||||
);
|
||||
|
@ -62,7 +62,7 @@ export const fetchDrafts = ({ commit, getters, state, dispatch }) =>
|
|||
});
|
||||
})
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('An error occurred while fetching pending comments'),
|
||||
}),
|
||||
);
|
||||
|
@ -122,7 +122,7 @@ export const updateDraft = (
|
|||
.then((data) => commit(types.RECEIVE_DRAFT_UPDATE_SUCCESS, data))
|
||||
.then(callback)
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('An error occurred while updating the comment'),
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable func-names */
|
||||
|
||||
import $ from 'jquery';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
|
@ -80,7 +80,7 @@ MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) {
|
|||
success(data);
|
||||
})
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('An error occurred while fetching Markdown preview'),
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@ import $ from 'jquery';
|
|||
|
||||
import Api from '~/api';
|
||||
import initPopover from '~/blob/suggest_gitlab_ci_yml';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import toast from '~/vue_shared/plugins/global_toast';
|
||||
|
||||
|
@ -155,7 +155,7 @@ export default class FileTemplateMediator {
|
|||
}
|
||||
})
|
||||
.catch((err) =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __(`An error occurred while fetching the template: ${err}`),
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { SwaggerUIBundle } from 'swagger-ui-dist';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default () => {
|
||||
|
@ -15,7 +15,7 @@ export default () => {
|
|||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('Something went wrong while initializing the OpenAPI viewer'),
|
||||
});
|
||||
throw error;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import $ from 'jquery';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import {
|
||||
REPO_BLOB_LOAD_VIEWER_START,
|
||||
|
@ -69,7 +69,7 @@ export const handleBlobRichViewer = (viewer, type) => {
|
|||
loadRichBlobViewer(type)
|
||||
.then((module) => module?.default(viewer))
|
||||
.catch((error) => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('Error loading file viewer.'),
|
||||
});
|
||||
throw error;
|
||||
|
@ -221,7 +221,7 @@ export class BlobViewer {
|
|||
});
|
||||
})
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('Error loading viewer'),
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import $ from 'jquery';
|
||||
import initPopover from '~/blob/suggest_gitlab_ci_yml';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { disableButtonIfEmptyField, setCookie } from '~/lib/utils/common_utils';
|
||||
import Tracking from '~/tracking';
|
||||
import BlobFileDropzone from '../blob/blob_file_dropzone';
|
||||
|
@ -79,7 +79,7 @@ export default () => {
|
|||
initPopovers();
|
||||
})
|
||||
.catch((e) =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: e,
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -3,7 +3,7 @@ import { SourceEditorExtension } from '~/editor/extensions/source_editor_extensi
|
|||
import { FileTemplateExtension } from '~/editor/extensions/source_editor_file_template_ext';
|
||||
import { ToolbarExtension } from '~/editor/extensions/source_editor_toolbar_ext';
|
||||
import SourceEditor from '~/editor/source_editor';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
|
||||
import { insertFinalNewline } from '~/lib/utils/text_utility';
|
||||
|
@ -44,7 +44,7 @@ export default class EditBlob {
|
|||
},
|
||||
]);
|
||||
} catch (e) {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: `${BLOB_EDITOR_ERROR}: ${e}`,
|
||||
});
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ export default class EditBlob {
|
|||
currentPane.renderGFM();
|
||||
})
|
||||
.catch(() =>
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: BLOB_PREVIEW_ERROR,
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,332 @@
|
|||
<script>
|
||||
import {
|
||||
GlFormGroup,
|
||||
GlFormInput,
|
||||
GlFormCheckbox,
|
||||
GlButton,
|
||||
GlDatepicker,
|
||||
GlFormInputGroup,
|
||||
GlSprintf,
|
||||
GlLink,
|
||||
} from '@gitlab/ui';
|
||||
import { createAlert, VARIANT_INFO } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { formatDate } from '~/lib/utils/datetime_utility';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import { s__ } from '~/locale';
|
||||
|
||||
function defaultData() {
|
||||
return {
|
||||
expiresAt: null,
|
||||
name: '',
|
||||
newTokenDetails: null,
|
||||
readRepository: false,
|
||||
writeRepository: false,
|
||||
readRegistry: false,
|
||||
writeRegistry: false,
|
||||
readPackageRegistry: false,
|
||||
writePackageRegistry: false,
|
||||
username: '',
|
||||
placeholders: {
|
||||
link: { link: ['link_start', 'link_end'] },
|
||||
i: { i: ['i_start', 'i_end'] },
|
||||
code: { code: ['code_start', 'code_end'] },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlFormGroup,
|
||||
GlFormInput,
|
||||
GlDatepicker,
|
||||
GlFormCheckbox,
|
||||
GlButton,
|
||||
GlFormInputGroup,
|
||||
ClipboardButton,
|
||||
GlSprintf,
|
||||
GlLink,
|
||||
},
|
||||
|
||||
props: {
|
||||
createNewTokenPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
deployTokensHelpUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
containerRegistryEnabled: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
packagesRegistryEnabled: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
tokenType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return defaultData();
|
||||
},
|
||||
translations: {
|
||||
addTokenButton: s__('DeployTokens|Create deploy token'),
|
||||
addTokenExpiryLabel: s__('DeployTokens|Expiration date (optional)'),
|
||||
addTokenExpiryDescription: s__(
|
||||
'DeployTokens|Enter an expiration date for your token. Defaults to never expire.',
|
||||
),
|
||||
addTokenHeader: s__('DeployTokens|New deploy token'),
|
||||
addTokenDescription: s__(
|
||||
'DeployTokens|Create a new deploy token for all projects in this group. %{link_start}What are deploy tokens?%{link_end}',
|
||||
),
|
||||
addTokenNameLabel: s__('DeployTokens|Name'),
|
||||
addTokenNameDescription: s__('DeployTokens|Enter a unique name for your deploy token.'),
|
||||
addTokenScopesLabel: s__('DeployTokens|Scopes (select at least one)'),
|
||||
addTokenUsernameDescription: s__(
|
||||
'DeployTokens|Enter a username for your token. Defaults to %{code_start}gitlab+deploy-token-{n}%{code_end}.',
|
||||
),
|
||||
addTokenUsernameLabel: s__('DeployTokens|Username (optional)'),
|
||||
newTokenCopyMessage: s__('DeployTokens|Copy deploy token'),
|
||||
newProjectTokenCreated: s__('DeployTokens|Your new project deploy token has been created.'),
|
||||
newGroupTokenCreated: s__('DeployTokens|Your new group deploy token has been created.'),
|
||||
newTokenDescription: s__(
|
||||
'DeployTokens|Use this token as a password. Save it. This password can %{i_start}not%{i_end} be recovered.',
|
||||
),
|
||||
newTokenMessage: s__('DeployTokens|Your New Deploy Token'),
|
||||
newTokenUsernameCopy: s__('DeployTokens|Copy username'),
|
||||
newTokenUsernameDescription: s__(
|
||||
'DeployTokens|This username supports access. %{link_start}What kind of access?%{link_end}',
|
||||
),
|
||||
readRepositoryHelp: s__('DeployTokens|Allows read-only access to the repository.'),
|
||||
readRegistryHelp: s__('DeployTokens|Allows read-only access to registry images.'),
|
||||
writeRegistryHelp: s__('DeployTokens|Allows read and write access to registry images.'),
|
||||
readPackageRegistryHelp: s__('DeployTokens|Allows read-only access to the package registry.'),
|
||||
writePackageRegistryHelp: s__(
|
||||
'DeployTokens|Allows read and write access to the package registry.',
|
||||
),
|
||||
},
|
||||
computed: {
|
||||
formattedExpiryDate() {
|
||||
return formatDate(this.expiresAt, 'yyyy-mm-dd');
|
||||
},
|
||||
newTokenCreatedMessage() {
|
||||
return this.tokenType === 'group'
|
||||
? this.$options.translations.newGroupTokenCreated
|
||||
: this.$options.translations.newProjectTokenCreated;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
createDeployToken() {
|
||||
return axios
|
||||
.post(this.createNewTokenPath, {
|
||||
deploy_token: {
|
||||
expires_at: this.expiresAt,
|
||||
name: this.name,
|
||||
read_repository: this.readRepository,
|
||||
read_registry: this.readRegistry,
|
||||
username: this.username,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
this.newTokenDetails = response.data;
|
||||
this.resetData();
|
||||
createAlert({
|
||||
variant: VARIANT_INFO,
|
||||
message: this.newTokenCreatedMessage,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
createAlert({
|
||||
message: error.response.data.message,
|
||||
});
|
||||
});
|
||||
},
|
||||
resetData() {
|
||||
const newData = defaultData();
|
||||
delete newData.newTokenDetails;
|
||||
Object.keys(newData).forEach((k) => {
|
||||
this[k] = newData[k];
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="newTokenDetails" class="created-deploy-token-container info-well">
|
||||
<div class="well-segment">
|
||||
<h5>{{ $options.translations.newTokenMessage }}</h5>
|
||||
<gl-form-group>
|
||||
<template #description>
|
||||
<div class="deploy-token-help-block gl-mt-2 text-success">
|
||||
<gl-sprintf
|
||||
:message="$options.translations.newTokenUsernameDescription"
|
||||
:placeholders="placeholders.link"
|
||||
>
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="deployTokensHelpUrl" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</template>
|
||||
<gl-form-input-group
|
||||
name="deploy-token-user"
|
||||
:value="newTokenDetails.username"
|
||||
select-on-click
|
||||
readonly
|
||||
>
|
||||
<template #append>
|
||||
<clipboard-button
|
||||
:text="newTokenDetails.username"
|
||||
:title="$options.translations.newTokenUsernameCopy"
|
||||
/>
|
||||
</template>
|
||||
</gl-form-input-group>
|
||||
</gl-form-group>
|
||||
<gl-form-group>
|
||||
<template #description>
|
||||
<div class="deploy-token-help-block gl-mt-2 text-danger">
|
||||
<gl-sprintf
|
||||
:message="$options.translations.newTokenDescription"
|
||||
:placeholders="placeholders.i"
|
||||
>
|
||||
<template #i="{ content }">
|
||||
<i>{{ content }}</i>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</template>
|
||||
<gl-form-input-group :value="newTokenDetails.token" name="deploy-token" readonly>
|
||||
<template #append>
|
||||
<clipboard-button
|
||||
:text="newTokenDetails.token"
|
||||
:title="$options.translations.newTokenCopyMessage"
|
||||
/>
|
||||
</template>
|
||||
</gl-form-input-group>
|
||||
</gl-form-group>
|
||||
</div>
|
||||
</div>
|
||||
<h5>{{ $options.translations.addTokenHeader }}</h5>
|
||||
<p class="profile-settings-content">
|
||||
<gl-sprintf
|
||||
:message="$options.translations.addTokenDescription"
|
||||
:placeholders="placeholders.link"
|
||||
>
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="deployTokensHelpUrl" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
<gl-form-group
|
||||
:label="$options.translations.addTokenNameLabel"
|
||||
:description="$options.translations.addTokenNameDescription"
|
||||
label-for="deploy_token_name"
|
||||
>
|
||||
<gl-form-input
|
||||
id="deploy_token_name"
|
||||
v-model="name"
|
||||
name="deploy_token_name"
|
||||
class="qa-deploy-token-name"
|
||||
data-qa-selector="deploy_token_name_field"
|
||||
/>
|
||||
</gl-form-group>
|
||||
<gl-form-group
|
||||
:label="$options.translations.addTokenExpiryLabel"
|
||||
:description="$options.translations.addTokenExpiryDescription"
|
||||
label-for="deploy_token_expires_at"
|
||||
>
|
||||
<gl-form-input
|
||||
id="deploy_token_expires_at"
|
||||
name="deploy_token_expires_at"
|
||||
:value="formattedExpiryDate"
|
||||
data-qa-selector="deploy_token_expires_at_field"
|
||||
/>
|
||||
</gl-form-group>
|
||||
<gl-form-group
|
||||
:label="$options.translations.addTokenUsernameLabel"
|
||||
label-for="deploy_token_username"
|
||||
>
|
||||
<template #description>
|
||||
<gl-sprintf
|
||||
:message="$options.translations.addTokenUsernameDescription"
|
||||
:placeholders="placeholders.code"
|
||||
>
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
<gl-form-input id="deploy_token_username" v-model="username" />
|
||||
</gl-form-group>
|
||||
<gl-form-group
|
||||
:label="$options.translations.addTokenScopesLabel"
|
||||
label-for="deploy-token-scopes"
|
||||
>
|
||||
<div id="deploy-token-scopes">
|
||||
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
|
||||
<gl-form-checkbox
|
||||
id="deploy_token_read_repository"
|
||||
v-model="readRepository"
|
||||
name="deploy_token_read_repository"
|
||||
data-qa-selector="deploy_token_read_repository_checkbox"
|
||||
>
|
||||
read_repository
|
||||
<template #help>{{ $options.translations.readRepositoryHelp }}</template>
|
||||
</gl-form-checkbox>
|
||||
<gl-form-checkbox
|
||||
v-if="containerRegistryEnabled"
|
||||
id="deploy_token_read_registry"
|
||||
v-model="readRegistry"
|
||||
name="deploy_token_read_registry"
|
||||
data-qa-selector="deploy_token_read_registry_checkbox"
|
||||
>
|
||||
read_registry
|
||||
<template #help>{{ $options.translations.readRegistryHelp }}</template>
|
||||
</gl-form-checkbox>
|
||||
<gl-form-checkbox
|
||||
v-if="containerRegistryEnabled"
|
||||
id="deploy_token_write_registry"
|
||||
v-model="writeRegistry"
|
||||
name="deploy_token_write_registry"
|
||||
data-qa-selector="deploy_token_write_registry_checkbox"
|
||||
>
|
||||
write_registry
|
||||
<template #help>{{ $options.translations.writeRegistryHelp }}</template>
|
||||
</gl-form-checkbox>
|
||||
<gl-form-checkbox
|
||||
v-if="packagesRegistryEnabled"
|
||||
id="deploy_token_read_package_registry"
|
||||
v-model="readPackageRegistry"
|
||||
name="deploy_token_read_package_registry"
|
||||
data-qa-selector="deploy_token_read_package_registry_checkbox"
|
||||
>
|
||||
read_package_registry
|
||||
<template #help>{{ $options.translations.readPackageRegistryHelp }}</template>
|
||||
</gl-form-checkbox>
|
||||
<gl-form-checkbox
|
||||
v-if="packagesRegistryEnabled"
|
||||
id="deploy_token_write_package_registry"
|
||||
v-model="writePackageRegistry"
|
||||
name="deploy_token_write_package_registry"
|
||||
data-qa-selector="deploy_token_write_package_registry_checkbox"
|
||||
>
|
||||
write_package_registry
|
||||
<template #help>{{ $options.translations.writePackageRegistryHelp }}</template>
|
||||
</gl-form-checkbox>
|
||||
<!-- eslint-enable @gitlab/vue-require-i18n-strings -->
|
||||
</div>
|
||||
</gl-form-group>
|
||||
<div>
|
||||
<gl-button variant="success" @click="createDeployToken">
|
||||
{{ $options.translations.addTokenButton }}
|
||||
</gl-button>
|
||||
</div>
|
||||
<gl-datepicker v-model="expiresAt" target="#deploy_token_expires_at" container="body" />
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,33 @@
|
|||
import Vue from 'vue';
|
||||
import NewDeployToken from './components/new_deploy_token.vue';
|
||||
|
||||
export default function initDeployTokens() {
|
||||
const el = document.getElementById('js-new-deploy-token');
|
||||
|
||||
if (el == null) return null;
|
||||
|
||||
const {
|
||||
createNewTokenPath,
|
||||
deployTokensHelpUrl,
|
||||
containerRegistryEnabled,
|
||||
packagesRegistryEnabled,
|
||||
tokenType,
|
||||
} = el.dataset;
|
||||
return new Vue({
|
||||
el,
|
||||
components: {
|
||||
NewDeployToken,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(NewDeployToken, {
|
||||
props: {
|
||||
createNewTokenPath,
|
||||
deployTokensHelpUrl,
|
||||
containerRegistryEnabled: containerRegistryEnabled !== undefined,
|
||||
packagesRegistryEnabled: packagesRegistryEnabled !== undefined,
|
||||
tokenType,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
|
@ -81,16 +81,18 @@ export default {
|
|||
:class="{
|
||||
'gl-bg-orange-50': blocksMerge && !allResolved,
|
||||
'gl-bg-gray-50': !blocksMerge || allResolved,
|
||||
'gl-pr-2': !allResolved,
|
||||
}"
|
||||
data-testid="discussions-counter-text"
|
||||
>
|
||||
<template v-if="allResolved">
|
||||
{{ __('All threads resolved!') }}
|
||||
<gl-dropdown
|
||||
v-gl-tooltip:discussionCounter.hover.bottom
|
||||
size="small"
|
||||
category="tertiary"
|
||||
right
|
||||
:title="__('Thread options')"
|
||||
:aria-label="__('Thread options')"
|
||||
toggle-class="btn-icon"
|
||||
class="gl-pt-0! gl-px-2 gl-h-full gl-ml-2"
|
||||
>
|
||||
|
@ -133,9 +135,12 @@ export default {
|
|||
@click="jumpNext"
|
||||
/>
|
||||
<gl-dropdown
|
||||
v-gl-tooltip:discussionCounter.hover.bottom
|
||||
size="small"
|
||||
category="tertiary"
|
||||
right
|
||||
:title="__('Thread options')"
|
||||
:aria-label="__('Thread options')"
|
||||
toggle-class="btn-icon"
|
||||
class="gl-pt-0! gl-px-2"
|
||||
>
|
||||
|
|
|
@ -57,6 +57,9 @@ export default {
|
|||
isEnabled() {
|
||||
return this.containerExpirationPolicy || this.enableHistoricEntries;
|
||||
},
|
||||
isLoading() {
|
||||
return this.$apollo.queries.containerExpirationPolicy.loading;
|
||||
},
|
||||
showDisabledFormMessage() {
|
||||
return !this.isEnabled && !this.fetchSettingsError;
|
||||
},
|
||||
|
@ -86,10 +89,10 @@ export default {
|
|||
<container-expiration-policy-form
|
||||
v-if="isEnabled"
|
||||
v-model="workingCopy"
|
||||
:is-loading="$apollo.queries.containerExpirationPolicy.loading"
|
||||
:is-loading="isLoading"
|
||||
:is-edited="isEdited"
|
||||
/>
|
||||
<template v-else>
|
||||
<template v-if="!isLoading">
|
||||
<gl-alert
|
||||
v-if="showDisabledFormMessage"
|
||||
:dismissible="false"
|
||||
|
|
|
@ -110,7 +110,7 @@ export default {
|
|||
{{ cleanupRulesButtonText }}
|
||||
</gl-button>
|
||||
</gl-card>
|
||||
<template v-else>
|
||||
<template v-if="!$apollo.queries.containerExpirationPolicy.loading">
|
||||
<gl-alert
|
||||
v-if="showDisabledFormMessage"
|
||||
:dismissible="false"
|
||||
|
|
|
@ -2,9 +2,11 @@ import initStaleRunnerCleanupSetting from 'ee_else_ce/group_settings/stale_runne
|
|||
import initVariableList from '~/ci_variable_list';
|
||||
import initSharedRunnersForm from '~/group_settings/mount_shared_runners';
|
||||
import initSettingsPanels from '~/settings_panels';
|
||||
import initDeployTokens from '~/deploy_tokens';
|
||||
|
||||
// Initialize expandable settings panels
|
||||
initSettingsPanels();
|
||||
initDeployTokens();
|
||||
|
||||
initSharedRunnersForm();
|
||||
initStaleRunnerCleanupSetting();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import initRevokeButton from '~/deploy_tokens/init_revoke_button';
|
||||
import initSearchSettings from '~/search_settings';
|
||||
import initDeployTokens from '~/deploy_tokens';
|
||||
|
||||
initDeployTokens();
|
||||
initSearchSettings();
|
||||
initRevokeButton();
|
||||
|
|
|
@ -10,6 +10,7 @@ import initSharedRunnersToggle from '~/projects/settings/mount_shared_runners_to
|
|||
import initSettingsPanels from '~/settings_panels';
|
||||
import { initTokenAccess } from '~/token_access';
|
||||
import { initCiSecureFiles } from '~/ci_secure_files';
|
||||
import initDeployTokens from '~/deploy_tokens';
|
||||
|
||||
// Initialize expandable settings panels
|
||||
initSettingsPanels();
|
||||
|
@ -34,6 +35,7 @@ document.querySelector('.js-toggle-extra-settings').addEventListener('click', (e
|
|||
});
|
||||
|
||||
registrySettingsApp();
|
||||
initDeployTokens();
|
||||
initDeployFreeze();
|
||||
|
||||
initSettingsPipelinesTriggers();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import initRevokeButton from '~/deploy_tokens/init_revoke_button';
|
||||
import initSearchSettings from '~/search_settings';
|
||||
import initDeployTokens from '~/deploy_tokens';
|
||||
|
||||
initDeployTokens();
|
||||
initSearchSettings();
|
||||
initRevokeButton();
|
||||
|
|
|
@ -315,7 +315,6 @@ export default {
|
|||
data-qa-selector="mr_widget_extension"
|
||||
>
|
||||
<state-container
|
||||
:mr="mr"
|
||||
:status="statusIconName"
|
||||
:is-loading="isLoadingSummary"
|
||||
:class="{ 'gl-cursor-pointer': isCollapsible }"
|
||||
|
|
|
@ -16,7 +16,8 @@ export default {
|
|||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
required: true,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
|
@ -80,6 +81,7 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="mr"
|
||||
class="gl-md-display-none gl-border-l-1 gl-border-l-solid gl-border-gray-100 gl-ml-3 gl-pl-3 gl-h-6 gl-mt-1"
|
||||
>
|
||||
<gl-button
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
- save_endpoint = local_assigns.fetch(:save_endpoint, nil)
|
||||
|
||||
- if ci_variable_protected_by_default?
|
||||
%p.settings-message.text-center
|
||||
- link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/index', anchor: 'protected-cicd-variables') }
|
||||
= s_('Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default.').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
|
||||
= render Pajamas::AlertComponent.new(variant: :warning, show_icon: false, dismissible: false,
|
||||
alert_options: { class: 'gl-mb-3'}) do |c|
|
||||
= c.body do
|
||||
- link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/index', anchor: 'protected-cicd-variables') }
|
||||
= _('Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default.').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
|
||||
|
||||
- is_group = !@group.nil?
|
||||
- is_project = !@project.nil?
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
- display_issuable_type = issuable_display_type(@merge_request)
|
||||
|
||||
.float-left.btn-group.gl-md-ml-3.gl-display-flex.dropdown.gl-new-dropdown.gl-md-w-auto.gl-w-full
|
||||
= button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret gl-display-none! gl-md-display-inline-flex!", data: { 'toggle' => 'dropdown' } do
|
||||
%span.gl-sr-only= _('Toggle dropdown')
|
||||
= button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret has-tooltip gl-display-none! gl-md-display-inline-flex!", data: { 'toggle' => 'dropdown' }, title: _('Merge request actions') , 'aria-label': _('Merge request actions') do
|
||||
= sprite_icon "ellipsis_v", size: 16, css_class: "dropdown-icon gl-icon"
|
||||
= button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md btn-block gl-button gl-dropdown-toggle gl-md-display-none!", data: { 'toggle' => 'dropdown' } do
|
||||
%span.gl-new-dropdown-button-text= _('Merge request actions')
|
||||
|
|
|
@ -8,10 +8,20 @@
|
|||
%p
|
||||
= description
|
||||
.settings-content
|
||||
- if @created_deploy_token
|
||||
= render 'shared/deploy_tokens/new_deploy_token', deploy_token: @created_deploy_token
|
||||
%h5.gl-mt-0
|
||||
= s_('DeployTokens|New deploy token')
|
||||
= render 'shared/deploy_tokens/form', group_or_project: group_or_project, token: @new_deploy_token, presenter: @deploy_tokens
|
||||
- if Feature.enabled?(:ajax_new_deploy_token, group_or_project)
|
||||
#js-new-deploy-token{ data: {
|
||||
container_registry_enabled: container_registry_enabled?(group_or_project),
|
||||
packages_registry_enabled: packages_registry_enabled?(group_or_project),
|
||||
create_new_token_path: create_deploy_token_path(group_or_project),
|
||||
token_type: group_or_project.is_a?(Group) ? 'group' : 'project',
|
||||
deploy_tokens_help_url: help_page_path('user/project/deploy_tokens/index.md')
|
||||
}
|
||||
}
|
||||
- else
|
||||
- if @created_deploy_token
|
||||
= render 'shared/deploy_tokens/new_deploy_token', deploy_token: @created_deploy_token
|
||||
%h5.gl-mt-0
|
||||
= s_('DeployTokens|New deploy token')
|
||||
= render 'shared/deploy_tokens/form', group_or_project: group_or_project, token: @new_deploy_token, presenter: @deploy_tokens
|
||||
%hr
|
||||
= render 'shared/deploy_tokens/table', group_or_project: group_or_project, active_tokens: @deploy_tokens
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: gitaly_simplify_find_local_branches_response
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitaly/-/merge_requests/4850
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitaly/-/issues/4452
|
||||
milestone: '15.4'
|
||||
type: undefined
|
||||
group: group::gitaly
|
||||
default_enabled: false
|
|
@ -24,6 +24,16 @@ module SawyerClassPatch
|
|||
end
|
||||
else
|
||||
define_method attribute do
|
||||
Gitlab::Import::Logger.warn(
|
||||
Gitlab::ApplicationContext.current.merge(
|
||||
{
|
||||
message: 'Sawyer attribute called',
|
||||
attribute: attribute,
|
||||
caller: Gitlab::BacktraceCleaner.clean_backtrace(caller)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@attrs[attribute.to_sym]
|
||||
end
|
||||
|
||||
|
|
|
@ -8,35 +8,36 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
# Amazon Web Services Cognito **(FREE SELF)**
|
||||
|
||||
Amazon Cognito lets you add user sign-up, sign-in, and access control to your GitLab instance.
|
||||
The following documentation enables Cognito as an OAuth2 provider.
|
||||
The following documentation enables Cognito as an OAuth 2.0 provider.
|
||||
|
||||
## Configure AWS Cognito
|
||||
|
||||
To enable the [AWS Cognito](https://aws.amazon.com/cognito/) OAuth2 OmniAuth provider, register your application with Cognito. This process generates a Client ID and Client Secret for your application.
|
||||
Any settings you configure in the following procedure can be modified later.
|
||||
The following steps enable AWS Cognito as an authentication provider:
|
||||
To enable the [AWS Cognito](https://aws.amazon.com/cognito/) OAuth 2.0 OmniAuth provider, register your application with Cognito. This process generates a Client ID and Client Secret for your application.
|
||||
To enable AWS Cognito as an authentication provider, complete the following steps. You can modify any settings you configure later.
|
||||
|
||||
1. Sign in to the [AWS console](https://console.aws.amazon.com/console/home).
|
||||
1. Select **Cognito** from the **Services** menu.
|
||||
1. Select **Manage User Pools**, and select the **Create a user pool** button in the top right corner.
|
||||
1. Enter the pool name and then select the **Step through settings** button.
|
||||
1. From the **Services** menu, select **Cognito**.
|
||||
1. Select **Manage User Pools** and then select **Create a user pool** in the top right corner.
|
||||
1. Enter the user pool name and then select **Step through settings**.
|
||||
1. Under **How do you want your end users to sign in?**, select **Email address or phone number** and **Allow email addresses**.
|
||||
1. Under **Which standard attributes do you want to require?**, select **email**.
|
||||
1. Go to the next steps of configuration and set the rest of the settings to suit your needs - in the basic setup they are not related to GitLab configuration.
|
||||
1. In the **App clients** settings, select **Add an app client**, add **App client name** and select the **Enable username password based authentication** checkbox.
|
||||
1. Configure the remaining settings to suit your needs. In the basic setup, these settings do not affect GitLab configuration.
|
||||
1. In the **App clients** settings:
|
||||
1. Select **Add an app client**.
|
||||
1. Add the **App client name**.
|
||||
1. Select the **Enable username password based authentication** checkbox.
|
||||
1. Select **Create app client**.
|
||||
1. In the next step, you can set up AWS Lambda functions for sending emails. You can then finish creating the pool.
|
||||
1. Set up the AWS Lambda functions for sending emails and finish creating the user pool.
|
||||
1. After creating the user pool, go to **App client settings** and provide the required information:
|
||||
|
||||
- **Enabled Identity Providers** - select all
|
||||
- **Callback URL** - `https://gitlab.example.com/users/auth/cognito/callback`
|
||||
- Substitute the URL of your GitLab instance for `gitlab.example.com`
|
||||
- **Callback URL** - `https://<your_gitlab_instance_url>/users/auth/cognito/callback`
|
||||
- **Allowed OAuth Flows** - Authorization code grant
|
||||
- **Allowed OAuth2 Scopes** - `email`, `openid`, and `profile`
|
||||
|
||||
1. Save changes for the app client settings.
|
||||
1. Under **Domain name** include the AWS domain name for your AWS Cognito application.
|
||||
1. Under **App Clients**, find your app client ID and app client secret. These values correspond to the OAuth2 Client ID and Client Secret. Save these values.
|
||||
1. Under **Domain name**, include the AWS domain name for your AWS Cognito application.
|
||||
1. Under **App Clients**, find your app client ID. Select **Show details* to display the app client secret. These values correspond to the OAuth 2.0 Client ID and Client Secret. Save these values.
|
||||
|
||||
## Configure GitLab
|
||||
|
||||
|
@ -49,8 +50,13 @@ The following steps enable AWS Cognito as an authentication provider:
|
|||
sudo editor /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
1. In the following code block, substitute the Client ID (`app_id`), Client Secret (`app_secret`), and the Amazon domain name (`site`) for your AWS Cognito application.
|
||||
Include the code block in the `/etc/gitlab/gitlab.rb` file:
|
||||
1. In the following code block, enter your AWS Cognito application information in the following parameters:
|
||||
|
||||
- `app_id`: Your client ID.
|
||||
- `app_secret`: Your client secret.
|
||||
- `site`: Your Amazon domain and region.
|
||||
|
||||
Include the code block in the `/etc/gitlab/gitlab.rb` file:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_allow_single_sign_on'] = ['cognito']
|
||||
|
@ -59,12 +65,12 @@ Include the code block in the `/etc/gitlab/gitlab.rb` file:
|
|||
name: "cognito",
|
||||
label: "Provider name", # optional label for login button, defaults to "Cognito"
|
||||
icon: nil, # Optional icon URL
|
||||
app_id: "CLIENT ID",
|
||||
app_secret: "CLIENT SECRET",
|
||||
app_id: "<client_id>",
|
||||
app_secret: "<client_secret>",
|
||||
args: {
|
||||
scope: "openid profile email",
|
||||
client_options: {
|
||||
site: "https://your_domain.auth.your_region.amazoncognito.com",
|
||||
site: "https://<your_domain>.auth.<your_region>.amazoncognito.com",
|
||||
authorize_url: "/oauth2/authorize",
|
||||
token_url: "/oauth2/token",
|
||||
user_info_url: "/oauth2/userInfo"
|
||||
|
@ -84,8 +90,9 @@ Include the code block in the `/etc/gitlab/gitlab.rb` file:
|
|||
1. Save the configuration file.
|
||||
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure) GitLab for the changes to take effect.
|
||||
|
||||
Your sign-in page should now display a Cognito button below the regular sign-in form.
|
||||
To begin the authentication process, select the icon, and AWS Cognito asks the user to sign in and authorize the GitLab application.
|
||||
If successful, the user is redirected and signed in to your GitLab instance.
|
||||
Your sign-in page should now display a Cognito option below the regular sign-in form.
|
||||
Select this option to begin the authentication process.
|
||||
AWS Cognito then asks you to sign in and authorize the GitLab application.
|
||||
If the authorization is successful, you're redirected and signed in to your GitLab instance.
|
||||
|
||||
For more information, see [Configure initial settings](../../integration/omniauth.md#configure-initial-settings).
|
||||
|
|
|
@ -229,12 +229,12 @@ To set the busy status indicator, either:
|
|||
- Set it directly:
|
||||
1. On the top bar, in the top-right corner, select your avatar.
|
||||
1. Select **Set status** or, if you have already set a status, **Edit status**.
|
||||
1. Select the **Busy** checkbox.
|
||||
1. Select the **Set yourself as busy** checkbox.
|
||||
|
||||
- Set it on your profile:
|
||||
1. On the top bar, in the top-right corner, select your avatar.
|
||||
1. Select **Edit profile**.
|
||||
1. In the **Current status** section, select the **Busy** checkbox.
|
||||
1. In the **Current status** section, select the **Set yourself as busy** checkbox.
|
||||
|
||||
The busy status is displayed in the user interface.
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Banzai
|
||||
module Filter
|
||||
class PathologicalMarkdownFilter < HTML::Pipeline::TextFilter
|
||||
# It's not necessary for this to be precise - we just need to detect
|
||||
# when there are a non-trivial number of unclosed image links.
|
||||
# So we don't really care about code blocks, etc.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/370428
|
||||
REGEX = /!\[(?:[^\]])+?!\[/.freeze
|
||||
DETECTION_MAX = 10
|
||||
|
||||
def call
|
||||
count = 0
|
||||
|
||||
@text.scan(REGEX) do |_match|
|
||||
count += 1
|
||||
break if count > DETECTION_MAX
|
||||
end
|
||||
|
||||
return @text if count <= DETECTION_MAX
|
||||
|
||||
"_Unable to render markdown - too many unclosed markdown image links detected._"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,7 +5,6 @@ module Banzai
|
|||
class PlainMarkdownPipeline < BasePipeline
|
||||
def self.filters
|
||||
FilterArray[
|
||||
Filter::PathologicalMarkdownFilter,
|
||||
Filter::MarkdownPreEscapeFilter,
|
||||
Filter::MarkdownFilter,
|
||||
Filter::MarkdownPostEscapeFilter
|
||||
|
|
|
@ -270,15 +270,13 @@ module Gitlab
|
|||
end
|
||||
|
||||
def consume_find_local_branches_response(response)
|
||||
if Feature.enabled?(:gitaly_simplify_find_local_branches_response, type: :undefined)
|
||||
response.flat_map do |message|
|
||||
response.flat_map do |message|
|
||||
if message.local_branches.present?
|
||||
message.local_branches.map do |branch|
|
||||
target_commit = Gitlab::Git::Commit.decorate(@repository, branch.target_commit)
|
||||
Gitlab::Git::Branch.new(@repository, branch.name, branch.target_commit.id, target_commit)
|
||||
end
|
||||
end
|
||||
else
|
||||
response.flat_map do |message|
|
||||
else
|
||||
message.branches.map do |gitaly_branch|
|
||||
Gitlab::Git::Branch.new(
|
||||
@repository,
|
||||
|
|
|
@ -69,7 +69,7 @@ module Gitlab
|
|||
#
|
||||
# username - The username of the user.
|
||||
def user(username)
|
||||
with_rate_limit { octokit.user(username) }
|
||||
with_rate_limit { octokit.user(username).to_h }
|
||||
end
|
||||
|
||||
def pull_request_reviews(repo_name, iid)
|
||||
|
@ -88,7 +88,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def pull_request(repo_name, iid)
|
||||
with_rate_limit { octokit.pull_request(repo_name, iid) }
|
||||
with_rate_limit { octokit.pull_request(repo_name, iid).to_h }
|
||||
end
|
||||
|
||||
def labels(*args)
|
||||
|
@ -150,7 +150,7 @@ module Gitlab
|
|||
|
||||
each_page(method, *args) do |page|
|
||||
page.objects.each do |object|
|
||||
yield object
|
||||
yield object.to_h
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,9 +11,9 @@ module Gitlab
|
|||
def each_object_to_import
|
||||
repo = project.import_source
|
||||
|
||||
protected_branches = client.branches(repo).select { |branch| branch.protection&.enabled }
|
||||
protected_branches = client.branches(repo).select { |branch| branch.dig(:protection, :enabled) }
|
||||
protected_branches.each do |protected_branch|
|
||||
object = client.branch_protection(repo, protected_branch.name)
|
||||
object = client.branch_protection(repo, protected_branch[:name])
|
||||
next if object.nil? || already_imported?(object)
|
||||
|
||||
yield object
|
||||
|
@ -44,7 +44,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def id_for_already_imported_cache(protected_branch)
|
||||
protected_branch.name
|
||||
protected_branch[:name]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,6 +48,8 @@ module Gitlab
|
|||
def each_object_to_import(&block)
|
||||
each_review_page do |page, merge_request|
|
||||
page.objects.each do |review|
|
||||
review = review.to_h
|
||||
|
||||
next if already_imported?(review)
|
||||
|
||||
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
|
||||
|
|
|
@ -125,6 +125,8 @@ module Gitlab
|
|||
next unless page_counter.set(page.number)
|
||||
|
||||
page.objects.each do |object|
|
||||
object = object.to_h
|
||||
|
||||
next if already_imported?(object)
|
||||
|
||||
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
|
||||
|
|
|
@ -19,7 +19,7 @@ module Gitlab
|
|||
|
||||
# Builds a diff note from a GitHub API response.
|
||||
#
|
||||
# note - An instance of `Sawyer::Resource` containing the note details.
|
||||
# note - An instance of `Hash` containing the note details.
|
||||
def self.from_api_response(note, additional_data = {})
|
||||
matches = note[:html_url].match(NOTEABLE_ID_REGEX)
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ module Gitlab
|
|||
|
||||
# Builds an issue from a GitHub API response.
|
||||
#
|
||||
# issue - An instance of `Sawyer::Resource` containing the issue
|
||||
# issue - An instance of `Hash` containing the issue
|
||||
# details.
|
||||
def self.from_api_response(issue, additional_data = {})
|
||||
user =
|
||||
|
|
|
@ -34,7 +34,7 @@ module Gitlab
|
|||
class << self
|
||||
# Builds an event from a GitHub API response.
|
||||
#
|
||||
# event - An instance of `Sawyer::Resource` containing the event details.
|
||||
# event - An instance of `Hash` containing the event details.
|
||||
def from_api_response(event, additional_data = {})
|
||||
new(
|
||||
id: event[:id],
|
||||
|
|
|
@ -16,7 +16,7 @@ module Gitlab
|
|||
|
||||
# Builds a note from a GitHub API response.
|
||||
#
|
||||
# note - An instance of `Sawyer::Resource` containing the note details.
|
||||
# note - An instance of `Hash` containing the note details.
|
||||
def self.from_api_response(note, additional_data = {})
|
||||
matches = note[:html_url].match(NOTEABLE_TYPE_REGEX)
|
||||
|
||||
|
|
|
@ -16,12 +16,12 @@ module Gitlab
|
|||
# https://docs.github.com/en/rest/branches/branch-protection#get-branch-protection
|
||||
# branch_protection - An instance of `Sawyer::Resource` containing the protection details.
|
||||
def self.from_api_response(branch_protection, _additional_object_data = {})
|
||||
branch_name = branch_protection.url.match(%r{/branches/(\S{1,255})/protection$})[1]
|
||||
branch_name = branch_protection[:url].match(%r{/branches/(\S{1,255})/protection$})[1]
|
||||
|
||||
hash = {
|
||||
id: branch_name,
|
||||
allow_force_pushes: branch_protection.allow_force_pushes.enabled,
|
||||
required_conversation_resolution: branch_protection.required_conversation_resolution.enabled
|
||||
allow_force_pushes: branch_protection.dig(:allow_force_pushes, :enabled),
|
||||
required_conversation_resolution: branch_protection.dig(:required_conversation_resolution, :enabled)
|
||||
}
|
||||
|
||||
new(hash)
|
||||
|
|
|
@ -17,7 +17,7 @@ module Gitlab
|
|||
|
||||
# Builds a PR from a GitHub API response.
|
||||
#
|
||||
# issue - An instance of `Sawyer::Resource` containing the PR details.
|
||||
# issue - An instance of `Hash` containing the PR details.
|
||||
def self.from_api_response(pr, additional_data = {})
|
||||
assignee = Representation::User.from_api_response(pr[:assignee]) if pr[:assignee]
|
||||
user = Representation::User.from_api_response(pr[:user]) if pr[:user]
|
||||
|
|
|
@ -13,7 +13,7 @@ module Gitlab
|
|||
|
||||
# Builds a PullRequestReview from a GitHub API response.
|
||||
#
|
||||
# review - An instance of `Sawyer::Resource` containing the note details.
|
||||
# review - An instance of `Hash` containing the note details.
|
||||
def self.from_api_response(review, additional_data = {})
|
||||
user = Representation::User.from_api_response(review[:user]) if review[:user]
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ module Gitlab
|
|||
|
||||
# Builds a user from a GitHub API response.
|
||||
#
|
||||
# user - An instance of `Sawyer::Resource` containing the user details.
|
||||
# user - An instance of `Hash` containing the user details.
|
||||
def self.from_api_response(user, additional_data = {})
|
||||
new(
|
||||
id: user[:id],
|
||||
|
|
|
@ -39,7 +39,7 @@ module Gitlab
|
|||
#
|
||||
# If the object has no author ID we'll use the ID of the GitLab ghost
|
||||
# user.
|
||||
# object - An instance of `Sawyer::Resource` or a `Github::Representer`
|
||||
# object - An instance of `Hash` or a `Github::Representer`
|
||||
def author_id_for(object, author_key: :author)
|
||||
user_info = case author_key
|
||||
when :actor
|
||||
|
@ -70,7 +70,7 @@ module Gitlab
|
|||
|
||||
# Returns the GitLab user ID for a GitHub user.
|
||||
#
|
||||
# user - An instance of `Gitlab::GithubImport::Representation::User` or `Sawyer::Resource`.
|
||||
# user - An instance of `Gitlab::GithubImport::Representation::User` or `Hash`.
|
||||
def user_id_for(user)
|
||||
find(user[:id], user[:login]) if user.present?
|
||||
end
|
||||
|
|
|
@ -13130,6 +13130,9 @@ msgstr ""
|
|||
msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
|
||||
msgstr ""
|
||||
|
||||
msgid "DeployTokens|Allows read and write access to registry images."
|
||||
msgstr ""
|
||||
|
||||
msgid "DeployTokens|Allows read and write access to the package registry."
|
||||
msgstr ""
|
||||
|
||||
|
@ -13175,6 +13178,9 @@ msgstr ""
|
|||
msgid "DeployTokens|Enter an expiration date for your token. Defaults to never expire."
|
||||
msgstr ""
|
||||
|
||||
msgid "DeployTokens|Expiration date (optional)"
|
||||
msgstr ""
|
||||
|
||||
msgid "DeployTokens|Expires"
|
||||
msgstr ""
|
||||
|
||||
|
@ -13196,6 +13202,9 @@ msgstr ""
|
|||
msgid "DeployTokens|Scopes"
|
||||
msgstr ""
|
||||
|
||||
msgid "DeployTokens|Scopes (select at least one)"
|
||||
msgstr ""
|
||||
|
||||
msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
|
||||
msgstr ""
|
||||
|
||||
|
@ -13211,6 +13220,12 @@ msgstr ""
|
|||
msgid "DeployTokens|Username"
|
||||
msgstr ""
|
||||
|
||||
msgid "DeployTokens|Username (optional)"
|
||||
msgstr ""
|
||||
|
||||
msgid "DeployTokens|Your New Deploy Token"
|
||||
msgstr ""
|
||||
|
||||
msgid "DeployTokens|Your new Deploy Token username"
|
||||
msgstr ""
|
||||
|
||||
|
@ -41346,6 +41361,9 @@ msgstr ""
|
|||
msgid "This will remove the fork relationship between this project and other projects in the fork network."
|
||||
msgstr ""
|
||||
|
||||
msgid "Thread options"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thread to reply to cannot be found"
|
||||
msgstr ""
|
||||
|
||||
|
@ -41944,9 +41962,6 @@ msgstr ""
|
|||
msgid "Toggle commit list"
|
||||
msgstr ""
|
||||
|
||||
msgid "Toggle dropdown"
|
||||
msgstr ""
|
||||
|
||||
msgid "Toggle emoji award"
|
||||
msgstr ""
|
||||
|
||||
|
@ -42211,9 +42226,6 @@ msgstr ""
|
|||
msgid "Trials|Go back to GitLab"
|
||||
msgstr ""
|
||||
|
||||
msgid "Trials|Hey there"
|
||||
msgstr ""
|
||||
|
||||
msgid "Trials|Skip Trial"
|
||||
msgstr ""
|
||||
|
||||
|
@ -42229,6 +42241,11 @@ msgstr ""
|
|||
msgid "Trials|You won't get a free trial right now but you can always resume this process by selecting your avatar and choosing 'Start an Ultimate trial'"
|
||||
msgstr ""
|
||||
|
||||
msgid "Trials|You've got %{daysRemaining} day remaining on GitLab %{planName}!"
|
||||
msgid_plural "Trials|You've got %{daysRemaining} days remaining on GitLab %{planName}!"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Trials|Your trial ends on %{boldStart}%{trialEndDate}%{boldEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -2,14 +2,17 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Group Repository settings' do
|
||||
RSpec.describe 'Group Repository settings', :js do
|
||||
include WaitForRequests
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:group) { create(:group) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:group, reload: true) { create(:group) }
|
||||
|
||||
before_all do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
|
@ -20,9 +23,26 @@ RSpec.describe 'Group Repository settings' do
|
|||
stub_container_registry_config(enabled: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'a deploy token in settings' do
|
||||
let(:entity_type) { 'group' }
|
||||
let(:page_path) { group_settings_repository_path(group) }
|
||||
context 'when ajax deploy tokens is enabled' do
|
||||
before do
|
||||
stub_feature_flags(ajax_new_deploy_token: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'a deploy token in settings' do
|
||||
let(:entity_type) { 'group' }
|
||||
let(:page_path) { group_settings_repository_path(group) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ajax deploy tokens is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ajax_new_deploy_token: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'a deploy token in settings' do
|
||||
let(:entity_type) { 'group' }
|
||||
let(:page_path) { group_settings_repository_path(group) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -24,14 +24,14 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
|
||||
context 'close/reopen/report toggle' do
|
||||
it 'opens a dropdown when toggle is clicked' do
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
|
||||
expect(container).to have_link("Close merge request")
|
||||
expect(container).to have_link('Report abuse')
|
||||
end
|
||||
|
||||
it 'links to Report Abuse' do
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
click_link 'Report abuse'
|
||||
|
||||
expect(page).to have_content('Report abuse to admin')
|
||||
|
@ -42,7 +42,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
let(:issuable) { create(:merge_request, :opened, source_project: project) }
|
||||
|
||||
it 'shows the `Edit` and `Mark as draft` buttons' do
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
|
||||
expect(container).to have_link('Edit')
|
||||
expect(container).to have_link('Mark as draft')
|
||||
|
@ -56,7 +56,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
let(:issuable) { create(:merge_request, :closed, source_project: project) }
|
||||
|
||||
it 'shows both the `Edit` and `Reopen` button' do
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
|
||||
expect(container).to have_link('Edit')
|
||||
expect(container).to have_link('Report abuse')
|
||||
|
@ -68,7 +68,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
|
|||
let(:issuable) { create(:merge_request, :closed, source_project: project, author: user) }
|
||||
|
||||
it 'shows both the `Edit` and `Reopen` button' do
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
|
||||
expect(container).to have_link('Edit')
|
||||
expect(container).to have_link('Reopen merge request')
|
||||
|
|
|
@ -90,7 +90,7 @@ RSpec.describe 'Merge Request Discussion Lock', :js do
|
|||
end
|
||||
|
||||
it 'the user can lock the merge_request' do
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
|
||||
expect(page).to have_content('Lock merge request')
|
||||
end
|
||||
|
@ -103,7 +103,7 @@ RSpec.describe 'Merge Request Discussion Lock', :js do
|
|||
end
|
||||
|
||||
it 'the user can unlock the merge_request' do
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
|
||||
expect(page).to have_content('Unlock merge request')
|
||||
end
|
||||
|
|
|
@ -43,7 +43,7 @@ RSpec.describe 'User manages subscription', :js do
|
|||
it 'toggles subscription' do
|
||||
wait_for_requests
|
||||
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
|
||||
expect(page).to have_selector('.gl-toggle:not(.is-checked)')
|
||||
find('[data-testid="notifications-toggle"] .gl-toggle').click
|
||||
|
|
|
@ -16,12 +16,12 @@ RSpec.describe 'Merge request > User marks merge request as draft', :js do
|
|||
end
|
||||
|
||||
it 'toggles draft status' do
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
click_link 'Mark as draft'
|
||||
|
||||
expect(page).to have_content("Draft: #{merge_request.title}")
|
||||
|
||||
click_button 'Toggle dropdown'
|
||||
click_button 'Merge request actions'
|
||||
|
||||
page.within('.detail-page-header-actions') do
|
||||
click_link 'Mark as ready'
|
||||
|
|
|
@ -25,7 +25,7 @@ RSpec.describe 'Projects > Settings > Repository settings' do
|
|||
context 'for maintainer' do
|
||||
let(:role) { :maintainer }
|
||||
|
||||
context 'Deploy tokens' do
|
||||
context 'Deploy tokens', :js do
|
||||
let!(:deploy_token) { create(:deploy_token, projects: [project]) }
|
||||
|
||||
before do
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import { GlButton, GlFormCheckbox, GlFormInput, GlFormInputGroup, GlDatepicker } from '@gitlab/ui';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { TEST_HOST } from 'helpers/test_constants';
|
||||
import NewDeployToken from '~/deploy_tokens/components/new_deploy_token.vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
|
||||
const createNewTokenPath = `${TEST_HOST}/create`;
|
||||
const deployTokensHelpUrl = `${TEST_HOST}/help`;
|
||||
describe('New Deploy Token', () => {
|
||||
let wrapper;
|
||||
|
||||
const factory = (options = {}) => {
|
||||
const defaults = {
|
||||
containerRegistryEnabled: true,
|
||||
packagesRegistryEnabled: true,
|
||||
tokenType: 'project',
|
||||
};
|
||||
const { containerRegistryEnabled, packagesRegistryEnabled, tokenType } = {
|
||||
...defaults,
|
||||
...options,
|
||||
};
|
||||
return shallowMount(NewDeployToken, {
|
||||
propsData: {
|
||||
deployTokensHelpUrl,
|
||||
containerRegistryEnabled,
|
||||
packagesRegistryEnabled,
|
||||
createNewTokenPath,
|
||||
tokenType,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('without a container registry', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = factory({ containerRegistryEnabled: false });
|
||||
});
|
||||
|
||||
it('should not show the read registry scope', () => {
|
||||
wrapper
|
||||
.findAllComponents(GlFormCheckbox)
|
||||
.wrappers.forEach((checkbox) => expect(checkbox.text()).not.toBe('read_registry'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('with a container registry', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = factory();
|
||||
});
|
||||
|
||||
it('should show the read registry scope', () => {
|
||||
const checkbox = wrapper.findAllComponents(GlFormCheckbox).at(1);
|
||||
expect(checkbox.text()).toBe('read_registry');
|
||||
});
|
||||
|
||||
it('should make a request to create a token on submit', () => {
|
||||
const mockAxios = new MockAdapter(axios);
|
||||
|
||||
const date = new Date();
|
||||
const formInputs = wrapper.findAllComponents(GlFormInput);
|
||||
const name = formInputs.at(0);
|
||||
const username = formInputs.at(2);
|
||||
name.vm.$emit('input', 'test name');
|
||||
username.vm.$emit('input', 'test username');
|
||||
|
||||
const datepicker = wrapper.findAllComponents(GlDatepicker).at(0);
|
||||
datepicker.vm.$emit('input', date);
|
||||
|
||||
const [readRepo, readRegistry] = wrapper.findAllComponents(GlFormCheckbox).wrappers;
|
||||
readRepo.vm.$emit('input', true);
|
||||
readRegistry.vm.$emit('input', true);
|
||||
|
||||
mockAxios
|
||||
.onPost(createNewTokenPath, {
|
||||
deploy_token: {
|
||||
name: 'test name',
|
||||
expires_at: date.toISOString(),
|
||||
username: 'test username',
|
||||
read_repository: true,
|
||||
read_registry: true,
|
||||
},
|
||||
})
|
||||
.replyOnce(200, { username: 'test token username', token: 'test token' });
|
||||
|
||||
wrapper.findAllComponents(GlButton).at(0).vm.$emit('click');
|
||||
|
||||
return waitForPromises()
|
||||
.then(() => nextTick())
|
||||
.then(() => {
|
||||
const [tokenUsername, tokenValue] = wrapper.findAllComponents(GlFormInputGroup).wrappers;
|
||||
|
||||
expect(tokenUsername.props('value')).toBe('test token username');
|
||||
expect(tokenValue.props('value')).toBe('test token');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -19,6 +19,7 @@ import {
|
|||
expirationPolicyPayload,
|
||||
emptyExpirationPolicyPayload,
|
||||
containerExpirationPolicyData,
|
||||
nullExpirationPolicyPayload,
|
||||
} from '../mock_data';
|
||||
|
||||
describe('Cleanup image tags project settings', () => {
|
||||
|
@ -98,15 +99,30 @@ describe('Cleanup image tags project settings', () => {
|
|||
expect(findDescription().text()).toMatchInterpolatedText(CONTAINER_CLEANUP_POLICY_DESCRIPTION);
|
||||
});
|
||||
|
||||
it('when loading does not render form or alert components', () => {
|
||||
mountComponentWithApollo({
|
||||
resolver: jest.fn().mockResolvedValue(),
|
||||
});
|
||||
|
||||
expect(findFormComponent().exists()).toBe(false);
|
||||
expect(findAlert().exists()).toBe(false);
|
||||
});
|
||||
|
||||
describe('the form is disabled', () => {
|
||||
it('hides the form', () => {
|
||||
mountComponent();
|
||||
it('hides the form', async () => {
|
||||
mountComponentWithApollo({
|
||||
resolver: jest.fn().mockResolvedValue(nullExpirationPolicyPayload()),
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
expect(findFormComponent().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('shows an alert', () => {
|
||||
mountComponent();
|
||||
it('shows an alert', async () => {
|
||||
mountComponentWithApollo({
|
||||
resolver: jest.fn().mockResolvedValue(nullExpirationPolicyPayload()),
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
const text = findAlert().text();
|
||||
expect(text).toContain(UNAVAILABLE_FEATURE_INTRO_TEXT);
|
||||
|
@ -114,8 +130,12 @@ describe('Cleanup image tags project settings', () => {
|
|||
});
|
||||
|
||||
describe('an admin is visiting the page', () => {
|
||||
it('shows the admin part of the alert message', () => {
|
||||
mountComponent({ ...defaultProvidedValues, isAdmin: true });
|
||||
it('shows the admin part of the alert message', async () => {
|
||||
mountComponentWithApollo({
|
||||
provide: { ...defaultProvidedValues, isAdmin: true },
|
||||
resolver: jest.fn().mockResolvedValue(nullExpirationPolicyPayload()),
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
const sprintf = findAlert().findComponent(GlSprintf);
|
||||
expect(sprintf.text()).toBe('administration settings');
|
||||
|
|
|
@ -16,7 +16,11 @@ import {
|
|||
import expirationPolicyQuery from '~/packages_and_registries/settings/project/graphql/queries/get_expiration_policy.query.graphql';
|
||||
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
|
||||
|
||||
import { expirationPolicyPayload, emptyExpirationPolicyPayload } from '../mock_data';
|
||||
import {
|
||||
expirationPolicyPayload,
|
||||
emptyExpirationPolicyPayload,
|
||||
nullExpirationPolicyPayload,
|
||||
} from '../mock_data';
|
||||
|
||||
describe('Container expiration policy project settings', () => {
|
||||
let wrapper;
|
||||
|
@ -78,15 +82,30 @@ describe('Container expiration policy project settings', () => {
|
|||
expect(findButton().attributes('href')).toBe(defaultProvidedValues.cleanupSettingsPath);
|
||||
});
|
||||
|
||||
it('when loading does not render form or alert components', () => {
|
||||
mountComponentWithApollo({
|
||||
resolver: jest.fn().mockResolvedValue(),
|
||||
});
|
||||
|
||||
expect(findFormComponent().exists()).toBe(false);
|
||||
expect(findAlert().exists()).toBe(false);
|
||||
});
|
||||
|
||||
describe('the form is disabled', () => {
|
||||
it('the form is hidden', () => {
|
||||
mountComponent();
|
||||
it('hides the form', async () => {
|
||||
mountComponentWithApollo({
|
||||
resolver: jest.fn().mockResolvedValue(nullExpirationPolicyPayload()),
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
expect(findFormComponent().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('shows an alert', () => {
|
||||
mountComponent();
|
||||
it('shows an alert', async () => {
|
||||
mountComponentWithApollo({
|
||||
resolver: jest.fn().mockResolvedValue(nullExpirationPolicyPayload()),
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
const text = findAlert().text();
|
||||
expect(text).toContain(UNAVAILABLE_FEATURE_INTRO_TEXT);
|
||||
|
@ -94,8 +113,12 @@ describe('Container expiration policy project settings', () => {
|
|||
});
|
||||
|
||||
describe('an admin is visiting the page', () => {
|
||||
it('shows the admin part of the alert message', () => {
|
||||
mountComponent({ ...defaultProvidedValues, isAdmin: true });
|
||||
it('shows the admin part of the alert message', async () => {
|
||||
mountComponentWithApollo({
|
||||
provide: { ...defaultProvidedValues, isAdmin: true },
|
||||
resolver: jest.fn().mockResolvedValue(nullExpirationPolicyPayload()),
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
const sprintf = findAlert().findComponent(GlSprintf);
|
||||
expect(sprintf.text()).toBe('administration settings');
|
||||
|
|
|
@ -29,6 +29,15 @@ export const emptyExpirationPolicyPayload = () => ({
|
|||
},
|
||||
});
|
||||
|
||||
export const nullExpirationPolicyPayload = () => ({
|
||||
data: {
|
||||
project: {
|
||||
id: '1',
|
||||
containerExpirationPolicy: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const expirationPolicyMutationPayload = ({ override, errors = [] } = {}) => ({
|
||||
data: {
|
||||
updateContainerExpirationPolicy: {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
require 'fast_spec_helper'
|
||||
require 'spec_helper'
|
||||
require 'sawyer'
|
||||
|
||||
require_relative '../../config/initializers/sawyer_patch'
|
||||
|
@ -64,6 +64,28 @@ RSpec.describe 'sawyer_patch' do
|
|||
expect(sawyer_resource.count_total).to eq(1)
|
||||
expect(sawyer_resource.count_total?).to eq(true)
|
||||
expect(sawyer_resource.count_total + 1).to eq(2)
|
||||
sawyer_resource.count_total = 3
|
||||
expect(sawyer_resource.count_total).to eq(3)
|
||||
expect(sawyer_resource.user.name).to eq('User name')
|
||||
end
|
||||
|
||||
it 'logs when a sawyer resource dynamic method is called' do
|
||||
sawyer_resource = Sawyer::Resource.new(
|
||||
Sawyer::Agent.new(''),
|
||||
{
|
||||
count_total: 1,
|
||||
user: { name: 'User name' }
|
||||
}
|
||||
)
|
||||
expected_attributes = []
|
||||
allow(Gitlab::Import::Logger).to receive(:warn) do |params|
|
||||
expected_attributes.push(params[:attribute])
|
||||
end
|
||||
|
||||
sawyer_resource.count_total
|
||||
sawyer_resource.user
|
||||
sawyer_resource.user.name
|
||||
|
||||
expect(expected_attributes).to match_array(%i[count_total user user name])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Banzai::Filter::PathologicalMarkdownFilter do
|
||||
include FilterSpecHelper
|
||||
|
||||
let_it_be(:short_text) { '![a' * 5 }
|
||||
let_it_be(:long_text) { ([short_text] * 10).join(' ') }
|
||||
let_it_be(:with_images_text) { "![One ![one](one.jpg) #{'and\n' * 200} ![two ![two](two.jpg)" }
|
||||
|
||||
it 'detects a significat number of unclosed image links' do
|
||||
msg = <<~TEXT
|
||||
_Unable to render markdown - too many unclosed markdown image links detected._
|
||||
TEXT
|
||||
|
||||
expect(filter(long_text)).to eq(msg.strip)
|
||||
end
|
||||
|
||||
it 'does nothing when there are only a few unclosed image links' do
|
||||
expect(filter(short_text)).to eq(short_text)
|
||||
end
|
||||
|
||||
it 'does nothing when there are only a few unclosed image links and images' do
|
||||
expect(filter(with_images_text)).to eq(with_images_text)
|
||||
end
|
||||
end
|
|
@ -168,15 +168,13 @@ RSpec.describe Banzai::Pipeline::FullPipeline do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'unclosed image links' do
|
||||
it 'detects a significat number of unclosed image links' do
|
||||
markdown = '![a ' * 30
|
||||
msg = <<~TEXT
|
||||
Unable to render markdown - too many unclosed markdown image links detected.
|
||||
TEXT
|
||||
output = described_class.to_html(markdown, project: nil)
|
||||
describe 'cmark-gfm and autlolinks' do
|
||||
it 'does not hang with significant number of unclosed image links' do
|
||||
markdown = '![a ' * 300000
|
||||
|
||||
expect(output).to include(msg.strip)
|
||||
expect do
|
||||
Timeout.timeout(2.seconds) { described_class.to_html(markdown, project: nil) }
|
||||
end.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ RSpec.describe Gitlab::ConfigChecker::ExternalDatabaseChecker do
|
|||
let(:new_database) { instance_double(Gitlab::Database::Reflection) }
|
||||
|
||||
before do
|
||||
allow(Gitlab::Database::Reflection).to receive(:new).and_call_original
|
||||
allow(Gitlab::Database::Reflection).to receive(:new).and_return(new_database)
|
||||
allow(old_database).to receive(:postgresql_minimum_supported_version?).and_return(false)
|
||||
allow(old_database).to receive(:version).and_return(old_database_version)
|
||||
allow(new_database).to receive(:postgresql_minimum_supported_version?).and_return(true)
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GitalyClient::RefService do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
||||
let(:storage_name) { project.repository_storage }
|
||||
let(:relative_path) { project.disk_path + '.git' }
|
||||
let(:repository) { project.repository }
|
||||
|
@ -179,13 +180,22 @@ RSpec.describe Gitlab::GitalyClient::RefService do
|
|||
)
|
||||
)
|
||||
end
|
||||
|
||||
local_branches = target_commits.each_with_index.map do |gitaly_commit, i|
|
||||
Gitaly::Branch.new(name: "#{remote_name}/#{i}", target_commit: gitaly_commit)
|
||||
end
|
||||
response = [
|
||||
Gitaly::FindLocalBranchesResponse.new(branches: branches[0, 2], local_branches: local_branches[0, 2]),
|
||||
Gitaly::FindLocalBranchesResponse.new(branches: branches[2, 2], local_branches: local_branches[2, 2])
|
||||
]
|
||||
|
||||
response = if set_local_branches
|
||||
[
|
||||
Gitaly::FindLocalBranchesResponse.new(local_branches: local_branches[0, 2]),
|
||||
Gitaly::FindLocalBranchesResponse.new(local_branches: local_branches[2, 2])
|
||||
]
|
||||
else
|
||||
[
|
||||
Gitaly::FindLocalBranchesResponse.new(branches: branches[0, 2]),
|
||||
Gitaly::FindLocalBranchesResponse.new(branches: branches[2, 2])
|
||||
]
|
||||
end
|
||||
|
||||
expect_any_instance_of(Gitaly::RefService::Stub)
|
||||
.to receive(:find_local_branches)
|
||||
|
@ -220,18 +230,14 @@ RSpec.describe Gitlab::GitalyClient::RefService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when feature flag :gitaly_simplify_find_local_branches_response is enabled' do
|
||||
before do
|
||||
stub_feature_flags(gitaly_simplify_find_local_branches_response: true)
|
||||
end
|
||||
context 'when local_branches variable is not set' do
|
||||
let(:set_local_branches) { false }
|
||||
|
||||
it_behaves_like 'common examples'
|
||||
end
|
||||
|
||||
context 'when feature flag :gitaly_simplify_find_local_branches_response is disabled' do
|
||||
before do
|
||||
stub_feature_flags(gitaly_simplify_find_local_branches_response: false)
|
||||
end
|
||||
context 'when local_branches variable is set' do
|
||||
let(:set_local_branches) { true }
|
||||
|
||||
it_behaves_like 'common examples'
|
||||
end
|
||||
|
|
|
@ -152,6 +152,22 @@ RSpec.describe Gitlab::GithubImport::Client do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#each_object' do
|
||||
it 'converts each object into a hash' do
|
||||
client = described_class.new('foo')
|
||||
|
||||
stub_request(:get, 'https://api.github.com/rate_limit')
|
||||
.to_return(status: 200, headers: { 'X-RateLimit-Limit' => 5000, 'X-RateLimit-Remaining' => 5000 })
|
||||
|
||||
stub_request(:get, 'https://api.github.com/repos/foo/bar/releases?per_page=100')
|
||||
.to_return(status: 200, body: [{ id: 1 }].to_json, headers: { 'Content-Type' => 'application/json' })
|
||||
|
||||
client.each_object(:releases, 'foo/bar') do |release|
|
||||
expect(release).to eq({ id: 1 })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#each_page' do
|
||||
let(:client) { described_class.new('foo') }
|
||||
let(:object1) { double(:object1) }
|
||||
|
|
|
@ -309,7 +309,7 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling do
|
|||
|
||||
describe '#each_object_to_import' do
|
||||
let(:importer) { importer_class.new(project, client) }
|
||||
let(:object) { double(:object) }
|
||||
let(:object) { {} }
|
||||
|
||||
before do
|
||||
expect(importer)
|
||||
|
|
|
@ -14,32 +14,32 @@ RSpec.shared_examples 'a deploy token in settings' do
|
|||
end
|
||||
end
|
||||
|
||||
it 'add a new deploy token' do
|
||||
it 'add a new deploy token', :js do
|
||||
visit page_path
|
||||
|
||||
fill_in 'deploy_token_name', with: 'new_deploy_key'
|
||||
fill_in 'deploy_token_expires_at', with: (Date.today + 1.month).to_s
|
||||
fill_in 'deploy_token_username', with: 'deployer'
|
||||
check 'deploy_token_read_repository'
|
||||
check 'deploy_token_read_registry'
|
||||
fill_in _('Name'), with: 'new_deploy_key'
|
||||
fill_in _('Expiration date (optional)'), with: (Date.today + 1.month).to_s
|
||||
fill_in _('Username (optional)'), with: 'deployer'
|
||||
check 'read_repository'
|
||||
check 'read_registry'
|
||||
click_button 'Create deploy token'
|
||||
|
||||
expect(page).to have_content("Your new #{entity_type} deploy token has been created")
|
||||
|
||||
within('.created-deploy-token-container') do
|
||||
expect(page).to have_selector("input[name='deploy-token-user'][value='deployer']")
|
||||
expect(page).to have_selector("input[name='deploy-token'][readonly='readonly']")
|
||||
expect(find("input[name='deploy-token-user']").value).to eq("deployer")
|
||||
expect(find("input[name='deploy-token'][readonly='readonly']")).to be_visible
|
||||
end
|
||||
|
||||
expect(find("input#deploy_token_name").value).to eq nil
|
||||
expect(find("input#deploy_token_name").value).to be_empty
|
||||
expect(find("input#deploy_token_read_repository").checked?).to eq false
|
||||
end
|
||||
|
||||
context "with form errors" do
|
||||
context "with form errors", :js do
|
||||
before do
|
||||
visit page_path
|
||||
fill_in "deploy_token_name", with: "new_deploy_key"
|
||||
fill_in "deploy_token_username", with: "deployer"
|
||||
fill_in _('Name'), with: "new_deploy_key"
|
||||
fill_in _('Username (optional)'), with: "deployer"
|
||||
click_button "Create deploy token"
|
||||
end
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ require (
|
|||
github.com/BurntSushi/toml v1.2.0
|
||||
github.com/FZambia/sentinel v1.1.1
|
||||
github.com/alecthomas/chroma/v2 v2.3.0
|
||||
github.com/aws/aws-sdk-go v1.43.31
|
||||
github.com/aws/aws-sdk-go v1.44.107
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/getsentry/raven-go v0.2.0
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2
|
||||
|
|
|
@ -178,8 +178,9 @@ github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevB
|
|||
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
||||
github.com/aws/aws-sdk-go v1.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.43.31 h1:yJZIr8nMV1hXjAvvOLUFqZRJcHV7udPQBfhJqawDzI0=
|
||||
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go v1.44.107 h1:VP7Rq3wzsOV7wrfHqjAAKRksD4We58PaoVSDPKhm8nw=
|
||||
github.com/aws/aws-sdk-go v1.44.107/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.2 h1:fqlCk6Iy3bnCumtrLz9r3mJ/2gUT0pJ0wLFVIdWh+JA=
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1 h1:SdK4Ppk5IzLs64ZMvr6MrSficMtjY2oS0WOORXTlxwU=
|
||||
|
|
Loading…
Reference in New Issue