Commit 69f78bfc authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-11-27

# Conflicts:
#	app/assets/javascripts/boards/index.js
#	app/assets/javascripts/boards/stores/boards_store.js

[ci skip]
parents 9f05c6ac 397fd09a
......@@ -245,7 +245,7 @@ gem 'asana', '~> 0.8.1'
gem 'ruby-fogbugz', '~> 0.2.1'
# Kubernetes integration
gem 'kubeclient', '~> 3.1.0'
gem 'kubeclient', '~> 4.0.0'
# Sanitize user input
gem 'sanitize', '~> 4.6'
......@@ -440,7 +440,7 @@ group :ed25519 do
end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.123.0', require: 'gitaly'
gem 'gitaly-proto', '~> 1.1.0', require: 'gitaly'
gem 'grpc', '~> 1.15.0'
gem 'google-protobuf', '~> 3.6'
......
......@@ -297,7 +297,7 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gitaly-proto (0.123.0)
gitaly-proto (1.1.0)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab-default_value_for (3.1.1)
......@@ -394,14 +394,14 @@ GEM
html2text (0.2.0)
nokogiri (~> 1.6)
htmlentities (4.3.4)
http (2.2.2)
http (3.3.0)
addressable (~> 2.3)
http-cookie (~> 1.0)
http-form_data (~> 1.0.1)
http-form_data (~> 2.0)
http_parser.rb (~> 0.6.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
http-form_data (1.0.3)
http-form_data (2.1.1)
http_parser.rb (0.6.0)
httparty (0.13.7)
json (~> 1.8)
......@@ -446,8 +446,8 @@ GEM
kgio (2.10.0)
knapsack (1.17.0)
rake
kubeclient (3.1.0)
http (~> 2.2.2)
kubeclient (4.0.0)
http (~> 3.0)
recursive-open-struct (~> 1.0, >= 1.0.4)
rest-client (~> 2.0)
launchy (2.4.3)
......@@ -1040,7 +1040,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.123.0)
gitaly-proto (~> 1.1.0)
github-markup (~> 1.7.0)
gitlab-default_value_for (~> 3.1.1)
gitlab-license (~> 1.0)
......@@ -1078,7 +1078,7 @@ DEPENDENCIES
jwt (~> 1.5.6)
kaminari (~> 1.0)
knapsack (~> 1.17)
kubeclient (~> 3.1.0)
kubeclient (~> 4.0.0)
letter_opener_web (~> 1.3.0)
license_finder (~> 5.4)
licensee (~> 8.9)
......
......@@ -296,7 +296,7 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gitaly-proto (0.123.0)
gitaly-proto (1.1.0)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab-license (1.0.0)
......@@ -391,14 +391,14 @@ GEM
html2text (0.2.0)
nokogiri (~> 1.6)
htmlentities (4.3.4)
http (2.2.2)
http (3.3.0)
addressable (~> 2.3)
http-cookie (~> 1.0)
http-form_data (~> 1.0.1)
http-form_data (~> 2.0)
http_parser.rb (~> 0.6.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
http-form_data (1.0.3)
http-form_data (2.1.1)
http_parser.rb (0.6.0)
httparty (0.13.7)
json (~> 1.8)
......@@ -443,8 +443,8 @@ GEM
kgio (2.10.0)
knapsack (1.17.0)
rake
kubeclient (3.1.0)
http (~> 2.2.2)
kubeclient (4.0.0)
http (~> 3.0)
recursive-open-struct (~> 1.0, >= 1.0.4)
rest-client (~> 2.0)
launchy (2.4.3)
......@@ -1032,7 +1032,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.123.0)
gitaly-proto (~> 1.1.0)
github-markup (~> 1.7.0)
gitlab-license (~> 1.0)
gitlab-markup (~> 1.6.5)
......@@ -1069,7 +1069,7 @@ DEPENDENCIES
jwt (~> 1.5.6)
kaminari (~> 1.0)
knapsack (~> 1.17)
kubeclient (~> 3.1.0)
kubeclient (~> 4.0.0)
letter_opener_web (~> 1.3.0)
license_finder (~> 5.4)
licensee (~> 8.9)
......
......@@ -16,9 +16,17 @@ export default () => {
const filePath = editBlobForm.data('blobFilename');
const currentAction = $('.js-file-title').data('currentAction');
const projectId = editBlobForm.data('project-id');
const commitButton = $('.js-commit-button');
commitButton.on('click', () => {
window.onbeforeunload = null;
});
new EditBlob(`${urlRoot}${assetsPath}`, filePath, currentAction, projectId);
new NewCommitForm(editBlobForm);
// returning here blocks page navigation
window.onbeforeunload = () => '';
}
if (uploadBlobForm.length) {
......
......@@ -22,6 +22,7 @@ import initNewListDropdown from './components/new_list_dropdown';
import BoardAddIssuesModal from 'ee/boards/components/modal/index';
import '~/vue_shared/vue_resource_interceptor';
import { NavigationType, parseBoolean } from '~/lib/utils/common_utils';
<<<<<<< HEAD
import 'ee/boards/models/list';
import 'ee/boards/models/issue';
......@@ -31,6 +32,8 @@ import BoardsSelector from 'ee/boards/components/boards_selector.vue';
import collapseIcon from 'ee/boards/icons/fullscreen_collapse.svg';
import expandIcon from 'ee/boards/icons/fullscreen_expand.svg';
import tooltip from '~/vue_shared/directives/tooltip';
=======
>>>>>>> upstream/master
let issueBoardsApp;
......
......@@ -5,7 +5,10 @@ import $ from 'jquery';
import _ from 'underscore';
import Vue from 'vue';
import Cookies from 'js-cookie';
<<<<<<< HEAD
import BoardsStoreEE from 'ee/boards/stores/boards_store_ee';
=======
>>>>>>> upstream/master
import { getUrlParamsArray, parseBoolean } from '~/lib/utils/common_utils';
const boardsStore = {
......
......@@ -168,6 +168,9 @@ export default {
knativeInstalled() {
return this.applications.knative.status === APPLICATION_STATUS.INSTALLED;
},
knativeExternalIp() {
return this.applications.knative.externalIp;
},
},
created() {
this.helmInstallIllustration = helmInstallIllustration;
......@@ -408,12 +411,11 @@ export default {
<div slot="description">
<p>
{{
s__(`ClusterIntegration|A Knative build extends Kubernetes
and utilizes existing Kubernetes primitives to provide you with
the ability to run on-cluster container builds from source.
For example, you can write a build that uses Kubernetes-native
resources to obtain your source code from a repository,
build it into container a image, and then run that image.`)
s__(`ClusterIntegration|Knative (pronounced kay-nay-tiv) extends
Kubernetes to provide a set of middleware components that are
essential to build modern, source-centric, and container-based
applications that can run anywhere: on premises, in the cloud, or
even in a third-party data center.`)
}}
</p>
......@@ -444,6 +446,49 @@ export default {
/>
</div>
</template>
<template v-if="knativeInstalled">
<div class="form-group">
<label for="knative-ip-address">
{{ s__('ClusterIntegration|Knative IP Address:') }}
</label>
<div v-if="knativeExternalIp" class="input-group">
<input
id="knative-ip-address"
:value="knativeExternalIp"
type="text"
class="form-control js-ip-address"
readonly
/>
<span class="input-group-append">
<clipboard-button
:text="knativeExternalIp"
:title="s__('ClusterIntegration|Copy Knative IP Address to clipboard')"
class="input-group-text js-clipboard-btn"
/>
</span>
</div>
<input v-else type="text" class="form-control js-ip-address" readonly value="?" />
</div>
<p v-if="!knativeExternalIp" class="settings-message js-no-ip-message">
{{
s__(`ClusterIntegration|The IP address is in
the process of being assigned. Please check your Kubernetes
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}}
</p>
<p>
{{
s__(`ClusterIntegration|Point a wildcard DNS to this
generated IP address in order to access
your application after it has been deployed.`)
}}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }}
</a>
</p>
</template>
</div>
</application-row>
</div>
......
......@@ -60,6 +60,7 @@ export default class ClusterStore {
requestStatus: null,
requestReason: null,
hostname: null,
externalIp: null,
},
},
};
......@@ -111,6 +112,8 @@ export default class ClusterStore {
} else if (appId === KNATIVE) {
this.state.applications.knative.hostname =
serverAppEntry.hostname || this.state.applications.knative.hostname;
this.state.applications.knative.externalIp =
serverAppEntry.external_ip || this.state.applications.knative.externalIp;
}
});
}
......
......@@ -44,9 +44,9 @@ export default {
title: 'Get started with performance monitoring',
description: `Stay updated about the performance and health
of your environment by configuring Prometheus to monitor your deployments.`,
buttonText: 'Install Prometheus on clusters',
buttonText: 'Install on clusters',
buttonPath: this.clustersPath,
secondaryButtonText: 'Configure existing Prometheus',
secondaryButtonText: 'Configure existing installation',
secondaryButtonPath: this.settingsPath,
},
loading: {
......@@ -88,26 +88,32 @@ export default {
</script>
<template>
<div class="prometheus-state">
<div class="state-svg svg-content"><img :src="currentState.svgUrl" /></div>
<h4 class="state-title">{{ currentState.title }}</h4>
<p class="state-description">
{{ currentState.description }}
<a v-if="showButtonDescription" :href="settingsPath"> Prometheus server </a>
</p>
<div class="state-button">
<a v-if="currentState.buttonPath" :href="currentState.buttonPath" class="btn btn-success">
{{ currentState.buttonText }}
</a>
<div class="row empty-state js-empty-state">
<div class="col-12">
<div class="state-svg svg-content"><img :src="currentState.svgUrl" /></div>
</div>
<div class="state-button">
<a
v-if="currentState.secondaryButtonPath"
:href="currentState.secondaryButtonPath"
class="btn"
>
{{ currentState.secondaryButtonText }}
</a>
<div class="col-12">
<div class="text-content">
<h4 class="state-title text-center">{{ currentState.title }}</h4>
<p class="state-description">
{{ currentState.description }}
<a v-if="showButtonDescription" :href="settingsPath"> Prometheus server </a>
</p>
<div class="text-center">
<a v-if="currentState.buttonPath" :href="currentState.buttonPath" class="btn btn-success">
{{ currentState.buttonText }}
</a>
<a
v-if="currentState.secondaryButtonPath"
:href="currentState.secondaryButtonPath"
class="btn"
>
{{ currentState.secondaryButtonText }}
</a>
</div>
</div>
</div>
</div>
</template>
......@@ -363,21 +363,6 @@
stroke: $gray-darkest;
}
.prometheus-state {
max-width: 460px;
margin: 10px auto;
text-align: center;
.state-svg {
max-width: 80vw;
margin: 0 auto;
}
.state-button {
padding: $gl-padding / 2;
}
}
.prometheus-graphs {
.environments {
.dropdown-menu-toggle {
......
......@@ -51,6 +51,10 @@ module Clusters
ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end
def ingress_service
cluster.kubeclient.get_service('ingress-nginx-ingress-controller', Gitlab::Kubernetes::Helm::NAMESPACE)
end
end
end
end
......@@ -6,9 +6,7 @@ module Clusters
VERSION = '0.1.3'.freeze
REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze
# This is required for helm version <= 2.10.x in order to support
# Setting up CRDs
ISTIO_CRDS = 'https://storage.googleapis.com/triggermesh-charts/istio-crds.yaml'.freeze
FETCH_IP_ADDRESS_DELAY = 30.seconds
self.table_name = 'clusters_applications_knative'
......@@ -16,6 +14,16 @@ module Clusters
include ::Clusters::Concerns::ApplicationStatus
include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData
include AfterCommitQueue
state_machine :status do
before_transition any => [:installed] do |application|
application.run_after_commit do
ClusterWaitForIngressIpAddressWorker.perform_in(
FETCH_IP_ADDRESS_DELAY, application.name, application.id)
end
end
end
default_value_for :version, VERSION
......@@ -36,19 +44,23 @@ module Clusters
rbac: cluster.platform_kubernetes_rbac?,
chart: chart,
files: files,
repository: REPOSITORY,
preinstall: install_script
repository: REPOSITORY
)
end
def client
cluster.platform_kubernetes.kubeclient.knative_client
def schedule_status_update
return unless installed?
return if external_ip
ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end
private
def ingress_service
cluster.kubeclient.get_service('knative-ingressgateway', 'istio-system')
end
def install_script
["/usr/bin/kubectl apply -f #{ISTIO_CRDS}"]
def client
cluster.platform_kubernetes.kubeclient.knative_client
end
end
end
......
......@@ -1395,7 +1395,7 @@ class Project < ActiveRecord::Base
def change_head(branch)
if repository.branch_exists?(branch)
repository.before_change_head
repository.raw_repository.write_ref('HEAD', "refs/heads/#{branch}", shell: false)
repository.raw_repository.write_ref('HEAD', "refs/heads/#{branch}")
repository.copy_gitattributes(branch)
repository.after_change_head
reload_default_branch
......
......@@ -263,7 +263,7 @@ class Repository
next if kept_around?(sha)
# This will still fail if the file is corrupted (e.g. 0 bytes)
raw_repository.write_ref(keep_around_ref_name(sha), sha, shell: false)
raw_repository.write_ref(keep_around_ref_name(sha), sha)
rescue Gitlab::Git::CommandError => ex
Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}"
end
......
......@@ -30,7 +30,7 @@ module Clusters
def service
strong_memoize(:ingress_service) do
kubeclient.get_service('ingress-nginx-ingress-controller', Gitlab::Kubernetes::Helm::NAMESPACE)
app.ingress_service
end
end
end
......
......@@ -7,15 +7,14 @@
- if @group&.persisted?
- create_group_project = can?(current_user, :create_projects, @group)
- create_group_subgroup = can?(current_user, :create_subgroup, @group)
- if create_group_project || create_group_subgroup
%li.dropdown-bold-header
= _('This group')
- if create_group_project
%li.header-new-group-project
= link_to _('New project'), new_project_path(namespace_id: @group.id)
%li= link_to _('New project'), new_project_path(namespace_id: @group.id)
- if create_group_subgroup
%li
= link_to _('New subgroup'), new_group_path(parent_id: @group.id)
%li= link_to _('New subgroup'), new_group_path(parent_id: @group.id)
%li.divider
%li.dropdown-bold-header GitLab
......@@ -23,25 +22,20 @@
- create_project_issue = show_new_issue_link?(@project)
- merge_project = merge_request_source_project_for_project(@project)
- create_project_snippet = can?(current_user, :create_project_snippet, @project)
- if create_project_issue || merge_project || create_project_snippet
%li.dropdown-bold-header
= _('This project')
- if create_project_issue
%li
= link_to _('New issue'), new_project_issue_path(@project)
%li= link_to _('New issue'), new_project_issue_path(@project)
- if merge_project
%li
= link_to _('New merge request'), project_new_merge_request_path(merge_project)
%li= link_to _('New merge request'), project_new_merge_request_path(merge_project)
- if create_project_snippet
%li.header-new-project-snippet
= link_to _('New snippet'), new_project_snippet_path(@project)
%li= link_to _('New snippet'), new_project_snippet_path(@project)
%li.divider
%li.dropdown-bold-header GitLab
- if current_user.can_create_project?
%li
= link_to _('New project'), new_project_path, class: 'qa-global-new-project-link'
%li= link_to _('New project'), new_project_path, class: 'qa-global-new-project-link'
- if current_user.can_create_group?
%li
= link_to _('New group'), new_group_path
%li
= link_to _('New snippet'), new_snippet_path
%li= link_to _('New group'), new_group_path
%li= link_to _('New snippet'), new_snippet_path
......@@ -13,7 +13,7 @@
.form-group.row
= label_tag :branch_name, nil, class: 'col-form-label col-sm-2'
.col-sm-10
= text_field_tag :branch_name, params[:branch_name], required: true, autofocus: true, class: 'form-control js-branch-name'
= text_field_tag :branch_name, params[:branch_name], required: true, autofocus: true, class: 'form-control js-branch-name monospace'
.form-text.text-muted.text-danger.js-branch-name-error
.form-group.row
= label_tag :ref, 'Create from', class: 'col-form-label col-sm-2'
......
......@@ -2267,7 +2267,7 @@
- Disable spellcheck and autocorrect for username field in admin page
- Delete tags using Rugged for performance reasons (Robert Schilling)
- Add Slack notifications when Wiki is edited (Sebastian Klier)
- Diffs load at the correct point when linking from from number
- Diffs load at the correct point when linking from number
- Selected diff rows highlight
- Fix emoji categories in the emoji picker
- API: Properly display annotated tags for GET /projects/:id/repository/tags (Robert Schilling)
......
---
title: Make new branch form fields' fonts consistent
merge_request:
author:
type: fixed
---
title: Prevent user from navigating away from file edit without commit
merge_request:
author:
type: fixed
---
title: Remove index for notes on updated_at
merge_request: 23356
author:
type: performance
---
title: Avoid creating invalid refs using rugged, shelling out for writing refs
merge_request: 23286
author:
type: fixed
---
title: Update environments metrics empty state
merge_request: 23074
author: George Tsiolis
type: changed
---
title: Gracefully handle references with null bytes
merge_request: 23365
author:
type: fixed
---
title: Add an external IP address to the knative cluster application page
merge_request:
author: Chris Baumbauer
type: fixed
---
title: Modify the wording for the knative cluster application to match upstream
merge_request: 23289
author: Chris Baumbauer
type: fixed
---
title: Upgrade kubeclient to 4.0.0
merge_request: 23261
author: Praveen Arimbrathodiyil @pravi
type: other
class Kubeclient::Client
# We need to monkey patch this method until
# https://github.com/abonas/kubeclient/pull/323 is merged
def proxy_url(kind, name, port, namespace = '')
discover unless @discovered
entity_name_plural =
if %w[services pods nodes].include?(kind.to_s)
kind.to_s
else
@entities[kind.to_s].resource_name
end
ns_prefix = build_namespace_prefix(namespace)
rest_client["#{ns_prefix}#{entity_name_plural}/#{name}:#{port}/proxy"].url
end
# Monkey patch to set `max_redirects: 0`, so that kubeclient
# does not follow redirects and expose internal services.
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/53158
......
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class KnativeExternalIp < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :clusters_applications_knative, :external_ip, :string
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveNotesIndexOnUpdatedAt < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_concurrent_index(*index_arguments)
end
def down
add_concurrent_index(*index_arguments)
end
private
def index_arguments
[
:notes,
[:updated_at],
{
name: 'index_notes_on_updated_at'
}
]
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20181126150622) do
ActiveRecord::Schema.define(version: 20181126153547) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -814,6 +814,7 @@ ActiveRecord::Schema.define(version: 20181126150622) do
t.string "version", null: false
t.string "hostname"
t.text "status_reason"
t.string "external_ip"
t.index ["cluster_id"], name: "index_clusters_applications_knative_on_cluster_id", unique: true, using: :btree
end
......@@ -1860,7 +1861,6 @@ ActiveRecord::Schema.define(version: 20181126150622) do
t.index ["noteable_id", "noteable_type"], name: "index_notes_on_noteable_id_and_noteable_type", using: :btree
t.index ["noteable_type"], name: "index_notes_on_noteable_type", using: :btree
t.index ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type", using: :btree
t.index ["updated_at"], name: "index_notes_on_updated_at", using: :btree
end
create_table "notification_settings", force: :cascade do |t|
......
......@@ -123,7 +123,7 @@ curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab
### Create new issue discussion
Creates a new discussion to a single project issue. This is similar to creating
a note but but another comments (replies) can be added to it later.
a note but other comments (replies) can be added to it later.
```
POST /projects/:id/issues/:issue_iid/discussions
......@@ -329,7 +329,7 @@ curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitla
### Create new snippet discussion
Creates a new discussion to a single project snippet. This is similar to creating
a note but but another comments (replies) can be added to it later.
a note but other comments (replies) can be added to it later.
```
POST /projects/:id/snippets/:snippet_id/discussions
......@@ -795,7 +795,7 @@ curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab
### Create new merge request discussion
Creates a new discussion to a single project merge request. This is similar to creating
a note but but another comments (replies) can be added to it later.
a note but other comments (replies) can be added to it later.
```
POST /projects/:id/merge_requests/:merge_request_iid/discussions
......@@ -1088,7 +1088,7 @@ curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab
### Create new commit discussion
Creates a new discussion to a single project commit. This is similar to creating
a note but but another comments (replies) can be added to it later.
a note but other comments (replies) can be added to it later.
```
POST /projects/:id/commits/:commit_id/discussions
......
......@@ -64,7 +64,7 @@ applications:
## Configure GitLab CI/CD to deploy your application
Now we need to add the the GitLab CI/CD configuration file
Now we need to add the GitLab CI/CD configuration file
([`.gitlab-ci.yml`](../../yaml/README.md)) to our
project's root. This is how GitLab figures out what commands need to be run whenever
code is pushed to our repository. We will add the following `.gitlab-ci.yml`
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
......@@ -61,7 +61,7 @@ For a list of supported languages on JUnit tests, check the
[Wikipedia article](https://en.wikipedia.org/wiki/JUnit#Ports).
To enable the JUnit reports in merge requests, you need to add
[`artifacts:reports:junit`](yaml/README.md#artifacts-reports-junit)
[`artifacts:reports:junit`](yaml/README.md#artifactsreportsjunit)
in `.gitlab-ci.yml`, and specify the path(s) of the generated test reports.
In the following examples, the job in the `test` stage runs and GitLab
......@@ -69,6 +69,10 @@ collects the JUnit test report from each job. After each job is executed, the
XML reports are stored in GitLab as artifacts and their results are shown in the
merge request widget.
NOTE: **Note:**
If you also want the ability to browse JUnit output files, include the
[`artifacts:paths`](yaml/README.md#artifactspaths) keyword.
### Ruby example
Use the following job in `.gitlab-ci.yml`:
......
......@@ -27,7 +27,7 @@ GitLab capitalizes the stages' names when shown in the [pipeline graphs](#pipeli
There are three types of pipelines that often use the single shorthand of "pipeline". People often talk about them as if each one is "the" pipeline, but really, they're just pieces of a single, comprehensive pipeline.
![Types of Pipelines](img/types-of-pipelines.svg)
![Types of Pipelines](img/types-of-pipelines.png)
1. **CI Pipeline**: Build and test stages defined in `.gitlab-ci.yml`.
1. **Deploy Pipeline**: Deploy stage(s) defined in `.gitlab-ci.yml` The flow of deploying code to servers through various stages: e.g. development to staging to production.
......@@ -43,7 +43,7 @@ Pipelines accommodate several development workflows:
Example continuous delivery flow:
![CD Flow](img/pipelines-goal.svg)
![CD Flow](img/pipelines-goal.png)
## Jobs
......
......@@ -43,7 +43,7 @@ sudo apt-get install redis-server
Verify that you can connect to the server with the `gitlab-runner` user:
```bash
# Try connecting the the Redis server
# Try connecting the Redis server
sudo -u gitlab-runner -H redis-cli
# Quit the session
......
......@@ -400,7 +400,7 @@ except master.
> `changes` policy [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/19232) in 11.4
CAUTION: **Warning:**
This an _alpha_ feature, and it it subject to change at any time without
This an _alpha_ feature, and it is subject to change at any time without
prior notice!
Since GitLab 10.0 it is possible to define a more elaborate only/except job
......@@ -1297,13 +1297,17 @@ GitLab 11.2. Requires GitLab Runner 11.2 and above.
The `reports` keyword is used for collecting test reports from jobs and
exposing them in GitLab's UI (merge requests, pipeline views). Read how to use
this with [JUnit reports](#artifacts-reports-junit).
this with [JUnit reports](#artifactsreportsjunit).
NOTE: **Note:**
The test reports are collected regardless of the job results (success or failure).
You can use [`artifacts:expire_in`](#artifacts-expire_in) to set up an expiration
date for their artifacts.
NOTE: **Note:**
If you also want the ability to browse the report output files, include the
[`artifacts:paths`](#artifactspaths) keyword.
#### `artifacts:reports:junit`
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20390) in
......@@ -1312,8 +1316,9 @@ GitLab 11.2. Requires GitLab Runner 11.2 and above.
The `junit` report collects [JUnit XML files](https://www.ibm.com/support/knowledgecenter/en/SSQ2R2_14.1.0/com.ibm.rsar.analysis.codereview.cobol.doc/topics/cac_useresults_junit.html)
as artifacts. Although JUnit was originally developed in Java, there are many
[third party ports](https://en.wikipedia.org/wiki/JUnit#Ports) for other
languages like Javascript, Python, Ruby, etc.
languages like JavaScript, Python, Ruby, etc.
See [JUnit test reports](../junit_test_reports.md) for more details and examples.
Below is an example of collecting a JUnit XML file from Ruby's RSpec test tool:
```yaml
......@@ -1330,8 +1335,6 @@ rspec:
The collected JUnit reports will be uploaded to GitLab as an artifact and will
be automatically shown in merge requests.
For more examples, see [JUnit test reports](../junit_test_reports.md).
NOTE: **Note:**
In case the JUnit tool you use exports to multiple XML files, you can specify
multiple test report paths within a single job and they will be automatically
......@@ -1532,7 +1535,7 @@ test:
```
By default, a job will be retried on all failure cases. To have a better control
on which failures to retry, `retry` can be a hash with with the following keys:
on which failures to retry, `retry` can be a hash with the following keys:
- `max`: The maximum number of retries.
- `when`: The failure cases to retry.
......
......@@ -42,7 +42,7 @@ run: unicorn: (pid 30960) 14204s; run: log: (pid 13809) 2432047s
GitLab can be considered to have two layers from a process perspective:
- **Monitoring**: Anything from this layer is not required to deliver GitLab the application, but will allow administrators more insight into their infrastructure and what the service as a whole is doing.
- **Core**: Any process that is vital for the delivery of GitLab as as platform. If any of these processes halt there will be a GitLab outage. For the Core layer, you can further divide into:
- **Core**: Any process that is vital for the delivery of GitLab as a platform. If any of these processes halt there will be a GitLab outage. For the Core layer, you can further divide into:
- **Processors**: These processes are responsible for actually performing operations and presenting the service.
- **Data**: These services store/expose structured data for the GitLab service.
......@@ -86,7 +86,7 @@ GitLab is comprised of a large number of services that all log. We started bundl
- [Omnibus configuration options](https://docs.gitlab.com/omnibus/settings/nginx.html)
- Layer: Core Service (Processor)
Nginx as as an ingress port for all HTTP requests and routes them to the approriate sub-systems within GitLab. We are bundling an unmodified version of the popular open source webserver.
Nginx as an ingress port for all HTTP requests and routes them to the approriate sub-systems within GitLab. We are bundling an unmodified version of the popular open source webserver.
### node-exporter
......
......@@ -175,7 +175,7 @@ Severity levels can be applied further depending on the facet of the impact; e.g
| ~S1 | >50% users affected (possible company extinction level event) | Significant impact on all of GitLab.com | |
| ~S2 | Many users or multiple paid customers affected (but not apocalyptic)| Significant impact on large portions of GitLab.com | Degradation is guaranteed to occur in the near future |
| ~S3 | A few users or a single paid customer affected | Limited impact on important portions of GitLab.com | Degradation is likely to occur in the near future |
| ~S4 | No paid users/customer affected, or expected to in the near future | Minor impact on on GitLab.com | Degradation _may_ occur but it's not likely |
| ~S4 | No paid users/customer affected, or expected to in the near future | Minor impact on GitLab.com | Degradation _may_ occur but it's not likely |
## Label for community contributors
......
......@@ -419,7 +419,7 @@ view. For instance the approval code in the project's settings page.
**Mitigations**
Blocks of code that are EE-specific should be moved to partials. This
avoids conflicts with big chunks of HAML code that that are not fun to
avoids conflicts with big chunks of HAML code that are not fun to
resolve when you add the indentation to the equation.
EE-specific views should be placed in `ee/app/views/`, using extra
......
......@@ -123,7 +123,7 @@ droplab.init().addData([{
```
Alternatively, you can specify a specific dropdown to add this data to but passing
the data as the second argument and and the `id` of the trigger element as the first argument.
the data as the second argument and the `id` of the trigger element as the first argument.
```html
<a href="#" data-dropdown-trigger="#list" id="trigger">Toggle</a>
......
......@@ -394,7 +394,7 @@ This is especially useful whenever it's showing 500 internal server error.
### Shared contexts
All shared contexts should be be placed under `spec/support/shared_contexts/`.
All shared contexts should be placed under `spec/support/shared_contexts/`.
Shared contexts can be placed in subfolder if they apply to a certain type of
specs only (e.g. features, requests etc.) but shouldn't be if they apply to
multiple type of specs.
......@@ -404,7 +404,7 @@ Each file should include only one context and have a descriptive name, e.g.
### Shared examples
All shared examples should be be placed under `spec/support/shared_examples/`.
All shared examples should be placed under `spec/support/shared_examples/`.
Shared examples can be placed in subfolder if they apply to a certain type of
specs only (e.g. features, requests etc.) but shouldn't be if they apply to
multiple type of specs.
......@@ -416,7 +416,7 @@ Each file should include only one context and have a descriptive name, e.g.
Helpers are usually modules that provide some methods to hide the complexity of
specific RSpec examples. You can define helpers in RSpec files if they're not
intended to be shared with other specs. Otherwise, they should be be placed
intended to be shared with other specs. Otherwise, they should be placed
under `spec/support/helpers/`. Helpers can be placed in subfolder if they apply
to a certain type of specs only (e.g. features, requests etc.) but shouldn't be
if they apply to multiple type of specs.
......@@ -470,7 +470,7 @@ GitLab uses [factory_bot] as a test fixture replacement.
### Fixtures
All fixtures should be be placed under `spec/fixtures/`.
All fixtures should be placed under `spec/fixtures/`.
### Repositories
......
......@@ -89,7 +89,7 @@ We'll now create a VPC, a virtual networking environment that you'll control:
### Subnets
Now, let's create some subnets in different Availability Zones. Make sure
that each subnet is associated the the VPC we just created and
that each subnet is associated to the VPC we just created and
that CIDR blocks don't overlap. This will also
allow us to enable multi AZ for redundancy.
......@@ -168,7 +168,7 @@ The security group is basically the firewall:
1. Select **Security Groups** from the left menu.
1. Click **Create Security Group** and fill in the details. Give it a name,
add a description, and choose the VPC we created previously
1. Select the security group from the list and at the the bottom select the
1. Select the security group from the list and at the bottom select the
Inbound Rules tab. You will need to open the SSH, HTTP, and HTTPS ports. Set
the source to `0.0.0.0/0`.
......
......@@ -37,7 +37,7 @@ Once you have an Azure account, you can get started. Login to Azure using
![Azure Dashboard](img/azure-dashboard.png)
The Dashboard gives you a quick overview of Azure resources, and from here you you can build VMs,
The Dashboard gives you a quick overview of Azure resources, and from here you can build VMs,
create SQL Databases, author websites, and perform lots of other cloud tasks.
## Create New VM
......
......@@ -84,7 +84,7 @@ rbac:
##
# serviceAccountName: default
## Configuration for the Pods that that the runner launches for each new job
## Configuration for the Pods that the runner launches for each new job
##
runners:
## Default container image to use for builds when none is specified
......
......@@ -75,7 +75,7 @@ The minimum key size is 1024 bits, defaulting to 2048. If you wish to generate a
stronger RSA key pair, specify the `-b` flag with a higher bit value than the
default.
The old, default password encoding for SSH private keys keys is
The old, default password encoding for SSH private keys is
[insecure](https://latacora.singles/2018/08/03/the-default-openssh.html);
it's only a single round of an MD5 hash. Since OpenSSH version 6.5, you should
use the `-o` option to `ssh-keygen` to encode your private key in a new, more
......
......@@ -22,7 +22,7 @@ an extensive selection of dependency managed libraries and applications.
If you are sure you don't need access to any additional development libraries
or don't have approximately 15gb of available disk space for Xcode and Homebrew
use one of the the aforementioned methods.
use one of the aforementioned methods.
### Installing Xcode
......
......@@ -689,7 +689,7 @@ A [model](http://www.umsl.edu/~hugheyd/is6840/waterfall.html) of building softwa
### Webhooks
A way for for an app to [provide](https://docs.gitlab.com/ce/user/project/integrations/webhooks.html) other applications with real-time information (e.g., send a message to a slack channel when a commit is pushed.) Read about setting up [custom git hooks](https://gitlab.com/help/administration/custom_hooks.md) for when webhooks are insufficient.
A way for an app to [provide](https://docs.gitlab.com/ce/user/project/integrations/webhooks.html) other applications with real-time information (e.g., send a message to a slack channel when a commit is pushed.) Read about setting up [custom git hooks](https://gitlab.com/help/administration/custom_hooks.md) for when webhooks are insufficient.
### Wiki
......
......@@ -269,7 +269,7 @@ sudo systemctl daemon-reload
### 9. Install libs, migrations, etc.
GitLab 9.0.11 [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/24570)
a dependency on on the `re2` regular expression library. To install this dependency:
a dependency on the `re2` regular expression library. To install this dependency:
```bash
sudo apt-get install libre2-dev
......
......@@ -269,7 +269,7 @@ sudo systemctl daemon-reload
### 9. Install libs, migrations, etc.
GitLab 9.1.8 [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/24570)
a dependency on on the `re2` regular expression library. To install this dependency:
a dependency on the `re2` regular expression library. To install this dependency:
```bash
sudo apt-get install libre2-dev
......
......@@ -227,7 +227,7 @@ sudo systemctl daemon-reload
### 10. Install libs, migrations, etc.
GitLab 9.2.8 [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/24570)
a dependency on on the `re2` regular expression library. To install this dependency:
a dependency on the `re2` regular expression library. To install this dependency:
```bash
sudo apt-get install libre2-dev
......
......@@ -263,7 +263,7 @@ sudo systemctl daemon-reload
### 12. Install libs, migrations, etc.
GitLab 9.3.8 [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/24570)
a dependency on on the `re2` regular expression library. To install this dependency:
a dependency on the `re2` regular expression library. To install this dependency:
```bash
sudo apt-get install libre2-dev
......
......@@ -276,7 +276,7 @@ sudo systemctl daemon-reload
### 12. Install libs, migrations, etc.
GitLab 9.4 [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/24570)
a dependency on on the `re2` regular expression library. To install this dependency:
a dependency on the `re2` regular expression library. To install this dependency:
```bash
sudo apt-get install libre2-dev
......
......@@ -4,7 +4,7 @@ You can block email addresses of specific domains, or whitelist only some
specific domains via the **Application Settings** in the Admin area.
>**Note**: These restrictions are only applied during sign-up. An admin is
able to add add a user through the admin panel with a disallowed domain. Also
able to add a user through the admin panel with a disallowed domain. Also
note that the users can change their email addresses after signup to
disallowed domains.
......
doc/user/project/img/issue_board.png

320 KB | W: | H:

doc/user/project/img/issue_board.png

283 KB | W: | H:

doc/user/project/img/issue_board.png
doc/user/project/img/issue_board.png
doc/user/project/img/issue_board.png
doc/user/project/img/issue_board.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -105,7 +105,7 @@ From the group epic list page, you can [filter](../search/index.md#issues-and-me
## Subscribing to labels
From the project label list page and the group label list page, you can subscribe to [notifications](../../workflow/notifications.md) of a given label, to alert you that that label has been assigned to an issue or merge request.
From the project label list page and the group label list page, you can subscribe to [notifications](../../workflow/notifications.md) of a given label, to alert you that the label has been assigned to an issue or merge request.
![Labels subscriptions](img/labels_subscriptions.png)
......
......@@ -21,7 +21,7 @@ the milestone to the issue.
Milestones can be used as releases.
Set the milestone due date to represent the release date of your release.
(And leave the milestone start date blank.)
Set the the milestone title to the version of your release,
Set the milestone title to the version of your release,
such as `Version 9.4`.
Add an issue to your release by associating
the milestone to the issue.
......
......@@ -11,7 +11,7 @@ date: 2017-02-22
Setting up GitLab Pages with custom domains, and adding SSL/TLS certificates to them, are optional features of GitLab Pages.
These steps assume you've already [set your site up](getting_started_part_two.md) and and it's served under the default Pages domain `namespace.gitlab.io`, or `namespace.gitlab.io/project-name`.
These steps assume you've already [set your site up](getting_started_part_two.md) and it's served under the default Pages domain `namespace.gitlab.io`, or `namespace.gitlab.io/project-name`.
## Adding your custom domain to GitLab Pages
......
......@@ -166,7 +166,7 @@ with Pages, read through this series:
If you're using GitLab Pages default domain (`.gitlab.io`), your website will be
automatically secure and available under HTTPS. If you're using your own domain, you can
optionally secure it with with SSL/TLS certificates. You can read the following
optionally secure it with SSL/TLS certificates. You can read the following
tutorials to learn how to use these third-party certificates with GitLab Pages:
- [CloudFlare](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/)
......
......@@ -723,11 +723,11 @@ module Gitlab
delete_refs(tmp_ref)
end
def write_ref(ref_path, ref, old_ref: nil, shell: true)
def write_ref(ref_path, ref, old_ref: nil)
ref_path = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{ref_path}" unless ref_path.start_with?("refs/") || ref_path == "HEAD"
wrapped_gitaly_errors do
gitaly_repository_client.write_ref(ref_path, ref, old_ref, shell)
gitaly_repository_client.write_ref(ref_path, ref, old_ref)
end
end
......
......@@ -13,7 +13,11 @@ module Gitlab
return false if ref_name.start_with?(*not_allowed_prefixes)
return false if ref_name == 'HEAD'
Rugged::Reference.valid_name? "refs/heads/#{ref_name}"
begin
Rugged::Reference.valid_name?("refs/heads/#{ref_name}")
rescue ArgumentError
return false
end
end
end
end
......@@ -251,20 +251,15 @@ module Gitlab
)
end
def write_ref(ref_path, ref, old_ref, shell)
def write_ref(ref_path, ref, old_ref)
request = Gitaly::WriteRefRequest.new(
repository: @gitaly_repo,
ref: ref_path.b,
revision: ref.b,
shell: shell
revision: ref.b
)
request.old_revision = old_ref.b unless old_ref.nil?
response = GitalyClient.call(@storage, :repository_service, :write_ref, request, timeout: GitalyClient.fast_timeout)
raise Gitlab::Git::CommandError, encode!(response.error) if response.error.present?
true
GitalyClient.call(@storage, :repository_service, :write_ref, request, timeout: GitalyClient.fast_timeout)
end
def set_config(entries)
......
......@@ -1714,9 +1714,6 @@ msgstr ""
msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which may incur additional costs depending on the hosting provider your Kubernetes cluster is installed on. If you are using Google Kubernetes Engine, you can %{pricingLink}."
msgstr ""
msgid "ClusterIntegration|A Knative build extends Kubernetes and utilizes existing Kubernetes primitives to provide you with the ability to run on-cluster container builds from source. For example, you can write a build that uses Kubernetes-native resources to obtain your source code from a repository, build it into container a image, and then run that image."
msgstr ""
msgid "ClusterIntegration|API URL"
msgstr ""
......@@ -1783,6 +1780,9 @@ msgstr ""
msgid "ClusterIntegration|Copy Jupyter Hostname to clipboard"
msgstr ""
msgid "ClusterIntegration|Copy Knative IP Address to clipboard"
msgstr ""
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
......@@ -1894,9 +1894,15 @@ msgstr ""
msgid "ClusterIntegration|Knative"
msgstr ""
msgid "ClusterIntegration|Knative (pronounced kay-nay-tiv) extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
msgid "ClusterIntegration|Knative Domain Name:"
msgstr ""
msgid "ClusterIntegration|Knative IP Address:"
msgstr ""
msgid "ClusterIntegration|Kubernetes cluster"
msgstr ""
......
......@@ -59,6 +59,7 @@ FactoryBot.define do
end
factory :clusters_applications_runner, class: Clusters::Applications::Runner do
runner factory: %i(ci_runner)
cluster factory: %i(cluster with_installed_helm provided_by_gcp)
end
......
require 'spec_helper'
describe 'Top Plus Menu', :js do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
let(:public_project) { create(:project, :public) }
before do
group.add_owner(user)
end
context 'used by full user' do
before do
sign_in(user)
end
it 'click on New project shows new project page' do
visit root_dashboard_path
click_topmenuitem("New project")
expect(page).to have_content('Project URL')
expect(page).to have_content('Project name')
end
it 'click on New group shows new group page' do
visit root_dashboard_path
click_topmenuitem("New group")
expect(page).to have_content('Group URL')
expect(page).to have_content('Group name')
end
it 'click on New snippet shows new snippet page' do
visit root_dashboard_path
click_topmenuitem("New snippet")
expect(page).to have_content('New Snippet')
expect(page).to have_content('Title')
end
it 'click on New issue shows new issue page' do
visit project_path(project)
click_topmenuitem("New issue")
expect(page).to have_content('New Issue')
expect(page).to have_content('Title')
end
it 'click on New merge request shows new merge request page' do
visit project_path(project)
click_topmenuitem("New merge request")
expect(page).to have_content('New Merge Request')
expect(page).to have_content('Source branch')
expect(page).to have_content('Target branch')
end
it 'click on New project snippet shows new snippet page' do
visit project_path(project)
page.within '.header-content' do
find('.header-new-dropdown-toggle').click
expect(page).to have_selector('.header-new.dropdown.show', count: 1)
find('.header-new-project-snippet a').click
end
expect(page).to have_content('New Snippet')
expect(page).to have_content('Title')
end
it 'Click on New subgroup shows new group page', :nested_groups do
visit group_path(group)
click_topmenuitem("New subgroup")
expect(page).to have_content('Group URL')
expect(page).to have_content('Group name')
end
it 'Click on New project in group shows new project page' do
visit group_path(group)
page.within '.header-content' do
find('.header-new-dropdown-toggle').click
expect(page).to have_selector('.header-new.dropdown.show', count: 1)
find('.header-new-group-project a').click
end
expect(page).to have_content('Project URL')
expect(page).to have_content('Project name')
end
end
context 'used by guest user' do
let(:guest_user) { create(:user) }
before do
group.add_guest(guest_user)
project.add_guest(guest_user)
sign_in(guest_user)
end
it 'click on New issue shows new issue page' do
visit project_path(project)
click_topmenuitem("New issue")
expect(page).to have_content('New Issue')
expect(page).to have_content('Title')
end
it 'has no New merge request menu item' do
visit project_path(project)
hasnot_topmenuitem("New merge request")
end
it 'has no New project snippet menu item' do
visit project_path(project)
expect(find('.header-new.dropdown')).not_to have_selector('.header-new-project-snippet')
end
it 'public project has no New merge request menu item' do
visit project_path(public_project)
hasnot_topmenuitem("New merge request")
end
it 'public project has no New project snippet menu item' do
visit project_path(public_project)
expect(find('.header-new.dropdown')).not_to have_selector('.header-new-project-snippet')
end
it 'has no New subgroup menu item' do
visit group_path(group)
hasnot_topmenuitem("New subgroup")
end
it 'has no New project for group menu item' do
visit group_path(group)
expect(find('.header-new.dropdown')).not_to have_selector('.header-new-group-project')
end
end
def click_topmenuitem(item_name)
page.within '.header-content' do
find('.header-new-dropdown-toggle').click
expect(page).to have_selector('.header-new.dropdown.show', count: 1)
click_link item_name
end
end
def hasnot_topmenuitem(item_name)
expect(find('.header-new.dropdown')).not_to have_content(item_name)
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'GPG signed commits', :js do
set(:ref) { :'2d1096e3a0ecf1d2baf6dee036cc80775d4940ba' }
let(:project) { create(:project, :repository) }
describe 'GPG signed commits' do
let(:project) { create(:project, :public, :repository) }
it 'changes from unverified to verified when the user changes his email to match the gpg key' do
user = create :user, email: 'unrelated.user@example.org'
project.add_maintainer(user)
ref = GpgHelpers::SIGNED_AND_AUTHORED_SHA
user = create(:user, email: 'unrelated.user@example.org')
perform_enqueued_jobs do
create :gpg_key, key: GpgHelpers::User1.public_key, user: user
end
sign_in(user)
visit project_commits_path(project, ref)
visit project_commit_path(project, ref)
within '#commits-list' do
expect(page).to have_content 'Unverified'
expect(page).not_to have_content 'Verified'
end
expect(page).to have_link 'Unverified'
expect(page).not_to have_link 'Verified'
# user changes his email which makes the gpg key verified
perform_enqueued_jobs do
......@@ -27,41 +24,33 @@ describe 'GPG signed commits', :js do
user.update!(email: GpgHelpers::User1.emails.first)
end
visit project_commits_path(project, ref)
visit project_commit_path(project, ref)
within '#commits-list' do
expect(page).to have_content 'Unverified'
expect(page).to have_content 'Verified'
end
expect(page).not_to have_link 'Unverified'
expect(page).to have_link 'Verified'
end
it 'changes from unverified to verified when the user adds the missing gpg key' do
user = create :user, email: GpgHelpers::User1.emails.first
project.add_maintainer(user)
ref = GpgHelpers::SIGNED_AND_AUTHORED_SHA
user = create(:user, email: GpgHelpers::User1.emails.first)
sign_in(user)
visit project_commit_path(project, ref)
visit project_commits_path(project, ref)
within '#commits-list' do
expect(page).to have_content 'Unverified'
expect(page).not_to have_content 'Verified'
end
expect(page).to have_link 'Unverified'
expect(page).not_to have_link 'Verified'
# user adds the gpg key which makes the signature valid
perform_enqueued_jobs do
create :gpg_key, key: GpgHelpers::User1.public_key, user: user
end
visit project_commits_path(project, ref)
visit project_commit_path(project, ref)
within '#commits-list' do
expect(page).to have_content 'Unverified'
expect(page).to have_content 'Verified'
end
expect(page).not_to have_link 'Unverified'
expect(page).to have_link 'Verified'
end
context 'shows popover badges' do
context 'shows popover badges', :js do
let(:user_1) do
create :user, email: GpgHelpers::User1.emails.first, username: 'nannie.bernhard', name: 'Nannie Bernhard'
end
......@@ -85,19 +74,10 @@ describe 'GPG signed commits', :js do
end
end
before do
user = create :user
project.add_maintainer(user)
sign_in(user)
end
it 'unverified signature' do
visit project_commits_path(project, ref)
visit project_commit_path(project, GpgHelpers::SIGNED_COMMIT_SHA)
within(find('.commit', text: 'signed commit by bette cartwright')) do
click_on 'Unverified'
end
click_on 'Unverified'
within '.popover' do
expect(page).to have_content 'This commit was signed with an unverified signature.'
......@@ -108,11 +88,9 @@ describe 'GPG signed commits', :js do
it 'unverified signature: user email does not match the committer email, but is the same user' do
user_2_key
visit project_commits_path(project, ref)
visit project_commit_path(project, GpgHelpers::DIFFERING_EMAIL_SHA)
within(find('.commit', text: 'signed and authored commit by bette cartwright, different email')) do
click_on 'Unverified'
end
click_on 'Unverified'
within '.popover' do
expect(page).to have_content 'This commit was signed with a verified signature, but the committer email is not verified to belong to the same user.'
......@@ -125,11 +103,9 @@ describe 'GPG signed commits', :js do
it 'unverified signature: user email does not match the committer email' do
user_2_key
visit project_commits_path(project, ref)
visit project_commit_path(project, GpgHelpers::SIGNED_COMMIT_SHA)
within(find('.commit', text: 'signed commit by bette cartwright')) do
click_on 'Unverified'
end
click_on 'Unverified'
within '.popover' do
expect(page).to have_content "This commit was signed with a different user's verified signature."
......@@ -142,11 +118,9 @@ describe 'GPG signed commits', :js do
it 'verified and the gpg user has a gitlab profile' do
user_1_key
visit project_commits_path(project, ref)
visit project_commit_path(project, GpgHelpers::SIGNED_AND_AUTHORED_SHA)
within(find('.commit', text: 'signed and authored commit by nannie bernhard')) do
click_on 'Verified'
end
click_on 'Verified'
within '.popover' do
expect(page).to have_content 'This commit was signed with a verified signature and the committer email is verified to belong to the same user.'
......@@ -159,20 +133,16 @@ describe 'GPG signed commits', :js do
it "verified and the gpg user's profile doesn't exist anymore" do
user_1_key
visit project_commits_path(project, ref)
visit project_commit_path(project, GpgHelpers::SIGNED_AND_AUTHORED_SHA)
# wait for the signature to get generated
within(find('.commit', text: 'signed and authored commit by nannie bernhard')) do
expect(page).to have_content 'Verified'
end
expect(page).to have_link 'Verified'
user_1.destroy!
refresh
within(find('.commit', text: 'signed and authored commit by nannie bernhard')) do
click_on 'Verified'
end
click_on 'Verified'
within '.popover' do
expect(page).to have_content 'This commit was signed with a verified signature and the committer email is verified to belong to the same user.'
......
import blobBundle from '~/blob_edit/blob_bundle';
import $ from 'jquery';
window.ace = {
config: {
set: () => {},
loadModule: () => {},
},
edit: () => ({ focus: () => {} }),
};
describe('EditBlob', () => {
beforeEach(() => {
setFixtures(`
<div class="js-edit-blob-form">
<button class="js-commit-button"></button>
</div>`);
blobBundle();
});
it('sets the window beforeunload listener to a function returning a string', () => {
expect(window.onbeforeunload()).toBe('');
});
it('removes beforeunload listener if commit button is clicked', () => {
$('.js-commit-button').click();
expect(window.onbeforeunload).toBeNull();
});
});
......@@ -107,6 +107,7 @@ describe('Clusters Store', () => {
requestStatus: null,
requestReason: null,
hostname: null,
externalIp: null,
},
cert_manager: {
title: 'Cert-Manager',
......
......@@ -1469,6 +1469,19 @@ describe Gitlab::Git::Repository, :seed_helper do
end
end
end
it 'writes the HEAD' do
repository.write_ref('HEAD', 'refs/heads/feature')
expect(repository.commit('HEAD')).to eq(repository.commit('feature'))
expect(repository.root_ref).to eq('feature')
end
it 'writes other refs' do
repository.write_ref('refs/heads/feature', SeedRepo::Commit::ID)
expect(repository.commit('feature').sha).to eq(SeedRepo::Commit::ID)
end
end
describe '#write_config' do
......
......@@ -27,4 +27,5 @@ describe Gitlab::GitRefValidator do
it { expect(described_class.validate('-branch')).to be_falsey }
it { expect(described_class.validate('.tag')).to be_falsey }
it { expect(described_class.validate('my branch')).to be_falsey }
it { expect(described_class.validate("\xA0\u0000\xB0")).to be_falsey }
end
......@@ -5,7 +5,7 @@ describe Clusters::Applications::Ingress do
include_examples 'cluster application core specs', :clusters_applications_ingress
include_examples 'cluster application status specs', :clusters_applications_ingress
include_examples 'cluster application helm specs', :clusters_applications_knative
include_examples 'cluster application helm specs', :clusters_applications_ingress
before do
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in)
......
......@@ -2,7 +2,7 @@ require 'rails_helper'
describe Clusters::Applications::Jupyter do
include_examples 'cluster application core specs', :clusters_applications_jupyter
include_examples 'cluster application helm specs', :clusters_applications_knative
include_examples 'cluster application helm specs', :clusters_applications_jupyter
it { is_expected.to belong_to(:oauth_application) }
......
......@@ -7,6 +7,11 @@ describe Clusters::Applications::Knative do
include_examples 'cluster application status specs', :clusters_applications_knative
include_examples 'cluster application helm specs', :clusters_applications_knative
before do
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in)
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async)
end
describe '.installed' do
subject { described_class.installed }
......@@ -45,6 +50,48 @@ describe Clusters::Applications::Knative do
it { is_expected.to contain_exactly(cluster) }
end
describe 'make_installed with external_ip' do
before do
application.make_installed!
end
let(:application) { create(:clusters_applications_knative, :installing) }
it 'schedules a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).to have_received(:perform_in)
.with(Clusters::Applications::Knative::FETCH_IP_ADDRESS_DELAY, 'knative', application.id)
end
end
describe '#schedule_status_update with external_ip' do
let(:application) { create(:clusters_applications_knative, :installed) }
before do
application.schedule_status_update
end
it 'schedules a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).to have_received(:perform_async)
.with('knative', application.id)
end
context 'when the application is not installed' do
let(:application) { create(:clusters_applications_knative, :installing) }
it 'does not schedule a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_async)
end
end
context 'when there is already an external_ip' do
let(:application) { create(:clusters_applications_knative, :installed, external_ip: '111.222.222.111') }
it 'does not schedule a ClusterWaitForIngressIpAddressWorker' do
expect(ClusterWaitForIngressIpAddressWorker).not_to have_received(:perform_in)
end
end
end
describe '#install_command' do
subject { knative.install_command }
......
......@@ -5,7 +5,7 @@ describe Clusters::Applications::Prometheus do
include_examples 'cluster application core specs', :clusters_applications_prometheus
include_examples 'cluster application status specs', :clusters_applications_prometheus
include_examples 'cluster application helm specs', :clusters_applications_knative
include_examples 'cluster application helm specs', :clusters_applications_prometheus
describe '.installed' do
subject { described_class.installed }
......
......@@ -5,7 +5,7 @@ describe Clusters::Applications::Runner do
include_examples 'cluster application core specs', :clusters_applications_runner
include_examples 'cluster application status specs', :clusters_applications_runner
include_examples 'cluster application helm specs', :clusters_applications_knative
include_examples 'cluster application helm specs', :clusters_applications_runner
it { is_expected.to belong_to(:runner) }
......@@ -90,7 +90,7 @@ describe Clusters::Applications::Runner do
context 'without a runner' do
let(:project) { create(:project) }
let(:cluster) { create(:cluster, :with_installed_helm, projects: [project]) }
let(:application) { create(:clusters_applications_runner, cluster: cluster) }
let(:application) { create(:clusters_applications_runner, runner: nil, cluster: cluster) }
it 'creates a runner' do
expect do
......
......@@ -2455,12 +2455,6 @@ describe Project do
project.change_head(project.default_branch)
end
it 'creates the new reference with rugged' do
expect(project.repository.raw_repository).to receive(:write_ref).with('HEAD', "refs/heads/#{project.default_branch}", shell: false)
project.change_head(project.default_branch)
end
it 'copies the gitattributes' do
expect(project.repository).to receive(:copy_gitattributes).with(project.default_branch)
project.change_head(project.default_branch)
......
......@@ -28,41 +28,7 @@ describe Clusters::Applications::CheckIngressIpAddressService do
allow(application.cluster).to receive(:kubeclient).and_return(kubeclient)
end
describe '#execute' do
context 'when the ingress ip address is available' do
it 'updates the external_ip for the app' do
subject
include_examples 'check ingress ip executions', :clusters_applications_ingress
expect(application.external_ip).to eq('111.222.111.222')
end
end
context 'when the ingress ip address is not available' do
let(:ingress) { nil }
it 'does not error' do
subject
end
end
context 'when the exclusive lease cannot be obtained' do
it 'does not call kubeclient' do
stub_exclusive_lease_taken(lease_key, timeout: 15.seconds.to_i)
subject
expect(kubeclient).not_to have_received(:get_service)
end
end
context 'when there is already an external_ip' do
let(:application) { create(:clusters_applications_ingress, :installed, external_ip: '001.111.002.111') }
it 'does not call kubeclient' do
subject
expect(kubeclient).not_to have_received(:get_service)
end
end
end
include_examples 'check ingress ip executions', :clusters_applications_knative
end
# frozen_string_literal: true
module GpgHelpers
SIGNED_COMMIT_SHA = '8a852d50dda17cc8fd1408d2fd0c5b0f24c76ca4'.freeze
SIGNED_COMMIT_SHA = '8a852d50dda17cc8fd1408d2fd0c5b0f24c76ca4'
SIGNED_AND_AUTHORED_SHA = '3c1d9a0266cb0c62d926f4a6c649beed561846f5'
DIFFERING_EMAIL_SHA = 'a17a9f66543673edf0a3d1c6b93bdda3fe600f32'
module User1
extend self
......
shared_examples 'check ingress ip executions' do |app_name|
describe '#execute' do
let(:application) { create(app_name, :installed) }
let(:service) { described_class.new(application) }
let(:kubeclient) { double(::Kubeclient::Client, get_service: kube_service) }
context 'when the ingress ip address is available' do
it 'updates the external_ip for the app' do
subject
expect(application.external_ip).to eq('111.222.111.222')
end
end
context 'when the ingress ip address is not available' do
let(:ingress) { nil }
it 'does not error' do
subject
end
end
context 'when the exclusive lease cannot be obtained' do
it 'does not call kubeclient' do
stub_exclusive_lease_taken(lease_key, timeout: 15.seconds.to_i)
subject
expect(kubeclient).not_to have_received(:get_service)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'layouts/header/_new_dropdown' do
let(:user) { create(:user) }
context 'group-specific links' do
let(:group) { create(:group) }
before do
stub_current_user(user)
assign(:group, group)
end
context 'as a Group owner' do
before do
group.add_owner(user)
end
it 'has a "New project" link' do
render
expect(rendered).to have_link(
'New project',
href: new_project_path(namespace_id: group.id)
)
end
it 'has a "New subgroup" link', :nested_groups do
render
expect(rendered).to have_link(
'New subgroup',
href: new_group_path(parent_id: group.id)
)
end
end
end
context 'project-specific links' do
let(:project) { create(:project, creator: user, namespace: user.namespace) }
before do
assign(:project, project)
end
context 'as a Project owner' do
before do
stub_current_user(user)
end
it 'has a "New issue" link' do
render
expect(rendered).to have_link(
'New issue',
href: new_project_issue_path(project)
)
end
it 'has a "New merge request" link' do
render
expect(rendered).to have_link(
'New merge request',
href: project_new_merge_request_path(project)
)
end
it 'has a "New snippet" link' do
render
expect(rendered).to have_link(
'New snippet',
href: new_project_snippet_path(project)
)
end
end
context 'as a Project guest' do
let(:guest) { create(:user) }
before do
stub_current_user(guest)
project.add_guest(guest)
end
it 'has no "New merge request" link' do
render
expect(rendered).not_to have_link('New merge request')
end
it 'has no "New snippet" link' do
render
expect(rendered).not_to have_link(
'New snippet',
href: new_project_snippet_path(project)
)
end
end
end
context 'global links' do
before do
stub_current_user(user)
end
it 'has a "New project" link' do
render
expect(rendered).to have_link('New project', href: new_project_path)
end
it 'has a "New group" link' do
render
expect(rendered).to have_link('New group', href: new_group_path)
end
it 'has a "New snippet" link' do
render
expect(rendered).to have_link('New snippet', href: new_snippet_path)
end
end
def stub_current_user(current_user)
allow(view).to receive(:current_user).and_return(current_user)
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment