Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b21276806d
commit
1bf106b172
28 changed files with 631 additions and 154 deletions
|
@ -0,0 +1,201 @@
|
|||
<script>
|
||||
import { GlFormGroup, GlButton, GlFormInput, GlForm, GlAlert } from '@gitlab/ui';
|
||||
import {
|
||||
CREATE_BRANCH_ERROR_GENERIC,
|
||||
CREATE_BRANCH_ERROR_WITH_CONTEXT,
|
||||
CREATE_BRANCH_SUCCESS_ALERT,
|
||||
I18N_NEW_BRANCH_PAGE_TITLE,
|
||||
I18N_NEW_BRANCH_LABEL_DROPDOWN,
|
||||
I18N_NEW_BRANCH_LABEL_BRANCH,
|
||||
I18N_NEW_BRANCH_LABEL_SOURCE,
|
||||
I18N_NEW_BRANCH_SUBMIT_BUTTON_TEXT,
|
||||
} from '../constants';
|
||||
import createBranchMutation from '../graphql/mutations/create_branch.mutation.graphql';
|
||||
import ProjectDropdown from './project_dropdown.vue';
|
||||
import SourceBranchDropdown from './source_branch_dropdown.vue';
|
||||
|
||||
const DEFAULT_ALERT_VARIANT = 'danger';
|
||||
const DEFAULT_ALERT_PARAMS = {
|
||||
title: '',
|
||||
message: '',
|
||||
variant: DEFAULT_ALERT_VARIANT,
|
||||
primaryButtonLink: '',
|
||||
primaryButtonText: '',
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'JiraConnectNewBranch',
|
||||
components: {
|
||||
GlFormGroup,
|
||||
GlButton,
|
||||
GlFormInput,
|
||||
GlForm,
|
||||
GlAlert,
|
||||
ProjectDropdown,
|
||||
SourceBranchDropdown,
|
||||
},
|
||||
props: {
|
||||
initialBranchName: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedProject: null,
|
||||
selectedSourceBranchName: null,
|
||||
branchName: this.initialBranchName,
|
||||
createBranchLoading: false,
|
||||
alertParams: {
|
||||
...DEFAULT_ALERT_PARAMS,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
selectedProjectId() {
|
||||
return this.selectedProject?.id;
|
||||
},
|
||||
showAlert() {
|
||||
return Boolean(this.alertParams?.message);
|
||||
},
|
||||
disableSubmitButton() {
|
||||
return !(this.selectedProject && this.selectedSourceBranchName && this.branchName);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
displayAlert({ title, message, variant = DEFAULT_ALERT_VARIANT } = {}) {
|
||||
this.alertParams = {
|
||||
title,
|
||||
message,
|
||||
variant,
|
||||
};
|
||||
},
|
||||
onAlertDismiss() {
|
||||
this.alertParams = {
|
||||
...DEFAULT_ALERT_PARAMS,
|
||||
};
|
||||
},
|
||||
onProjectSelect(project) {
|
||||
this.selectedProject = project;
|
||||
this.selectedSourceBranchName = null; // reset branch selection
|
||||
},
|
||||
onSourceBranchSelect(branchName) {
|
||||
this.selectedSourceBranchName = branchName;
|
||||
},
|
||||
onError({ title, message } = {}) {
|
||||
this.displayAlert({
|
||||
message,
|
||||
title,
|
||||
});
|
||||
},
|
||||
onSubmit() {
|
||||
this.createBranch();
|
||||
},
|
||||
async createBranch() {
|
||||
this.createBranchLoading = true;
|
||||
|
||||
try {
|
||||
const { data } = await this.$apollo.mutate({
|
||||
mutation: createBranchMutation,
|
||||
variables: {
|
||||
name: this.branchName,
|
||||
ref: this.selectedSourceBranchName,
|
||||
projectPath: this.selectedProject.fullPath,
|
||||
},
|
||||
});
|
||||
const { errors } = data.createBranch;
|
||||
if (errors.length > 0) {
|
||||
this.onError({
|
||||
title: CREATE_BRANCH_ERROR_WITH_CONTEXT,
|
||||
message: errors[0],
|
||||
});
|
||||
} else {
|
||||
this.displayAlert({
|
||||
...CREATE_BRANCH_SUCCESS_ALERT,
|
||||
variant: 'success',
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
this.onError({
|
||||
message: CREATE_BRANCH_ERROR_GENERIC,
|
||||
});
|
||||
}
|
||||
|
||||
this.createBranchLoading = false;
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
I18N_NEW_BRANCH_PAGE_TITLE,
|
||||
I18N_NEW_BRANCH_LABEL_DROPDOWN,
|
||||
I18N_NEW_BRANCH_LABEL_BRANCH,
|
||||
I18N_NEW_BRANCH_LABEL_SOURCE,
|
||||
I18N_NEW_BRANCH_SUBMIT_BUTTON_TEXT,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="gl-border-1 gl-border-b-solid gl-border-gray-100 gl-mb-5 gl-mt-7">
|
||||
<h1 class="page-title">
|
||||
{{ $options.i18n.I18N_NEW_BRANCH_PAGE_TITLE }}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<gl-alert
|
||||
v-if="showAlert"
|
||||
class="gl-mb-5"
|
||||
:variant="alertParams.variant"
|
||||
:title="alertParams.title"
|
||||
@dismiss="onAlertDismiss"
|
||||
>
|
||||
{{ alertParams.message }}
|
||||
</gl-alert>
|
||||
|
||||
<gl-form @submit.prevent="onSubmit">
|
||||
<gl-form-group
|
||||
:label="$options.i18n.I18N_NEW_BRANCH_LABEL_DROPDOWN"
|
||||
label-for="project-select"
|
||||
>
|
||||
<project-dropdown
|
||||
id="project-select"
|
||||
:selected-project="selectedProject"
|
||||
@change="onProjectSelect"
|
||||
@error="onError"
|
||||
/>
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-group
|
||||
:label="$options.i18n.I18N_NEW_BRANCH_LABEL_BRANCH"
|
||||
label-for="branch-name-input"
|
||||
>
|
||||
<gl-form-input id="branch-name-input" v-model="branchName" type="text" required />
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-group
|
||||
:label="$options.i18n.I18N_NEW_BRANCH_LABEL_SOURCE"
|
||||
label-for="source-branch-select"
|
||||
>
|
||||
<source-branch-dropdown
|
||||
id="source-branch-select"
|
||||
:selected-project="selectedProject"
|
||||
:selected-branch-name="selectedSourceBranchName"
|
||||
@change="onSourceBranchSelect"
|
||||
@error="onError"
|
||||
/>
|
||||
</gl-form-group>
|
||||
|
||||
<div class="form-actions">
|
||||
<gl-button
|
||||
:loading="createBranchLoading"
|
||||
type="submit"
|
||||
variant="confirm"
|
||||
:disabled="disableSubmitButton"
|
||||
>
|
||||
{{ $options.i18n.I18N_NEW_BRANCH_SUBMIT_BUTTON_TEXT }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</gl-form>
|
||||
</div>
|
||||
</template>
|
|
@ -60,7 +60,7 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
async onProjectSelect(project) {
|
||||
onProjectSelect(project) {
|
||||
this.$emit('change', project);
|
||||
},
|
||||
onError({ message } = {}) {
|
||||
|
|
|
@ -1,2 +1,20 @@
|
|||
import { __, s__ } from '~/locale';
|
||||
|
||||
export const BRANCHES_PER_PAGE = 20;
|
||||
export const PROJECTS_PER_PAGE = 20;
|
||||
|
||||
export const I18N_NEW_BRANCH_PAGE_TITLE = __('New branch');
|
||||
export const I18N_NEW_BRANCH_LABEL_DROPDOWN = __('Project');
|
||||
export const I18N_NEW_BRANCH_LABEL_BRANCH = __('Branch name');
|
||||
export const I18N_NEW_BRANCH_LABEL_SOURCE = __('Source branch');
|
||||
export const I18N_NEW_BRANCH_SUBMIT_BUTTON_TEXT = __('Create branch');
|
||||
|
||||
export const CREATE_BRANCH_ERROR_GENERIC = s__(
|
||||
'JiraConnect|Failed to create branch. Please try again.',
|
||||
);
|
||||
export const CREATE_BRANCH_ERROR_WITH_CONTEXT = s__('JiraConnect|Failed to create branch.');
|
||||
|
||||
export const CREATE_BRANCH_SUCCESS_ALERT = {
|
||||
title: s__('JiraConnect|New branch was successfully created.'),
|
||||
message: s__('JiraConnect|You can now close this window and return to Jira.'),
|
||||
};
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
mutation createBranch($name: String!, $projectPath: ID!, $ref: String!) {
|
||||
createBranch(input: { name: $name, projectPath: $projectPath, ref: $ref }) {
|
||||
clientMutationId
|
||||
errors
|
||||
}
|
||||
}
|
36
app/assets/javascripts/jira_connect/branches/index.js
Normal file
36
app/assets/javascripts/jira_connect/branches/index.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import JiraConnectNewBranchForm from '~/jira_connect/branches/components/new_branch_form.vue';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
export default async function initJiraConnectBranches() {
|
||||
const el = document.querySelector('.js-jira-connect-create-branch');
|
||||
if (!el) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { initialBranchName } = el.dataset;
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(
|
||||
{},
|
||||
{
|
||||
assumeImmutableResults: true,
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
apolloProvider,
|
||||
render(createElement) {
|
||||
return createElement(JiraConnectNewBranchForm, {
|
||||
props: {
|
||||
initialBranchName,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
|
@ -132,7 +132,7 @@ export const logLinesParserLegacy = (lines = [], accumulator = []) =>
|
|||
);
|
||||
|
||||
export const logLinesParser = (lines = [], previousTraceState = {}, prevParsedLines = []) => {
|
||||
let currentLine = previousTraceState?.prevLineCount ?? 0;
|
||||
let currentLineCount = previousTraceState?.prevLineCount ?? 0;
|
||||
let currentHeader = previousTraceState?.currentHeader;
|
||||
let isPreviousLineHeader = previousTraceState?.isPreviousLineHeader ?? false;
|
||||
const parsedLines = prevParsedLines.length > 0 ? prevParsedLines : [];
|
||||
|
@ -141,27 +141,27 @@ export const logLinesParser = (lines = [], previousTraceState = {}, prevParsedLi
|
|||
for (let i = 0; i < lines.length; i += 1) {
|
||||
const line = lines[i];
|
||||
// First run we can use the current index, later runs we have to retrieve the last number of lines
|
||||
currentLine = previousTraceState?.prevLineCount ? currentLine + 1 : i + 1;
|
||||
currentLineCount = previousTraceState?.prevLineCount ? currentLineCount + 1 : i + 1;
|
||||
|
||||
if (line.section_header && !isPreviousLineHeader) {
|
||||
// If there's no previous line header that means we're at the root of the log
|
||||
|
||||
isPreviousLineHeader = true;
|
||||
parsedLines.push(parseHeaderLine(line, currentLine));
|
||||
parsedLines.push(parseHeaderLine(line, currentLineCount));
|
||||
currentHeader = { index: parsedLines.length - 1 };
|
||||
} else if (line.section_header && isPreviousLineHeader) {
|
||||
// If there's a current section, we can't push to the parsedLines array
|
||||
sectionsQueue.push(currentHeader);
|
||||
currentHeader = parseHeaderLine(line, currentLine); // Let's parse the incoming header line
|
||||
currentHeader = parseHeaderLine(line, currentLineCount); // Let's parse the incoming header line
|
||||
} else if (line.section && !line.section_duration) {
|
||||
// We're inside a collapsible section and want to parse a standard line
|
||||
if (currentHeader?.index) {
|
||||
// If the current section header is only an index, add the line as part of the lines
|
||||
// array of the current collapsible section
|
||||
parsedLines[currentHeader.index].lines.push(parseLine(line, currentLine));
|
||||
parsedLines[currentHeader.index].lines.push(parseLine(line, currentLineCount));
|
||||
} else {
|
||||
// Otherwise add it to the innermost collapsible section lines array
|
||||
currentHeader.lines.push(parseLine(line, currentLine));
|
||||
currentHeader.lines.push(parseLine(line, currentLineCount));
|
||||
}
|
||||
} else if (line.section && line.section_duration) {
|
||||
// NOTE: This marks the end of a section_header
|
||||
|
@ -187,7 +187,7 @@ export const logLinesParser = (lines = [], previousTraceState = {}, prevParsedLi
|
|||
currentHeader = previousSection;
|
||||
}
|
||||
} else {
|
||||
parsedLines.push(parseLine(line, currentLine));
|
||||
parsedLines.push(parseLine(line, currentLineCount));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ export const logLinesParser = (lines = [], previousTraceState = {}, prevParsedLi
|
|||
isPreviousLineHeader,
|
||||
currentHeader,
|
||||
sectionsQueue,
|
||||
prevLineCount: lines.length,
|
||||
prevLineCount: currentLineCount,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -187,12 +187,7 @@ export default {
|
|||
/>
|
||||
</template>
|
||||
<template #footer>
|
||||
<gl-button
|
||||
variant="confirm"
|
||||
:disabled="isProjectPathEmpty"
|
||||
data-testid="add-project-button"
|
||||
@click="addProject"
|
||||
>
|
||||
<gl-button variant="confirm" :disabled="isProjectPathEmpty" @click="addProject">
|
||||
{{ $options.i18n.addProject }}
|
||||
</gl-button>
|
||||
<gl-button @click="clearTargetProjectPath">{{ $options.i18n.cancel }}</gl-button>
|
||||
|
|
|
@ -73,7 +73,6 @@ export default {
|
|||
variant="danger"
|
||||
icon="remove"
|
||||
:aria-label="__('Remove access')"
|
||||
data-testid="remove-project-button"
|
||||
@click="removeProject(item.fullPath)"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -41,7 +41,7 @@ module Registrations
|
|||
end
|
||||
|
||||
def update_params
|
||||
params.require(:user).permit(:role, :other_role, :setup_for_company, :email_opted_in)
|
||||
params.require(:user).permit(:role, :other_role, :setup_for_company)
|
||||
end
|
||||
|
||||
def requires_confirmation?(user)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- is_hidden = local_assigns.fetch(:hidden, Gitlab.dev_env_or_com?)
|
||||
- return unless Gitlab.dev_env_or_com?
|
||||
|
||||
.gl-mb-3.js-email-opt-in{ class: is_hidden ? 'hidden' : '' }
|
||||
.gl-mb-3.js-email-opt-in.hidden
|
||||
.gl-font-weight-bold.gl-mb-3
|
||||
= _('Email updates (optional)')
|
||||
= f.check_box :email_opted_in
|
||||
|
|
|
@ -5,31 +5,33 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: howto
|
||||
---
|
||||
|
||||
# Activate GitLab EE with a license **(PREMIUM SELF)**
|
||||
# Activating GitLab EE
|
||||
|
||||
To activate all GitLab Enterprise Edition (EE) functionality, you need to upload
|
||||
a license. It's only possible to activate GitLab Enterprise Edition, so first verify which edition
|
||||
you are running. To verify, sign in to GitLab and browse to `/help`. The GitLab edition and version
|
||||
are listed at the top of the **Help** page.
|
||||
To enable features of GitLab Enterprise Edition (EE), you need to activate your instance. Ensure you are running an enterprise edition. To verify, sign in to GitLab and browse to `/help`. The GitLab edition and version are listed at the top of the **Help** page.
|
||||
|
||||
If you are running GitLab Community Edition (CE), upgrade your installation to
|
||||
GitLab Enterprise Edition (EE). For more details, see [Upgrading between editions](../../update/index.md#upgrading-between-editions).
|
||||
If you have questions or need assistance upgrading from GitLab CE to EE please [contact GitLab Support](https://about.gitlab.com/support/#contact-support).
|
||||
|
||||
The license is a base64-encoded ASCII text file with a `.gitlab-license`
|
||||
extension. You can obtain the file by [purchasing a license](https://about.gitlab.com/pricing/)
|
||||
or by signing up for a [free trial](https://about.gitlab.com/free-trial/).
|
||||
|
||||
After you've received your license from GitLab Inc., you can upload it
|
||||
by **signing into your GitLab instance as an admin** or adding it at
|
||||
installation time.
|
||||
If you are running GitLab Community Edition (CE), upgrade your installation to GitLab Enterprise Edition (EE). For more details, see [Upgrading between editions](../../update/index.md#upgrading-between-editions). If you have questions or need assistance upgrading from GitLab CE to EE please [contact GitLab Support](https://about.gitlab.com/support/#contact-support).
|
||||
|
||||
As of GitLab Enterprise Edition 9.4.0, a newly-installed instance without an
|
||||
uploaded license only has the Free features active. A trial license
|
||||
activates all Ultimate features, but after
|
||||
[the trial expires](#what-happens-when-your-license-expires), some functionality
|
||||
uploaded license only has the Free features active. A trial license activates all Ultimate features, but after [the trial expires](#what-happens-when-your-license-expires), some functionality
|
||||
is locked.
|
||||
|
||||
## Activate GitLab EE with an Activation Code **(PREMIUM SELF)**
|
||||
|
||||
As of GitLab Enterprise Edition 14.0, you need an activation code to activate your instance. You can obtain an activation code by [purchasing a license](https://about.gitlab.com/pricing/) or by signing up for a [free trial](https://about.gitlab.com/free-trial/). This activation code is a 24-character alphanumeric string you receive in a confirmation email. You can also sign in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in) to copy the activation code to your clipboard.
|
||||
|
||||
To begin the activation process with your activation code:
|
||||
|
||||
1. Sign in to your GitLab self-managed instance.
|
||||
1. From the top menu, select the Admin Area **{admin}**.
|
||||
1. From the left sidebar, select **Subscriptions**.
|
||||
1. Paste the activation code onto the input field.
|
||||
1. Read and accept the terms of service.
|
||||
1. Select **Activate**.
|
||||
|
||||
## Activate GitLab EE with a License File **(PREMIUM SELF)**
|
||||
|
||||
If you receive a license file from GitLab (for example a new trial), you can upload it by signing into your GitLab instance as an admin or adding it during installation. The license is a base64-encoded ASCII text file with a `.gitlab-license` extension.
|
||||
|
||||
## Uploading your license
|
||||
|
||||
The first time you visit your GitLab EE installation signed in as an administrator,
|
||||
|
@ -150,3 +152,7 @@ without enough users is uploaded, GitLab displays a message prompting you to pur
|
|||
additional users. More information on how to determine the required number of users
|
||||
and how to add additional seats can be found in the
|
||||
[licensing FAQ](https://about.gitlab.com/pricing/licensing-faq/).
|
||||
|
||||
### There is a connectivity issue
|
||||
|
||||
In GitLab 14.0 and later, to activate your subscription, your GitLab instance must be connected to the internet. If you have questions or need assistance activating your instance please [contact GitLab Support](https://about.gitlab.com/support/#contact-support).
|
||||
|
|
|
@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
When we describe GitLab analytics, we use the following terms:
|
||||
|
||||
- **Cycle time:** The duration of only the execution work alone. Often displayed in combination with "lead time," which is longer. GitLab measures cycle time from issue first merge request creation to issue close. This approach underestimates lead time because merge request creation is always later than commit time. GitLab displays cycle time in [group-level Value Stream Analytics](../group/value_stream_analytics/index.md).
|
||||
- **Deploys:** The total number of successful deployments to production in the given time frame (across all applicable projects). GitLab displays deploys in [group-level Value Stream Analytics](../group/value_stream_analytics/index.md).
|
||||
- **Deploys:** The total number of successful deployments to production in the given time frame (across all applicable projects). GitLab displays deploys in [group-level Value Stream Analytics](../group/value_stream_analytics/index.md) and [project-level Value Stream Analytics](value_stream_analytics.md).
|
||||
- **DORA (DevOps Research and Assessment)** ["Four Keys"](https://cloud.google.com/blog/products/devops-sre/using-the-four-keys-to-measure-your-devops-performance):
|
||||
- **Speed/Velocity**
|
||||
|
||||
|
@ -21,7 +21,7 @@ When we describe GitLab analytics, we use the following terms:
|
|||
improvements and features faster. GitLab measures this as the number of deployments to a
|
||||
[production environment](../../ci/environments/index.md#deployment-tier-of-environments) in
|
||||
the given time period.
|
||||
GitLab displays deployment frequency in [group-level Value Stream Analytics](../group/value_stream_analytics/index.md).
|
||||
GitLab displays deployment frequency in [group-level Value Stream Analytics](../group/value_stream_analytics/index.md) and [project-level Value Stream Analytics](value_stream_analytics.md).
|
||||
- **Lead Time for Changes:** The time it takes for a commit to get into production. (1) GitLab
|
||||
measures this as the median duration between merge request merge and deployment to a
|
||||
[production environment](../../ci/environments/index.md#deployment-tier-of-environments) for
|
||||
|
|
|
@ -20,7 +20,12 @@ to uncover, triage, and identify the root cause of slowdowns in the software dev
|
|||
|
||||
For information on how to contribute to the development of Value Stream Analytics, see our [contributor documentation](../../../development/value_stream_analytics.md).
|
||||
|
||||
Group-level Value Stream Analytics is available via **Group > Analytics > Value Stream**.
|
||||
To view group-level Value Stream Analytics:
|
||||
|
||||
1. On the top bar, select **Menu > Groups** and find your group.
|
||||
1. On the left sidebar, select **Analytics > Value stream**.
|
||||
|
||||
Value Stream Analytics at the group level includes data for the selected group and its subgroups.
|
||||
|
||||
[Project-level Value Stream Analytics](../../analytics/value_stream_analytics.md) is also available.
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ a group's namespace, rather than a user's namespace. Composer packages
|
|||
git commit -m 'Composer package test'
|
||||
git tag v1.0.0
|
||||
git remote add origin git@gitlab.example.com:<namespace>/<project-name>.git
|
||||
git push --set-upstream origin master
|
||||
git push --set-upstream origin main
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ combining the two to save us some typing in the `script` section.
|
|||
Here's a more elaborate example that splits up the tasks into 4 pipeline stages,
|
||||
including two tests that run in parallel. The `build` is stored in the container
|
||||
registry and used by subsequent stages, downloading the image
|
||||
when needed. Changes to `master` also get tagged as `latest` and deployed using
|
||||
when needed. Changes to `main` also get tagged as `latest` and deployed using
|
||||
an application-specific deploy script:
|
||||
|
||||
```yaml
|
||||
|
@ -285,14 +285,14 @@ release-image:
|
|||
- docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
|
||||
- docker push $CONTAINER_RELEASE_IMAGE
|
||||
only:
|
||||
- master
|
||||
- main
|
||||
|
||||
deploy:
|
||||
stage: deploy
|
||||
script:
|
||||
- ./deploy.sh
|
||||
only:
|
||||
- master
|
||||
- main
|
||||
```
|
||||
|
||||
NOTE:
|
||||
|
@ -436,7 +436,7 @@ build_image:
|
|||
only:
|
||||
- branches
|
||||
except:
|
||||
- master
|
||||
- main
|
||||
|
||||
delete_image:
|
||||
image: docker:19.03.12
|
||||
|
@ -457,7 +457,7 @@ delete_image:
|
|||
only:
|
||||
- branches
|
||||
except:
|
||||
- master
|
||||
- main
|
||||
```
|
||||
|
||||
NOTE:
|
||||
|
@ -605,10 +605,10 @@ Here are examples of regex patterns you may want to use:
|
|||
v.+
|
||||
```
|
||||
|
||||
- Match only the tag named `master`:
|
||||
- Match only the tag named `main`:
|
||||
|
||||
```plaintext
|
||||
master
|
||||
main
|
||||
```
|
||||
|
||||
- Match tags that are either named or start with `release`:
|
||||
|
@ -617,10 +617,10 @@ Here are examples of regex patterns you may want to use:
|
|||
release.*
|
||||
```
|
||||
|
||||
- Match tags that either start with `v`, are named `master`, or begin with `release`:
|
||||
- Match tags that either start with `v`, are named `main`, or begin with `release`:
|
||||
|
||||
```plaintext
|
||||
(?:v.+|master|release.*)
|
||||
(?:v.+|main|release.*)
|
||||
```
|
||||
|
||||
### Set cleanup limits to conserve resources
|
||||
|
@ -675,11 +675,11 @@ You can set, update, and disable the cleanup policies using the GitLab API.
|
|||
|
||||
Examples:
|
||||
|
||||
- Select all tags, keep at least 1 tag per image, clean up any tag older than 14 days, run once a month, preserve any images with the name `master` and the policy is enabled:
|
||||
- Select all tags, keep at least 1 tag per image, clean up any tag older than 14 days, run once a month, preserve any images with the name `main` and the policy is enabled:
|
||||
|
||||
```shell
|
||||
curl --request PUT --header 'Content-Type: application/json;charset=UTF-8' --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--data-binary '{"container_expiration_policy_attributes":{"cadence":"1month","enabled":true,"keep_n":1,"older_than":"14d","name_regex":"","name_regex_delete":".*","name_regex_keep":".*-master"}}' \
|
||||
--data-binary '{"container_expiration_policy_attributes":{"cadence":"1month","enabled":true,"keep_n":1,"older_than":"14d","name_regex":"","name_regex_delete":".*","name_regex_keep":".*-main"}}' \
|
||||
"https://gitlab.example.com/api/v4/projects/2"
|
||||
```
|
||||
|
||||
|
|
|
@ -711,7 +711,7 @@ you can configure GitLab CI/CD to build new packages automatically.
|
|||
|
||||
### Create Maven packages with GitLab CI/CD by using Maven
|
||||
|
||||
You can create a new package each time the `master` branch is updated.
|
||||
You can create a new package each time the `main` branch is updated.
|
||||
|
||||
1. Create a `ci_settings.xml` file that serves as Maven's `settings.xml` file.
|
||||
|
||||
|
@ -768,7 +768,7 @@ You can create a new package each time the `master` branch is updated.
|
|||
script:
|
||||
- 'mvn deploy -s ci_settings.xml'
|
||||
only:
|
||||
- master
|
||||
- main
|
||||
```
|
||||
|
||||
1. Push those files to your repository.
|
||||
|
@ -781,7 +781,7 @@ user's home location. In this example:
|
|||
|
||||
### Create Maven packages with GitLab CI/CD by using Gradle
|
||||
|
||||
You can create a package each time the `master` branch
|
||||
You can create a package each time the `main` branch
|
||||
is updated.
|
||||
|
||||
1. Authenticate with [a CI job token in Gradle](#authenticate-with-a-ci-job-token-in-gradle).
|
||||
|
@ -794,7 +794,7 @@ is updated.
|
|||
script:
|
||||
- 'gradle publish'
|
||||
only:
|
||||
- master
|
||||
- main
|
||||
```
|
||||
|
||||
1. Commit files to your repository.
|
||||
|
|
|
@ -322,7 +322,7 @@ If you're using NuGet with GitLab CI/CD, a CI job token can be used instead of a
|
|||
personal access token or deploy token. The token inherits the permissions of the
|
||||
user that generates the pipeline.
|
||||
|
||||
This example shows how to create a new package each time the `master` branch is
|
||||
This example shows how to create a new package each time the `main` branch is
|
||||
updated:
|
||||
|
||||
1. Add a `deploy` job to your `.gitlab-ci.yml` file:
|
||||
|
@ -340,7 +340,7 @@ updated:
|
|||
- dotnet nuget add source "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/nuget/index.json" --name gitlab --username gitlab-ci-token --password $CI_JOB_TOKEN --store-password-in-clear-text
|
||||
- dotnet nuget push "bin/Release/*.nupkg" --source gitlab
|
||||
only:
|
||||
- master
|
||||
- main
|
||||
```
|
||||
|
||||
1. Commit the changes and push it to your GitLab repository to trigger a new CI/CD build.
|
||||
|
|
|
@ -37,7 +37,7 @@ the [Git commands you need](#update-the-default-branch-name-in-your-repository)
|
|||
|
||||
To update the default branch name for an individual [project](../../index.md):
|
||||
|
||||
1. Sign in to GitLab as a user with [Administrator](../../../permissions.md) permissions.
|
||||
1. Sign in to GitLab as a user with the [Administrator](../../../permissions.md) role.
|
||||
1. In the left navigation menu, go to **Settings > Repository**.
|
||||
1. Expand **Default branch**, and select a new default branch.
|
||||
1. (Optional) Select the **Auto-close referenced issues on default branch** check box to close
|
||||
|
@ -168,6 +168,7 @@ current default branch, instead of displaying the "not found" page.
|
|||
|
||||
## Resources
|
||||
|
||||
- [Configure a default branch for your wiki](../../wiki/index.md)
|
||||
- [Discussion of default branch renaming](https://lore.kernel.org/git/pull.656.v4.git.1593009996.gitgitgadget@gmail.com/)
|
||||
on the Git mailing list
|
||||
- [March 2021 blog post: The new Git default branch name](https://about.gitlab.com/blog/2021/03/10/new-git-default-branch-name/)
|
||||
|
|
|
@ -29,6 +29,21 @@ with sibling pages listed in alphabetical order. To view a list of all pages, se
|
|||
|
||||
![Wiki sidebar](img/wiki_sidebar_v13_5.png)
|
||||
|
||||
## Configure a default branch for your wiki
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/221159) in GitLab 14.1.
|
||||
|
||||
The default branch for your wiki repository depends on your version of GitLab:
|
||||
|
||||
- *GitLab versions 14.1 and later:* Wikis inherit the
|
||||
[default branch name](../repository/branches/default.md) configured for
|
||||
your instance or group. If no custom value is configured, GitLab uses `main`.
|
||||
- *GitLab versions 14.0 and earlier:* GitLab uses `master`.
|
||||
|
||||
For any version of GitLab, you can
|
||||
[rename this default branch](../repository/branches/default.md#update-the-default-branch-name-in-your-repository)
|
||||
for previously created wikis.
|
||||
|
||||
## Create the wiki home page
|
||||
|
||||
When a wiki is created, it is empty. On your first visit, create the landing page
|
||||
|
|
|
@ -31,16 +31,16 @@ server {
|
|||
|
||||
## Strong SSL Security
|
||||
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
|
||||
ssl on;
|
||||
ssl_certificate /etc/nginx/ssl/gitlab-pages.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/gitlab-pages.key;
|
||||
|
||||
# GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
|
||||
ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 5m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
## See app/controllers/application_controller.rb for headers set
|
||||
|
||||
|
@ -58,6 +58,9 @@ server {
|
|||
##
|
||||
# ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
||||
|
||||
## [Optional] Enable HTTP Strict Transport Security
|
||||
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
|
||||
|
||||
## Individual nginx logs for GitLab pages
|
||||
access_log /var/log/nginx/gitlab_pages_access.log;
|
||||
error_log /var/log/nginx/gitlab_pages_error.log;
|
||||
|
|
|
@ -83,23 +83,23 @@ server {
|
|||
|
||||
## HTTPS host
|
||||
server {
|
||||
listen 0.0.0.0:443 ssl;
|
||||
listen [::]:443 ipv6only=on ssl default_server;
|
||||
listen 0.0.0.0:443 ssl http2;
|
||||
listen [::]:443 ipv6only=on ssl http2 default_server;
|
||||
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
|
||||
server_tokens off; ## Don't show the nginx version number, a security best practice
|
||||
|
||||
## Strong SSL Security
|
||||
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
|
||||
ssl on;
|
||||
ssl_certificate /etc/nginx/ssl/gitlab.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/gitlab.key;
|
||||
|
||||
# GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
|
||||
ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 5m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
## See app/controllers/application_controller.rb for headers set
|
||||
|
||||
|
@ -120,7 +120,7 @@ server {
|
|||
# ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
||||
|
||||
## [Optional] Enable HTTP Strict Transport Security
|
||||
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
|
||||
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
|
||||
|
||||
## Real IP Module Config
|
||||
## http://nginx.org/en/docs/http/ngx_http_realip_module.html
|
||||
|
|
|
@ -27,15 +27,24 @@ server {
|
|||
|
||||
## Strong SSL Security
|
||||
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
|
||||
ssl on;
|
||||
ssl_certificate /etc/gitlab/ssl/registry.gitlab.example.com.crt
|
||||
ssl_certificate_key /etc/gitlab/ssl/registry.gitlab.example.com.key
|
||||
|
||||
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache builtin:1000 shared:SSL:10m;
|
||||
ssl_session_timeout 5m;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
## [Optional] Generate a stronger DHE parameter:
|
||||
## sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
|
||||
##
|
||||
# ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
||||
|
||||
## [Optional] Enable HTTP Strict Transport Security
|
||||
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
|
||||
|
||||
access_log /var/log/gitlab/nginx/gitlab_registry_access.log gitlab_access;
|
||||
error_log /var/log/gitlab/nginx/gitlab_registry_error.log;
|
||||
|
|
|
@ -18523,6 +18523,18 @@ msgstr ""
|
|||
msgid "Jira-GitLab user mapping template"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraConnect|Failed to create branch."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraConnect|Failed to create branch. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraConnect|New branch was successfully created."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraConnect|You can now close this window and return to Jira."
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService| on branch %{branch_link}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -30846,6 +30858,9 @@ msgstr ""
|
|||
msgid "Source IP"
|
||||
msgstr ""
|
||||
|
||||
msgid "Source branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -60,10 +60,8 @@ RSpec.describe Registrations::WelcomeController do
|
|||
end
|
||||
|
||||
describe '#update' do
|
||||
let(:email_opted_in) { '0' }
|
||||
|
||||
subject(:update) do
|
||||
patch :update, params: { user: { role: 'software_developer', setup_for_company: 'false', email_opted_in: email_opted_in } }
|
||||
patch :update, params: { user: { role: 'software_developer', setup_for_company: 'false' } }
|
||||
end
|
||||
|
||||
context 'without a signed in user' do
|
||||
|
@ -100,24 +98,6 @@ RSpec.describe Registrations::WelcomeController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user opted in' do
|
||||
let(:email_opted_in) { '1' }
|
||||
|
||||
it 'sets the email_opted_in field' do
|
||||
subject
|
||||
|
||||
expect(controller.current_user.email_opted_in).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user opted out' do
|
||||
it 'sets the email_opted_in field' do
|
||||
subject
|
||||
|
||||
expect(controller.current_user.email_opted_in).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Welcome screen' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
gitlab_sign_in(user)
|
||||
|
||||
visit users_sign_up_welcome_path
|
||||
end
|
||||
|
||||
it 'shows the email opt in' do
|
||||
select 'Software Developer', from: 'user_role'
|
||||
check 'user_email_opted_in'
|
||||
click_button 'Get started!'
|
||||
|
||||
expect(user.reload.email_opted_in).to eq(true)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,230 @@
|
|||
import { GlAlert, GlForm, GlFormInput, GlButton } from '@gitlab/ui';
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import NewBranchForm from '~/jira_connect/branches/components/new_branch_form.vue';
|
||||
import ProjectDropdown from '~/jira_connect/branches/components/project_dropdown.vue';
|
||||
import SourceBranchDropdown from '~/jira_connect/branches/components/source_branch_dropdown.vue';
|
||||
import {
|
||||
CREATE_BRANCH_ERROR_GENERIC,
|
||||
CREATE_BRANCH_ERROR_WITH_CONTEXT,
|
||||
CREATE_BRANCH_SUCCESS_ALERT,
|
||||
} from '~/jira_connect/branches/constants';
|
||||
import createBranchMutation from '~/jira_connect/branches/graphql/mutations/create_branch.mutation.graphql';
|
||||
|
||||
const mockProject = {
|
||||
id: 'test',
|
||||
fullPath: 'test-path',
|
||||
repository: {
|
||||
branchNames: ['main', 'f-test', 'release'],
|
||||
rootRef: 'main',
|
||||
},
|
||||
};
|
||||
const mockCreateBranchMutationResponse = {
|
||||
data: {
|
||||
createBranch: {
|
||||
clientMutationId: 1,
|
||||
errors: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockCreateBranchMutationResponseWithErrors = {
|
||||
data: {
|
||||
createBranch: {
|
||||
clientMutationId: 1,
|
||||
errors: ['everything is broken, sorry.'],
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockCreateBranchMutationSuccess = jest
|
||||
.fn()
|
||||
.mockResolvedValue(mockCreateBranchMutationResponse);
|
||||
const mockCreateBranchMutationWithErrors = jest
|
||||
.fn()
|
||||
.mockResolvedValue(mockCreateBranchMutationResponseWithErrors);
|
||||
const mockCreateBranchMutationFailed = jest.fn().mockRejectedValue(new Error('GraphQL error'));
|
||||
const mockMutationLoading = jest.fn().mockReturnValue(new Promise(() => {}));
|
||||
|
||||
const localVue = createLocalVue();
|
||||
|
||||
describe('NewBranchForm', () => {
|
||||
let wrapper;
|
||||
|
||||
const findSourceBranchDropdown = () => wrapper.findComponent(SourceBranchDropdown);
|
||||
const findProjectDropdown = () => wrapper.findComponent(ProjectDropdown);
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findForm = () => wrapper.findComponent(GlForm);
|
||||
const findInput = () => wrapper.findComponent(GlFormInput);
|
||||
const findButton = () => wrapper.findComponent(GlButton);
|
||||
|
||||
const completeForm = async () => {
|
||||
await findInput().vm.$emit('input', 'cool-branch-name');
|
||||
await findProjectDropdown().vm.$emit('change', mockProject);
|
||||
await findSourceBranchDropdown().vm.$emit('change', 'source-branch');
|
||||
};
|
||||
|
||||
function createMockApolloProvider({
|
||||
mockCreateBranchMutation = mockCreateBranchMutationSuccess,
|
||||
} = {}) {
|
||||
localVue.use(VueApollo);
|
||||
|
||||
const mockApollo = createMockApollo([[createBranchMutation, mockCreateBranchMutation]]);
|
||||
|
||||
return mockApollo;
|
||||
}
|
||||
|
||||
function createComponent({ mockApollo } = {}) {
|
||||
wrapper = shallowMount(NewBranchForm, {
|
||||
localVue,
|
||||
apolloProvider: mockApollo || createMockApolloProvider(),
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('when selecting items from dropdowns', () => {
|
||||
describe('when a project is selected', () => {
|
||||
it('sets the `selectedProject` prop for ProjectDropdown and SourceBranchDropdown', async () => {
|
||||
createComponent();
|
||||
|
||||
const projectDropdown = findProjectDropdown();
|
||||
await projectDropdown.vm.$emit('change', mockProject);
|
||||
|
||||
expect(projectDropdown.props('selectedProject')).toEqual(mockProject);
|
||||
expect(findSourceBranchDropdown().props('selectedProject')).toEqual(mockProject);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a source branch is selected', () => {
|
||||
it('sets the `selectedBranchName` prop for SourceBranchDropdown', async () => {
|
||||
createComponent();
|
||||
|
||||
const mockBranchName = 'main';
|
||||
const sourceBranchDropdown = findSourceBranchDropdown();
|
||||
await sourceBranchDropdown.vm.$emit('change', mockBranchName);
|
||||
|
||||
expect(sourceBranchDropdown.props('selectedBranchName')).toBe(mockBranchName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when submitting form', () => {
|
||||
describe('when form submission is loading', () => {
|
||||
it('sets submit button `loading` prop to `true`', async () => {
|
||||
createComponent({
|
||||
mockApollo: createMockApolloProvider({
|
||||
mockCreateBranchMutation: mockMutationLoading,
|
||||
}),
|
||||
});
|
||||
|
||||
await completeForm();
|
||||
|
||||
await findForm().vm.$emit('submit', new Event('submit'));
|
||||
await waitForPromises();
|
||||
|
||||
expect(findButton().props('loading')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when form submission is successful', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
|
||||
await completeForm();
|
||||
|
||||
await findForm().vm.$emit('submit', new Event('submit'));
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
it('displays a success message', () => {
|
||||
const alert = findAlert();
|
||||
expect(alert.exists()).toBe(true);
|
||||
expect(alert.text()).toBe(CREATE_BRANCH_SUCCESS_ALERT.message);
|
||||
expect(alert.props()).toMatchObject({
|
||||
title: CREATE_BRANCH_SUCCESS_ALERT.title,
|
||||
variant: 'success',
|
||||
});
|
||||
});
|
||||
|
||||
it('called `createBranch` mutation correctly', () => {
|
||||
expect(mockCreateBranchMutationSuccess).toHaveBeenCalledWith({
|
||||
name: 'cool-branch-name',
|
||||
projectPath: mockProject.fullPath,
|
||||
ref: 'source-branch',
|
||||
});
|
||||
});
|
||||
|
||||
it('sets submit button `loading` prop to `false`', () => {
|
||||
expect(findButton().props('loading')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when form submission fails', () => {
|
||||
describe.each`
|
||||
scenario | mutation | alertTitle | alertText
|
||||
${'with errors-as-data'} | ${mockCreateBranchMutationWithErrors} | ${CREATE_BRANCH_ERROR_WITH_CONTEXT} | ${mockCreateBranchMutationResponseWithErrors.data.createBranch.errors[0]}
|
||||
${'top-level error'} | ${mockCreateBranchMutationFailed} | ${''} | ${CREATE_BRANCH_ERROR_GENERIC}
|
||||
`('', ({ mutation, alertTitle, alertText }) => {
|
||||
beforeEach(async () => {
|
||||
createComponent({
|
||||
mockApollo: createMockApolloProvider({
|
||||
mockCreateBranchMutation: mutation,
|
||||
}),
|
||||
});
|
||||
|
||||
await completeForm();
|
||||
|
||||
await findForm().vm.$emit('submit', new Event('submit'));
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
it('displays an alert', () => {
|
||||
const alert = findAlert();
|
||||
expect(alert.exists()).toBe(true);
|
||||
expect(alert.text()).toBe(alertText);
|
||||
expect(alert.props()).toMatchObject({ title: alertTitle, variant: 'danger' });
|
||||
});
|
||||
|
||||
it('sets submit button `loading` prop to `false`', () => {
|
||||
expect(findButton().props('loading')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
describe.each`
|
||||
component | componentName
|
||||
${SourceBranchDropdown} | ${'SourceBranchDropdown'}
|
||||
${ProjectDropdown} | ${'ProjectDropdown'}
|
||||
`('when $componentName emits error', ({ component }) => {
|
||||
const mockErrorMessage = 'oh noes!';
|
||||
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
await wrapper.findComponent(component).vm.$emit('error', { message: mockErrorMessage });
|
||||
});
|
||||
|
||||
it('displays an alert', () => {
|
||||
const alert = findAlert();
|
||||
expect(alert.exists()).toBe(true);
|
||||
expect(alert.text()).toBe(mockErrorMessage);
|
||||
expect(alert.props('variant')).toBe('danger');
|
||||
});
|
||||
|
||||
describe('when alert is dismissed', () => {
|
||||
it('hides alert', async () => {
|
||||
const alert = findAlert();
|
||||
expect(alert.exists()).toBe(true);
|
||||
|
||||
await alert.vm.$emit('dismiss');
|
||||
|
||||
expect(alert.exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,7 +1,8 @@
|
|||
import { GlToggle, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { createLocalVue, shallowMount, mount } from '@vue/test-utils';
|
||||
import { createLocalVue } from '@vue/test-utils';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import createFlash from '~/flash';
|
||||
import TokenAccess from '~/token_access/components/token_access.vue';
|
||||
|
@ -41,15 +42,15 @@ describe('TokenAccess component', () => {
|
|||
|
||||
const findToggle = () => wrapper.findComponent(GlToggle);
|
||||
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findAddProjectBtn = () => wrapper.find('[data-testid="add-project-button"]');
|
||||
const findRemoveProjectBtn = () => wrapper.find('[data-testid="remove-project-button"]');
|
||||
const findAddProjectBtn = () => wrapper.findByRole('button', { name: 'Add project' });
|
||||
const findRemoveProjectBtn = () => wrapper.findByRole('button', { name: 'Remove access' });
|
||||
const findTokenSection = () => wrapper.find('[data-testid="token-section"]');
|
||||
|
||||
const createMockApolloProvider = (requestHandlers) => {
|
||||
return createMockApollo(requestHandlers);
|
||||
};
|
||||
|
||||
const createComponent = (requestHandlers, mountFn = shallowMount) => {
|
||||
const createComponent = (requestHandlers, mountFn = shallowMountExtended) => {
|
||||
wrapper = mountFn(TokenAccess, {
|
||||
localVue,
|
||||
provide: {
|
||||
|
@ -138,7 +139,7 @@ describe('TokenAccess component', () => {
|
|||
[getProjectsWithCIJobTokenScopeQuery, getProjectsWithScope],
|
||||
[addProjectCIJobTokenScopeMutation, addProjectSuccessHandler],
|
||||
],
|
||||
mount,
|
||||
mountExtended,
|
||||
);
|
||||
|
||||
await waitForPromises();
|
||||
|
@ -160,7 +161,7 @@ describe('TokenAccess component', () => {
|
|||
[getProjectsWithCIJobTokenScopeQuery, getProjectsWithScope],
|
||||
[addProjectCIJobTokenScopeMutation, addProjectFailureHandler],
|
||||
],
|
||||
mount,
|
||||
mountExtended,
|
||||
);
|
||||
|
||||
await waitForPromises();
|
||||
|
@ -181,7 +182,7 @@ describe('TokenAccess component', () => {
|
|||
[getProjectsWithCIJobTokenScopeQuery, getProjectsWithScope],
|
||||
[removeProjectCIJobTokenScopeMutation, removeProjectSuccessHandler],
|
||||
],
|
||||
mount,
|
||||
mountExtended,
|
||||
);
|
||||
|
||||
await waitForPromises();
|
||||
|
@ -203,7 +204,7 @@ describe('TokenAccess component', () => {
|
|||
[getProjectsWithCIJobTokenScopeQuery, getProjectsWithScope],
|
||||
[removeProjectCIJobTokenScopeMutation, removeProjectFailureHandler],
|
||||
],
|
||||
mount,
|
||||
mountExtended,
|
||||
);
|
||||
|
||||
await waitForPromises();
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'registrations/welcome/show' do
|
||||
let(:is_gitlab_com) { false }
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
|
@ -13,7 +11,6 @@ RSpec.describe 'registrations/welcome/show' do
|
|||
allow(view).to receive(:in_trial_flow?).and_return(false)
|
||||
allow(view).to receive(:user_has_memberships?).and_return(false)
|
||||
allow(view).to receive(:in_oauth_flow?).and_return(false)
|
||||
allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
|
||||
|
||||
render
|
||||
end
|
||||
|
@ -22,24 +19,5 @@ RSpec.describe 'registrations/welcome/show' do
|
|||
|
||||
it { is_expected.not_to have_selector('label[for="user_setup_for_company"]') }
|
||||
it { is_expected.to have_button('Get started!') }
|
||||
it { is_expected.to have_selector('input[name="user[email_opted_in]"]') }
|
||||
|
||||
describe 'email opt in' do
|
||||
context 'when on gitlab.com' do
|
||||
let(:is_gitlab_com) { true }
|
||||
|
||||
it 'hides the email-opt in by default' do
|
||||
expect(subject).to have_css('.js-email-opt-in.hidden')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not on gitlab.com' do
|
||||
let(:is_gitlab_com) { false }
|
||||
|
||||
it 'hides the email-opt in by default' do
|
||||
expect(subject).not_to have_css('.js-email-opt-in.hidden')
|
||||
expect(subject).to have_css('.js-email-opt-in')
|
||||
end
|
||||
end
|
||||
end
|
||||
it { is_expected.not_to have_selector('input[name="user[email_opted_in]"]') }
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue