Commit 1eeef229 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 5d32a7a1
---
title: Add Bitbucket Importer metrics
merge_request: 27524
author:
type: other
---
title: Add initial support for Cloud Native Buildpacks in Auto DevOps builds
merge_request: 28165
author:
type: added
...@@ -38,24 +38,32 @@ MARKDOWN ...@@ -38,24 +38,32 @@ MARKDOWN
NO_REVIEWER = 'No reviewer available'.freeze NO_REVIEWER = 'No reviewer available'.freeze
NO_MAINTAINER = 'No maintainer available'.freeze NO_MAINTAINER = 'No maintainer available'.freeze
def spin_for_category(team, project, category, branch_name) Spin = Struct.new(:reviewer, :maintainer)
random = roulette.new_random(branch_name)
labels = gitlab.mr_labels def spin_role_for_category(team, role, project, category)
team.select do |member|
member.public_send("#{role}?", project, category, gitlab.mr_labels) # rubocop:disable GitlabSecurity/PublicSend
end
end
def spin_for_category(team, project, category, branch_name)
reviewers, traintainers, maintainers = reviewers, traintainers, maintainers =
%i[reviewer? traintainer? maintainer?].map do |kind| %i[reviewer traintainer maintainer].map do |role|
team.select do |member| spin_role_for_category(team, role, project, category)
member.public_send(kind, project, category, labels) # rubocop:disable GitlabSecurity/PublicSend
end
end end
# TODO: take CODEOWNERS into account? # TODO: take CODEOWNERS into account?
# https://gitlab.com/gitlab-org/gitlab/issues/26723 # https://gitlab.com/gitlab-org/gitlab/issues/26723
# Make traintainers have triple the chance to be picked as a reviewer # Make traintainers have triple the chance to be picked as a reviewer
random = roulette.new_random(branch_name)
reviewer = roulette.spin_for_person(reviewers + traintainers + traintainers, random: random) reviewer = roulette.spin_for_person(reviewers + traintainers + traintainers, random: random)
maintainer = roulette.spin_for_person(maintainers, random: random) maintainer = roulette.spin_for_person(maintainers, random: random)
Spin.new(reviewer, maintainer)
end
def markdown_row_for_category(category, reviewer, maintainer)
"| #{helper.label_for_category(category)} | #{reviewer&.markdown_name || NO_REVIEWER} | #{maintainer&.markdown_name || NO_MAINTAINER} |" "| #{helper.label_for_category(category)} | #{reviewer&.markdown_name || NO_REVIEWER} | #{maintainer&.markdown_name || NO_MAINTAINER} |"
end end
...@@ -85,8 +93,29 @@ if changes.any? && !gitlab.mr_labels.include?('CSS cleanup') ...@@ -85,8 +93,29 @@ if changes.any? && !gitlab.mr_labels.include?('CSS cleanup')
project = helper.project_name project = helper.project_name
unknown = changes.fetch(:unknown, []) unknown = changes.fetch(:unknown, [])
spin_per_category = categories.each_with_object({}) do |category, memo|
memo[category] = spin_for_category(team, project, category, canonical_branch_name)
end
rows = spin_per_category.map do |category, spin|
reviewer = spin.reviewer
maintainer = spin.maintainer
case category
when :test
if reviewer.nil?
# Fetch an already picked backend reviewer, or pick one otherwise
reviewer = spin_per_category[:backend]&.reviewer || spin_for_category(team, project, :backend, canonical_branch_name).reviewer
end
when :engineering_productivity
if maintainer.nil?
# Fetch an already picked backend maintainer, or pick one otherwise
maintainer = spin_per_category[:backend]&.maintainer || spin_for_category(team, project, :backend, canonical_branch_name).maintainer
end
end
rows = categories.map { |category| spin_for_category(team, project, category, canonical_branch_name) } markdown_row_for_category(category, reviewer, maintainer)
end
markdown(MESSAGE) markdown(MESSAGE)
markdown(CATEGORY_TABLE_HEADER + rows.join("\n")) unless rows.empty? markdown(CATEGORY_TABLE_HEADER + rows.join("\n")) unless rows.empty?
......
...@@ -306,7 +306,7 @@ The following documentation relates to the DevOps **Configure** stage: ...@@ -306,7 +306,7 @@ The following documentation relates to the DevOps **Configure** stage:
| Configure Topics | Description | | Configure Topics | Description |
|:-----------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------| |:-----------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------|
| [Auto DevOps](topics/autodevops/index.md) | Automatically employ a complete DevOps lifecycle. | | [Auto DevOps](topics/autodevops/index.md) | Automatically employ a complete DevOps lifecycle. |
| [Create Kubernetes clusters](user/project/clusters/add_remove_clusters.md#add-new-cluster) | Use Kubernetes and GitLab. | | [Create Kubernetes clusters](user/project/clusters/add_remove_clusters.md#create-new-cluster) | Use Kubernetes and GitLab. |
| [Executable Runbooks](user/project/clusters/runbooks/index.md) | Documented procedures that explain how to carry out particular processes. | | [Executable Runbooks](user/project/clusters/runbooks/index.md) | Documented procedures that explain how to carry out particular processes. |
| [GitLab ChatOps](ci/chatops/README.md) | Interact with CI/CD jobs through chat services. | | [GitLab ChatOps](ci/chatops/README.md) | Interact with CI/CD jobs through chat services. |
| [Installing Applications](user/project/clusters/index.md#installing-applications) | Deploy Helm, Ingress, and Prometheus on Kubernetes. | | [Installing Applications](user/project/clusters/index.md#installing-applications) | Deploy Helm, Ingress, and Prometheus on Kubernetes. |
......
...@@ -151,6 +151,21 @@ java: ...@@ -151,6 +151,21 @@ java:
- target/failsafe-reports/TEST-*.xml - target/failsafe-reports/TEST-*.xml
``` ```
### Python example
This example uses pytest with the `--junitxml=report.xml` flag to format the output
for JUnit:
```yaml
pytest:
stage: test
script:
- pytest --junitxml=report.xml
artifacts:
reports:
junit: report.xml
```
### C/C++ example ### C/C++ example
There are a few tools that can produce JUnit reports in C/C++. There are a few tools that can produce JUnit reports in C/C++.
......
...@@ -10,8 +10,6 @@ type: reference ...@@ -10,8 +10,6 @@ type: reference
You can set up [GitLab CI/CD](README.md) across multiple projects, so that a pipeline You can set up [GitLab CI/CD](README.md) across multiple projects, so that a pipeline
in one project can trigger a pipeline in another project. in one project can trigger a pipeline in another project.
## Overview
GitLab CI/CD is a powerful continuous integration tool that works not only per project, GitLab CI/CD is a powerful continuous integration tool that works not only per project,
but also across projects with multi-project pipelines. but also across projects with multi-project pipelines.
......
...@@ -12,8 +12,6 @@ Watch our ...@@ -12,8 +12,6 @@ Watch our
["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/) ["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
webcast to see a comprehensive demo of GitLab CI/CD pipeline. webcast to see a comprehensive demo of GitLab CI/CD pipeline.
## Introduction
Pipelines are the top-level component of continuous integration, delivery, and deployment. Pipelines are the top-level component of continuous integration, delivery, and deployment.
Pipelines comprise: Pipelines comprise:
...@@ -33,7 +31,7 @@ If you have a [mirrored repository that GitLab pulls from](../../user/project/re ...@@ -33,7 +31,7 @@ If you have a [mirrored repository that GitLab pulls from](../../user/project/re
you may need to enable pipeline triggering in your project's you may need to enable pipeline triggering in your project's
**Settings > Repository > Pull from a remote repository > Trigger pipelines for mirror updates**. **Settings > Repository > Pull from a remote repository > Trigger pipelines for mirror updates**.
### Simple pipeline example ## Simple pipeline example
As an example, imagine a pipeline consisting of four stages, executed in the following order: As an example, imagine a pipeline consisting of four stages, executed in the following order:
......
...@@ -3,7 +3,7 @@ disqus_identifier: 'https://docs.gitlab.com/ee/user/project/pipelines/job_artifa ...@@ -3,7 +3,7 @@ disqus_identifier: 'https://docs.gitlab.com/ee/user/project/pipelines/job_artifa
type: reference, howto type: reference, howto
--- ---
# Introduction to job artifacts # Job artifacts
> - Introduced in GitLab 8.2 and GitLab Runner 0.7.0. > - Introduced in GitLab 8.2 and GitLab Runner 0.7.0.
> - Starting with GitLab 8.4 and GitLab Runner 1.0, the artifacts archive format changed to `ZIP`, and it is now possible to browse its contents, with the added ability of downloading the files separately. > - Starting with GitLab 8.4 and GitLab Runner 1.0, the artifacts archive format changed to `ZIP`, and it is now possible to browse its contents, with the added ability of downloading the files separately.
......
...@@ -3,7 +3,7 @@ disqus_identifier: 'https://docs.gitlab.com/ee/user/project/pipelines/settings.h ...@@ -3,7 +3,7 @@ disqus_identifier: 'https://docs.gitlab.com/ee/user/project/pipelines/settings.h
type: reference, howto type: reference, howto
--- ---
# Pipelines settings # Pipeline settings
To reach the pipelines settings navigate to your project's To reach the pipelines settings navigate to your project's
**Settings > CI/CD**. **Settings > CI/CD**.
......
...@@ -109,7 +109,7 @@ To make full use of Auto DevOps, you will need: ...@@ -109,7 +109,7 @@ To make full use of Auto DevOps, you will need:
To enable deployments, you will need: To enable deployments, you will need:
1. A [Kubernetes 1.12+ cluster](../../user/project/clusters/index.md) for the project. The easiest 1. A [Kubernetes 1.12+ cluster](../../user/project/clusters/index.md) for the project. The easiest
way is to add a [new cluster using the GitLab UI](../../user/project/clusters/add_remove_clusters.md#add-new-cluster). way is to create a [new cluster using the GitLab UI](../../user/project/clusters/add_remove_clusters.md#create-new-cluster).
For Kubernetes 1.16+ clusters, there is some additional configuration for [Auto Deploy for Kubernetes 1.16+](#kubernetes-116). For Kubernetes 1.16+ clusters, there is some additional configuration for [Auto Deploy for Kubernetes 1.16+](#kubernetes-116).
1. NGINX Ingress. You can deploy it to your Kubernetes cluster by installing 1. NGINX Ingress. You can deploy it to your Kubernetes cluster by installing
the [GitLab-managed app for Ingress](../../user/clusters/applications.md#ingress), the [GitLab-managed app for Ingress](../../user/clusters/applications.md#ingress),
...@@ -404,6 +404,33 @@ If Auto Build fails despite the project meeting the buildpack requirements, set ...@@ -404,6 +404,33 @@ If Auto Build fails despite the project meeting the buildpack requirements, set
a project variable `TRACE=true` to enable verbose logging, which may help to a project variable `TRACE=true` to enable verbose logging, which may help to
troubleshoot. troubleshoot.
#### Auto Build using Cloud Native Buildpacks (beta)
> Introduced in [GitLab 12.10](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28165).
Auto Build supports building your application using [Cloud Native Buildpacks](https://buildpacks.io)
through the [`pack` command](https://github.com/buildpacks/pack). To use Cloud Native Buildpacks,
set the CI variable `AUTO_DEVOPS_BUILD_IMAGE_CNB_ENABLED` to a non-empty value.
Cloud Native Buildpacks (CNBs) are an evolution of Heroku buildpacks, and
will eventually supersede Herokuish-based builds within Auto DevOps. For more
information, see [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/212692).
Builds using Cloud Native Buildpacks support the same options as builds using
Heroku buildpacks, with the following caveats:
- The buildpack must be a Cloud Native Buildpack. A Heroku buildpack can be
converted to a Cloud Native Buildpack using Heroku's
[`cnb-shim`](https://github.com/heroku/cnb-shim).
- `BUILDPACK_URL` must be in a form
[supported by `pack`](https://buildpacks.io/docs/app-developer-guide/specific-buildpacks/).
- The `/bin/herokuish` command is not present in the resulting image, and prefixing
commands with `/bin/herokuish procfile exec` is no longer required (nor possible).
NOTE: **Note**: Auto Test still uses Herokuish, as test suite detection is not
yet part of the Cloud Native Buildpack specification. For more information, see
[this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/212689).
### Auto Test ### Auto Test
Auto Test automatically runs the appropriate tests for your application using Auto Test automatically runs the appropriate tests for your application using
...@@ -1162,6 +1189,7 @@ applications. ...@@ -1162,6 +1189,7 @@ applications.
|-----------------------------------------|------------------------------------| |-----------------------------------------|------------------------------------|
| `ADDITIONAL_HOSTS` | Fully qualified domain names specified as a comma-separated list that are added to the Ingress hosts. | | `ADDITIONAL_HOSTS` | Fully qualified domain names specified as a comma-separated list that are added to the Ingress hosts. |
| `<ENVIRONMENT>_ADDITIONAL_HOSTS` | For a specific environment, the fully qualified domain names specified as a comma-separated list that are added to the Ingress hosts. This takes precedence over `ADDITIONAL_HOSTS`. | | `<ENVIRONMENT>_ADDITIONAL_HOSTS` | For a specific environment, the fully qualified domain names specified as a comma-separated list that are added to the Ingress hosts. This takes precedence over `ADDITIONAL_HOSTS`. |
| `AUTO_DEVOPS_BUILD_IMAGE_CNB_ENABLED` | When set to a non-empty value and no `Dockerfile` is present, Auto Build builds your application using Cloud Native Buildpacks instead of Herokuish. [More details](#auto-build-using-cloud-native-buildpacks-beta). |
| `AUTO_DEVOPS_BUILD_IMAGE_EXTRA_ARGS` | Extra arguments to be passed to the `docker build` command. Note that using quotes will not prevent word splitting. [More details](#passing-arguments-to-docker-build). | | `AUTO_DEVOPS_BUILD_IMAGE_EXTRA_ARGS` | Extra arguments to be passed to the `docker build` command. Note that using quotes will not prevent word splitting. [More details](#passing-arguments-to-docker-build). |
| `AUTO_DEVOPS_BUILD_IMAGE_FORWARDED_CI_VARIABLES` | A [comma-separated list of CI variable names](#passing-secrets-to-docker-build) to be passed to the `docker build` command as secrets. | | `AUTO_DEVOPS_BUILD_IMAGE_FORWARDED_CI_VARIABLES` | A [comma-separated list of CI variable names](#passing-secrets-to-docker-build) to be passed to the `docker build` command as secrets. |
| `AUTO_DEVOPS_CHART` | Helm Chart used to deploy your apps. Defaults to the one [provided by GitLab](https://gitlab.com/gitlab-org/charts/auto-deploy-app). | | `AUTO_DEVOPS_CHART` | Helm Chart used to deploy your apps. Defaults to the one [provided by GitLab](https://gitlab.com/gitlab-org/charts/auto-deploy-app). |
......
...@@ -14,7 +14,7 @@ Google Kubernetes Engine Integration. All you have to do is [follow this link](h ...@@ -14,7 +14,7 @@ Google Kubernetes Engine Integration. All you have to do is [follow this link](h
## Before you begin ## Before you begin
Before [adding a Kubernetes cluster](#add-new-cluster) using GitLab, you need: Before [adding a Kubernetes cluster](#create-new-cluster) using GitLab, you need:
- GitLab itself. Either: - GitLab itself. Either:
- A GitLab.com [account](https://about.gitlab.com/pricing/#gitlab-com). - A GitLab.com [account](https://about.gitlab.com/pricing/#gitlab-com).
...@@ -127,9 +127,9 @@ If you don't want to use GitLab Runner in privileged mode, either: ...@@ -127,9 +127,9 @@ If you don't want to use GitLab Runner in privileged mode, either:
1. Installing a Runner 1. Installing a Runner
[using `docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html). [using `docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html).
## Add new cluster ## Create new cluster
New clusters can be added using GitLab for: New clusters can be created using GitLab for:
- [Google Kubernetes Engine (GKE)](add_gke_clusters.md). - [Google Kubernetes Engine (GKE)](add_gke_clusters.md).
- [Amazon Elastic Kubernetes Service (EKS)](add_eks_clusters.md). - [Amazon Elastic Kubernetes Service (EKS)](add_eks_clusters.md).
......
...@@ -35,7 +35,7 @@ for an overview of how this is accomplished in GitLab!** ...@@ -35,7 +35,7 @@ for an overview of how this is accomplished in GitLab!**
To create an executable runbook, you will need: To create an executable runbook, you will need:
1. **Kubernetes** - A Kubernetes cluster is required to deploy the rest of the applications. 1. **Kubernetes** - A Kubernetes cluster is required to deploy the rest of the applications.
The simplest way to get started is to add a cluster using one of [GitLab's integrations](../add_remove_clusters.md#add-new-cluster). The simplest way to get started is to add a cluster using one of [GitLab's integrations](../add_remove_clusters.md#create-new-cluster).
1. **Helm Tiller** - Helm is a package manager for Kubernetes and is required to install 1. **Helm Tiller** - Helm is a package manager for Kubernetes and is required to install
all the other applications. It is installed in its own pod inside the cluster which all the other applications. It is installed in its own pod inside the cluster which
can run the Helm CLI in a safe environment. can run the Helm CLI in a safe environment.
...@@ -60,7 +60,7 @@ the components outlined above and the preloaded demo runbook. ...@@ -60,7 +60,7 @@ the components outlined above and the preloaded demo runbook.
### 1. Add a Kubernetes cluster ### 1. Add a Kubernetes cluster
Follow the steps outlined in [Add new cluster](../add_remove_clusters.md#add-new-cluster) Follow the steps outlined in [Create new cluster](../add_remove_clusters.md#create-new-cluster)
to add a Kubernetes cluster to your project. to add a Kubernetes cluster to your project.
### 2. Install Helm Tiller, Ingress, and JupyterHub ### 2. Install Helm Tiller, Ingress, and JupyterHub
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
module Gitlab module Gitlab
module BitbucketImport module BitbucketImport
class Importer class Importer
include Gitlab::BitbucketImport::Metrics
LABELS = [{ title: 'bug', color: '#FF0000' }, LABELS = [{ title: 'bug', color: '#FF0000' },
{ title: 'enhancement', color: '#428BCA' }, { title: 'enhancement', color: '#428BCA' },
{ title: 'proposal', color: '#69D100' }, { title: 'proposal', color: '#69D100' },
...@@ -83,38 +85,42 @@ module Gitlab ...@@ -83,38 +85,42 @@ module Gitlab
errors << { type: :wiki, errors: e.message } errors << { type: :wiki, errors: e.message }
end end
# rubocop: disable CodeReuse/ActiveRecord
def import_issues def import_issues
return unless repo.issues_enabled? return unless repo.issues_enabled?
create_labels create_labels
client.issues(repo).each do |issue| client.issues(repo).each do |issue|
description = '' import_issue(issue)
description += @formatter.author_line(issue.author) unless find_user_id(issue.author)
description += issue.description
label_name = issue.kind
milestone = issue.milestone ? project.milestones.find_or_create_by(title: issue.milestone) : nil
gitlab_issue = project.issues.create!(
iid: issue.iid,
title: issue.title,
description: description,
state_id: Issue.available_states[issue.state],
author_id: gitlab_user_id(project, issue.author),
milestone: milestone,
created_at: issue.created_at,
updated_at: issue.updated_at
)
gitlab_issue.labels << @labels[label_name]
import_issue_comments(issue, gitlab_issue) if gitlab_issue.persisted?
rescue StandardError => e
errors << { type: :issue, iid: issue.iid, errors: e.message }
end end
end end
# rubocop: disable CodeReuse/ActiveRecord
def import_issue(issue)
description = ''
description += @formatter.author_line(issue.author) unless find_user_id(issue.author)
description += issue.description
label_name = issue.kind
milestone = issue.milestone ? project.milestones.find_or_create_by(title: issue.milestone) : nil
gitlab_issue = project.issues.create!(
iid: issue.iid,
title: issue.title,
description: description,
state_id: Issue.available_states[issue.state],
author_id: gitlab_user_id(project, issue.author),
milestone: milestone,
created_at: issue.created_at,
updated_at: issue.updated_at
)
gitlab_issue.labels << @labels[label_name]
import_issue_comments(issue, gitlab_issue) if gitlab_issue.persisted?
rescue StandardError => e
errors << { type: :issue, iid: issue.iid, errors: e.message }
end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def import_issue_comments(issue, gitlab_issue) def import_issue_comments(issue, gitlab_issue)
...@@ -159,37 +165,41 @@ module Gitlab ...@@ -159,37 +165,41 @@ module Gitlab
pull_requests = client.pull_requests(repo) pull_requests = client.pull_requests(repo)
pull_requests.each do |pull_request| pull_requests.each do |pull_request|
description = '' import_pull_request(pull_request)
description += @formatter.author_line(pull_request.author) unless find_user_id(pull_request.author)
description += pull_request.description
source_branch_sha = pull_request.source_branch_sha
target_branch_sha = pull_request.target_branch_sha
source_branch_sha = project.repository.commit(source_branch_sha)&.sha || source_branch_sha
target_branch_sha = project.repository.commit(target_branch_sha)&.sha || target_branch_sha
merge_request = project.merge_requests.create!(
iid: pull_request.iid,
title: pull_request.title,
description: description,
source_project: project,
source_branch: pull_request.source_branch_name,
source_branch_sha: source_branch_sha,
target_project: project,
target_branch: pull_request.target_branch_name,
target_branch_sha: target_branch_sha,
state: pull_request.state,
author_id: gitlab_user_id(project, pull_request.author),
created_at: pull_request.created_at,
updated_at: pull_request.updated_at
)
import_pull_request_comments(pull_request, merge_request) if merge_request.persisted?
rescue StandardError => e
store_pull_request_error(pull_request, e)
end end
end end
def import_pull_request(pull_request)
description = ''
description += @formatter.author_line(pull_request.author) unless find_user_id(pull_request.author)
description += pull_request.description
source_branch_sha = pull_request.source_branch_sha
target_branch_sha = pull_request.target_branch_sha
source_branch_sha = project.repository.commit(source_branch_sha)&.sha || source_branch_sha
target_branch_sha = project.repository.commit(target_branch_sha)&.sha || target_branch_sha
merge_request = project.merge_requests.create!(
iid: pull_request.iid,
title: pull_request.title,
description: description,
source_project: project,
source_branch: pull_request.source_branch_name,
source_branch_sha: source_branch_sha,
target_project: project,
target_branch: pull_request.target_branch_name,
target_branch_sha: target_branch_sha,
state: pull_request.state,
author_id: gitlab_user_id(project, pull_request.author),
created_at: pull_request.created_at,
updated_at: pull_request.updated_at
)
import_pull_request_comments(pull_request, merge_request) if merge_request.persisted?
rescue StandardError => e
store_pull_request_error(pull_request, e)
end
def import_pull_request_comments(pull_request, merge_request) def import_pull_request_comments(pull_request, merge_request)
comments = client.pull_request_comments(repo, pull_request.iid) comments = client.pull_request_comments(repo, pull_request.iid)
......
# frozen_string_literal: true
module Gitlab
module BitbucketImport
module Metrics
extend ActiveSupport::Concern
IMPORTER = :bitbucket_importer
included do
prepend Gitlab::Import::Metrics
Gitlab::Import::Metrics.measure(:execute, metrics: {
"#{IMPORTER}_imported_projects": {
type: :counter,
description: 'The number of imported Bitbucket projects'
},
"#{IMPORTER}_total_duration_seconds": {
type: :histogram,
labels: { importer: IMPORTER },
description: 'Total time spent importing Bitbucket projects, in seconds'
}
})
Gitlab::Import::Metrics.measure(:import_issue, metrics: {
"#{IMPORTER}_imported_issues": {
type: :counter,
description: 'The number of imported Bitbucket issues'
}
})
Gitlab::Import::Metrics.measure(:import_pull_request, metrics: {
"#{IMPORTER}_imported_pull_requests": {
type: :counter,
description: 'The number of imported Bitbucket pull requests'
}
})
end
end
end
end
build: build:
stage: build stage: build
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-build-image/master:stable" image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-build-image:v0.2.0"
variables: variables:
DOCKER_TLS_CERTDIR: "" DOCKER_TLS_CERTDIR: ""
services: services:
......
...@@ -100,6 +100,7 @@ module Gitlab ...@@ -100,6 +100,7 @@ module Gitlab
test: "~test ~Quality for `spec/features/*`", test: "~test ~Quality for `spec/features/*`",
engineering_productivity: '~"Engineering Productivity" for CI, Danger' engineering_productivity: '~"Engineering Productivity" for CI, Danger'
}.freeze }.freeze
# First-match win, so be sure to put more specific regex at the top...
CATEGORIES = { CATEGORIES = {
%r{\Adoc/} => :none, # To reinstate roulette for documentation, set to `:docs`. %r{\Adoc/} => :none, # To reinstate roulette for documentation, set to `:docs`.
%r{\A(CONTRIBUTING|LICENSE|MAINTENANCE|PHILOSOPHY|PROCESS|README)(\.md)?\z} => :none, # To reinstate roulette for documentation, set to `:docs`. %r{\A(CONTRIBUTING|LICENSE|MAINTENANCE|PHILOSOPHY|PROCESS|README)(\.md)?\z} => :none, # To reinstate roulette for documentation, set to `:docs`.
...@@ -145,9 +146,8 @@ module Gitlab ...@@ -145,9 +146,8 @@ module Gitlab
%r{\A(ee/)?app/(?!assets|views)[^/]+} => :backend, %r{\A(ee/)?app/(?!assets|views)[^/]+} => :backend,
%r{\A(ee/)?(bin|config|generator_templates|lib|rubocop)/} => :backend, %r{\A(ee/)?(bin|config|generator_templates|lib|rubocop)/} => :backend,
%r{\A(ee/)?spec/features/} => :test, %r{\A(ee/)?spec/features/} => :test,
%r{\A(ee/)?spec/(?!javascripts|frontend)[^/]+} => :backend, %r{\A(ee/)?spec/} => :backend,
%r{\A(ee/)?vendor/(?!assets)[^/]+} => :backend, %r{\A(ee/)?vendor/} => :backend,
%r{\A(ee/)?vendor/(languages\.yml|licenses\.csv)\z} => :backend,
%r{\A(Gemfile|Gemfile.lock|Rakefile)\z} => :backend, %r{\A(Gemfile|Gemfile.lock|Rakefile)\z} => :backend,
%r{\A[A-Z_]+_VERSION\z} => :backend, %r{\A[A-Z_]+_VERSION\z} => :backend,
%r{\A\.rubocop(_todo)?\.yml\z} => :backend, %r{\A\.rubocop(_todo)?\.yml\z} => :backend,
......
# frozen_string_literal: true
# Prepend `Gitlab::Import::Metrics` to a class in order
# to measure and emit `Gitlab::Metrics` metrics of specified methods.
#
# @example
# class Importer
# prepend Gitlab::Import::Metrics
#
# Gitlab::ImportExport::Metrics.measure :execute, metrics: {
# importer_counter: {
# type: :counter,
# description: 'counter'
# },
# importer_histogram: {
# type: :histogram,
# labels: { importer: 'importer' },
# description: 'histogram'
# }
# }
#
# def execute
# ...
# end
# end
#
# Each call to `#execute` increments `importer_counter` as well as
# measures `#execute` duration and reports histogram `importer_histogram`
module Gitlab
module Import
module Metrics
def self.measure(method_name, metrics:)
define_method "#{method_name}" do |*args|
start_time = Time.zone.now
result = super(*args)
end_time = Time.zone.now
report_measurement_metrics(metrics, end_time - start_time)
result
end
end
def report_measurement_metrics(metrics, duration)
metrics.each do |metric_name, metric_value|
case metric_value[:type]
when :counter
Gitlab::Metrics.counter(metric_name, metric_value[:description]).increment
when :histogram
Gitlab::Metrics.histogram(metric_name, metric_value[:description]).observe(metric_value[:labels], duration)
else
nil
end
end
end
end
end
end
...@@ -87,6 +87,7 @@ describe Gitlab::BitbucketImport::Importer do ...@@ -87,6 +87,7 @@ describe Gitlab::BitbucketImport::Importer do
values: sample_issues_statuses values: sample_issues_statuses
} }
end end
let(:counter) { double('counter', increment: true) }
subject { described_class.new(project) } subject { described_class.new(project) }
...@@ -213,6 +214,24 @@ describe Gitlab::BitbucketImport::Importer do ...@@ -213,6 +214,24 @@ describe Gitlab::BitbucketImport::Importer do
expect(merge_request_diff.start_commit_sha).to eq target_branch_sha expect(merge_request_diff.start_commit_sha).to eq target_branch_sha
end end
end end
context 'metrics' do
before do
allow(Gitlab::Metrics).to receive(:counter) { counter }
allow(pull_request).to receive(:raw).and_return('hello world')
end
it 'counts imported pull requests' do
expect(Gitlab::Metrics).to receive(:counter).with(
:bitbucket_importer_imported_pull_requests,
'The number of imported Bitbucket pull requests'
)
expect(counter).to receive(:increment)
subject.execute
end
end
end end
context 'issues statuses' do context 'issues statuses' do
...@@ -339,5 +358,54 @@ describe Gitlab::BitbucketImport::Importer do ...@@ -339,5 +358,54 @@ describe Gitlab::BitbucketImport::Importer do
expect(importer.errors).to be_empty expect(importer.errors).to be_empty
end end
end end
context 'metrics' do
before do
allow(Gitlab::Metrics).to receive(:counter) { counter }
end
it 'counts imported issues' do
expect(Gitlab::Metrics).to receive(:counter).with(
:bitbucket_importer_imported_issues,
'The number of imported Bitbucket issues'
)
expect(counter).to receive(:increment)
subject.execute
end
end
end
describe '#execute' do
context 'metrics' do
let(:histogram) { double(:histogram) }
before do
allow(subject).to receive(:import_wiki)
allow(subject).to receive(:import_issues)
allow(subject).to receive(:import_pull_requests)
allow(Gitlab::Metrics).to receive(:counter) { counter }
allow(Gitlab::Metrics).to receive(:histogram) { histogram }
end
it 'counts and measures duration of imported projects' do
expect(Gitlab::Metrics).to receive(:counter).with(
:bitbucket_importer_imported_projects,
'The number of imported Bitbucket projects'
)
expect(Gitlab::Metrics).to receive(:histogram).with(
:bitbucket_importer_total_duration_seconds,
'Total time spent importing Bitbucket projects, in seconds'
)
expect(counter).to receive(:increment)
expect(histogram).to receive(:observe).with({ importer: described_class::IMPORTER }, anything)
subject.execute
end
end
end end
end end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Import::Metrics do
let(:importer_stub) do
Class.new do
prepend Gitlab::Import::Metrics
Gitlab::Import::Metrics.measure :execute, metrics: {
importer_counter: {
type: :counter,
description: 'description'
},
importer_histogram: {
type: :histogram,
labels: { importer: 'importer' },
description: 'description'
}
}
def execute
true
end
end
end
subject { importer_stub.new.execute }
describe '#execute' do
let(:counter) { double(:counter) }
let(:histogram) { double(:histogram) }
it 'increments counter metric' do
expect(Gitlab::Metrics)
.to receive(:counter)
.with(:importer_counter, 'description')
.and_return(counter)
expect(counter).to receive(:increment)
subject
end
it 'measures method duration and reports histogram metric' do
expect(Gitlab::Metrics)
.to receive(:histogram)
.with(:importer_histogram, 'description')
.and_return(histogram)
expect(histogram).to receive(:observe).with({ importer: 'importer' }, anything)
subject
end
end
end
...@@ -123,8 +123,13 @@ describe Projects::ImportService do ...@@ -123,8 +123,13 @@ describe Projects::ImportService do
it 'succeeds if repository import is successful' do it 'succeeds if repository import is successful' do
expect(project.repository).to receive(:import_repository).and_return(true) expect(project.repository).to receive(:import_repository).and_return(true)
expect_any_instance_of(Gitlab::BitbucketImport::Importer).to receive(:execute).and_return(true) expect_next_instance_of(Gitlab::BitbucketImport::Importer) do |importer|
expect_any_instance_of(Projects::LfsPointers::LfsImportService).to receive(:execute).and_return(status: :success) expect(importer).to receive(:execute).and_return(true)
end
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
expect(service).to receive(:execute).and_return(status: :success)
end
result = subject.execute result = subject.execute
...@@ -147,8 +152,15 @@ describe Projects::ImportService do ...@@ -147,8 +152,15 @@ describe Projects::ImportService do
error_message = 'error message' error_message = 'error message'
expect(project.repository).to receive(:import_repository).and_return(true) expect(project.repository).to receive(:import_repository).and_return(true)
expect_any_instance_of(Gitlab::BitbucketImport::Importer).to receive(:execute).and_return(true)
expect_any_instance_of(Projects::LfsPointers::LfsImportService).to receive(:execute).and_return(status: :error, message: error_message) expect_next_instance_of(Gitlab::BitbucketImport::Importer) do |importer|
expect(importer).to receive(:execute).and_return(true)
end
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
expect(service).to receive(:execute).and_return(status: :error, message: error_message)
end
expect(Gitlab::AppLogger).to receive(:error).with("The Lfs import process failed. #{error_message}") expect(Gitlab::AppLogger).to receive(:error).with("The Lfs import process failed. #{error_message}")
subject.execute subject.execute
......
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