Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-06-09 12:08:25 +00:00
parent 5f2a8d5813
commit 48d25238c3
88 changed files with 306 additions and 646 deletions

View File

@ -3,7 +3,6 @@ import syntaxHighlight from '~/syntax_highlight';
import highlightCurrentUser from './highlight_current_user';
import { renderKroki } from './render_kroki';
import renderMath from './render_math';
import renderMermaid from './render_mermaid';
import renderSandboxedMermaid from './render_sandboxed_mermaid';
import renderMetrics from './render_metrics';
@ -15,11 +14,8 @@ $.fn.renderGFM = function renderGFM() {
syntaxHighlight(this.find('.js-syntax-highlight').get());
renderKroki(this.find('.js-render-kroki[hidden]').get());
renderMath(this.find('.js-render-math'));
if (gon.features?.sandboxedMermaid) {
renderSandboxedMermaid(this.find('.js-render-mermaid'));
} else {
renderMermaid(this.find('.js-render-mermaid'));
}
renderSandboxedMermaid(this.find('.js-render-mermaid'));
highlightCurrentUser(this.find('.gfm-project_member').get());
const issuablePopoverElements = this.find('.gfm-issue, .gfm-merge_request').get();

View File

@ -47,6 +47,11 @@ export default {
required: false,
default: true,
},
overrideCopy: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
@ -106,6 +111,7 @@ export default {
:environment-name="blob.environmentFormattedExternalUrl"
:environment-path="blob.environmentExternalUrlForRouteMap"
:is-empty="isEmpty"
:override-copy="overrideCopy"
@copy="proxyCopyRequest"
/>
</div>

View File

@ -54,6 +54,11 @@ export default {
required: false,
default: false,
},
overrideCopy: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
downloadUrl() {
@ -63,6 +68,10 @@ export default {
return this.activeViewer === RICH_BLOB_VIEWER;
},
getBlobHashTarget() {
if (this.overrideCopy) {
return null;
}
return `[data-blob-hash="${this.blobHash}"]`;
},
showCopyButton() {
@ -74,6 +83,13 @@ export default {
});
},
},
methods: {
onCopy() {
if (this.overrideCopy) {
this.$emit('copy');
}
},
},
BTN_COPY_CONTENTS_TITLE,
BTN_DOWNLOAD_TITLE,
BTN_RAW_TITLE,
@ -94,6 +110,7 @@ export default {
category="primary"
variant="default"
class="js-copy-blob-source-btn"
@click="onCopy"
/>
<gl-button
v-if="!isBinary"

View File

@ -227,6 +227,9 @@ export default {
setForkTarget(target) {
this.forkTarget = target;
},
onCopy() {
navigator.clipboard.writeText(this.blobInfo.rawTextBlob);
},
},
};
</script>
@ -242,7 +245,9 @@ export default {
:active-viewer-type="viewer.type"
:has-render-error="hasRenderError"
:show-path="false"
:override-copy="glFeatures.highlightJs"
@viewer-changed="switchViewer"
@copy="onCopy"
>
<template #actions>
<web-ide-link

View File

@ -292,12 +292,28 @@
padding: 0;
form {
position: sticky;
top: 100px;
height: calc(100vh - 100px);
overflow: auto;
--initial-top: calc(#{$header-height} + #{$mr-tabs-height});
--top: var(--initial-top);
@include gl-sticky;
@include gl-overflow-auto;
top: var(--top);
height: calc(100vh - var(--top));
padding: 0 15px;
margin-bottom: -100px;
margin-bottom: calc(var(--top) * -1);
.with-performance-bar & {
--top: calc(var(--initial-top) + #{$performance-bar-height});
}
.with-system-header & {
--top: calc(var(--initial-top) + #{$system-header-height});
}
.with-performance-bar.with-system-header & {
--top: calc(var(--initial-top) + #{$system-header-height} + #{$performance-bar-height});
}
}
}
}

View File

@ -401,4 +401,16 @@ to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1709
margin-right: $gl-spacing-scale-10;
}
}
.gl-lg-w-30p {
@include gl-media-breakpoint-up(lg) {
width: 30%;
}
}
.gl-lg-w-40p {
@include gl-media-breakpoint-up(lg) {
width: 40%;
}
}
/* END-#1825 */

View File

@ -2166,6 +2166,7 @@ class Project < ApplicationRecord
.append(key: 'CI_PROJECT_ID', value: id.to_s)
.append(key: 'CI_PROJECT_NAME', value: path)
.append(key: 'CI_PROJECT_TITLE', value: title)
.append(key: 'CI_PROJECT_DESCRIPTION', value: description)
.append(key: 'CI_PROJECT_PATH', value: full_path)
.append(key: 'CI_PROJECT_PATH_SLUG', value: full_path_slug)
.append(key: 'CI_PROJECT_NAMESPACE', value: namespace.full_path)

View File

@ -17,7 +17,7 @@
.detail-page-header-body
.issuable-meta.gl-display-flex
#js-issuable-header-warnings
%h1.title.gl-font-size-h-display.gl-my-0.gl-display-inline-block{ data: { qa_selector: 'title_content' } }
%h1.title.page-title.gl-font-size-h-display.gl-my-0.gl-display-inline-block{ data: { qa_selector: 'title_content' } }
= markdown_field(@merge_request, :title)
- unless hide_gutter_toggle

View File

@ -5,7 +5,7 @@
.detail-page-description.content-block.js-detail-page-description
#js-issuable-app{ data: { initial: issuable_initial_data(issuable).to_json, full_path: @project.full_path } }
.title-container
%h1.title= markdown_field(issuable, :title)
%h1.title.page-title.gl-font-size-h-display= markdown_field(issuable, :title)
- if issuable.description.present?
.description
.md= markdown_field(issuable, :description)

View File

@ -1,8 +0,0 @@
---
name: sandboxed_mermaid
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74414
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/349755
milestone: '14.7'
type: development
group: group::analyzer frontend
default_enabled: true

View File

@ -348,7 +348,7 @@ to support CI/CD data partitioning.
This strategy should reduce the risk of implementing CI/CD partitioning to
acceptable levels. We are also focusing on implementing partitioning for
reading only two partitions initially to make it possible to detach zero
reading only from two partitions initially to make it possible to detach zero
partitions in case of problems in our production environment. Every iteration
phase, described below has a revert strategy and before shipping database
changes we want to test them in our benchmarking environment.
@ -357,6 +357,49 @@ The main way of reducing risk in case of this effort is iteration and making
things reversible. Shipping changes, described in this document, in a safe and
reliable way is our priority.
As we move forward with the implementation we will need to find even more ways
to iterate on the design, support incremental rollouts and have better control
over reverting changes in case of something going wrong. It is sometimes
challenging to ship database schema changes iteratively, and even more
difficult to support incremental rollouts to the production environment. This
can, however, be done, it just sometimes requires additional creativity, that
we will certainly need here. Some examples of how this could look like:
### Incremental rollout of partitioned schema
Once we introduce a first partitioned routing table (presumably
`p_ci_pipelines`) and attach its zero partition (`ci_pipelines`), we will need
to start interacting with the new routing table, instead of a concrete
partition zero. Usually we would override the database table the `Ci::Pipeline`
Rails model would use with something like `self.table_name = 'p_ci_pipelines'`.
Unfortunately this approach might not support incremental rollout, because
`self.table_name` will be read upon application boot up, and later we might be
unable revert this change without restarting the application.
One way of solving this might be introducing `Ci::Partitioned::Pipeline` model,
that will inherit from `Ci::Pipeline`. In that model we would set
`self.table_name` to `p_ci_pipeline` and return its meta class from
`Ci::Pipeline.partitioned` as a scope. This will allow us to use feature flags
to route reads from `ci_pipelines` to `p_ci_pipelines` with a simple revert
strategy.
### Incremental experimentation with partitioned reads
Another example would be related to the time when we decide to attach another
partition. The goal of Phase 1 will be have two partitions per partitioned
schema / routing table, meaning that for `p_ci_pipelines` we will have
`ci_pipelines` attached as partition zero, and a new `ci_pipelines_p1`
partition created for new data. All reads from `p_ci_pipelines` will also need
to read data from the `p1` partition and we should also iteratively experiment
with reads targeting more than one partition, to evaluate performance and
overhead of partitioning.
We can do that by moving _old_ data to `ci_pipelines_m1` (minus 1) partition
iteratively. Perhaps we will create `partition_id = 1` and move some really old
pipelines there. We can then iteratively migrate data into `m1` partition to
measure the impact, performance and increase our confidence before creating a
new partition `p1` for _new_ (still not created) data.
## Iterations
We want to focus on Phase 1 iteration first. The goal and the main objective of

View File

@ -526,6 +526,7 @@ export CI_PROJECT_ID="34"
export CI_PROJECT_DIR="/builds/gitlab-org/gitlab-foss"
export CI_PROJECT_NAME="gitlab-foss"
export CI_PROJECT_TITLE="GitLab FOSS"
export CI_PROJECT_DESCRIPTION="GitLab FOSS is a read-only mirror of GitLab, with all proprietary code removed."
export CI_PROJECT_NAMESPACE="gitlab-org"
export CI_PROJECT_ROOT_NAMESPACE="gitlab-org"
export CI_PROJECT_PATH="gitlab-org/gitlab-foss"
@ -863,6 +864,8 @@ if [[ -d "/builds/gitlab-examples/ci-debug-trace/.git" ]]; then
++ CI_PROJECT_NAME=ci-debug-trace
++ export CI_PROJECT_TITLE='GitLab FOSS'
++ CI_PROJECT_TITLE='GitLab FOSS'
++ export CI_PROJECT_DESCRIPTION='GitLab FOSS is a read-only mirror of GitLab, with all proprietary code removed.'
++ CI_PROJECT_DESCRIPTION='GitLab FOSS is a read-only mirror of GitLab, with all proprietary code removed.'
++ export CI_PROJECT_PATH=gitlab-examples/ci-debug-trace
++ CI_PROJECT_PATH=gitlab-examples/ci-debug-trace
++ export CI_PROJECT_PATH_SLUG=gitlab-examples-ci-debug-trace

View File

@ -96,6 +96,7 @@ as it can cause the pipeline to behave unexpectedly.
| `CI_PROJECT_REPOSITORY_LANGUAGES` | 12.3 | all | A comma-separated, lowercase list of the languages used in the repository. For example `ruby,javascript,html,css`. |
| `CI_PROJECT_ROOT_NAMESPACE` | 13.2 | 0.5 | The root project namespace (username or group name) of the job. For example, if `CI_PROJECT_NAMESPACE` is `root-group/child-group/grandchild-group`, `CI_PROJECT_ROOT_NAMESPACE` is `root-group`. |
| `CI_PROJECT_TITLE` | 12.4 | all | The human-readable project name as displayed in the GitLab web interface. |
| `CI_PROJECT_DESCRIPTION` | 15.1 | all | The project description as displayed in the GitLab web interface. |
| `CI_PROJECT_URL` | 8.10 | 0.5 | The HTTP(S) address of the project. |
| `CI_PROJECT_VISIBILITY` | 10.3 | all | The project visibility. Can be `internal`, `private`, or `public`. |
| `CI_PROJECT_CLASSIFICATION_LABEL` | 14.2 | all | The project [external authorization classification label](../../user/admin_area/settings/external_authorization.md). |

View File

@ -100,27 +100,31 @@ class a {
## Converting Strings to Integers
When converting strings to integers, `parseInt` has a slight performance advantage over `Number`, but `Number` is semantic and can be more readable. Prefer `parseInt`, but do not discourage `Number` if it significantly helps readability.
When converting strings to integers, `Number` is semantic and can be more readable. Both are allowable, but `Number` has a slight maintainability advantage.
**WARNING:** `parseInt` **must** include the [radix argument](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt).
```javascript
// bad
// bad (missing radix argument)
parseInt('10');
// bad
things.map(parseInt)
// ok
Number("106")
// good
parseInt("106", 10);
// good
things.map(Number)
// good
parseInt("106", 10)
Number("106");
```
```javascript
// bad (missing radix argument)
things.map(parseInt);
// good
things.map(Number);
```
**PLEASE NOTE:** If the String could represent a non-integer (i.e., it includes a decimal), **do not** use `parseInt`. Consider `Number` or `parseFloat` instead.
## CSS Selectors - Use `js-` prefix
If a CSS class is only being used in JavaScript as a reference to the element, prefix

View File

@ -37,7 +37,7 @@ flowchart LR
subgraph backend
be["Backend code"]--tested with-->rspec
end
be--generates-->fixtures["frontend fixtures"]
fixtures--used in-->jest
```
@ -277,16 +277,6 @@ In the event of an emergency, or false positive from this job, add the
`pipeline:skip-undercoverage` label to the merge request to allow this job to
fail.
You can disable the `undercover` code coverage check by wrapping the desired block of code in `# :nocov:` lines:
```ruby
# :nocov:
def some_method
# code coverage for this method will be skipped
end
# :nocov:
```
## PostgreSQL versions testing
Our test suite runs against PG12 as GitLab.com runs on PG12 and

View File

@ -55,7 +55,6 @@ module Gitlab
push_frontend_feature_flag(:security_auto_fix)
push_frontend_feature_flag(:new_header_search)
push_frontend_feature_flag(:bootstrap_confirmation_modals)
push_frontend_feature_flag(:sandboxed_mermaid)
push_frontend_feature_flag(:source_editor_toolbar)
push_frontend_feature_flag(:gl_avatar_for_all_user_avatars)
push_frontend_feature_flag(:mr_attention_requests, current_user)

View File

@ -10,7 +10,6 @@ RSpec.describe "User comments on issue", :js do
let(:user) { create(:user) }
before do
stub_feature_flags(sandboxed_mermaid: false)
project.add_guest(user)
sign_in(user)
@ -42,17 +41,6 @@ RSpec.describe "User comments on issue", :js do
expect(page.find('pre code').text).to eq code_block_content
end
it "renders HTML content as text in Mermaid" do
html_content = "<img onerror=location=`javascript\\u003aalert\\u0028document.domain\\u0029` src=x>"
mermaid_content = "graph LR\n B-->D(#{html_content});"
comment = "```mermaid\n#{mermaid_content}\n```"
add_note(comment)
expect(page.find('svg.mermaid')).not_to have_content 'javascript'
within('svg.mermaid') { expect(page).not_to have_selector('img') }
end
it 'opens autocomplete menu for quick actions and have `/label` first choice' do
project.add_maintainer(user)
create(:label, project: project, title: 'label')

View File

@ -1,361 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Mermaid rendering', :js do
let_it_be(:project) { create(:project, :public) }
let(:is_mac) { page.evaluate_script('navigator.platform').include?('Mac') }
let(:modifier_key) { is_mac ? :command : :control }
before do
stub_feature_flags(sandboxed_mermaid: false)
end
it 'renders Mermaid diagrams correctly' do
description = <<~MERMAID
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
MERMAID
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
%w[A B C D].each do |label|
expect(page).to have_selector('svg text', text: label)
end
end
it 'renders linebreaks in Mermaid diagrams' do
description = <<~MERMAID
```mermaid
graph TD;
A(Line 1<br>Line 2)-->B(Line 1<br/>Line 2);
C(Line 1<br />Line 2)-->D(Line 1<br />Line 2);
```
MERMAID
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
# From # From https://github.com/mermaid-js/mermaid/blob/170ed89e9ef3e33dc84f8656eed1725379d505df/src/dagre-wrapper/createLabel.js#L39-L42
expected = %(<div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Line 1<br>Line 2</div>)
expect(page.html.scan(expected).count).to be(4)
end
it 'does not allow XSS in HTML labels' do
description = <<~MERMAID
```mermaid
graph LR;
A-->CLICK_HERE_AND_GET_BONUS;
click A alert "aaa"
click CLICK_HERE_AND_GET_BONUS "javascript:alert%28%64%6f%63%75%6d%65%6e%74%2e%64%6f%6d%61%69%6e%29" "Here is the XSS"
```
MERMAID
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
# From https://github.com/mermaid-js/mermaid/blob/170ed89e9ef3e33dc84f8656eed1725379d505df/src/dagre-wrapper/createLabel.js#L39-L42
expected = %(<div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">CLICK_HERE_AND_GET_BONUS</div>)
expect(page.html).to include(expected)
end
it 'renders only 2 Mermaid blocks and', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/234081' do
description = <<~MERMAID
```mermaid
graph LR
A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;
```
```mermaid
graph LR
A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;
```
```mermaid
graph LR
A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;
```
MERMAID
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
page.within('.description') do
expect(page).to have_selector('svg')
expect(page).to have_selector('pre.mermaid')
end
end
it 'correctly sizes mermaid diagram inside <details> block' do
description = <<~MERMAID
<details>
<summary>Click to show diagram</summary>
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
</details>
MERMAID
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
page.within('.description') do
page.find('summary').click
svg = page.find('svg.mermaid')
expect(svg[:style]).to match(/max-width/)
expect(svg[:width].to_i).to eq(100)
expect(svg[:height].to_i).to be_within(5).of(236)
end
end
it 'renders V2 state diagrams' do
description = <<~MERMAID
```mermaid
stateDiagram-v2
[*] --> Idle
Idle --> Active : CONTINUE
state Active {
[*] --> Run
Run--> Stop: CONTINUE
Stop--> Run: CONTINUE
Run: Run
Run: entry/start
Run: check
}
```
MERMAID
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
page.within('.description') do
expect(page).to have_selector('svg')
end
end
it 'correctly sizes mermaid diagram block' do
description = <<~MERMAID
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
MERMAID
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
expect(page).to have_css('svg.mermaid[style*="max-width"][width="100%"]')
end
it 'display button when diagram exceeds length', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/287806' do
graph_edges = "A-->B;B-->A;" * 420
description = <<~MERMAID
```mermaid
graph LR
#{graph_edges}
```
MERMAID
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
page.within('.description') do
expect(page).not_to have_selector('svg')
expect(page).to have_selector('pre.mermaid')
expect(page).to have_selector('.lazy-alert-shown')
expect(page).to have_selector('.js-lazy-render-mermaid-container')
end
wait_for_requests
wait_for_mermaid
find('.js-lazy-render-mermaid').click
page.within('.description') do
expect(page).to have_selector('svg')
expect(page).not_to have_selector('.js-lazy-render-mermaid-container')
end
end
it 'does not render more than 50 mermaid blocks', :js, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/234081' } do
graph_edges = "A-->B;B-->A;"
description = <<~MERMAID
```mermaid
graph LR
#{graph_edges}
```
MERMAID
description *= 51
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
page.within('.description') do
expect(page).to have_selector('svg')
expect(page).to have_selector('.lazy-alert-shown')
expect(page).to have_selector('.js-lazy-render-mermaid-container')
end
end
it 'renders without any limits on wiki page', :js do
graph_edges = "A-->B;B-->A;"
description = <<~MERMAID
```mermaid
graph LR
#{graph_edges}
```
MERMAID
description *= 51
wiki_page = build(:wiki_page, { container: project, content: description })
wiki_page.create message: 'mermaid test commit' # rubocop:disable Rails/SaveBang
wiki_page = project.wiki.find_page(wiki_page.slug)
visit project_wiki_path(project, wiki_page)
wait_for_requests
wait_for_mermaid
page.within('.js-wiki-page-content') do
expect(page).not_to have_selector('.lazy-alert-shown')
expect(page).not_to have_selector('.js-lazy-render-mermaid-container')
end
end
it 'does not allow HTML injection' do
description = <<~MERMAID
```mermaid
%%{init: {"flowchart": {"htmlLabels": "false"}} }%%
flowchart
A["<iframe></iframe>"]
```
MERMAID
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
page.within('.description') do
expect(page).not_to have_xpath("//iframe")
end
end
it 'correctly copies and pastes to/from the clipboard' do
stub_feature_flags(sandboxed_mermaid: true)
description = <<~MERMAID
```mermaid
graph TD;
A-->B;
A-->C;
```
MERMAID
issue = create(:issue, project: project, description: description)
user = create(:user)
sign_in(user)
visit project_issue_path(project, issue)
wait_for_requests
wait_for_mermaid
find('pre.language-mermaid').hover
find('copy-code button').click
sleep 2
find('#note-body').send_keys [modifier_key, 'v']
wait_for_requests
# The codefences do actually get included, but we can't get spec to pass
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83202#note_880621264
expect(find('#note-body').value.strip).to eq("graph TD;\n A-->B;\n A-->C;")
end
end
def wait_for_mermaid
run_idle_callback = <<~RUN_IDLE_CALLBACK
window.requestIdleCallback(() => {
window.__CAPYBARA_IDLE_CALLBACK_EXEC__ = 1;
})
RUN_IDLE_CALLBACK
page.evaluate_script(run_idle_callback)
Timeout.timeout(Capybara.default_max_wait_time) do
loop until finished_rendering?
end
end
def finished_rendering?
check_idle_callback = <<~CHECK_IDLE_CALLBACK
window.__CAPYBARA_IDLE_CALLBACK_EXEC__
CHECK_IDLE_CALLBACK
page.evaluate_script(check_idle_callback) == 1
end

View File

@ -1,25 +0,0 @@
import { initMermaid } from '~/behaviors/markdown/render_mermaid';
import * as ColorUtils from '~/lib/utils/color_utils';
describe('Render mermaid diagrams for Gitlab Flavoured Markdown', () => {
it.each`
darkMode | expectedTheme
${false} | ${'neutral'}
${true} | ${'dark'}
`('is $darkMode $expectedTheme', async ({ darkMode, expectedTheme }) => {
jest.spyOn(ColorUtils, 'darkModeEnabled').mockImplementation(() => darkMode);
const mermaid = {
initialize: jest.fn(),
};
await initMermaid(mermaid);
expect(mermaid.initialize).toHaveBeenCalledTimes(1);
expect(mermaid.initialize).toHaveBeenCalledWith(
expect.objectContaining({
theme: expectedTheme,
}),
);
});
});

View File

@ -88,6 +88,14 @@ describe('Blob Header Default Actions', () => {
expect(findCopyButton().exists()).toBe(false);
expect(findViewRawButton().exists()).toBe(false);
});
it('emits a copy event if overrideCopy is set to true', () => {
createComponent({ overrideCopy: true });
jest.spyOn(wrapper.vm, '$emit');
findCopyButton().vm.$emit('click');
expect(wrapper.vm.$emit).toHaveBeenCalledWith('copy');
});
});
describe('view on environment button', () => {

View File

@ -163,6 +163,14 @@ describe('Blob content viewer component', () => {
expect(findBlobHeader().props('blob')).toEqual(simpleViewerMock);
});
it('copies blob text to clipboard', async () => {
jest.spyOn(navigator.clipboard, 'writeText');
await createComponent();
findBlobHeader().vm.$emit('copy');
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(simpleViewerMock.rawTextBlob);
});
it('renders a BlobContent component', async () => {
await createComponent();

View File

@ -64,6 +64,8 @@ RSpec.describe Gitlab::Ci::Variables::Builder do
value: project.path },
{ key: 'CI_PROJECT_TITLE',
value: project.title },
{ key: 'CI_PROJECT_DESCRIPTION',
value: project.description },
{ key: 'CI_PROJECT_PATH',
value: project.full_path },
{ key: 'CI_PROJECT_PATH_SLUG',

View File

@ -2809,6 +2809,7 @@ RSpec.describe Ci::Build do
{ key: 'CI_PROJECT_ID', value: project.id.to_s, public: true, masked: false },
{ key: 'CI_PROJECT_NAME', value: project.path, public: true, masked: false },
{ key: 'CI_PROJECT_TITLE', value: project.title, public: true, masked: false },
{ key: 'CI_PROJECT_DESCRIPTION', value: project.description, public: true, masked: false },
{ key: 'CI_PROJECT_PATH', value: project.full_path, public: true, masked: false },
{ key: 'CI_PROJECT_PATH_SLUG', value: project.full_path_slug, public: true, masked: false },
{ key: 'CI_PROJECT_NAMESPACE', value: project.namespace.full_path, public: true, masked: false },

View File

@ -5,7 +5,6 @@ import (
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"os"
)
@ -53,7 +52,7 @@ func (r *Reader) Read(p []byte) (int, error) {
chunkLen := int64(binary.BigEndian.Uint32(header[:4]))
if chunkType := string(header[4:]); chunkType == "iCCP" {
debug("!! iCCP chunk found; skipping")
if _, err := io.CopyN(ioutil.Discard, r.underlying, chunkLen+crcLen); err != nil {
if _, err := io.CopyN(io.Discard, r.underlying, chunkLen+crcLen); err != nil {
return 0, err
}
continue

View File

@ -5,7 +5,6 @@ import (
"hash/crc64"
"image"
"io"
"io/ioutil"
"os"
"testing"
@ -85,9 +84,9 @@ func requireValidImage(t *testing.T, r io.Reader, expected string) {
}
func requireStreamUnchanged(t *testing.T, actual io.Reader, expected io.Reader) {
actualBytes, err := ioutil.ReadAll(actual)
actualBytes, err := io.ReadAll(actual)
require.NoError(t, err)
expectedBytes, err := ioutil.ReadAll(expected)
expectedBytes, err := io.ReadAll(expected)
require.NoError(t, err)
table := crc64.MakeTable(crc64.ISO)

View File

@ -3,7 +3,6 @@ package main
import (
"flag"
"io"
"io/ioutil"
"net/url"
"os"
"testing"
@ -24,7 +23,7 @@ func TestDefaultConfig(t *testing.T) {
}
func TestConfigFile(t *testing.T) {
f, err := ioutil.TempFile("", "workhorse-config-test")
f, err := os.CreateTemp("", "workhorse-config-test")
require.NoError(t, err)
defer os.Remove(f.Name())
@ -119,7 +118,7 @@ key = "/path/to/private/key"
}
func TestTwoMetricsAddrsAreSpecifiedError(t *testing.T) {
f, err := ioutil.TempFile("", "workhorse-config-test")
f, err := os.CreateTemp("", "workhorse-config-test")
require.NoError(t, err)
defer os.Remove(f.Name())

View File

@ -5,7 +5,6 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"net"
"net/http"
@ -651,7 +650,7 @@ func TestGetArchiveProxiedToGitalySuccessfully(t *testing.T) {
_, err := os.Stat(tc.archivePath)
require.True(t, os.IsNotExist(err), "expected 'does not exist', got: %v", err)
} else {
cachedArchive, err := ioutil.ReadFile(tc.archivePath)
cachedArchive, err := os.ReadFile(tc.archivePath)
require.NoError(t, err)
require.Equal(t, expectedBody, string(cachedArchive))
}

View File

@ -1,7 +1,7 @@
package api
import (
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"testing"
@ -46,7 +46,7 @@ func TestBlocker(t *testing.T) {
rw.Flush()
body := rw.Result().Body
data, err := ioutil.ReadAll(body)
data, err := io.ReadAll(body)
require.NoError(t, err)
require.NoError(t, body.Close())

View File

@ -4,7 +4,6 @@ import (
"archive/zip"
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
@ -36,7 +35,7 @@ func testEntryServer(t *testing.T, archive string, entry string) *httptest.Respo
}
func TestDownloadingFromValidArchive(t *testing.T) {
tempFile, err := ioutil.TempFile("", "uploads")
tempFile, err := os.CreateTemp("", "uploads")
require.NoError(t, err)
defer tempFile.Close()
defer os.Remove(tempFile.Name())
@ -95,10 +94,9 @@ func TestDownloadingFromValidHTTPArchive(t *testing.T) {
}
func TestDownloadingNonExistingFile(t *testing.T) {
tempFile, err := ioutil.TempFile("", "uploads")
tempFile, err := os.CreateTemp(t.TempDir(), "uploads")
require.NoError(t, err)
defer tempFile.Close()
defer os.Remove(tempFile.Name())
archive := zip.NewWriter(tempFile)
defer archive.Close()

View File

@ -4,7 +4,7 @@ import (
"bytes"
"fmt"
"html/template"
"io/ioutil"
"io"
"net/http"
"strings"
"time"
@ -60,7 +60,7 @@ func (t *roundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
message, contentType = developmentModeResponse(err)
}
injectedResponse.Body = ioutil.NopCloser(strings.NewReader(message))
injectedResponse.Body = io.NopCloser(strings.NewReader(message))
injectedResponse.Header.Set("Content-Type", contentType)
return injectedResponse, nil

View File

@ -2,7 +2,7 @@ package badgateway
import (
"errors"
"io/ioutil"
"io"
"net/http"
"testing"
@ -45,7 +45,7 @@ func TestErrorPage502(t *testing.T) {
require.NoError(t, err, "perform roundtrip")
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
body, err := io.ReadAll(response.Body)
require.NoError(t, err)
require.Equal(t, tc.contentType, response.Header.Get("content-type"), "content type")

View File

@ -7,7 +7,6 @@ package git
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path"
@ -180,7 +179,7 @@ func prepareArchiveTempfile(dir string, prefix string) (*os.File, error) {
if err := os.MkdirAll(dir, 0700); err != nil {
return nil, err
}
return ioutil.TempFile(dir, prefix)
return os.CreateTemp(dir, prefix)
}
func finalizeCachedArchive(tempFile *os.File, archivePath string) error {

View File

@ -1,8 +1,8 @@
package git
import (
"io/ioutil"
"net/http/httptest"
"os"
"testing"
"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
@ -40,7 +40,7 @@ func TestParseBasename(t *testing.T) {
}
func TestFinalizeArchive(t *testing.T) {
tempFile, err := ioutil.TempFile("", "gitlab-workhorse-test")
tempFile, err := os.CreateTemp("", "gitlab-workhorse-test")
if err != nil {
t.Fatal(err)
}

View File

@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http/httptest"
"path/filepath"
@ -56,7 +55,7 @@ func TestUploadPackTimesOut(t *testing.T) {
}
defer conn.Close()
_, _ = io.Copy(ioutil.Discard, conn)
_, _ = io.Copy(io.Discard, conn)
return &gitalypb.PostUploadPackWithSidechannelResponse{}, nil
},
})

View File

@ -3,7 +3,7 @@ package helper
import (
"bytes"
"errors"
"io/ioutil"
"io"
"mime"
"net"
"net/http"
@ -197,12 +197,12 @@ func ReadRequestBody(w http.ResponseWriter, r *http.Request, maxBodySize int64)
limitedBody := http.MaxBytesReader(w, r.Body, maxBodySize)
defer limitedBody.Close()
return ioutil.ReadAll(limitedBody)
return io.ReadAll(limitedBody)
}
func CloneRequestWithNewBody(r *http.Request, body []byte) *http.Request {
newReq := *r
newReq.Body = ioutil.NopCloser(bytes.NewReader(body))
newReq.Body = io.NopCloser(bytes.NewReader(body))
newReq.Header = HeaderClone(r.Header)
newReq.ContentLength = int64(len(body))
return &newReq

View File

@ -2,12 +2,11 @@ package helper
import (
"io"
"io/ioutil"
"os"
)
func ReadAllTempfile(r io.Reader) (tempfile *os.File, err error) {
tempfile, err = ioutil.TempFile("", "gitlab-workhorse-read-all-tempfile")
tempfile, err = os.CreateTemp("", "gitlab-workhorse-read-all-tempfile")
if err != nil {
return nil, err
}

View File

@ -3,7 +3,6 @@ package helper
import (
"fmt"
"io"
"io/ioutil"
"os"
"sync"
)
@ -131,7 +130,7 @@ func (w *coupledWriter) tempfileWrite(data []byte) (int, error) {
}
func (*coupledWriter) newTempfile() (tempfile *os.File, err error) {
tempfile, err = ioutil.TempFile("", "gitlab-workhorse-coupledWriter")
tempfile, err = os.CreateTemp("", "gitlab-workhorse-coupledWriter")
if err != nil {
return nil, err
}

View File

@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"testing"
"testing/iotest"
)
@ -14,7 +13,7 @@ func TestBusyReader(t *testing.T) {
r := testReader(testData)
br, _ := NewWriteAfterReader(r, &bytes.Buffer{})
result, err := ioutil.ReadAll(br)
result, err := io.ReadAll(br)
if err != nil {
t.Fatal(err)
}
@ -27,7 +26,7 @@ func TestBusyReader(t *testing.T) {
func TestFirstWriteAfterReadDone(t *testing.T) {
writeRecorder := &bytes.Buffer{}
br, cw := NewWriteAfterReader(&bytes.Buffer{}, writeRecorder)
if _, err := io.Copy(ioutil.Discard, br); err != nil {
if _, err := io.Copy(io.Discard, br); err != nil {
t.Fatalf("copy from busyreader: %v", err)
}
testData := "test data"
@ -53,7 +52,7 @@ func TestWriteDelay(t *testing.T) {
}
// Unblock the coupled writer by draining the reader
if _, err := io.Copy(ioutil.Discard, br); err != nil {
if _, err := io.Copy(io.Discard, br); err != nil {
t.Fatalf("copy from busyreader: %v", err)
}
// Now it is no longer an error if 'w' receives a Write()

View File

@ -20,7 +20,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"github.com/mitchellh/copystructure"
@ -148,7 +147,7 @@ func (r *HttpReadSeeker) Seek(offset int64, whence int) (int64, error) {
if r.r != nil {
// Try to read, which is cheaper than doing a request
if r.pos < offset && offset-r.pos <= shortSeekBytes {
_, err := io.CopyN(ioutil.Discard, r, offset-r.pos)
_, err := io.CopyN(io.Discard, r, offset-r.pos)
if err != nil {
return 0, err
}

View File

@ -3,7 +3,6 @@ package httprs
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
@ -49,7 +48,7 @@ type fakeRoundTripper struct {
func (f *fakeRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
fw := &fakeResponseWriter{h: http.Header{}}
var err error
fw.tmp, err = ioutil.TempFile(os.TempDir(), "httprs")
fw.tmp, err = os.CreateTemp(os.TempDir(), "httprs")
if err != nil {
return nil, err
}
@ -79,7 +78,7 @@ type RSFactory func() *HttpReadSeeker
func newRSFactory(flags int) RSFactory {
return func() *HttpReadSeeker {
tmp, err := ioutil.TempFile(os.TempDir(), "httprs")
tmp, err := os.CreateTemp(os.TempDir(), "httprs")
if err != nil {
return nil
}
@ -113,7 +112,7 @@ func TestHttpWebServer(t *testing.T) {
Convey("Scenario: testing WebServer", t, func() {
dir := t.TempDir()
err := ioutil.WriteFile(filepath.Join(dir, "file"), make([]byte, 10000), 0755)
err := os.WriteFile(filepath.Join(dir, "file"), make([]byte, 10000), 0755)
So(err, ShouldBeNil)
server := httptest.NewServer(http.FileServer(http.Dir(dir)))

View File

@ -5,7 +5,7 @@ import (
"encoding/json"
"image"
"image/png"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
@ -184,7 +184,7 @@ func TestServeOriginalImageWhenSourceImageFormatIsNotAllowed(t *testing.T) {
cfg := config.DefaultImageResizerConfig
// SVG images are not allowed to be resized
svgImagePath := "../../testdata/image.svg"
svgImage, err := ioutil.ReadFile(svgImagePath)
svgImage, err := os.ReadFile(svgImagePath)
require.NoError(t, err)
// ContentType is no longer used to perform the format validation.
// To make the test more strict, we'll use allowed, but incorrect ContentType.
@ -193,7 +193,7 @@ func TestServeOriginalImageWhenSourceImageFormatIsNotAllowed(t *testing.T) {
resp := requestScaledImage(t, nil, params, cfg)
require.Equal(t, http.StatusOK, resp.StatusCode)
responseData, err := ioutil.ReadAll(resp.Body)
responseData, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, svgImage, responseData, "expected original image")
}
@ -201,7 +201,7 @@ func TestServeOriginalImageWhenSourceImageFormatIsNotAllowed(t *testing.T) {
func TestServeOriginalImageWhenSourceImageIsTooSmall(t *testing.T) {
content := []byte("PNG") // 3 bytes only, invalid as PNG/JPEG image
img, err := ioutil.TempFile("", "*.png")
img, err := os.CreateTemp("", "*.png")
require.NoError(t, err)
defer img.Close()
@ -216,7 +216,7 @@ func TestServeOriginalImageWhenSourceImageIsTooSmall(t *testing.T) {
resp := requestScaledImage(t, nil, params, cfg)
require.Equal(t, http.StatusOK, resp.StatusCode)
responseData, err := ioutil.ReadAll(resp.Body)
responseData, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, content, responseData, "expected original image")
}

View File

@ -3,7 +3,6 @@ package parser
import (
"encoding/binary"
"io"
"io/ioutil"
"os"
)
@ -16,7 +15,7 @@ type cache struct {
}
func newCache(tempDir, filename string, data interface{}) (*cache, error) {
f, err := ioutil.TempFile(tempDir, filename)
f, err := os.CreateTemp(tempDir, filename)
if err != nil {
return nil, err
}

View File

@ -1,7 +1,7 @@
package parser
import (
"io/ioutil"
"io"
"testing"
"github.com/stretchr/testify/require"
@ -21,7 +21,7 @@ func TestCache(t *testing.T) {
require.NoError(t, cache.SetEntry(1, &c))
require.NoError(t, cache.setOffset(0))
content, err := ioutil.ReadAll(cache.file)
content, err := io.ReadAll(cache.file)
require.NoError(t, err)
expected := []byte{0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x0}

View File

@ -2,7 +2,6 @@ package parser
import (
"encoding/json"
"io/ioutil"
"os"
)
@ -39,7 +38,7 @@ type ResultSetRef struct {
func NewHovers(config Config) (*Hovers, error) {
tempPath := config.TempPath
file, err := ioutil.TempFile(tempPath, "hovers")
file, err := os.CreateTemp(tempPath, "hovers")
if err != nil {
return nil, err
}

View File

@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"gitlab.com/gitlab-org/labkit/log"
@ -33,7 +32,7 @@ func NewParser(ctx context.Context, r io.Reader, config Config) (io.ReadCloser,
}
// ZIP files need to be seekable. Don't hold it all in RAM, use a tempfile
tempFile, err := ioutil.TempFile(config.TempPath, Lsif)
tempFile, err := os.CreateTemp(config.TempPath, Lsif)
if err != nil {
return nil, err
}

View File

@ -6,7 +6,6 @@ import (
"context"
"encoding/json"
"io"
"io/ioutil"
"os"
"path/filepath"
"testing"
@ -26,13 +25,13 @@ func TestGenerate(t *testing.T) {
}
func verifyCorrectnessOf(t *testing.T, tmpDir, fileName string) {
file, err := ioutil.ReadFile(filepath.Join(tmpDir, fileName))
file, err := os.ReadFile(filepath.Join(tmpDir, fileName))
require.NoError(t, err)
var buf bytes.Buffer
require.NoError(t, json.Indent(&buf, file, "", " "))
expected, err := ioutil.ReadFile(filepath.Join("testdata/expected/", fileName))
expected, err := os.ReadFile(filepath.Join("testdata/expected/", fileName))
require.NoError(t, err)
require.Equal(t, string(expected), buf.String())

View File

@ -3,7 +3,6 @@ package parser
import (
"context"
"io"
"io/ioutil"
"os"
"runtime"
"testing"
@ -25,7 +24,7 @@ func BenchmarkGenerate(b *testing.B) {
parser, err := NewParser(context.Background(), file, Config{})
require.NoError(b, err)
_, err = io.Copy(ioutil.Discard, parser)
_, err = io.Copy(io.Discard, parser)
require.NoError(b, err)
require.NoError(b, parser.Close())
})

View File

@ -3,7 +3,7 @@ package secret
import (
"encoding/base64"
"fmt"
"io/ioutil"
"os"
"sync"
)
@ -57,7 +57,7 @@ func setBytes() ([]byte, error) {
return theSecret.bytes, nil
}
base64Bytes, err := ioutil.ReadFile(theSecret.path)
base64Bytes, err := os.ReadFile(theSecret.path)
if err != nil {
return nil, fmt.Errorf("secret.setBytes: read %q: %v", theSecret.path, err)
}

View File

@ -2,7 +2,6 @@ package contentprocessor
import (
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
@ -306,7 +305,7 @@ func makeRequest(t *testing.T, handler http.HandlerFunc, body string, dispositio
SetContentHeaders(handler).ServeHTTP(rw, req)
resp := rw.Result()
respBody, err := ioutil.ReadAll(resp.Body)
respBody, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, body, string(respBody))

View File

@ -2,7 +2,6 @@ package senddata
import (
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
@ -47,7 +46,7 @@ func TestWriter(t *testing.T) {
recorder.Flush()
body := recorder.Result().Body
data, err := ioutil.ReadAll(body)
data, err := io.ReadAll(body)
require.NoError(t, err)
require.NoError(t, body.Close())

View File

@ -9,7 +9,6 @@ package sendfile
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"regexp"
@ -128,7 +127,7 @@ func sendFileFromDisk(w http.ResponseWriter, r *http.Request, file string) {
countSendFileMetrics(fi.Size(), r)
if contentTypeHeaderPresent {
data, err := ioutil.ReadAll(io.LimitReader(content, headers.MaxDetectSize))
data, err := io.ReadAll(io.LimitReader(content, headers.MaxDetectSize))
if err != nil {
helper.Fail500(w, r, fmt.Errorf("content type detection: %v", err))
return

View File

@ -1,9 +1,10 @@
package sendfile
import (
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/require"
@ -15,7 +16,7 @@ func TestResponseWriter(t *testing.T) {
upstreamResponse := "hello world"
fixturePath := "testdata/sent-file.txt"
fixtureContent, err := ioutil.ReadFile(fixturePath)
fixtureContent, err := os.ReadFile(fixturePath)
require.NoError(t, err)
testCases := []struct {
@ -52,7 +53,7 @@ func TestResponseWriter(t *testing.T) {
rw.Flush()
body := rw.Result().Body
data, err := ioutil.ReadAll(body)
data, err := io.ReadAll(body)
require.NoError(t, err)
require.NoError(t, body.Close())
@ -90,7 +91,7 @@ func TestSuccessOverrideContentHeadersFeatureEnabled(t *testing.T) {
func TestSuccessOverrideContentHeadersRangeRequestFeatureEnabled(t *testing.T) {
fixturePath := "../../testdata/forgedfile.png"
fixtureContent, err := ioutil.ReadFile(fixturePath)
fixtureContent, err := os.ReadFile(fixturePath)
require.NoError(t, err)
r, err := http.NewRequest("GET", "/foo", nil)
@ -113,7 +114,7 @@ func TestSuccessOverrideContentHeadersRangeRequestFeatureEnabled(t *testing.T) {
resp := rw.Result()
body := resp.Body
data, err := ioutil.ReadAll(body)
data, err := io.ReadAll(body)
require.NoError(t, err)
require.NoError(t, body.Close())
@ -138,7 +139,7 @@ func TestSuccessInlineWhitelistedTypesFeatureEnabled(t *testing.T) {
}
func makeRequest(t *testing.T, fixturePath string, httpHeaders map[string]string) *http.Response {
fixtureContent, err := ioutil.ReadFile(fixturePath)
fixtureContent, err := os.ReadFile(fixturePath)
require.NoError(t, err)
r, err := http.NewRequest("GET", "/foo", nil)
@ -161,7 +162,7 @@ func makeRequest(t *testing.T, fixturePath string, httpHeaders map[string]string
resp := rw.Result()
body := resp.Body
data, err := ioutil.ReadAll(body)
data, err := io.ReadAll(body)
require.NoError(t, err)
require.NoError(t, body.Close())

View File

@ -3,7 +3,6 @@ package sendurl
import (
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
@ -40,7 +39,7 @@ func testEntryServer(t *testing.T, requestURL string, httpHeaders http.Header, a
serveFile := func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "GET", r.Method)
tempFile, err := ioutil.TempFile("", "download_file")
tempFile, err := os.CreateTemp("", "download_file")
require.NoError(t, err)
require.NoError(t, os.Remove(tempFile.Name()))
defer tempFile.Close()

View File

@ -1,8 +1,8 @@
package staticpages
import (
"io/ioutil"
"net/http"
"os"
"path/filepath"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/helper"
@ -12,7 +12,7 @@ func (s *Static) DeployPage(handler http.Handler) http.Handler {
deployPage := filepath.Join(s.DocumentRoot, "index.html")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
data, err := ioutil.ReadFile(deployPage)
data, err := os.ReadFile(deployPage)
if err != nil {
handler.ServeHTTP(w, r)
return

View File

@ -1,9 +1,9 @@
package staticpages
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
@ -31,7 +31,7 @@ func TestIfDeployPageExist(t *testing.T) {
dir := t.TempDir()
deployPage := "DEPLOY"
ioutil.WriteFile(filepath.Join(dir, "index.html"), []byte(deployPage), 0600)
os.WriteFile(filepath.Join(dir, "index.html"), []byte(deployPage), 0600)
w := httptest.NewRecorder()

View File

@ -3,8 +3,8 @@ package staticpages
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"github.com/prometheus/client_golang/prometheus"
@ -97,7 +97,7 @@ func (s *errorPageResponseWriter) writeHTML() (string, []byte) {
errorPageFile := filepath.Join(s.path, fmt.Sprintf("%d.html", s.status))
// check if custom error page exists, serve this page instead
if data, err := ioutil.ReadFile(errorPageFile); err == nil {
if data, err := os.ReadFile(errorPageFile); err == nil {
return "text/html; charset=utf-8", data
}
}

View File

@ -2,9 +2,9 @@ package staticpages
import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
@ -17,7 +17,7 @@ func TestIfErrorPageIsPresented(t *testing.T) {
dir := t.TempDir()
errorPage := "ERROR"
ioutil.WriteFile(filepath.Join(dir, "404.html"), []byte(errorPage), 0600)
os.WriteFile(filepath.Join(dir, "404.html"), []byte(errorPage), 0600)
w := httptest.NewRecorder()
h := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
@ -57,7 +57,7 @@ func TestIfErrorPageIsIgnoredInDevelopment(t *testing.T) {
dir := t.TempDir()
errorPage := "ERROR"
ioutil.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0600)
os.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0600)
w := httptest.NewRecorder()
serverError := "Interesting Server Error"
@ -76,7 +76,7 @@ func TestIfErrorPageIsIgnoredIfCustomError(t *testing.T) {
dir := t.TempDir()
errorPage := "ERROR"
ioutil.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0600)
os.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0600)
w := httptest.NewRecorder()
serverError := "Interesting Server Error"
@ -107,7 +107,7 @@ func TestErrorPageInterceptedByContentType(t *testing.T) {
dir := t.TempDir()
errorPage := "ERROR"
ioutil.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0600)
os.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0600)
w := httptest.NewRecorder()
serverError := "Interesting Server Error"

View File

@ -3,9 +3,9 @@ package staticpages
import (
"bytes"
"compress/gzip"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
@ -64,7 +64,7 @@ func TestServingTheActualFile(t *testing.T) {
httpRequest, _ := http.NewRequest("GET", "/file", nil)
fileContent := "STATIC"
ioutil.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600)
os.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600)
w := httptest.NewRecorder()
st := &Static{DocumentRoot: dir}
@ -127,8 +127,8 @@ func testServingThePregzippedFile(t *testing.T, enableGzip bool) {
fileGzip.Write([]byte(fileContent))
fileGzip.Close()
ioutil.WriteFile(filepath.Join(dir, "file.gz"), fileGzipContent.Bytes(), 0600)
ioutil.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600)
os.WriteFile(filepath.Join(dir, "file.gz"), fileGzipContent.Bytes(), 0600)
os.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600)
w := httptest.NewRecorder()
st := &Static{DocumentRoot: dir}

View File

@ -4,7 +4,7 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"strings"
"sync"
@ -49,10 +49,10 @@ var (
func init() {
var err error
if GitalyReceivePackResponseMock, err = ioutil.ReadFile(path.Join(RootDir(), "testdata/receive-pack-fixture.txt")); err != nil {
if GitalyReceivePackResponseMock, err = os.ReadFile(path.Join(RootDir(), "testdata/receive-pack-fixture.txt")); err != nil {
log.WithError(err).Fatal("Unable to read pack response")
}
if GitalyUploadPackResponseMock, err = ioutil.ReadFile(path.Join(RootDir(), "testdata/upload-pack-fixture.txt")); err != nil {
if GitalyUploadPackResponseMock, err = os.ReadFile(path.Join(RootDir(), "testdata/upload-pack-fixture.txt")); err != nil {
log.WithError(err).Fatal("Unable to read pack response")
}
}

View File

@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
@ -121,7 +120,7 @@ func RootDir() string {
func LoadFile(t *testing.T, filePath string) string {
t.Helper()
content, err := ioutil.ReadFile(path.Join(RootDir(), filePath))
content, err := os.ReadFile(path.Join(RootDir(), filePath))
require.NoError(t, err)
return string(content)
}
@ -129,7 +128,7 @@ func LoadFile(t *testing.T, filePath string) string {
func ReadAll(t *testing.T, r io.Reader) []byte {
t.Helper()
b, err := ioutil.ReadAll(r)
b, err := io.ReadAll(r)
require.NoError(t, err)
return b
}
@ -176,7 +175,7 @@ func SetupStaticFileHelper(t *testing.T, fpath, content, directory string) strin
require.NoError(t, os.MkdirAll(path.Join(absDocumentRoot, path.Dir(fpath)), 0755), "create document root")
staticFile := path.Join(absDocumentRoot, fpath)
require.NoError(t, ioutil.WriteFile(staticFile, []byte(content), 0666), "write file content")
require.NoError(t, os.WriteFile(staticFile, []byte(content), 0666), "write file content")
return absDocumentRoot
}

View File

@ -6,10 +6,11 @@ import (
"crypto/md5"
"encoding/hex"
"fmt"
"io/ioutil"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
@ -58,7 +59,7 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) {
tempPath := t.TempDir()
archiveData, md5 := createTestZipArchive(t)
archiveFile, err := ioutil.TempFile(tempPath, "artifact.zip")
archiveFile, err := os.CreateTemp(tempPath, "artifact.zip")
require.NoError(t, err)
_, err = archiveFile.Write(archiveData)
require.NoError(t, err)
@ -69,7 +70,7 @@ func TestUploadHandlerSendingToExternalStorage(t *testing.T) {
storeServerMux.HandleFunc("/url/put", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "PUT", r.Method)
receivedData, err := ioutil.ReadAll(r.Body)
receivedData, err := io.ReadAll(r.Body)
require.NoError(t, err)
require.Equal(t, archiveData, receivedData)

View File

@ -7,7 +7,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/http/httptest"
@ -72,7 +71,7 @@ func testArtifactsUploadServer(t *testing.T, authResponse *api.Response, bodyPro
return
}
_, err := ioutil.ReadFile(r.FormValue("file.path"))
_, err := os.ReadFile(r.FormValue("file.path"))
if err != nil {
t.Fatal("Expected file to be readable")
return
@ -85,7 +84,7 @@ func testArtifactsUploadServer(t *testing.T, authResponse *api.Response, bodyPro
}
if r.FormValue("metadata.path") != "" {
metadata, err := ioutil.ReadFile(r.FormValue("metadata.path"))
metadata, err := os.ReadFile(r.FormValue("metadata.path"))
if err != nil {
t.Fatal("Expected metadata to be readable")
return
@ -96,7 +95,7 @@ func testArtifactsUploadServer(t *testing.T, authResponse *api.Response, bodyPro
return
}
defer gz.Close()
metadata, err = ioutil.ReadAll(gz)
metadata, err = io.ReadAll(gz)
if err != nil {
t.Fatal("Expected metadata to be valid")
return

View File

@ -3,7 +3,6 @@ package upload
import (
"context"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
@ -53,9 +52,6 @@ func Artifacts(myAPI *api.API, h http.Handler, p Preparer) http.Handler {
}
func (a *artifactsUploadProcessor) generateMetadataFromZip(ctx context.Context, file *destination.FileHandler) (*destination.FileHandler, error) {
metaReader, metaWriter := io.Pipe()
defer metaWriter.Close()
metaOpts := &destination.UploadOpts{
LocalTempPath: os.TempDir(),
}
@ -68,24 +64,22 @@ func (a *artifactsUploadProcessor) generateMetadataFromZip(ctx context.Context,
zipMd := exec.CommandContext(ctx, "gitlab-zip-metadata", fileName)
zipMd.Stderr = log.ContextLogger(ctx).Writer()
zipMd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
zipMd.Stdout = metaWriter
zipMdOut, err := zipMd.StdoutPipe()
if err != nil {
return nil, err
}
defer zipMdOut.Close()
if err := zipMd.Start(); err != nil {
return nil, err
}
defer helper.CleanUpProcessGroup(zipMd)
type saveResult struct {
error
*destination.FileHandler
fh, err := destination.Upload(ctx, zipMdOut, -1, "metadata.gz", metaOpts)
if err != nil {
return nil, err
}
done := make(chan saveResult)
go func() {
var result saveResult
result.FileHandler, result.error = destination.Upload(ctx, metaReader, -1, "metadata.gz", metaOpts)
done <- result
}()
if err := zipMd.Wait(); err != nil {
st, ok := helper.ExitStatus(err)
@ -105,9 +99,7 @@ func (a *artifactsUploadProcessor) generateMetadataFromZip(ctx context.Context,
}
}
metaWriter.Close()
result := <-done
return result.FileHandler, result.error
return fh, nil
}
func (a *artifactsUploadProcessor) ProcessFile(ctx context.Context, formName string, file *destination.FileHandler, writer *multipart.Writer) error {

View File

@ -2,7 +2,7 @@ package upload
import (
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"strings"
@ -42,7 +42,7 @@ func RequestBody(rails PreAuthorizer, h http.Handler, p Preparer) http.Handler {
// Hijack body
body := data.Encode()
r.Body = ioutil.NopCloser(strings.NewReader(body))
r.Body = io.NopCloser(strings.NewReader(body))
r.ContentLength = int64(len(body))
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")

View File

@ -3,7 +3,6 @@ package upload
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
@ -32,7 +31,7 @@ func TestRequestBody(t *testing.T) {
resp := testUpload(&rails{}, &alwaysLocalPreparer{}, echoProxy(t, fileLen), body)
require.Equal(t, http.StatusOK, resp.StatusCode)
uploadEcho, err := ioutil.ReadAll(resp.Body)
uploadEcho, err := io.ReadAll(resp.Body)
require.NoError(t, err, "Can't read response body")
require.Equal(t, fileContent, string(uploadEcho))
@ -44,7 +43,7 @@ func TestRequestBodyCustomPreparer(t *testing.T) {
resp := testUpload(&rails{}, &alwaysLocalPreparer{}, echoProxy(t, fileLen), body)
require.Equal(t, http.StatusOK, resp.StatusCode)
uploadEcho, err := ioutil.ReadAll(resp.Body)
uploadEcho, err := io.ReadAll(resp.Body)
require.NoError(t, err, "Can't read response body")
require.Equal(t, fileContent, string(uploadEcho))
}

View File

@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strconv"
"time"
@ -226,7 +225,7 @@ func (fh *FileHandler) newLocalFile(ctx context.Context, opts *UploadOpts) (cons
return nil, fmt.Errorf("newLocalFile: mkdir %q: %v", opts.LocalTempPath, err)
}
file, err := ioutil.TempFile(opts.LocalTempPath, "gitlab-workhorse-upload")
file, err := os.CreateTemp(opts.LocalTempPath, "gitlab-workhorse-upload")
if err != nil {
return nil, fmt.Errorf("newLocalFile: create file: %v", err)
}

View File

@ -2,7 +2,6 @@ package filestore
import (
"context"
"io/ioutil"
"os"
"strings"
"testing"
@ -12,7 +11,7 @@ import (
)
func TestConsume(t *testing.T) {
f, err := ioutil.TempFile("", "filestore-local-file")
f, err := os.CreateTemp("", "filestore-local-file")
if f != nil {
defer os.Remove(f.Name())
}
@ -32,7 +31,7 @@ func TestConsume(t *testing.T) {
require.NoError(t, err)
require.Equal(t, int64(len(content)), n)
consumedContent, err := ioutil.ReadFile(f.Name())
consumedContent, err := os.ReadFile(f.Name())
require.NoError(t, err)
require.Equal(t, content, string(consumedContent))
}

View File

@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
@ -66,7 +65,7 @@ func (m *Multipart) Upload(ctx context.Context, r io.Reader) error {
}
}
n, err := io.Copy(ioutil.Discard, r)
n, err := io.Copy(io.Discard, r)
if err != nil {
return fmt.Errorf("drain pipe: %v", err)
}
@ -93,7 +92,7 @@ func (m *Multipart) Delete() {
}
func (m *Multipart) readAndUploadOnePart(ctx context.Context, partURL string, putHeaders map[string]string, src io.Reader, partNumber int) (*completeMultipartUploadPart, error) {
file, err := ioutil.TempFile("", "part-buffer")
file, err := os.CreateTemp("", "part-buffer")
if err != nil {
return nil, fmt.Errorf("create temporary buffer file: %v", err)
}

View File

@ -2,7 +2,7 @@ package objectstore_test
import (
"context"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"strings"
@ -22,7 +22,7 @@ func TestMultipartUploadWithUpcaseETags(t *testing.T) {
var putCnt, postCnt int
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := ioutil.ReadAll(r.Body)
_, err := io.ReadAll(r.Body)
require.NoError(t, err)
defer r.Body.Close()

View File

@ -4,7 +4,6 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"gitlab.com/gitlab-org/labkit/mask"
@ -53,7 +52,7 @@ func newObject(putURL, deleteURL string, putHeaders map[string]string, size int6
func (o *Object) Upload(ctx context.Context, r io.Reader) error {
// we should prevent pr.Close() otherwise it may shadow error set with pr.CloseWithError(err)
req, err := http.NewRequest(http.MethodPut, o.putURL, ioutil.NopCloser(r))
req, err := http.NewRequest(http.MethodPut, o.putURL, io.NopCloser(r))
if err != nil {
return fmt.Errorf("PUT %q: %v", mask.URL(o.putURL), err)

View File

@ -6,7 +6,6 @@ import (
"encoding/xml"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"strconv"
@ -207,7 +206,7 @@ func (o *ObjectstoreStub) completeMultipartUpload(w http.ResponseWriter, r *http
return
}
buf, err := ioutil.ReadAll(r.Body)
buf, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), 500)
return

View File

@ -1,7 +1,6 @@
package test
import (
"io/ioutil"
"net/http/httptest"
"os"
"strings"
@ -76,7 +75,7 @@ func S3ObjectExists(t *testing.T, sess *session.Session, config config.S3Config,
require.NoError(t, err)
require.Equal(t, int64(len(expectedBytes)), numBytes)
output, err := ioutil.ReadFile(tmpfile.Name())
output, err := os.ReadFile(tmpfile.Name())
require.NoError(t, err)
require.Equal(t, []byte(expectedBytes), output)
@ -126,7 +125,7 @@ func S3ObjectDoesNotExist(t *testing.T, sess *session.Session, config config.S3C
func downloadObject(t *testing.T, sess *session.Session, config config.S3Config, objectName string, handler func(tmpfile *os.File, numBytes int64, err error)) {
tmpDir := t.TempDir()
tmpfile, err := ioutil.TempFile(tmpDir, "s3-output")
tmpfile, err := os.CreateTemp(tmpDir, "s3-output")
require.NoError(t, err)
downloadSvc := s3manager.NewDownloader(sess)

View File

@ -2,7 +2,7 @@ package destination
import (
"fmt"
"io/ioutil"
"io"
"strings"
"testing"
"testing/iotest"
@ -19,7 +19,7 @@ func TestHardLimitReader(t *testing.T) {
},
)
out, err := ioutil.ReadAll(r)
out, err := io.ReadAll(r)
require.NoError(t, err)
require.Equal(t, text, string(out))
}

View File

@ -3,7 +3,6 @@ package exif
import (
"context"
"io"
"io/ioutil"
"os"
"strings"
"testing"
@ -75,7 +74,7 @@ func TestNewCleanerWithValidFile(t *testing.T) {
cleaner, err := NewCleaner(ctx, input)
require.NoError(t, err, "Expected no error when creating cleaner command")
size, err := io.Copy(ioutil.Discard, cleaner)
size, err := io.Copy(io.Discard, cleaner)
require.NoError(t, err, "Expected no error when reading output")
sizeAfterStrip := int64(25399)
@ -89,7 +88,7 @@ func TestNewCleanerWithInvalidFile(t *testing.T) {
cleaner, err := NewCleaner(ctx, strings.NewReader("invalid image"))
require.NoError(t, err, "Expected no error when creating cleaner command")
size, err := io.Copy(ioutil.Discard, cleaner)
size, err := io.Copy(io.Discard, cleaner)
require.Error(t, err, "Expected error when reading output")
require.Equal(t, int64(0), size, "Size of invalid image should be 0")
}
@ -103,7 +102,7 @@ func TestNewCleanerReadingAfterEOF(t *testing.T) {
cleaner, err := NewCleaner(ctx, input)
require.NoError(t, err, "Expected no error when creating cleaner command")
_, err = io.Copy(ioutil.Discard, cleaner)
_, err = io.Copy(io.Discard, cleaner)
require.NoError(t, err, "Expected no error when reading output")
buf := make([]byte, 1)

View File

@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"mime"
"mime/multipart"
"net/http"
@ -165,7 +164,7 @@ func (rew *rewriter) handleFilePart(r *http.Request, name string, p *multipart.P
return err
}
} else {
inputReader = ioutil.NopCloser(p)
inputReader = io.NopCloser(p)
}
defer inputReader.Close()
@ -196,7 +195,7 @@ func (rew *rewriter) handleFilePart(r *http.Request, name string, p *multipart.P
}
func handleExifUpload(ctx context.Context, r io.Reader, filename string, imageType exif.FileType) (io.ReadCloser, error) {
tmpfile, err := ioutil.TempFile("", "exifremove")
tmpfile, err := os.CreateTemp("", "exifremove")
if err != nil {
return nil, err
}
@ -265,7 +264,7 @@ func isTIFF(r io.Reader) bool {
func isJPEG(r io.Reader) bool {
// Only the first 512 bytes are used to sniff the content type.
buf, err := ioutil.ReadAll(io.LimitReader(r, 512))
buf, err := io.ReadAll(io.LimitReader(r, 512))
if err != nil {
return false
}

View File

@ -4,7 +4,7 @@ import (
"bytes"
"context"
"fmt"
"io/ioutil"
"io"
"mime/multipart"
"net/http"
@ -71,7 +71,7 @@ func interceptMultipartFiles(w http.ResponseWriter, r *http.Request, h http.Hand
writer.Close()
// Hijack the request
r.Body = ioutil.NopCloser(&body)
r.Body = io.NopCloser(&body)
r.ContentLength = int64(body.Len())
r.Header.Set("Content-Type", writer.FormDataContentType())

View File

@ -6,7 +6,6 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/http/httptest"
@ -55,7 +54,7 @@ func TestUploadHandlerForwardingRawData(t *testing.T) {
ts := testhelper.TestServerWithHandler(regexp.MustCompile(`/url/path\z`), func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "PATCH", r.Method, "method")
body, err := ioutil.ReadAll(r.Body)
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
require.Equal(t, "REQUEST", string(body), "request body")
@ -130,7 +129,7 @@ func TestUploadHandlerRewritingMultiPartData(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
httpRequest = httpRequest.WithContext(ctx)
httpRequest.Body = ioutil.NopCloser(&buffer)
httpRequest.Body = io.NopCloser(&buffer)
httpRequest.ContentLength = int64(buffer.Len())
httpRequest.Header.Set("Content-Type", writer.FormDataContentType())
response := httptest.NewRecorder()
@ -419,7 +418,7 @@ func TestContentDispositionRewrite(t *testing.T) {
}
func TestUploadHandlerRemovingExif(t *testing.T) {
content, err := ioutil.ReadFile("exif/testdata/sample_exif.jpg")
content, err := os.ReadFile("exif/testdata/sample_exif.jpg")
require.NoError(t, err)
runUploadTest(t, content, "sample_exif.jpg", 200, func(w http.ResponseWriter, r *http.Request) {
@ -437,7 +436,7 @@ func TestUploadHandlerRemovingExif(t *testing.T) {
}
func TestUploadHandlerRemovingExifTiff(t *testing.T) {
content, err := ioutil.ReadFile("exif/testdata/sample_exif.tiff")
content, err := os.ReadFile("exif/testdata/sample_exif.tiff")
require.NoError(t, err)
runUploadTest(t, content, "sample_exif.tiff", 200, func(w http.ResponseWriter, r *http.Request) {
@ -455,14 +454,14 @@ func TestUploadHandlerRemovingExifTiff(t *testing.T) {
}
func TestUploadHandlerRemovingExifInvalidContentType(t *testing.T) {
content, err := ioutil.ReadFile("exif/testdata/sample_exif_invalid.jpg")
content, err := os.ReadFile("exif/testdata/sample_exif_invalid.jpg")
require.NoError(t, err)
runUploadTest(t, content, "sample_exif_invalid.jpg", 200, func(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(100000)
require.NoError(t, err)
output, err := ioutil.ReadFile(r.FormValue("file.path"))
output, err := os.ReadFile(r.FormValue("file.path"))
require.NoError(t, err)
require.Equal(t, content, output, "Expected the file to be same as before")
@ -472,7 +471,7 @@ func TestUploadHandlerRemovingExifInvalidContentType(t *testing.T) {
}
func TestUploadHandlerRemovingExifCorruptedFile(t *testing.T) {
content, err := ioutil.ReadFile("exif/testdata/sample_exif_corrupted.jpg")
content, err := os.ReadFile("exif/testdata/sample_exif_corrupted.jpg")
require.NoError(t, err)
runUploadTest(t, content, "sample_exif_corrupted.jpg", 422, func(w http.ResponseWriter, r *http.Request) {

View File

@ -4,7 +4,7 @@ import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"testing"
@ -20,7 +20,7 @@ func TestGzipEncoding(t *testing.T) {
fmt.Fprint(w, "test")
w.Close()
body := ioutil.NopCloser(&b)
body := io.NopCloser(&b)
req, err := http.NewRequest("POST", "http://address/test", body)
require.NoError(t, err)
@ -38,7 +38,7 @@ func TestNoEncoding(t *testing.T) {
resp := httptest.NewRecorder()
var b bytes.Buffer
body := ioutil.NopCloser(&b)
body := io.NopCloser(&b)
req, err := http.NewRequest("POST", "http://address/test", body)
require.NoError(t, err)

View File

@ -4,7 +4,7 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"net/url"
@ -86,7 +86,7 @@ func testNewBackendRoundTripper(t *testing.T, ts *httptest.Server, tlsClientConf
require.NoError(t, err, "perform roundtrip")
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
body, err := io.ReadAll(response.Body)
require.NoError(t, err)
require.Equal(t, expectedResponseBody, string(body))

View File

@ -3,7 +3,6 @@ package upstream
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
@ -287,7 +286,7 @@ func runTestCases(t *testing.T, ws *httptest.Server, testCases []testCase) {
require.NoError(t, err)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, 200, resp.StatusCode, "response code")

View File

@ -15,13 +15,13 @@ package main
import (
"fmt"
"io/ioutil"
"os"
svg "github.com/h2non/go-is-svg"
)
func main() {
buf, err := ioutil.ReadFile("_example/example.svg")
buf, err := os.ReadFile("_example/example.svg")
if err != nil {
fmt.Printf("Error: %s\n", err)
return

View File

@ -6,7 +6,6 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"os"
"testing"
@ -41,7 +40,7 @@ func validateMetadata(r io.Reader) error {
return err
}
meta, err := ioutil.ReadAll(gz)
meta, err := io.ReadAll(gz)
if err != nil {
return err
}
@ -59,7 +58,7 @@ func validateMetadata(r io.Reader) error {
func TestGenerateZipMetadataFromFile(t *testing.T) {
var metaBuffer bytes.Buffer
f, err := ioutil.TempFile("", "workhorse-metadata.zip-")
f, err := os.CreateTemp("", "workhorse-metadata.zip-")
if f != nil {
defer os.Remove(f.Name())
}
@ -84,7 +83,7 @@ func TestGenerateZipMetadataFromFile(t *testing.T) {
}
func TestErrNotAZip(t *testing.T) {
f, err := ioutil.TempFile("", "workhorse-metadata.zip-")
f, err := os.CreateTemp("", "workhorse-metadata.zip-")
if f != nil {
defer os.Remove(f.Name())
}

View File

@ -3,7 +3,6 @@ package main
import (
"fmt"
"io"
"io/ioutil"
goLog "log"
"os"
@ -28,7 +27,7 @@ func startLogging(file string, format string) (io.Closer, error) {
switch format {
case noneLogType:
return logkit.Initialize(logkit.WithWriter(ioutil.Discard))
return logkit.Initialize(logkit.WithWriter(io.Discard))
case jsonLogFormat:
return logkit.Initialize(
logkit.WithOutputName(file),
@ -53,7 +52,7 @@ func startLogging(file string, format string) (io.Closer, error) {
// In text format, we use a separate logger for access logs
func getAccessLogger(file string, format string) (*log.Logger, io.Closer, error) {
if format != "text" {
return log.StandardLogger(), ioutil.NopCloser(nil), nil
return log.StandardLogger(), io.NopCloser(nil), nil
}
if file == "" {

View File

@ -4,7 +4,6 @@ import (
"context"
"flag"
"fmt"
"io/ioutil"
"net"
"net/http"
_ "net/http/pprof"
@ -137,7 +136,7 @@ func buildConfig(arg0 string, args []string) (*bootConfig, *config.Config, error
tomlData := ""
if *configFile != "" {
buf, err := ioutil.ReadFile(*configFile)
buf, err := os.ReadFile(*configFile)
if err != nil {
return nil, nil, fmt.Errorf("configFile: %v", err)
}

View File

@ -8,7 +8,6 @@ import (
"fmt"
"image/png"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
@ -307,7 +306,7 @@ func TestGzipAssets(t *testing.T) {
resp, err := http.DefaultTransport.RoundTrip(req)
require.NoError(t, err, desc)
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
b, err := io.ReadAll(resp.Body)
require.NoError(t, err, desc)
require.Equal(t, 200, resp.StatusCode, "%s: status code", desc)
@ -366,7 +365,7 @@ func TestAltDocumentAssets(t *testing.T) {
resp, err := http.DefaultTransport.RoundTrip(req)
require.NoError(t, err)
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
b, err := io.ReadAll(resp.Body)
require.NoError(t, err)
if tc.content != "" {
@ -412,7 +411,7 @@ func doSendDataRequest(path string, command, literalJSON string) (*http.Response
}
defer resp.Body.Close()
bodyData, err := ioutil.ReadAll(resp.Body)
bodyData, err := io.ReadAll(resp.Body)
if err != nil {
return resp, nil, err
}
@ -574,7 +573,7 @@ func TestAPIFalsePositivesAreProxied(t *testing.T) {
require.NoError(t, err, "%s %q", tc.method, tc.path)
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
respBody, err := io.ReadAll(resp.Body)
require.NoError(t, err, "%s %q: reading body", tc.method, tc.path)
require.Equal(t, 200, resp.StatusCode, "%s %q: status code", tc.method, tc.path)
@ -833,7 +832,7 @@ func httpGet(t *testing.T, url string, headers map[string]string) (*http.Respons
require.NoError(t, err)
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
b, err := io.ReadAll(resp.Body)
require.NoError(t, err)
return resp, string(b)

View File

@ -3,7 +3,7 @@ package main
import (
"bytes"
"fmt"
"io/ioutil"
"io"
"net"
"net/http"
"net/http/httptest"
@ -51,7 +51,7 @@ func TestProxyRequest(t *testing.T) {
"expect Gitlab-Workhorse-Proxy-Start to start with 1",
)
body, err := ioutil.ReadAll(r.Body)
body, err := io.ReadAll(r.Body)
require.NoError(t, err, "read body")
require.Equal(t, "REQUEST", string(body), "body contents")

View File

@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"mime"
"net/http"
"os"
@ -53,14 +53,14 @@ func allowedXSendfileDownload(t *testing.T, contentFilename string, filePath str
require.NoError(t, os.MkdirAll(cacheDir, 0755))
contentBytes := []byte("content")
require.NoError(t, ioutil.WriteFile(contentPath, contentBytes, 0644))
require.NoError(t, os.WriteFile(contentPath, contentBytes, 0644))
resp, err := http.Get(fmt.Sprintf("%s/%s", ws.URL, filePath))
require.NoError(t, err)
requireAttachmentName(t, resp, contentFilename)
actual, err := ioutil.ReadAll(resp.Body)
actual, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.NoError(t, resp.Body.Close())
@ -89,7 +89,7 @@ func deniedXSendfileDownload(t *testing.T, contentFilename string, filePath stri
requireAttachmentName(t, resp, contentFilename)
actual, err := ioutil.ReadAll(resp.Body)
actual, err := io.ReadAll(resp.Body)
require.NoError(t, err, "read body")
require.NoError(t, resp.Body.Close())

View File

@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/http/httptest"
@ -345,7 +344,7 @@ func TestLfsUpload(t *testing.T) {
require.Equal(t, oid, r.Form.Get("file.sha256"), "Invalid SHA256 populated")
require.Equal(t, strconv.Itoa(len(reqBody)), r.Form.Get("file.size"), "Invalid size populated")
tempfile, err := ioutil.ReadFile(r.Form.Get("file.path"))
tempfile, err := os.ReadFile(r.Form.Get("file.path"))
require.NoError(t, err)
require.Equal(t, reqBody, string(tempfile), "Temporary file has the wrong body")
@ -369,7 +368,7 @@ func TestLfsUpload(t *testing.T) {
require.NoError(t, err)
defer resp.Body.Close()
rspData, err := ioutil.ReadAll(resp.Body)
rspData, err := io.ReadAll(resp.Body)
require.NoError(t, err)
// Expect the (eventual) response to be proxied through, untouched
@ -431,7 +430,7 @@ func TestLfsUploadRouting(t *testing.T) {
require.NoError(t, err)
defer resp.Body.Close()
rspData, err := ioutil.ReadAll(resp.Body)
rspData, err := io.ReadAll(resp.Body)
require.NoError(t, err)
if tc.match {
@ -470,7 +469,7 @@ func packageUploadTestServer(t *testing.T, method string, resource string, reqBo
require.Equal(t, len, r.Form.Get("file.size"), "Invalid size populated")
tmpFilePath := r.Form.Get("file.path")
fileData, err := ioutil.ReadFile(tmpFilePath)
fileData, err := os.ReadFile(tmpFilePath)
defer os.Remove(tmpFilePath)
require.NoError(t, err)
@ -499,7 +498,7 @@ func testPackageFileUpload(t *testing.T, method string, resource string) {
resp, err := http.DefaultClient.Do(req)
require.NoError(t, err)
respData, err := ioutil.ReadAll(resp.Body)
respData, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, rspBody, string(respData), "Temporary file has the wrong body")
defer resp.Body.Close()