Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-07-20 18:08:46 +00:00
parent b21276806d
commit 1bf106b172
28 changed files with 631 additions and 154 deletions

View file

@ -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>

View file

@ -60,7 +60,7 @@ export default {
},
},
methods: {
async onProjectSelect(project) {
onProjectSelect(project) {
this.$emit('change', project);
},
onError({ message } = {}) {

View file

@ -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.'),
};

View file

@ -0,0 +1,6 @@
mutation createBranch($name: String!, $projectPath: ID!, $ref: String!) {
createBranch(input: { name: $name, projectPath: $projectPath, ref: $ref }) {
clientMutationId
errors
}
}

View 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,
},
});
},
});
}

View file

@ -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,
},
};
};

View file

@ -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>

View file

@ -73,7 +73,6 @@ export default {
variant="danger"
icon="remove"
:aria-label="__('Remove access')"
data-testid="remove-project-button"
@click="removeProject(item.fullPath)"
/>
</template>

View file

@ -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)

View file

@ -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

View file

@ -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).

View file

@ -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

View file

@ -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.

View file

@ -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
```

View file

@ -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"
```

View file

@ -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.

View file

@ -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.

View file

@ -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/)

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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 ""

View file

@ -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

View file

@ -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

View file

@ -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);
});
});
});
});
});

View file

@ -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();

View file

@ -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