Commit 77004fe8 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'ce-to-ee' into 'master'

CE upstream: Thursday

Closes gitaly#689 et gitlab-ce#39513

See merge request gitlab-org/gitlab-ee!3250
parents 97cffea7 5477331b
## Contributor license agreement ## Developer Certificate of Origin + License
By submitting code as an individual you agree to the By contributing to GitLab B.V., You accept and agree to the following terms and
[individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md). conditions for Your present and future Contributions submitted to GitLab B.V.
By submitting code as an entity you agree to the Except for the license granted herein to GitLab B.V. and recipients of software
[corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md). distributed by GitLab B.V., You reserve all right, title, and interest in and to
Your Contributions. All Contributions are subject to the following DCO + License
terms.
[DCO + License](https://gitlab.com/gitlab-org/dco/blob/master/README.md)
_This notice should stay as the first item in the CONTRIBUTING.md file._ _This notice should stay as the first item in the CONTRIBUTING.md file._
......
...@@ -316,7 +316,7 @@ GEM ...@@ -316,7 +316,7 @@ GEM
mime-types (>= 1.16) mime-types (>= 1.16)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab-license (1.0.0) gitlab-license (1.0.0)
gitlab-markup (1.6.2) gitlab-markup (1.6.3)
gitlab_omniauth-ldap (2.0.4) gitlab_omniauth-ldap (2.0.4)
net-ldap (~> 0.16) net-ldap (~> 0.16)
omniauth (~> 1.3) omniauth (~> 1.3)
......
...@@ -46,8 +46,13 @@ import './board_new_form'; ...@@ -46,8 +46,13 @@ import './board_new_form';
currentPage() { currentPage() {
return this.state.currentPage; return this.state.currentPage;
}, },
reload() { reload: {
return this.state.reload; get() {
return this.state.reload;
},
set(newValue) {
this.state.reload = newValue;
},
}, },
board() { board() {
return this.state.currentBoard; return this.state.currentBoard;
......
...@@ -4,6 +4,7 @@ import _ from 'underscore'; ...@@ -4,6 +4,7 @@ import _ from 'underscore';
import d3 from 'd3'; import d3 from 'd3';
import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph'; import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph';
import ContributorsStatGraphUtil from './stat_graph_contributors_util'; import ContributorsStatGraphUtil from './stat_graph_contributors_util';
import { n__ } from '../locale';
export default (function() { export default (function() {
function ContributorsStatGraph() {} function ContributorsStatGraph() {}
...@@ -44,7 +45,7 @@ export default (function() { ...@@ -44,7 +45,7 @@ export default (function() {
commits = $('<span/>', { commits = $('<span/>', {
"class": 'graph-author-commits-count' "class": 'graph-author-commits-count'
}); });
commits.text(author.commits + " commits"); commits.text(n__('%d commit', '%d commits', author.commits));
return $('<span/>').append(commits); return $('<span/>').append(commits);
}; };
......
/* eslint-disable one-export, one-var, one-var-declaration-per-line */
import _ from 'underscore'; import _ from 'underscore';
export const placeholderImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; export const placeholderImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
...@@ -21,7 +19,10 @@ export default class LazyLoader { ...@@ -21,7 +19,10 @@ export default class LazyLoader {
} }
searchLazyImages() { searchLazyImages() {
this.lazyImages = [].slice.call(document.querySelectorAll('.lazy')); this.lazyImages = [].slice.call(document.querySelectorAll('.lazy'));
this.checkElementsInView();
if (this.lazyImages.length) {
this.checkElementsInView();
}
} }
startContentObserver() { startContentObserver() {
const contentNode = document.querySelector(this.observerNode) || document.querySelector('body'); const contentNode = document.querySelector(this.observerNode) || document.querySelector('body');
...@@ -45,15 +46,13 @@ export default class LazyLoader { ...@@ -45,15 +46,13 @@ export default class LazyLoader {
checkElementsInView() { checkElementsInView() {
const scrollTop = pageYOffset; const scrollTop = pageYOffset;
const visHeight = scrollTop + innerHeight + SCROLL_THRESHOLD; const visHeight = scrollTop + innerHeight + SCROLL_THRESHOLD;
let imgBoundRect, imgTop, imgBound;
// Loading Images which are in the current viewport or close to them // Loading Images which are in the current viewport or close to them
this.lazyImages = this.lazyImages.filter((selectedImage) => { this.lazyImages = this.lazyImages.filter((selectedImage) => {
if (selectedImage.getAttribute('data-src')) { if (selectedImage.getAttribute('data-src')) {
imgBoundRect = selectedImage.getBoundingClientRect(); const imgBoundRect = selectedImage.getBoundingClientRect();
const imgTop = scrollTop + imgBoundRect.top;
imgTop = scrollTop + imgBoundRect.top; const imgBound = imgTop + imgBoundRect.height;
imgBound = imgTop + imgBoundRect.height;
if (scrollTop < imgBound && visHeight > imgTop) { if (scrollTop < imgBound && visHeight > imgTop) {
LazyLoader.loadImage(selectedImage); LazyLoader.loadImage(selectedImage);
......
...@@ -122,7 +122,9 @@ ...@@ -122,7 +122,9 @@
// we need to do this to prevent noteForm inconsistent content warning // we need to do this to prevent noteForm inconsistent content warning
// this is something we intentionally do so we need to recover the content // this is something we intentionally do so we need to recover the content
this.note.note = noteText; this.note.note = noteText;
this.$refs.noteBody.$refs.noteForm.note = noteText; // TODO: This could be better if (this.$refs.noteBody) {
this.$refs.noteBody.$refs.noteForm.note = noteText; // TODO: This could be better
}
}, },
}, },
created() { created() {
......
...@@ -98,7 +98,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`), ...@@ -98,7 +98,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
@toggle="toggleOpen" @toggle="toggleOpen"
@submit="onSubmit"> @submit="onSubmit">
<template slot="body" scope="props"> <template slot="body" slot-scope="props">
<p v-html="props.text"></p> <p v-html="props.text"></p>
<form <form
......
...@@ -23,11 +23,16 @@ ...@@ -23,11 +23,16 @@
@include webkit-prefix(animation-duration, 2s); @include webkit-prefix(animation-duration, 2s);
} }
&.spin { &.spin-cw {
transform-origin: center; transform-origin: center;
animation: spin 4s linear infinite; animation: spin 4s linear infinite;
} }
&.spin-ccw {
transform-origin: center;
animation: spin 4s linear infinite reverse;
}
&.flipOutX, &.flipOutX,
&.flipOutY, &.flipOutY,
&.bounceIn, &.bounceIn,
......
...@@ -209,7 +209,6 @@ ...@@ -209,7 +209,6 @@
padding: 24px 0 0; padding: 24px 0 0;
.nav-links { .nav-links {
justify-content: center;
width: 100%; width: 100%;
float: none; float: none;
...@@ -217,6 +216,14 @@ ...@@ -217,6 +216,14 @@
float: none; float: none;
} }
} }
li:first-child {
margin-left: auto;
}
li:last-child {
margin-right: auto;
}
} }
.group-info { .group-info {
......
...@@ -50,3 +50,10 @@ ...@@ -50,3 +50,10 @@
font-size: 11px; font-size: 11px;
} }
} }
@media (max-width: $screen-md-max) {
.runners-content {
width: 100%;
overflow: auto;
}
}
...@@ -12,12 +12,7 @@ class Projects::GroupLinksController < Projects::ApplicationController ...@@ -12,12 +12,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
if group if group
return render_404 unless can?(current_user, :read_group, group) return render_404 unless can?(current_user, :read_group, group)
Projects::GroupLinks::CreateService.new(project, current_user, group_link_create_params).execute(group)
project.project_group_links.create(
group: group,
group_access: params[:link_group_access],
expires_at: params[:expires_at]
)
else else
flash[:alert] = 'Please select a group.' flash[:alert] = 'Please select a group.'
end end
...@@ -32,7 +27,9 @@ class Projects::GroupLinksController < Projects::ApplicationController ...@@ -32,7 +27,9 @@ class Projects::GroupLinksController < Projects::ApplicationController
end end
def destroy def destroy
project.project_group_links.find(params[:id]).destroy group_link = project.project_group_links.find(params[:id])
::Projects::GroupLinks::DestroyService.new(project, current_user).execute(group_link)
respond_to do |format| respond_to do |format|
format.html do format.html do
...@@ -47,4 +44,8 @@ class Projects::GroupLinksController < Projects::ApplicationController ...@@ -47,4 +44,8 @@ class Projects::GroupLinksController < Projects::ApplicationController
def group_link_params def group_link_params
params.require(:group_link).permit(:group_access, :expires_at) params.require(:group_link).permit(:group_access, :expires_at)
end end
def group_link_create_params
params.permit(:link_group_access, :expires_at)
end
end end
module Projects
module GroupLinks
class CreateService < BaseService
def execute(group)
return false unless group
project.project_group_links.create(
group: group,
group_access: params[:link_group_access],
expires_at: params[:expires_at]
)
end
end
end
end
module Projects
module GroupLinks
class DestroyService < BaseService
def execute(group_link)
return false unless group_link
group_link.destroy
end
end
end
end
...@@ -52,22 +52,23 @@ ...@@ -52,22 +52,23 @@
%br %br
- if @runners.any? - if @runners.any?
.table-holder .runners-content
%table.table .table-holder
%thead %table.table
%tr %thead
%th Type %tr
%th Runner token %th Type
%th Description %th Runner token
%th Version %th Description
%th Projects %th Version
%th Jobs %th Projects
%th Tags %th Jobs
%th= link_to 'Last contact', admin_runners_path(params.slice(:search).merge(sort: 'contacted_asc')) %th Tags
%th %th Last contact
%th
- @runners.each do |runner| - @runners.each do |runner|
= render "admin/runners/runner", runner: runner = render "admin/runners/runner", runner: runner
= paginate @runners, theme: "gitlab" = paginate @runners, theme: "gitlab"
- else - else
.nothing-here-block No runners found .nothing-here-block No runners found
- @no_container = true - @no_container = true
- page_title "Contributors" - page_title _('Contributors')
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= webpack_bundle_tag('common_d3') = webpack_bundle_tag('common_d3')
= webpack_bundle_tag('graphs') = webpack_bundle_tag('graphs')
...@@ -7,23 +7,23 @@ ...@@ -7,23 +7,23 @@
.js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) } .js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
.sub-header-block .sub-header-block
.tree-ref-holder .tree-ref-holder.inline.vertical-align-middle
= render 'shared/ref_switcher', destination: 'graphs' = render 'shared/ref_switcher', destination: 'graphs'
%ul.breadcrumb.repo-breadcrumb = link_to s_('Commits|History'), project_commits_path(@project, current_ref), class: 'btn'
= commits_breadcrumbs
.loading-graph .loading-graph
.center .center
%h3.page-title %h3.page-title
%i.fa.fa-spinner.fa-spin %i.fa.fa-spinner.fa-spin
Building repository graph. = s_('ContributorsPage|Building repository graph.')
%p.slead Please wait a moment, this page will automatically refresh when ready. %p.slead
= s_('ContributorsPage|Please wait a moment, this page will automatically refresh when ready.')
.stat-graph.hide .stat-graph.hide
.header.clearfix .header.clearfix
%h3#date_header.page-title %h3#date_header.page-title
%p.light %p.light
Commits to #{@ref}, excluding merge commits. Limited to 6,000 commits. = s_('ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits.') % { branch_name: @ref }
%input#brush_change{ :type => "hidden" } %input#brush_change{ :type => "hidden" }
.graphs.row .graphs.row
#contributors-master #contributors-master
......
This diff is collapsed.
...@@ -2,6 +2,10 @@ class UpdateMergeRequestsWorker ...@@ -2,6 +2,10 @@ class UpdateMergeRequestsWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue include DedicatedSidekiqQueue
def metrics_tags
@metrics_tags || {}
end
def perform(project_id, user_id, oldrev, newrev, ref) def perform(project_id, user_id, oldrev, newrev, ref)
project = Project.find_by(id: project_id) project = Project.find_by(id: project_id)
return unless project return unless project
...@@ -9,6 +13,11 @@ class UpdateMergeRequestsWorker ...@@ -9,6 +13,11 @@ class UpdateMergeRequestsWorker
user = User.find_by(id: user_id) user = User.find_by(id: user_id)
return unless user return unless user
@metrics_tags = {
project_id: project_id,
user_id: user_id
}
MergeRequests::RefreshService.new(project, user).execute(oldrev, newrev, ref) MergeRequests::RefreshService.new(project, user).execute(oldrev, newrev, ref)
end end
end end
---
title: Add metric tagging for sidekiq workers
merge_request: 15111
author:
type: added
---
title: Support show-all-refs for git over HTTP
merge_request: 14834
author:
type: added
---
title: 'Support uml:: and captions in reStructuredText'
merge_request: 15120
author: Markus Koller
type: changed
---
title: Fixed user profile activity tab being off-screen on mobile
merge_request:
author:
type: fixed
---
title: Mobile-friendly table on Admin Runners
merge_request:
author: Takuya Noguchi
type: fixed
---
title: Refactor GroupLinksController
merge_request:
author: 15121
type: other
---
title: Disable Unicorn sampling in Sidekiq since there are no Unicorn sockets to monitor
merge_request:
author:
type: performance
---
title: Make contributors page translatable
merge_request: 14915
author:
type: other
...@@ -151,7 +151,9 @@ def instrument_classes(instrumentation) ...@@ -151,7 +151,9 @@ def instrument_classes(instrumentation)
end end
# rubocop:enable Metrics/AbcSize # rubocop:enable Metrics/AbcSize
Gitlab::Metrics::UnicornSampler.initialize_instance(Settings.monitoring.unicorn_sampler_interval).start unless Sidekiq.server?
Gitlab::Metrics::UnicornSampler.initialize_instance(Settings.monitoring.unicorn_sampler_interval).start
end
Gitlab::Application.configure do |config| Gitlab::Application.configure do |config|
# 0 should be Sentry to catch errors in this middleware # 0 should be Sentry to catch errors in this middleware
......
...@@ -56,29 +56,34 @@ that, login with an Admin account and do following: ...@@ -56,29 +56,34 @@ that, login with an Admin account and do following:
With PlantUML integration enabled and configured, we can start adding diagrams to With PlantUML integration enabled and configured, we can start adding diagrams to
our AsciiDoc snippets, wikis and repos using delimited blocks: our AsciiDoc snippets, wikis and repos using delimited blocks:
``` - **Markdown**
[plantuml, format="png", id="myDiagram", width="200px"]
-- ```plantuml
Bob->Alice : hello Bob -> Alice : hello
Alice -> Bob : Go Away Alice -> Bob : Go Away
-- ```
```
And in Markdown using fenced code blocks: - **AsciiDoc**
```plantuml ```
Bob -> Alice : hello [plantuml, format="png", id="myDiagram", width="200px"]
--
Bob->Alice : hello
Alice -> Bob : Go Away Alice -> Bob : Go Away
--
``` ```
And in reStructuredText using a directive: - **reStructuredText**
``` ```
.. plantuml:: .. plantuml::
:caption: Caption with **bold** and *italic*
Bob -> Alice: hello Bob -> Alice: hello
Alice -> Bob: Go Away Alice -> Bob: Go Away
``` ```
You can also use the `uml::` directive for compatibility with [sphinxcontrib-plantuml](https://pypi.python.org/pypi/sphinxcontrib-plantuml), but please note that we currently only support the `caption` option.
The above blocks will be converted to an HTML img tag with source pointing to the The above blocks will be converted to an HTML img tag with source pointing to the
PlantUML instance. If the PlantUML server is correctly configured, this should PlantUML instance. If the PlantUML server is correctly configured, this should
......
...@@ -76,7 +76,7 @@ To migrate your existing projects to the new storage type, check the specific [r ...@@ -76,7 +76,7 @@ To migrate your existing projects to the new storage type, check the specific [r
We are incrementally moving every storable object in GitLab to the Hashed Storage pattern. You can check the current We are incrementally moving every storable object in GitLab to the Hashed Storage pattern. You can check the current
coverage status below. coverage status below.
Not that things stored in S3 compatible endpoint, will not have the downsides mentioned earlier, if they are not Note that things stored in an S3 compatible endpoint will not have the downsides mentioned earlier, if they are not
prefixed with `#{namespace}/#{project_name}`, which is true for CI Cache and LFS Objects. prefixed with `#{namespace}/#{project_name}`, which is true for CI Cache and LFS Objects.
| Storable Object | Legacy Storage | Hashed Storage | S3 Compatible | GitLab Version | | Storable Object | Legacy Storage | Hashed Storage | S3 Compatible | GitLab Version |
......
...@@ -43,7 +43,7 @@ future GitLab releases.** ...@@ -43,7 +43,7 @@ future GitLab releases.**
| **CI_COMMIT_TAG** | 9.0 | 0.5 | The commit tag name. Present only when building tags. | | **CI_COMMIT_TAG** | 9.0 | 0.5 | The commit tag name. Present only when building tags. |
| **CI_CONFIG_PATH** | 9.4 | 0.5 | The path to CI config file. Defaults to `.gitlab-ci.yml` | | **CI_CONFIG_PATH** | 9.4 | 0.5 | The path to CI config file. Defaults to `.gitlab-ci.yml` |
| **CI_DEBUG_TRACE** | all | 1.7 | Whether [debug tracing](#debug-tracing) is enabled | | **CI_DEBUG_TRACE** | all | 1.7 | Whether [debug tracing](#debug-tracing) is enabled |
| **CI_DISPOSABLE_ENVIRONMENT** | all | 10.1 | Mark that job is executed in a disposable environment (something that is created only for this job and disposed of/destroyed after the execution - all executors except `shell` and `ssh`). If the environment is disposable, it is set to true, otherwise it is not defined at all. | | **CI_DISPOSABLE_ENVIRONMENT** | all | 10.1 | Marks that the job is executed in a disposable environment (something that is created only for this job and disposed of/destroyed after the execution - all executors except `shell` and `ssh`). If the environment is disposable, it is set to true, otherwise it is not defined at all. |
| **CI_ENVIRONMENT_NAME** | 8.15 | all | The name of the environment for this job | | **CI_ENVIRONMENT_NAME** | 8.15 | all | The name of the environment for this job |
| **CI_ENVIRONMENT_SLUG** | 8.15 | all | A simplified version of the environment name, suitable for inclusion in DNS, URLs, Kubernetes labels, etc. | | **CI_ENVIRONMENT_SLUG** | 8.15 | all | A simplified version of the environment name, suitable for inclusion in DNS, URLs, Kubernetes labels, etc. |
| **CI_ENVIRONMENT_URL** | 9.3 | all | The URL of the environment for this job | | **CI_ENVIRONMENT_URL** | 9.3 | all | The URL of the environment for this job |
...@@ -75,7 +75,7 @@ future GitLab releases.** ...@@ -75,7 +75,7 @@ future GitLab releases.**
| **CI_SERVER_NAME** | all | all | The name of CI server that is used to coordinate jobs | | **CI_SERVER_NAME** | all | all | The name of CI server that is used to coordinate jobs |
| **CI_SERVER_REVISION** | all | all | GitLab revision that is used to schedule jobs | | **CI_SERVER_REVISION** | all | all | GitLab revision that is used to schedule jobs |
| **CI_SERVER_VERSION** | all | all | GitLab version that is used to schedule jobs | | **CI_SERVER_VERSION** | all | all | GitLab version that is used to schedule jobs |
| **CI_SHARED_ENVIRONMENT** | all | 10.1 | Mark that job is executed in a shared environment (something that is persisted across CI invocations like `shell` or `ssh` executor). If the environment is shared, it is set to true, otherwise it is not defined at all. | | **CI_SHARED_ENVIRONMENT** | all | 10.1 | Marks that the job is executed in a shared environment (something that is persisted across CI invocations like `shell` or `ssh` executor). If the environment is shared, it is set to true, otherwise it is not defined at all. |
| **ARTIFACT_DOWNLOAD_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to download artifacts running a job | | **ARTIFACT_DOWNLOAD_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to download artifacts running a job |
| **GET_SOURCES_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to fetch sources running a job | | **GET_SOURCES_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to fetch sources running a job |
| **GITLAB_CI** | all | all | Mark that job is executed in GitLab CI environment | | **GITLAB_CI** | all | all | Mark that job is executed in GitLab CI environment |
......
...@@ -123,7 +123,7 @@ Existing users using GitLab with MySQL/MariaDB are advised to ...@@ -123,7 +123,7 @@ Existing users using GitLab with MySQL/MariaDB are advised to
### PostgreSQL Requirements ### PostgreSQL Requirements
As of GitLab 10.0, PostgreSQL 9.6 or newer is required, and earlier versions are As of GitLab 10.0, PostgreSQL 9.6 or newer (but less than 10) is required, and earlier versions are
not supported. We highly recommend users to use PostgreSQL 9.6 as this not supported. We highly recommend users to use PostgreSQL 9.6 as this
is the PostgreSQL version used for development and testing. is the PostgreSQL version used for development and testing.
......
# Corporate contributor license agreement This document has been replaced by a Developer Certificate of Origin and License,
as described in [Contributing.md](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md).
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions. \ No newline at end of file
1. Definitions.
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Contribution" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, that is submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
2. Grant of Copyright License.
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
3. Grant of Patent License.
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
4. You represent that You are legally entitled to grant the above license. You represent further that each of Your employees is authorized to submit Contributions on Your behalf, but excluding employees that are designated in writing by You as "Not authorized to submit Contributions on behalf of [name of Your corporation here]." Such designations of exclusion for unauthorized employees are to be submitted via email to legal@gitlab.com.
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others).
6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
8. It is Your responsibility to notify GitLab.com when any change is required to the list of designated employees excluded from submitting Contributions on Your behalf per Section 4. Such notification should be sent via email to legal@gitlab.com.
This text is licensed under the [Creative Commons Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office.
# Individual contributor license agreement This document has been replaced by a Developer Certificate of Origin and License,
as described in [Contributing.md](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md).
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions. \ No newline at end of file
1. Definitions.
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to GitLab B.V., or that your employer has executed a separate Corporate CLA with GitLab B.V..
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.
6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [insert_name_here]".
8. You agree to notify GitLab B.V. of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
This text is licensed under the [Creative Commons Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office.
...@@ -1165,6 +1165,18 @@ From this page, you can repeat delivery with the same data by clicking `Resend R ...@@ -1165,6 +1165,18 @@ From this page, you can repeat delivery with the same data by clicking `Resend R
>**Note:** If URL or secret token of the webhook were updated, data will be delivered to the new address. >**Note:** If URL or secret token of the webhook were updated, data will be delivered to the new address.
### Receiving duplicate or multiple web hook requests triggered by one event
When GitLab sends a webhook it expects a response in 10 seconds (set default value). If it does not receive one, it'll retry the webhook.
If the endpoint doesn't send its HTTP response within those 10 seconds, GitLab may decide the hook failed and retry it.
If you are receiving multiple requests, you can try increasing the default value to wait for the HTTP response after sending the webhook
by uncommenting or adding the following setting to your `/etc/gitlab/gitlab.rb`:
```
gitlab_rails['webhook_timeout'] = 10
```
## Example webhook receiver ## Example webhook receiver
If you want to see GitLab's webhooks in action for testing purposes you can use If you want to see GitLab's webhooks in action for testing purposes you can use
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
module Gitlab module Gitlab
# Checks if a set of migrations requires downtime or not. # Checks if a set of migrations requires downtime or not.
class EeCompatCheck class EeCompatCheck
DEFAULT_CE_REPO = 'https://gitlab.com/gitlab-org/gitlab-ce.git'.freeze DEFAULT_CE_PROJECT_URL = 'https://gitlab.com/gitlab-org/gitlab-ce'.freeze
EE_REPO = 'https://gitlab.com/gitlab-org/gitlab-ee.git'.freeze EE_REPO_URL = 'https://gitlab.com/gitlab-org/gitlab-ee.git'.freeze
CHECK_DIR = Rails.root.join('ee_compat_check') CHECK_DIR = Rails.root.join('ee_compat_check')
IGNORED_FILES_REGEX = /(VERSION|CHANGELOG\.md:\d+)/.freeze IGNORED_FILES_REGEX = /(VERSION|CHANGELOG\.md:\d+)/.freeze
PLEASE_READ_THIS_BANNER = %Q{ PLEASE_READ_THIS_BANNER = %Q{
...@@ -17,14 +17,16 @@ module Gitlab ...@@ -17,14 +17,16 @@ module Gitlab
============================================================\n ============================================================\n
}.freeze }.freeze
attr_reader :ee_repo_dir, :patches_dir, :ce_repo, :ce_branch, :ee_branch_found attr_reader :ee_repo_dir, :patches_dir, :ce_project_url, :ce_repo_url, :ce_branch, :ee_branch_found
attr_reader :failed_files attr_reader :job_id, :failed_files
def initialize(branch:, ce_repo: DEFAULT_CE_REPO) def initialize(branch:, ce_project_url: DEFAULT_CE_PROJECT_URL, job_id: nil)
@ee_repo_dir = CHECK_DIR.join('ee-repo') @ee_repo_dir = CHECK_DIR.join('ee-repo')
@patches_dir = CHECK_DIR.join('patches') @patches_dir = CHECK_DIR.join('patches')
@ce_branch = branch @ce_branch = branch
@ce_repo = ce_repo @ce_project_url = ce_project_url
@ce_repo_url = "#{ce_project_url}.git"
@job_id = job_id
end end
def check def check
...@@ -59,8 +61,8 @@ module Gitlab ...@@ -59,8 +61,8 @@ module Gitlab
step("#{ee_repo_dir} already exists") step("#{ee_repo_dir} already exists")
else else
step( step(
"Cloning #{EE_REPO} into #{ee_repo_dir}", "Cloning #{EE_REPO_URL} into #{ee_repo_dir}",
%W[git clone --branch master --single-branch --depth=200 #{EE_REPO} #{ee_repo_dir}] %W[git clone --branch master --single-branch --depth=200 #{EE_REPO_URL} #{ee_repo_dir}]
) )
end end
end end
...@@ -132,7 +134,7 @@ module Gitlab ...@@ -132,7 +134,7 @@ module Gitlab
def check_patch(patch_path) def check_patch(patch_path)
step("Checking out master", %w[git checkout master]) step("Checking out master", %w[git checkout master])
step("Resetting to latest master", %w[git reset --hard origin/master]) step("Resetting to latest master", %w[git reset --hard origin/master])
step("Fetching CE/#{ce_branch}", %W[git fetch #{ce_repo} #{ce_branch}]) step("Fetching CE/#{ce_branch}", %W[git fetch #{ce_repo_url} #{ce_branch}])
step( step(
"Checking if #{patch_path} applies cleanly to EE/master", "Checking if #{patch_path} applies cleanly to EE/master",
# Don't use --check here because it can result in a 0-exit status even # Don't use --check here because it can result in a 0-exit status even
...@@ -237,7 +239,7 @@ module Gitlab ...@@ -237,7 +239,7 @@ module Gitlab
end end
def patch_url def patch_url
"https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/#{ENV['CI_JOB_ID']}/artifacts/raw/ee_compat_check/patches/#{ce_patch_name}" "#{ce_project_url}/-/jobs/#{job_id}/artifacts/raw/ee_compat_check/patches/#{ce_patch_name}"
end end
def step(desc, cmd = nil) def step(desc, cmd = nil)
...@@ -304,7 +306,7 @@ module Gitlab ...@@ -304,7 +306,7 @@ module Gitlab
# In the EE repo # In the EE repo
$ git fetch origin $ git fetch origin
$ git checkout -b #{ee_branch_prefix} origin/master $ git checkout -b #{ee_branch_prefix} origin/master
$ git fetch #{ce_repo} #{ce_branch} $ git fetch #{ce_repo_url} #{ce_branch}
$ git cherry-pick SHA # Repeat for all the commits you want to pick $ git cherry-pick SHA # Repeat for all the commits you want to pick
You can squash the `#{ce_branch}` commits into a single "Port of #{ce_branch} to EE" commit. You can squash the `#{ce_branch}` commits into a single "Port of #{ce_branch} to EE" commit.
......
...@@ -12,6 +12,12 @@ module Gitlab ...@@ -12,6 +12,12 @@ module Gitlab
# blob data should use load_all_data!. # blob data should use load_all_data!.
MAX_DATA_DISPLAY_SIZE = 10.megabytes MAX_DATA_DISPLAY_SIZE = 10.megabytes
# These limits are used as a heuristic to ignore files which can't be LFS
# pointers. The format of these is described in
# https://github.com/git-lfs/git-lfs/blob/master/docs/spec.md#the-pointer
LFS_POINTER_MIN_SIZE = 120.bytes
LFS_POINTER_MAX_SIZE = 200.bytes
attr_accessor :name, :path, :size, :data, :mode, :id, :commit_id, :loaded_size, :binary attr_accessor :name, :path, :size, :data, :mode, :id, :commit_id, :loaded_size, :binary
class << self class << self
...@@ -30,16 +36,7 @@ module Gitlab ...@@ -30,16 +36,7 @@ module Gitlab
if is_enabled if is_enabled
Gitlab::GitalyClient::BlobService.new(repository).get_blob(oid: sha, limit: MAX_DATA_DISPLAY_SIZE) Gitlab::GitalyClient::BlobService.new(repository).get_blob(oid: sha, limit: MAX_DATA_DISPLAY_SIZE)
else else
blob = repository.lookup(sha) rugged_raw(repository, sha, limit: MAX_DATA_DISPLAY_SIZE)
next unless blob.is_a?(Rugged::Blob)
new(
id: blob.oid,
size: blob.size,
data: blob.content(MAX_DATA_DISPLAY_SIZE),
binary: blob.binary?
)
end end
end end
end end
...@@ -59,10 +56,25 @@ module Gitlab ...@@ -59,10 +56,25 @@ module Gitlab
end end
end end
# Find LFS blobs given an array of sha ids
# Returns array of Gitlab::Git::Blob
# Does not guarantee blob data will be set
def batch_lfs_pointers(repository, blob_ids)
blob_ids.lazy
.select { |sha| possible_lfs_blob?(repository, sha) }
.map { |sha| rugged_raw(repository, sha, limit: LFS_POINTER_MAX_SIZE) }
.select(&:lfs_pointer?)
.force
end
def binary?(data) def binary?(data)
EncodingHelper.detect_libgit2_binary?(data) EncodingHelper.detect_libgit2_binary?(data)
end end
def size_could_be_lfs?(size)
size.between?(LFS_POINTER_MIN_SIZE, LFS_POINTER_MAX_SIZE)
end
private private
# Recursive search of blob id by path # Recursive search of blob id by path
...@@ -167,6 +179,29 @@ module Gitlab ...@@ -167,6 +179,29 @@ module Gitlab
end end
end end
end end
def rugged_raw(repository, sha, limit:)
blob = repository.lookup(sha)
return unless blob.is_a?(Rugged::Blob)
new(
id: blob.oid,
size: blob.size,
data: blob.content(limit),
binary: blob.binary?
)
end
# Efficient lookup to determine if object size
# and type make it a possible LFS blob without loading
# blob content into memory with repository.lookup(sha)
def possible_lfs_blob?(repository, sha)
object_header = repository.rugged.read_header(sha)
object_header[:type] == :blob &&
size_could_be_lfs?(object_header[:len])
end
end end
def initialize(options) def initialize(options)
...@@ -226,7 +261,7 @@ module Gitlab ...@@ -226,7 +261,7 @@ module Gitlab
# size # size
# see https://github.com/github/git-lfs/blob/v1.1.0/docs/spec.md#the-pointer # see https://github.com/github/git-lfs/blob/v1.1.0/docs/spec.md#the-pointer
def lfs_pointer? def lfs_pointer?
has_lfs_version_key? && lfs_oid.present? && lfs_size.present? self.class.size_could_be_lfs?(size) && has_lfs_version_key? && lfs_oid.present? && lfs_size.present?
end end
def lfs_oid def lfs_oid
......
module Gitlab
module Git
class LfsChanges
def initialize(repository, newrev)
@repository = repository
@newrev = newrev
end
def new_pointers(object_limit: nil, not_in: nil)
@new_pointers ||= begin
object_ids = new_objects(not_in: not_in)
object_ids = object_ids.take(object_limit) if object_limit
Gitlab::Git::Blob.batch_lfs_pointers(@repository, object_ids)
end
end
def all_pointers
object_ids = rev_list.all_objects(require_path: true)
Gitlab::Git::Blob.batch_lfs_pointers(@repository, object_ids)
end
private
def new_objects(not_in:)
rev_list.new_objects(require_path: true, lazy: true, not_in: not_in)
end
def rev_list
::Gitlab::Git::RevList.new(path_to_repo: @repository.path_to_repo,
newrev: @newrev)
end
end
end
end
...@@ -290,6 +290,14 @@ module Gitlab ...@@ -290,6 +290,14 @@ module Gitlab
end end
end end
def batch_existence(object_ids, existing: true)
filter_method = existing ? :select : :reject
object_ids.public_send(filter_method) do |oid| # rubocop:disable GitlabSecurity/PublicSend
rugged.exists?(oid)
end
end
# Returns an Array of branch and tag names # Returns an Array of branch and tag names
def ref_names def ref_names
branch_names + tag_names branch_names + tag_names
......
...@@ -13,11 +13,31 @@ module Gitlab ...@@ -13,11 +13,31 @@ module Gitlab
@path_to_repo = path_to_repo @path_to_repo = path_to_repo
end end
# This method returns an array of new references # This method returns an array of new commit references
def new_refs def new_refs
execute([*base_args, newrev, '--not', '--all']) execute([*base_args, newrev, '--not', '--all'])
end end
# Finds newly added objects
# Returns an array of shas
#
# Can skip objects which do not have a path using required_path: true
# This skips commit objects and root trees, which might not be needed when
# looking for blobs
#
# Can return a lazy enumerator to limit work done on megabytes of data
def new_objects(require_path: nil, lazy: false, not_in: nil)
object_output = execute([*base_args, newrev, *not_in_refs(not_in), '--objects'])
objects_from_output(object_output, require_path: require_path, lazy: lazy)
end
def all_objects(require_path: nil)
object_output = execute([*base_args, '--all', '--objects'])
objects_from_output(object_output, require_path: require_path, lazy: true)
end
# This methods returns an array of missed references # This methods returns an array of missed references
# #
# Should become obsolete after https://gitlab.com/gitlab-org/gitaly/issues/348. # Should become obsolete after https://gitlab.com/gitlab-org/gitaly/issues/348.
...@@ -27,6 +47,13 @@ module Gitlab ...@@ -27,6 +47,13 @@ module Gitlab
private private
def not_in_refs(references)
return ['--not', '--all'] unless references
return [] if references.empty?
references.prepend('--not')
end
def execute(args) def execute(args)
output, status = popen(args, nil, Gitlab::Git::Env.to_env_hash) output, status = popen(args, nil, Gitlab::Git::Env.to_env_hash)
...@@ -44,6 +71,22 @@ module Gitlab ...@@ -44,6 +71,22 @@ module Gitlab
'rev-list' 'rev-list'
] ]
end end
def objects_from_output(object_output, require_path: nil, lazy: nil)
objects = object_output.lazy.map do |output_line|
sha, path = output_line.split(' ', 2)
next if require_path && path.blank?
sha
end.reject(&:nil?)
if lazy
objects
else
objects.force
end
end
end end
end end
end end
...@@ -68,11 +68,13 @@ module Gitlab ...@@ -68,11 +68,13 @@ module Gitlab
end end
def file(name, version) def file(name, version)
version ||= self.class.default_ref @repository.gitaly_migrate(:wiki_find_file) do |is_enabled|
gollum_file = gollum_wiki.file(name, version) if is_enabled
return unless gollum_file gitaly_find_file(name, version)
else
Gitlab::Git::WikiFile.new(gollum_file) gollum_find_file(name, version)
end
end
end end
def page_versions(page_path) def page_versions(page_path)
...@@ -156,6 +158,14 @@ module Gitlab ...@@ -156,6 +158,14 @@ module Gitlab
new_page(gollum_page) new_page(gollum_page)
end end
def gollum_find_file(name, version)
version ||= self.class.default_ref
gollum_file = gollum_wiki.file(name, version)
return unless gollum_file
Gitlab::Git::WikiFile.new(gollum_file)
end
def gitaly_write_page(name, format, content, commit_details) def gitaly_write_page(name, format, content, commit_details)
gitaly_wiki_client.write_page(name, format, content, commit_details) gitaly_wiki_client.write_page(name, format, content, commit_details)
end end
...@@ -170,6 +180,13 @@ module Gitlab ...@@ -170,6 +180,13 @@ module Gitlab
Gitlab::Git::WikiPage.new(wiki_page, version) Gitlab::Git::WikiPage.new(wiki_page, version)
end end
def gitaly_find_file(name, version)
wiki_file = gitaly_wiki_client.find_file(name, version)
return unless wiki_file
Gitlab::Git::WikiFile.new(wiki_file)
end
end end
end end
end end
...@@ -18,7 +18,7 @@ module Gitlab ...@@ -18,7 +18,7 @@ module Gitlab
response = GitalyClient.call(@repository.storage, :commit_service, :list_files, request) response = GitalyClient.call(@repository.storage, :commit_service, :list_files, request)
response.flat_map do |msg| response.flat_map do |msg|
msg.paths.map { |d| d.dup.force_encoding(Encoding::UTF_8) } msg.paths.map { |d| EncodingHelper.encode!(d.dup) }
end end
end end
......
module Gitlab
module GitalyClient
class WikiFile
FIELDS = %i(name mime_type path raw_data).freeze
attr_accessor(*FIELDS)
def initialize(params)
params = params.with_indifferent_access
FIELDS.each do |field|
instance_variable_set("@#{field}", params[field])
end
end
end
end
end
...@@ -80,6 +80,32 @@ module Gitlab ...@@ -80,6 +80,32 @@ module Gitlab
[wiki_page, version] [wiki_page, version]
end end
def find_file(name, revision)
request = Gitaly::WikiFindFileRequest.new(
repository: @gitaly_repo,
name: GitalyClient.encode(name),
revision: GitalyClient.encode(revision)
)
response = GitalyClient.call(@repository.storage, :wiki_service, :wiki_find_file, request)
wiki_file = nil
response.each do |message|
next unless message.name.present?
if wiki_file
wiki_file.raw_data << message.raw_data
else
wiki_file = GitalyClient::WikiFile.new(message.to_h)
# All gRPC strings in a response are frozen, so we get
# an unfrozen version here so appending in the else clause below doesn't blow up.
wiki_file.raw_data = wiki_file.raw_data.dup
end
end
wiki_file
end
private private
def gitaly_commit_details(commit_details) def gitaly_commit_details(commit_details)
......
...@@ -11,6 +11,8 @@ module Gitlab ...@@ -11,6 +11,8 @@ module Gitlab
# Old gitlad-shell messages don't provide enqueued_at/created_at attributes # Old gitlad-shell messages don't provide enqueued_at/created_at attributes
trans.set(:sidekiq_queue_duration, Time.now.to_f - (message['enqueued_at'] || message['created_at'] || 0)) trans.set(:sidekiq_queue_duration, Time.now.to_f - (message['enqueued_at'] || message['created_at'] || 0))
trans.run { yield } trans.run { yield }
worker.metrics_tags.each { |tag, value| trans.add_tag(tag, value) } if worker.respond_to?(:metrics_tags)
rescue Exception => error # rubocop: disable Lint/RescueException rescue Exception => error # rubocop: disable Lint/RescueException
trans.add_event(:sidekiq_exception) trans.add_event(:sidekiq_exception)
......
...@@ -16,14 +16,15 @@ module Gitlab ...@@ -16,14 +16,15 @@ module Gitlab
SECRET_LENGTH = 32 SECRET_LENGTH = 32
class << self class << self
def git_http_ok(repository, is_wiki, user, action) def git_http_ok(repository, is_wiki, user, action, show_all_refs: false)
project = repository.project project = repository.project
repo_path = repository.path_to_repo repo_path = repository.path_to_repo
params = { params = {
GL_ID: Gitlab::GlId.gl_id(user), GL_ID: Gitlab::GlId.gl_id(user),
GL_REPOSITORY: Gitlab::GlRepository.gl_repository(project, is_wiki), GL_REPOSITORY: Gitlab::GlRepository.gl_repository(project, is_wiki),
GL_USERNAME: user&.username, GL_USERNAME: user&.username,
RepoPath: repo_path RepoPath: repo_path,
ShowAllRefs: show_all_refs
} }
server = { server = {
address: Gitlab::GitalyClient.address(project.repository_storage), address: Gitlab::GitalyClient.address(project.repository_storage),
......
...@@ -5,10 +5,9 @@ namespace :gitlab do ...@@ -5,10 +5,9 @@ namespace :gitlab do
opts = opts =
if ENV['CI'] if ENV['CI']
{ {
# We don't use CI_REPOSITORY_URL since it includes `gitlab-ci-token:xxxxxxxxxxxxxxxxxxxx@` ce_project_url: ENV['CI_PROJECT_URL'],
# which is confusing in the steps suggested in the job's output. branch: ENV['CI_COMMIT_REF_NAME'],
ce_repo: "#{ENV['CI_PROJECT_URL']}.git", job_id: ENV['CI_JOB_ID']
branch: ENV['CI_COMMIT_REF_NAME']
} }
else else
unless args[:branch] unless args[:branch]
......
...@@ -81,10 +81,15 @@ describe 'User views a wiki page' do ...@@ -81,10 +81,15 @@ describe 'User views a wiki page' do
end end
it 'shows a file stored in a page' do it 'shows a file stored in a page' do
file = Gollum::File.new(project.wiki) gollum_file_double = double('Gollum::File',
mime_type: 'image/jpeg',
allow_any_instance_of(Gollum::Wiki).to receive(:file).with('image.jpg', 'master').and_return(file) name: 'images/image.jpg',
allow_any_instance_of(Gollum::File).to receive(:mime_type).and_return('image/jpeg') path: 'images/image.jpg',
raw_data: '')
wiki_file = Gitlab::Git::WikiFile.new(gollum_file_double)
allow(wiki_file).to receive(:mime_type).and_return('image/jpeg')
allow_any_instance_of(ProjectWiki).to receive(:find_file).with('image.jpg', nil).and_return(wiki_file)
expect(page).to have_xpath('//img[@data-src="image.jpg"]') expect(page).to have_xpath('//img[@data-src="image.jpg"]')
expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/image.jpg") expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/image.jpg")
......
...@@ -431,9 +431,9 @@ describe('AppComponent', () => { ...@@ -431,9 +431,9 @@ describe('AppComponent', () => {
}); });
it('should render groups tree', (done) => { it('should render groups tree', (done) => {
vm.groups = [mockParentGroupItem]; vm.store.state.groups = [mockParentGroupItem];
vm.isLoading = false; vm.isLoading = false;
vm.pageInfo = mockPageInfo; vm.store.state.pageInfo = mockPageInfo;
Vue.nextTick(() => { Vue.nextTick(() => {
expect(vm.$el.querySelector('.groups-list-tree-container')).toBeDefined(); expect(vm.$el.querySelector('.groups-list-tree-container')).toBeDefined();
done(); done();
......
...@@ -106,8 +106,8 @@ describe('Merge Request Code Quality', () => { ...@@ -106,8 +106,8 @@ describe('Merge Request Code Quality', () => {
Vue.nextTick(() => { Vue.nextTick(() => {
expect( expect(
vm.$el.querySelector('.code-quality-container').geAttribute('style'), vm.$el.querySelector('.code-quality-container').getAttribute('style'),
).toEqual(null); ).toEqual('');
expect( expect(
vm.$el.querySelector('button').textContent.trim(), vm.$el.querySelector('button').textContent.trim(),
).toEqual('Collapse'); ).toEqual('Collapse');
...@@ -116,14 +116,15 @@ describe('Merge Request Code Quality', () => { ...@@ -116,14 +116,15 @@ describe('Merge Request Code Quality', () => {
Vue.nextTick(() => { Vue.nextTick(() => {
expect( expect(
vm.$el.querySelector('.code-quality-container').geAttribute('style'), vm.$el.querySelector('.code-quality-container').getAttribute('style'),
).toEqual('display: none;'); ).toEqual('display: none;');
expect( expect(
vm.$el.querySelector('button').textContent.trim(), vm.$el.querySelector('button').textContent.trim(),
).toEqual('Expand'); ).toEqual('Expand');
done();
}); });
}); });
done();
}, 0); }, 0);
}); });
}); });
......
...@@ -42,12 +42,14 @@ describe('Markdown field component', () => { ...@@ -42,12 +42,14 @@ describe('Markdown field component', () => {
beforeEach(() => { beforeEach(() => {
spyOn(Vue.http, 'post').and.callFake(() => new Promise((resolve) => { spyOn(Vue.http, 'post').and.callFake(() => new Promise((resolve) => {
resolve({ setTimeout(() => {
json() { resolve({
return { json() {
body: '<p>markdown preview</p>', return {
}; body: '<p>markdown preview</p>',
}, };
},
});
}); });
})); }));
......
...@@ -143,6 +143,16 @@ describe Gitlab::Git::Blob, seed_helper: true do ...@@ -143,6 +143,16 @@ describe Gitlab::Git::Blob, seed_helper: true do
expect(blob.loaded_size).to eq(blob_size) expect(blob.loaded_size).to eq(blob_size)
end end
end end
context 'when sha references a tree' do
it 'returns nil' do
tree = Gitlab::Git::Commit.find(repository, 'master').tree
blob = Gitlab::Git::Blob.raw(repository, tree.oid)
expect(blob).to be_nil
end
end
end end
describe '.raw' do describe '.raw' do
...@@ -226,6 +236,51 @@ describe Gitlab::Git::Blob, seed_helper: true do ...@@ -226,6 +236,51 @@ describe Gitlab::Git::Blob, seed_helper: true do
end end
end end
describe '.batch_lfs_pointers' do
let(:tree_object) { Gitlab::Git::Commit.find(repository, 'master').tree }
let(:non_lfs_blob) do
Gitlab::Git::Blob.find(
repository,
'master',
'README.md'
)
end
let(:lfs_blob) do
Gitlab::Git::Blob.find(
repository,
'33bcff41c232a11727ac6d660bd4b0c2ba86d63d',
'files/lfs/image.jpg'
)
end
it 'returns a list of Gitlab::Git::Blob' do
blobs = described_class.batch_lfs_pointers(repository, [lfs_blob.id])
expect(blobs.count).to eq(1)
expect(blobs).to all( be_a(Gitlab::Git::Blob) )
end
it 'silently ignores tree objects' do
blobs = described_class.batch_lfs_pointers(repository, [tree_object.oid])
expect(blobs).to eq([])
end
it 'silently ignores non lfs objects' do
blobs = described_class.batch_lfs_pointers(repository, [non_lfs_blob.id])
expect(blobs).to eq([])
end
it 'avoids loading large blobs into memory' do
expect(repository).not_to receive(:lookup)
described_class.batch_lfs_pointers(repository, [non_lfs_blob.id])
end
end
describe 'encoding' do describe 'encoding' do
context 'file with russian text' do context 'file with russian text' do
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "encoding/russian.rb") } let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "encoding/russian.rb") }
......
require 'spec_helper'
describe Gitlab::Git::LfsChanges do
let(:project) { create(:project, :repository) }
let(:newrev) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' }
let(:blob_object_id) { '0c304a93cb8430108629bbbcaa27db3343299bc0' }
subject { described_class.new(project.repository, newrev) }
describe 'new_pointers' do
before do
allow_any_instance_of(Gitlab::Git::RevList).to receive(:new_objects).and_return([blob_object_id])
end
it 'uses rev-list to find new objects' do
rev_list = double
allow(Gitlab::Git::RevList).to receive(:new).and_return(rev_list)
expect(rev_list).to receive(:new_objects).and_return([])
subject.new_pointers
end
it 'filters new objects to find lfs pointers' do
expect(Gitlab::Git::Blob).to receive(:batch_lfs_pointers).with(project.repository, [blob_object_id])
subject.new_pointers(object_limit: 1)
end
it 'limits new_objects using object_limit' do
expect(Gitlab::Git::Blob).to receive(:batch_lfs_pointers).with(project.repository, [])
subject.new_pointers(object_limit: 0)
end
end
describe 'all_pointers' do
it 'uses rev-list to find all objects' do
rev_list = double
allow(Gitlab::Git::RevList).to receive(:new).and_return(rev_list)
allow(rev_list).to receive(:all_objects).and_return([blob_object_id])
expect(Gitlab::Git::Blob).to receive(:batch_lfs_pointers).with(project.repository, [blob_object_id])
subject.all_pointers
end
end
end
...@@ -1163,6 +1163,7 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -1163,6 +1163,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe "#ls_files" do describe "#ls_files" do
let(:master_file_paths) { repository.ls_files("master") } let(:master_file_paths) { repository.ls_files("master") }
let(:utf8_file_paths) { repository.ls_files("ls-files-utf8") }
let(:not_existed_branch) { repository.ls_files("not_existed_branch") } let(:not_existed_branch) { repository.ls_files("not_existed_branch") }
it "read every file paths of master branch" do it "read every file paths of master branch" do
...@@ -1184,6 +1185,10 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -1184,6 +1185,10 @@ describe Gitlab::Git::Repository, seed_helper: true do
it "returns empty array when not existed branch" do it "returns empty array when not existed branch" do
expect(not_existed_branch.length).to equal(0) expect(not_existed_branch.length).to equal(0)
end end
it "returns valid utf-8 data" do
expect(utf8_file_paths.map { |file| file.force_encoding('utf-8') }).to all(be_valid_encoding)
end
end end
describe "#copy_gitattributes" do describe "#copy_gitattributes" do
...@@ -1336,6 +1341,24 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -1336,6 +1341,24 @@ describe Gitlab::Git::Repository, seed_helper: true do
end end
end end
describe '#batch_existence' do
let(:refs) { ['deadbeef', SeedRepo::RubyBlob::ID, '909e6157199'] }
it 'returns existing refs back' do
result = repository.batch_existence(refs)
expect(result).to eq([SeedRepo::RubyBlob::ID])
end
context 'existing: true' do
it 'inverts meaning and returns non-existing refs' do
result = repository.batch_existence(refs, existing: false)
expect(result).to eq(%w(deadbeef 909e6157199))
end
end
end
describe '#local_branches' do describe '#local_branches' do
before(:all) do before(:all) do
@repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
......
...@@ -2,53 +2,82 @@ require 'spec_helper' ...@@ -2,53 +2,82 @@ require 'spec_helper'
describe Gitlab::Git::RevList do describe Gitlab::Git::RevList do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:rev_list) { described_class.new(newrev: 'newrev', path_to_repo: project.repository.path_to_repo) }
before do before do
expect(Gitlab::Git::Env).to receive(:all).and_return({ allow(Gitlab::Git::Env).to receive(:all).and_return({
GIT_OBJECT_DIRECTORY: 'foo', GIT_OBJECT_DIRECTORY: 'foo',
GIT_ALTERNATE_OBJECT_DIRECTORIES: 'bar' GIT_ALTERNATE_OBJECT_DIRECTORIES: 'bar'
}) })
end end
context "#new_refs" do def stub_popen_rev_list(*additional_args, output:)
let(:rev_list) { described_class.new(newrev: 'newrev', path_to_repo: project.repository.path_to_repo) } expect(rev_list).to receive(:popen).with([
Gitlab.config.git.bin_path,
"--git-dir=#{project.repository.path_to_repo}",
'rev-list',
*additional_args
],
nil,
{
'GIT_OBJECT_DIRECTORY' => 'foo',
'GIT_ALTERNATE_OBJECT_DIRECTORIES' => 'bar'
}).and_return([output, 0])
end
context "#new_refs" do
it 'calls out to `popen`' do it 'calls out to `popen`' do
expect(rev_list).to receive(:popen).with([ stub_popen_rev_list('newrev', '--not', '--all', output: "sha1\nsha2")
Gitlab.config.git.bin_path,
"--git-dir=#{project.repository.path_to_repo}",
'rev-list',
'newrev',
'--not',
'--all'
],
nil,
{
'GIT_OBJECT_DIRECTORY' => 'foo',
'GIT_ALTERNATE_OBJECT_DIRECTORIES' => 'bar'
}).and_return(["sha1\nsha2", 0])
expect(rev_list.new_refs).to eq(%w[sha1 sha2]) expect(rev_list.new_refs).to eq(%w[sha1 sha2])
end end
end end
context '#new_objects' do
it 'fetches list of newly pushed objects using rev-list' do
stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2")
expect(rev_list.new_objects).to eq(%w[sha1 sha2])
end
it 'can skip pathless objects' do
stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2 path/to/file")
expect(rev_list.new_objects(require_path: true)).to eq(%w[sha2])
end
it 'can return a lazy enumerator' do
stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2")
expect(rev_list.new_objects(lazy: true)).to be_a Enumerator::Lazy
end
it 'can accept list of references to exclude' do
stub_popen_rev_list('newrev', '--not', 'master', '--objects', output: "sha1\nsha2")
expect(rev_list.new_objects(not_in: ['master'])).to eq(%w[sha1 sha2])
end
it 'handles empty list of references to exclude as listing all known objects' do
stub_popen_rev_list('newrev', '--objects', output: "sha1\nsha2")
expect(rev_list.new_objects(not_in: [])).to eq(%w[sha1 sha2])
end
end
context '#all_objects' do
it 'fetches list of all pushed objects using rev-list' do
stub_popen_rev_list('--all', '--objects', output: "sha1\nsha2")
expect(rev_list.all_objects.force).to eq(%w[sha1 sha2])
end
end
context "#missed_ref" do context "#missed_ref" do
let(:rev_list) { described_class.new(oldrev: 'oldrev', newrev: 'newrev', path_to_repo: project.repository.path_to_repo) } let(:rev_list) { described_class.new(oldrev: 'oldrev', newrev: 'newrev', path_to_repo: project.repository.path_to_repo) }
it 'calls out to `popen`' do it 'calls out to `popen`' do
expect(rev_list).to receive(:popen).with([ stub_popen_rev_list('--max-count=1', 'oldrev', '^newrev', output: "sha1\nsha2")
Gitlab.config.git.bin_path,
"--git-dir=#{project.repository.path_to_repo}",
'rev-list',
'--max-count=1',
'oldrev',
'^newrev'
],
nil,
{
'GIT_OBJECT_DIRECTORY' => 'foo',
'GIT_ALTERNATE_OBJECT_DIRECTORIES' => 'bar'
}).and_return(["sha1\nsha2", 0])
expect(rev_list.missed_ref).to eq(%w[sha1 sha2]) expect(rev_list.missed_ref).to eq(%w[sha1 sha2])
end end
......
...@@ -4,35 +4,30 @@ describe Gitlab::Metrics::SidekiqMiddleware do ...@@ -4,35 +4,30 @@ describe Gitlab::Metrics::SidekiqMiddleware do
let(:middleware) { described_class.new } let(:middleware) { described_class.new }
let(:message) { { 'args' => ['test'], 'enqueued_at' => Time.new(2016, 6, 23, 6, 59).to_f } } let(:message) { { 'args' => ['test'], 'enqueued_at' => Time.new(2016, 6, 23, 6, 59).to_f } }
describe '#call' do def run(worker, message)
it 'tracks the transaction' do expect(Gitlab::Metrics::Transaction).to receive(:new)
worker = double(:worker, class: double(:class, name: 'TestWorker')) .with('TestWorker#perform')
.and_call_original
expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set)
.with(:sidekiq_queue_duration, instance_of(Float))
expect(Gitlab::Metrics::Transaction).to receive(:new) expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:finish)
.with('TestWorker#perform')
.and_call_original
expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set) middleware.call(worker, message, :test) { nil }
.with(:sidekiq_queue_duration, instance_of(Float)) end
expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:finish) describe '#call' do
it 'tracks the transaction' do
worker = double(:worker, class: double(:class, name: 'TestWorker'))
middleware.call(worker, message, :test) { nil } run(worker, message)
end end
it 'tracks the transaction (for messages without `enqueued_at`)' do it 'tracks the transaction (for messages without `enqueued_at`)' do
worker = double(:worker, class: double(:class, name: 'TestWorker')) worker = double(:worker, class: double(:class, name: 'TestWorker'))
expect(Gitlab::Metrics::Transaction).to receive(:new) run(worker, {})
.with('TestWorker#perform')
.and_call_original
expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set)
.with(:sidekiq_queue_duration, instance_of(Float))
expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:finish)
middleware.call(worker, {}, :test) { nil }
end end
it 'tracks any raised exceptions' do it 'tracks any raised exceptions' do
...@@ -50,5 +45,18 @@ describe Gitlab::Metrics::SidekiqMiddleware do ...@@ -50,5 +45,18 @@ describe Gitlab::Metrics::SidekiqMiddleware do
expect { middleware.call(worker, message, :test) } expect { middleware.call(worker, message, :test) }
.to raise_error(RuntimeError) .to raise_error(RuntimeError)
end end
it 'tags the metrics accordingly' do
tags = { one: 1, two: 2 }
worker = double(:worker, class: double(:class, name: 'TestWorker'))
allow(worker).to receive(:metrics_tags).and_return(tags)
tags.each do |tag, value|
expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:add_tag)
.with(tag, value)
end
run(worker, message)
end
end end
end end
...@@ -268,7 +268,8 @@ describe Gitlab::Workhorse do ...@@ -268,7 +268,8 @@ describe Gitlab::Workhorse do
GL_ID: "user-#{user.id}", GL_ID: "user-#{user.id}",
GL_USERNAME: user.username, GL_USERNAME: user.username,
GL_REPOSITORY: "project-#{project.id}", GL_REPOSITORY: "project-#{project.id}",
RepoPath: repo_path RepoPath: repo_path,
ShowAllRefs: false
} }
end end
...@@ -282,7 +283,8 @@ describe Gitlab::Workhorse do ...@@ -282,7 +283,8 @@ describe Gitlab::Workhorse do
GL_ID: "user-#{user.id}", GL_ID: "user-#{user.id}",
GL_USERNAME: user.username, GL_USERNAME: user.username,
GL_REPOSITORY: "wiki-#{project.id}", GL_REPOSITORY: "wiki-#{project.id}",
RepoPath: repo_path RepoPath: repo_path,
ShowAllRefs: false
} }
end end
...@@ -324,6 +326,12 @@ describe Gitlab::Workhorse do ...@@ -324,6 +326,12 @@ describe Gitlab::Workhorse do
expect(subject).to include(gitaly_params) expect(subject).to include(gitaly_params)
end end
context 'show_all_refs enabled' do
subject { described_class.git_http_ok(repository, false, user, action, show_all_refs: true) }
it { is_expected.to include(ShowAllRefs: true) }
end
end end
context "when git_receive_pack action is passed" do context "when git_receive_pack action is passed" do
...@@ -336,6 +344,12 @@ describe Gitlab::Workhorse do ...@@ -336,6 +344,12 @@ describe Gitlab::Workhorse do
let(:action) { 'info_refs' } let(:action) { 'info_refs' }
it { expect(subject).to include(gitaly_params) } it { expect(subject).to include(gitaly_params) }
context 'show_all_refs enabled' do
subject { described_class.git_http_ok(repository, false, user, action, show_all_refs: true) }
it { is_expected.to include(ShowAllRefs: true) }
end
end end
context 'when action passed is not supported by Gitaly' do context 'when action passed is not supported by Gitaly' do
......
...@@ -164,36 +164,35 @@ describe ProjectWiki do ...@@ -164,36 +164,35 @@ describe ProjectWiki do
end end
describe '#find_file' do describe '#find_file' do
before do shared_examples 'finding a wiki file' do
file = Gollum::File.new(subject.wiki) before do
allow_any_instance_of(Gollum::Wiki) file = File.open(Rails.root.join('spec', 'fixtures', 'dk.png'))
.to receive(:file).with('image.jpg', 'master') subject.wiki # Make sure the wiki repo exists
.and_return(file)
allow_any_instance_of(Gollum::File)
.to receive(:mime_type)
.and_return('image/jpeg')
allow_any_instance_of(Gollum::Wiki)
.to receive(:file).with('non-existant', 'master')
.and_return(nil)
end
after do BareRepoOperations.new(subject.repository.path_to_repo).commit_file(file, 'image.png')
allow_any_instance_of(Gollum::Wiki).to receive(:file).and_call_original end
allow_any_instance_of(Gollum::File).to receive(:mime_type).and_call_original
end
it 'returns the latest version of the file if it exists' do it 'returns the latest version of the file if it exists' do
file = subject.find_file('image.jpg') file = subject.find_file('image.png')
expect(file.mime_type).to eq('image/jpeg') expect(file.mime_type).to eq('image/png')
end
it 'returns nil if the page does not exist' do
expect(subject.find_file('non-existant')).to eq(nil)
end
it 'returns a Gitlab::Git::WikiFile instance' do
file = subject.find_file('image.png')
expect(file).to be_a Gitlab::Git::WikiFile
end
end end
it 'returns nil if the page does not exist' do context 'when Gitaly wiki_find_file is enabled' do
expect(subject.find_file('non-existant')).to eq(nil) it_behaves_like 'finding a wiki file'
end end
it 'returns a Gitlab::Git::WikiFile instance' do context 'when Gitaly wiki_find_file is disabled', :skip_gitaly_mock do
file = subject.find_file('image.jpg') it_behaves_like 'finding a wiki file'
expect(file).to be_a Gitlab::Git::WikiFile
end end
end end
......
require 'spec_helper'
describe Projects::GroupLinks::CreateService, '#execute' do
let(:user) { create :user }
let(:group) { create :group }
let(:project) { create :project }
let(:opts) do
{
link_group_access: '30',
expires_at: nil
}
end
let(:subject) { described_class.new(project, user, opts) }
it 'adds group to project' do
expect { subject.execute(group) }.to change { project.project_group_links.count }.from(0).to(1)
end
it 'returns false if group is blank' do
expect { subject.execute(nil) }.not_to change { project.project_group_links.count }
end
end
require 'spec_helper'
describe Projects::GroupLinks::DestroyService, '#execute' do
let(:group_link) { create :project_group_link }
let(:project) { group_link.project }
let(:user) { create :user }
let(:subject) { described_class.new(project, user) }
it 'removes group from project' do
expect { subject.execute(group_link) }.to change { project.project_group_links.count }.from(1).to(0)
end
it 'returns false if group_link is blank' do
expect { subject.execute(nil) }.not_to change { project.project_group_links.count }
end
end
require 'zlib'
class BareRepoOperations
# The ID of empty tree.
# See http://stackoverflow.com/a/40884093/1856239 and https://github.com/git/git/blob/3ad8b5bf26362ac67c9020bf8c30eee54a84f56d/cache.h#L1011-L1012
EMPTY_TREE_ID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'.freeze
include Gitlab::Popen
def initialize(path_to_repo)
@path_to_repo = path_to_repo
end
# Based on https://stackoverflow.com/a/25556917/1856239
def commit_file(file, dst_path, branch = 'master')
head_id = execute(['show', '--format=format:%H', '--no-patch', branch], allow_failure: true)[0] || EMPTY_TREE_ID
execute(['read-tree', '--empty'])
execute(['read-tree', head_id])
blob_id = execute(['hash-object', '--stdin', '-w']) do |stdin|
stdin.write(file.read)
end
execute(['update-index', '--add', '--cacheinfo', '100644', blob_id[0], dst_path])
tree_id = execute(['write-tree'])
commit_tree_args = ['commit-tree', tree_id[0], '-m', "Add #{dst_path}"]
commit_tree_args += ['-p', head_id] unless head_id == EMPTY_TREE_ID
commit_id = execute(commit_tree_args)
execute(['update-ref', "refs/heads/#{branch}", commit_id[0]])
end
private
def execute(args, allow_failure: false)
output, status = popen(base_args + args, nil) do |stdin|
yield stdin if block_given?
end
unless status.zero?
if allow_failure
return []
else
raise "Got a non-zero exit code while calling out `#{args.join(' ')}`: #{output}"
end
end
output.split("\n")
end
def base_args
[
Gitlab.config.git.bin_path,
"--git-dir=#{@path_to_repo}"
]
end
end
xK
0EgNI|ADt*^ mZ qGčY8ZK7"Fc%oHD9rZLsMJ2=ACmeFgVxI9H2XJrp6;N8z??>+zWƏBÞ f}bN@K\SY iSC
\ No newline at end of file
...@@ -6398,9 +6398,9 @@ vue-style-loader@^2.0.0: ...@@ -6398,9 +6398,9 @@ vue-style-loader@^2.0.0:
hash-sum "^1.0.2" hash-sum "^1.0.2"
loader-utils "^1.0.2" loader-utils "^1.0.2"
vue-template-compiler@^2.2.6: vue-template-compiler@^2.5.2:
version "2.2.6" version "2.5.2"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.2.6.tgz#2e2928daf0cd0feca9dfc35a9729adeae173ec68" resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.2.tgz#6f198ebc677b8f804315cd33b91e849315ae7177"
dependencies: dependencies:
de-indent "^1.0.2" de-indent "^1.0.2"
he "^1.1.0" he "^1.1.0"
...@@ -6409,9 +6409,9 @@ vue-template-es2015-compiler@^1.2.2: ...@@ -6409,9 +6409,9 @@ vue-template-es2015-compiler@^1.2.2:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.5.1.tgz#0c36cc57aa3a9ec13e846342cb14a72fcac8bd93" resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.5.1.tgz#0c36cc57aa3a9ec13e846342cb14a72fcac8bd93"
vue@^2.2.6: vue@^2.5.2:
version "2.2.6" version "2.5.2"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.2.6.tgz#451714b394dd6d4eae7b773c40c2034a59621aed" resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.2.tgz#fd367a87bae7535e47f9dc5c9ec3b496e5feb5a4"
vuex@^3.0.0: vuex@^3.0.0:
version "3.0.0" version "3.0.0"
......
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