Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKim Carlbäcker <kim.carlbacker@gmail.com>2017-05-18 00:11:07 +0300
committerKim Carlbäcker <kim.carlbacker@gmail.com>2017-05-18 00:11:07 +0300
commit4c5edb084f04591e9e791d7245c0a5db2d7c7c71 (patch)
tree63f8a08ce900b6861aaa2fe7fbc4bde147bae6f4
parentb6ea68afb87c346437413af491a93e9e6ada51fb (diff)
parent1a2f425e3fa80521bd8c094937d0f1ad6542222e (diff)
Merge branch 'master' into '171-fix-error-msgs'171-fix-error-msgs
# Conflicts: # internal/service/commit/isancestor.go
-rw-r--r--.gitlab/issue_templates/Migration_Acceptance_Testing.md22
-rw-r--r--.gitlab/issue_templates/Migration_Analysis.md16
-rw-r--r--.gitlab/issue_templates/Migration_Client_Implementation.md5
-rw-r--r--.gitlab/issue_templates/Migration_RPC_Design.md9
-rw-r--r--.gitlab/issue_templates/Migration_Server_Implementation.md4
-rw-r--r--CHANGELOG.md18
-rw-r--r--CONTRIBUTING.md5
-rw-r--r--Makefile2
-rw-r--r--README.md28
-rw-r--r--VERSION2
-rw-r--r--_support/test-cluster/.gitignore3
-rw-r--r--_support/test-cluster/README.md12
-rw-r--r--_support/test-cluster/app1/etc-gitlab/gitlab.rb13
-rw-r--r--_support/test-cluster/docker-compose.yml28
-rw-r--r--_support/test-cluster/gitaly1/etc-gitlab/gitlab.rb20
-rw-r--r--_support/test-cluster/gitaly2/etc-gitlab/gitlab.rb23
-rw-r--r--cmd/gitaly/main.go10
-rw-r--r--doc/MIGRATION_PROCESS.md157
-rw-r--r--doc/PROCESS.md4
-rw-r--r--doc/configuration/README.md16
-rw-r--r--internal/connectioncounter/connectioncounter.go42
-rw-r--r--internal/helper/command.go12
-rw-r--r--internal/helper/debug.go15
-rw-r--r--internal/helper/error.go15
-rw-r--r--internal/helper/repo.go11
-rw-r--r--internal/helper/repo_test.go36
-rw-r--r--internal/service/commit/isancestor.go14
-rw-r--r--internal/service/diff/commit.go156
-rw-r--r--internal/service/diff/commit_test.go293
-rw-r--r--internal/service/diff/server.go8
-rw-r--r--internal/service/middleware/loghandler/loghandler.go32
-rw-r--r--internal/service/notifications/post_receive.go6
-rw-r--r--internal/service/ref/refname.go7
-rw-r--r--internal/service/ref/refs.go10
-rw-r--r--internal/service/register.go2
-rw-r--r--internal/service/smarthttp/inforefs.go3
-rw-r--r--internal/service/smarthttp/receive_pack.go10
-rw-r--r--internal/service/smarthttp/receive_pack_test.go2
-rw-r--r--internal/service/smarthttp/stream_reader.go24
-rw-r--r--internal/service/smarthttp/upload_pack.go5
-rw-r--r--internal/service/ssh/receive_pack.go79
-rw-r--r--internal/service/ssh/receive_pack_test.go50
-rw-r--r--internal/service/ssh/server.go10
-rw-r--r--internal/service/ssh/testhelper_test.go64
-rw-r--r--internal/service/ssh/upload_pack_test.go49
-rw-r--r--internal/service/ssh/uploadpack.go66
-rw-r--r--vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION2
-rw-r--r--vendor/gitlab.com/gitlab-org/gitaly-proto/go/commit.pb.go3
-rw-r--r--vendor/gitlab.com/gitlab-org/gitaly-proto/go/diff.pb.go232
-rw-r--r--vendor/gitlab.com/gitlab-org/gitaly-proto/go/smarthttp.pb.go54
-rw-r--r--vendor/gitlab.com/gitlab-org/gitaly-proto/go/ssh.pb.go52
-rw-r--r--vendor/vendor.json18
52 files changed, 1584 insertions, 195 deletions
diff --git a/.gitlab/issue_templates/Migration_Acceptance_Testing.md b/.gitlab/issue_templates/Migration_Acceptance_Testing.md
new file mode 100644
index 000000000..4709bf8b2
--- /dev/null
+++ b/.gitlab/issue_templates/Migration_Acceptance_Testing.md
@@ -0,0 +1,22 @@
+~Conversation: #XXX (*complete this*)
+
+See the [Migration Process documentation](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/MIGRATION_PROCESS.md#acceptance-testing-acceptance-testing)
+for more information on the Acceptance Testing stage of the process.
+
+Feature Toggle Environment Variable: `XXXXXXXXXXXXXXX`
+
+--------------------------------------------------------------------------------
+
+- [ ] [Chef recipes](https://dev.gitlab.org/cookbooks/chef-repo) to enable/disable this feature (link to MR)
+- [ ] [Grafana dashboard](https://gitlab.com/gitlab-org/gitaly-dashboards) for monitoring (link to MR)
+- [ ] Environments
+ - [ ] `dev.gitlab.org`
+ - [ ] Staging
+ - [ ] `gitlab.com`
+- [ ] Test Results (post as comments on this issue)
+ - [ ] Did the migration perform as expected?
+ - [ ] Did the code have reasonable performance characteristics?
+ - [ ] Did error rates jump to an unacceptable level?
+- [ ] Have the changes been rolled back pending final review?
+- [ ] Runbook Added (link to MR)
+- [ ] Prometheus Alerts Added (link to MR) \ No newline at end of file
diff --git a/.gitlab/issue_templates/Migration_Analysis.md b/.gitlab/issue_templates/Migration_Analysis.md
new file mode 100644
index 000000000..fff80de50
--- /dev/null
+++ b/.gitlab/issue_templates/Migration_Analysis.md
@@ -0,0 +1,16 @@
+~Conversation: TBD
+
+## Perform a Migration Analysis
+
+- **Client**: `GitLab-CE`/`Workhorse`/`GitLab-Shell` (choose one)
+- **Route**:
+
+## Expected Artefacts
+
+See the [Migration Process documentation](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/MIGRATION_PROCESS.md#migration-analysis-migration-analysis)
+for more information on the analysis stage of the process.
+
+- [ ] **Decision to move ahead with migration**. Is it worth the effort right now?
+- [ ] **Existing reusable RPC endpoints**. What have we already implemented?
+- [ ] **New RPC endpoints to be implemented**. Just names. Leave the full design to the ~"RPC Design" stage next.
+- [ ] **Effort - for each new and existing RPC endpoint**, roughly (small/medium/large) how much effort will be required to implement it? \ No newline at end of file
diff --git a/.gitlab/issue_templates/Migration_Client_Implementation.md b/.gitlab/issue_templates/Migration_Client_Implementation.md
new file mode 100644
index 000000000..6c00e88f9
--- /dev/null
+++ b/.gitlab/issue_templates/Migration_Client_Implementation.md
@@ -0,0 +1,5 @@
+~Conversation: #XXX (*complete this*)
+
+See the [Migration Process documentation](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/MIGRATION_PROCESS.md#client-implementation-client-implementation)
+for more information on the Client Implementation stage of the process.
+
diff --git a/.gitlab/issue_templates/Migration_RPC_Design.md b/.gitlab/issue_templates/Migration_RPC_Design.md
new file mode 100644
index 000000000..57c0e9f3d
--- /dev/null
+++ b/.gitlab/issue_templates/Migration_RPC_Design.md
@@ -0,0 +1,9 @@
+~Conversation: #XXX (*complete this*)
+
+
+## Expected Artefacts
+
+See the [Migration Process documentation](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/MIGRATION_PROCESS.md#rpc-design-rpc-design)
+for more information on the RPC Design stage of the process.
+
+- [ ] **`grpc-proto` RPC prototypes**: merged change \ No newline at end of file
diff --git a/.gitlab/issue_templates/Migration_Server_Implementation.md b/.gitlab/issue_templates/Migration_Server_Implementation.md
new file mode 100644
index 000000000..62a0d695d
--- /dev/null
+++ b/.gitlab/issue_templates/Migration_Server_Implementation.md
@@ -0,0 +1,4 @@
+~Conversation: #XXX (*complete this*)
+
+See the [Migration Process documentation](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/MIGRATION_PROCESS.md#server-implementation-server-implementation)
+for more information on the Server Implementation stage of the process.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c44ef135..4616a32aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,25 @@
UNRELEASED
+- FindDefaultBranchName: decorate error
+ https://gitlab.com/gitlab-org/gitaly/merge_requests/148
+- Hide chatty logs behind GITALY_DEBUG=1. Log access times.
+ https://gitlab.com/gitlab-org/gitaly/merge_requests/149
+- Count accepted gRPC connections
+ https://gitlab.com/gitlab-org/gitaly/merge_requests/151
+- Disallow directory traversal in repository paths for security
+ https://gitlab.com/gitlab-org/gitaly/merge_requests/152
+
+v0.10.0
+
- CommitDiff: Parse a typechange diff correctly
https://gitlab.com/gitlab-org/gitaly/merge_requests/136
+- CommitDiff: Implement CommitDelta RPC
+ https://gitlab.com/gitlab-org/gitaly/merge_requests/139
+- PostReceivePack: Set GL_REPOSITORY env variable when provided in request
+ https://gitlab.com/gitlab-org/gitaly/merge_requests/137
+- Add SSHUpload/ReceivePack Implementation
+ https://gitlab.com/gitlab-org/gitaly/merge_requests/132
v0.9.0
@@ -27,4 +44,3 @@ v0.7.0
resolving repository paths.
https://gitlab.com/gitlab-org/gitaly/merge_requests/119
- Add CHANGELOG.md
-
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d7140fa8e..03a24f178 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -7,3 +7,8 @@ This document describes requirements for merge requests to Gitaly.
Any new merge request must contain either a CHANGELOG.md entry or a
justification why no changelog entry is needed. New changelog entries
should be added to the 'UNRELEASED' section of CHANGELOG.md.
+
+If a change is specific to an RPC, start the changelog line with the
+RPC name. So for a change to RPC `FooBar` you would get:
+
+> FooBar: Add support for `fluffy_bunnies` parameter
diff --git a/Makefile b/Makefile
index c82205924..ac03b0dc4 100644
--- a/Makefile
+++ b/Makefile
@@ -58,7 +58,7 @@ notice-up-to-date: notice
git diff --exit-code # there are no changed files
clean: clean-build
- rm -rf client/testdata
+ rm -rf internal/testhelper/testdata
rm -f $(foreach cmd,${CMDS},./${cmd})
clean-build:
diff --git a/README.md b/README.md
index 54026d6ec..4672fea19 100644
--- a/README.md
+++ b/README.md
@@ -173,20 +173,20 @@ in descending order of **99% Cumulative Time** (that is `(number of calls) * (99
A [Google Spreadsheet](https://docs.google.com/spreadsheets/d/1MVjsbLIjBVryMxO0UhBWebrwXuqpbCz18ZtrThcSFFU/edit) is available
with these calculations.
-|**Controller**|**Analysis**|**RPCS**|**Server Impl**|**Client Impl**|**Optim 1**|**Optim 2**|
-|--------------|------------|--------|---------------|---------------|-----------|-----------|
-| SmartHTTP Workhorse Interceptors | #36 | - | | | | |
-| `Projects::CommitController#show` | #64 | #80 | #88 | #89| | |
-| `Projects::MergeRequestsController#ci_status.json` / `Projects::MergeRequestsController#ci_environments_status.json` | #66 | #81 | #86 | #87 | | |
-| `Projects::TreeController#show` | #65 | #82 | #84 | #85 | | |
-| Git HTTP: `POST /{upload,receive}-pack` | #92 | gitlab-org/gitaly-proto!4 | #122 | #125 | | |
-| Git SSH: handle gitlab-shell sessions | #91 | gitlab-org/gitaly-proto!5 | #123 | #124 | | |
-| `Projects::BranchesController#index` | #127 | #128 | | | | |
-| `ProjectsController#show` | #157 | -- | -- | gitlab-org/gitlab-ce!10780 | | |
-| `Projects::GraphsController#charts` (shelved for now) | #158 | | | | | |
-| `Projects::MergeRequestsController#new` | #159 | | | | | |
-| `Projects::RawController#show` | #160 | #195 | | | | |
-| Workhorse `sendblob` | #194 | | | | | |
+|**Controller**|**~"Migration Analysis"**|**~"RPC Design"**|**~"Server Implementation"**|**~"Client Implementation"**|**~"Acceptance Testing"**|**Optim 1**|**Optim 2**|
+|--------------|-------------------------|-----------------|----------------------------|----------------------------|-------------------------|-----------|-----------|
+| [`SmartHTTP::InfoRefsUploadPack` and `SmartHTTP::InfoRefsReceivePack`](https://gitlab.com/gitlab-org/gitaly/issues/223) | #36 | - | | | | | |
+| [`Diff::CommitDiff`](https://gitlab.com/gitlab-org/gitaly/issues/222) | #64 | #80 | #88 | #89| #209 | | |
+| [`Ref::FindRefName` and `Commit::CommitIsAncestor`](https://gitlab.com/gitlab-org/gitaly/issues/221) | #66 | #81 | #86 | #87 | #210 | | |
+| [`Ref::FindDefaultBranchName`, `Ref::FindAllBranchNames`, `Ref::FindAllTagNames`](https://gitlab.com/gitlab-org/gitaly/issues/220) | #65 | #82 | #84 | #85 | #211 | | |
+| [`SmartHTTP::PostUploadPack` and `SmartHTTP::PostReceivePack`](https://gitlab.com/gitlab-org/gitaly/issues/219) | #92 | gitlab-org/gitaly-proto!4 | #122 | #125 | #184 | | |
+| [`SSH:SSHUploadPack` and `SSH::SSHReceivePack`](https://gitlab.com/gitlab-org/gitaly/issues/218) | #91 | gitlab-org/gitaly-proto!5 | #123 | #124 | | | |
+| [`Ref::FindLocalBranches`](https://gitlab.com/gitlab-org/gitaly/issues/217) | #127 | #128 | !103 | gitlab-org/gitlab-ce!10059 | | | |
+| [`Ref::count_branch_names` and `Ref::count_tag_names`](https://gitlab.com/gitlab-org/gitaly/issues/214) | #157 | -- | -- | gitlab-org/gitlab-ce!10780 | #215 | | |
+| `Projects::GraphsController#charts` (shelved for now) | #158 | | | | | | |
+| [`Commit::GetAuthor`](https://gitlab.com/gitlab-org/gitaly/issues/216) | #159 | | | | | | |
+| `Projects::RawController#show` | #160 | #195 | | | | | |
+| [`CatFile::Blob`](https://gitlab.com/gitlab-org/gitaly/issues/212) | #194 | | | | | | |
(More to follow!)
diff --git a/VERSION b/VERSION
index ac39a106c..78bc1abd1 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.9.0
+0.10.0
diff --git a/_support/test-cluster/.gitignore b/_support/test-cluster/.gitignore
new file mode 100644
index 000000000..fd330b7a2
--- /dev/null
+++ b/_support/test-cluster/.gitignore
@@ -0,0 +1,3 @@
+ssh_host*
+gitlab-secrets.json
+/gitaly1/data/
diff --git a/_support/test-cluster/README.md b/_support/test-cluster/README.md
new file mode 100644
index 000000000..e1e010cf7
--- /dev/null
+++ b/_support/test-cluster/README.md
@@ -0,0 +1,12 @@
+# Test cluster with multiple Gitaly servers
+
+This directory contains a
+[docker-compose.yml](https://docs.docker.com/compose/) and Omnibus
+GitLab configuration files to boot GitLab with multiple Gitaly servers
+behind it. This is meant for testing purposes.
+
+Boot the cluster with `docker-compose up`. After some time you can log
+in to your GitLab instance at `localhost:8080`.
+
+Edit `docker-compose.yml` if you want to use a different GitLab
+version from what is currently in there.
diff --git a/_support/test-cluster/app1/etc-gitlab/gitlab.rb b/_support/test-cluster/app1/etc-gitlab/gitlab.rb
new file mode 100644
index 000000000..13d7b0bfa
--- /dev/null
+++ b/_support/test-cluster/app1/etc-gitlab/gitlab.rb
@@ -0,0 +1,13 @@
+# This is not strictly necessary but it makes the logs a little 'quieter'
+prometheus_monitoring['enable'] = false
+
+# Disable the local Gitaly instance
+gitaly['enable'] = false
+
+# Don't disable Gitaly altogether
+gitlab_rails['gitaly_enabled'] = true
+
+git_data_dirs({
+ 'default' => {'path' => '/mnt/data1', 'gitaly_address' => 'tcp://gitaly1:6666'},
+ 'gitaly2' => {'path' => '/mnt/data2', 'gitaly_address' => 'tcp://gitaly2:6666'},
+})
diff --git a/_support/test-cluster/docker-compose.yml b/_support/test-cluster/docker-compose.yml
new file mode 100644
index 000000000..46ccf93c7
--- /dev/null
+++ b/_support/test-cluster/docker-compose.yml
@@ -0,0 +1,28 @@
+version: "3"
+services:
+ app1:
+ image: gitlab/gitlab-ce:9.2.0-rc1.ce.0
+ ports:
+ - "8080:80"
+ - "2222:22"
+ links:
+ - gitaly1
+ - gitaly2
+ volumes:
+ - ./app1/etc-gitlab:/etc/gitlab
+ - ./gitaly1/data:/mnt/data1
+ - ./gitaly2/data:/mnt/data2
+ gitaly1:
+ image: gitlab/gitlab-ce:9.2.0-rc1.ce.0
+ expose:
+ - 6666
+ volumes:
+ - ./gitaly1/data:/var/opt/gitlab/git-data
+ - ./gitaly1/etc-gitlab:/etc/gitlab
+ gitaly2:
+ image: gitlab/gitlab-ce:9.2.0-rc1.ce.0
+ expose:
+ - 6666
+ volumes:
+ - ./gitaly2/data:/var/opt/gitlab/git-data-2
+ - ./gitaly2/etc-gitlab:/etc/gitlab
diff --git a/_support/test-cluster/gitaly1/etc-gitlab/gitlab.rb b/_support/test-cluster/gitaly1/etc-gitlab/gitlab.rb
new file mode 100644
index 000000000..1ac79c6bc
--- /dev/null
+++ b/_support/test-cluster/gitaly1/etc-gitlab/gitlab.rb
@@ -0,0 +1,20 @@
+gitaly['enable'] = true
+gitaly['listen_addr'] = ':6666'
+
+# This instance will be serving the 'default' repository storage
+
+# Disable as many Omnibus services as we can
+unicorn['enable'] = false
+sidekiq['enable'] = false
+gitlab_workhorse['enable'] = false
+gitlab_monitor['enable'] = false
+prometheus_monitoring['enable'] = false
+redis['enable'] = false
+postgresql['enable']=false
+nginx['enable'] = false
+
+# We need these settings to prevent Omnibus from erroring out because
+# Postgres/Redis are unavailable
+gitlab_rails['rake_cache_clear'] = false
+gitlab_rails['auto_migrate'] = false
+
diff --git a/_support/test-cluster/gitaly2/etc-gitlab/gitlab.rb b/_support/test-cluster/gitaly2/etc-gitlab/gitlab.rb
new file mode 100644
index 000000000..3e65f3e4c
--- /dev/null
+++ b/_support/test-cluster/gitaly2/etc-gitlab/gitlab.rb
@@ -0,0 +1,23 @@
+gitaly['enable'] = true
+gitaly['listen_addr'] = ':6666'
+
+# This instance will be serving the 'gitaly2' repository storage
+git_data_dirs({
+ 'gitaly2' => '/var/opt/gitlab/git-data-2'
+})
+
+# Disable as many Omnibus services as we can
+unicorn['enable'] = false
+sidekiq['enable'] = false
+gitlab_workhorse['enable'] = false
+gitlab_monitor['enable'] = false
+prometheus_monitoring['enable'] = false
+redis['enable'] = false
+postgresql['enable']=false
+nginx['enable'] = false
+
+# We need these settings to prevent Omnibus from erroring out because
+# Postgres/Redis are unavailable
+gitlab_rails['rake_cache_clear'] = false
+gitlab_rails['auto_migrate'] = false
+
diff --git a/cmd/gitaly/main.go b/cmd/gitaly/main.go
index 0a73134ec..24bfbd8cc 100644
--- a/cmd/gitaly/main.go
+++ b/cmd/gitaly/main.go
@@ -8,7 +8,9 @@ import (
"os"
"gitlab.com/gitlab-org/gitaly/internal/config"
+ "gitlab.com/gitlab-org/gitaly/internal/connectioncounter"
"gitlab.com/gitlab-org/gitaly/internal/service"
+ "gitlab.com/gitlab-org/gitaly/internal/service/middleware/loghandler"
"gitlab.com/gitlab-org/gitaly/internal/service/middleware/panichandler"
"github.com/grpc-ecosystem/go-grpc-prometheus"
@@ -76,17 +78,19 @@ func main() {
log.Fatalf("configure tcp listener: %v", err)
}
log.Printf("listening at tcp address %q", addr)
- listeners = append(listeners, l)
+ listeners = append(listeners, connectioncounter.New("tcp", l))
}
server := grpc.NewServer(
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
panichandler.StreamPanicHandler, // Panic Handler first: handle panics gracefully
grpc_prometheus.StreamServerInterceptor, // Prometheus Metrics next: measure RPC times
+ loghandler.StreamLogHandler,
)),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
panichandler.UnaryPanicHandler, // Panic Handler first: handle panics gracefully
grpc_prometheus.UnaryServerInterceptor, // Prometheus Metrics next: measure RPC times
+ loghandler.UnaryLogHandler,
)),
)
@@ -121,6 +125,6 @@ func createUnixListener(socketPath string) (net.Listener, error) {
if err := os.Remove(socketPath); err != nil && !os.IsNotExist(err) {
return nil, err
}
-
- return net.Listen("unix", socketPath)
+ l, err := net.Listen("unix", socketPath)
+ return connectioncounter.New("unix", l), err
}
diff --git a/doc/MIGRATION_PROCESS.md b/doc/MIGRATION_PROCESS.md
new file mode 100644
index 000000000..d1789951f
--- /dev/null
+++ b/doc/MIGRATION_PROCESS.md
@@ -0,0 +1,157 @@
+[All current migrations](https://gitlab.com/gitlab-org/gitaly/issues?label_name%5B%5D=Migration&scope=all&state=all)
+
+# Gitaly Migration Process
+
+This document describes the Gitaly migration process.
+
+Migration is done on a feature-by-feature basis. Although not strictly correct, for simplicity, think of each migrated feature as being a single Gitaly endpoint.
+
+![](https://docs.google.com/drawings/d/1wPwweMnEUPgffsdmoVmHwho5wzKtj61ll_Q90N9eZc8/pub?w=756&h=720)
+
+[Edit this document](https://docs.google.com/drawings/d/1wPwweMnEUPgffsdmoVmHwho5wzKtj61ll_Q90N9eZc8/edit)
+
+---------------------------------------------------------------------
+
+## Selection
+
+First step is to consider a route for migration. A route is an endpoint in one of the following GitLab projects:
+
+* GitLab-CE
+* GitLab Workhorse
+* GitLab Shell
+
+The order of migration is roughly determined using the formula described in the [Order of Migration](../README.md#order-of-migration) section in the Gitaly readme, although tactical and strategic reasons may affect the actual order.
+
+---------------------------------------------------------------------
+
+## Migration Analysis: ~"Migration Analysis"
+
+Once a route has been selected, the route in the client will be analysed and profiled in order to figure out the best way of migrating the route to Gitaly.
+
+The artefacts of this stage will be:
+
+1. **Rough estimation of the amount of work involved in the migration**: from the analysis, we should have a rough idea of how long this migration will take.
+1. **Decision to move ahead with migration**: At this stage of the project, we're working to achieve the best value for effort. If we feel that a migration will take too much effort for the value gained, then it may be shelved.
+1. **Optional: a new grpc Endpoint**: the analysis may show that the route can be migrated using an existing Gitaly endpoint, or that a new endpoint needs to be designed. If an existing endpoint is used, jump directly to **Client Implementation**, skipping **RPC design** and **Server Implementation**
+
+---------------------------------------------------------------------
+
+## RPC Design: ~"RPC Design"
+
+A new GRPC endpoint is added to the [`gitaly-proto`](https://gitlab.com/gitlab-org/gitaly-proto) project.
+
+---------------------------------------------------------------------
+
+## Server Implementation: ~"Server Implementation"
+
+The server implementation of the `gitaly-proto` endpoint is completed, including:
+* Unit tests
+* Integration tests
+
+Note: the client and server implementations may occur in parallel, or sequentially
+depending on the particular case.
+
+---------------------------------------------------------------------
+
+## Client Implementation: ~"Client Implementation"
+
+The client implementation in `gitlab-ce`, `GitLab-Workhorse` or `GitLab-Shell` is completed.
+
+
+
+#### Feature Flags
+
+The client code will either call the old route or the new route, depending on a **feature flag**. This flag name should be derived from the name of the grpc endpoint.
+
+---------------------------------------------------------------------
+
+## Feature Status: *Ready-for-Testing*
+
+At this stage, the feature will be considered to complete, but should remain
+disabled by default until acceptance testing has been completed.
+
+This happens in three stages:
+* Feature Status: Ready-for-Testing
+* Feature Status Opt-In
+* Feature Status: Opt-Out
+* Feature Status: Mandatory
+
+---------------------------------------------------------------------
+
+## Acceptance Testing: ~"Acceptance Testing"
+
+A feature is tested in dev, staging and gitlab.com. If the results are satisfactory, the testing continues on to the next environment until the test is complete.
+
+The following procedure should be used for testing:
+
+1. Update the relevant [chef roles](https://dev.gitlab.org/cookbooks/chef-repo) to enable the feature flag(s) under `default_attributes -> omnibus-gitlab -> gitlab_rb -> gitlab-rails -> env`:
+ - For dev: roles/dev-gitlab-org.json
+ - For staging: roles/gitlab-staging-base.json
+ - For producion: roles/gitlab-cluster-base.json
+1. Create a new row in the Gitaly dashboard to monitor the feature in the [`gitaly-dashboards`](https://gitlab.com/gitlab-org/gitaly-dashboards) repo.
+ - Merge the chef-repo MRs
+ - Make sure new role file is on chef server `bundle exec knife role from file [role-path]`
+ - Run chef client and restart unicorn: `bundle exec knife ssh -C 1 role:[role-name] 'sudo chef-client; sleep 60; sudo gitlab-ctl term unicorn; echo done $?'`
+ - Verify the process have the env values set: `bundle exec knife ssh role:[role-name] 'for p in $(pgrep -f "unicorn master"); do ps -o pid,etime,args -p $p; sudo cat /proc/$p/environ | xargs --null --max-args=1 | grep GITALY; done'`
+1. Restart client process (unicorn, workhorse, etc) if necessary to enable the feature.
+1. Monitor dashboards and host systems to ensure that feature is working.
+1. Get the production engineer to roll the feature back.
+1. Review data:
+ 1. Did the test route perform well?
+ 1. Did the client or server processes consume excessive resources during the test?
+ 1. Did error rates jump during the test?
+1. If the test if successful, proceed to next environment.
+
+Once acceptance testing has been successfully completed in all three environments, we need to prepare for opt-in status.
+
+* The [Gitaly runbook](https://gitlab.com/gitlab-com/runbooks/blob/master/troubleshooting/gitaly-error-rate.md) should be updated to include any diagnosis information and a description of how to disable the feature flag.
+* Using the error-rate data from the gitlab.com acceptance testing, new alerts need to be added to the [Gitaly prometheus rules](https://gitlab.com/gitlab-com/runbooks/blob/master/alerts/gitaly.rules). The alert should also include a link to the new runbook amendments.
+
+---------------------------------------------------------------------
+
+## Feature Status: *Opt-In*
+
+As the maintainer of Gitaly, Jacob to review:
+
+* The testing evidence completed in the acceptance testing stage is sufficient, using the dashboards created in the previous stage.
+* The alerts are in-place
+* The runbooks are good
+
+Once Jacob has approved, the feature flag will be enabled on dev.gitlab.org, staging and GitLab.com, but the feature flag will be disabled by default. On-premise installations can enable the feature if they wish, but it will be disabled by default.
+
+For a feature toggle `GITALY_EXAMPLE_FEATURE`, the toggle would be enabled by setting the environment variable:
+
+```shell
+GITALY_EXAMPLE_FEATURE=1 # "One" to enable
+```
+
+If the flag is missing, the feature will be **disabled by default**.
+
+---------------------------------------------------------------------
+
+## Feature Status: *Opt-Out*
+
+In the next GitLab release, the client application logic will be switched around to make the feature toggle enabled by default.
+
+This gives on-premise installations a month to test a feature and disable it if there are any problems.
+
+Disabling a feature is done by:
+
+For a feature toggle `GITALY_EXAMPLE_FEATURE`, the toggle would be enabled by setting the environment variable:
+
+```shell
+GITALY_EXAMPLE_FEATURE=0 # "Zero" to disable
+```
+
+If the flag is missing, the feature will be **enabled by default**.
+
+---------------------------------------------------------------------
+
+## Feature Status: *Mandatory*
+
+In the next GitLab release following the change to Opt-Out feature status, the feature will be made mandatory. At this point, the option to opt-out will be gone and all GitLab installations will need to use the feature.
+
+The change will be made by:
+
+* Removing the references to the feature flag in Omnibus, Chef repo, etc
+* Remove the feature flag switching code from the client application (GitLab-CE, Workhorse, GitLab-Shell) code
diff --git a/doc/PROCESS.md b/doc/PROCESS.md
index 04a758bb0..585779e0f 100644
--- a/doc/PROCESS.md
+++ b/doc/PROCESS.md
@@ -38,3 +38,7 @@ Like other GitLab projects, Gitaly uses the [GitLab Workflow](https://docs.gitla
* Merge requests will target the master branch.
* If the merge request is an optimisation of the previous stable branch, i.e. the branch currently running on GitLab.com, the MR will be cherry picked across to the stable branch and deployed to Gitlab.com from there.
+
+# Migration Process
+
+The Gitaly team aim to migrate each feature across to Gitaly according to a standardised process - read about the [Gitaly Migration Process here](MIGRATION_PROCESS.md) \ No newline at end of file
diff --git a/doc/configuration/README.md b/doc/configuration/README.md
index 7a44a3e15..e656f0665 100644
--- a/doc/configuration/README.md
+++ b/doc/configuration/README.md
@@ -57,14 +57,16 @@ match those in gitlab.yml.
|path|string|yes|Path to storage shard|
|name|string|yes|Name of storage shard|
-## Legacy environment variables
+## Environment variables
-These were used to configure earlier version of Gitaly. When present,
-they take precendence over the configuration file.
+### GITALY_DEBUG
+
+When set to `1`, Gitaly will print debug log messages.
### GITALY_SOCKET_PATH
-Required unless GITALY_LISTEN_ADDR is set.
+Required unless GITALY_LISTEN_ADDR is set. Overrides `socket_path` in
+config.toml. Deprecated; use config.toml.
A path at which Gitaly should open a Unix socket. Example value:
@@ -74,7 +76,8 @@ GITALY_SOCKET_PATH=/home/git/gitlab/tmp/sockets/private/gitaly.socket
### GITALY_LISTEN_ADDR
-Required unless GITALY_SOCKET_PATH is set.
+Required unless GITALY_SOCKET_PATH is set. Overrides `listen_addr` in
+config.toml. Deprecated; use config.toml.
TCP address for Gitaly to listen on. Note: at the moment Gitaly does
not offer any form of authentication. When you use a TCP listener you
@@ -89,7 +92,8 @@ GITALY_LISTEN_ADDR=localhost:1234
### GITALY_PROMETHEUS_LISTEN_ADDR
-Optional.
+Optional. Overrides `prometheus_listen_addr` in config.toml.
+Deprecated; use config.toml.
TCP listen address for Prometheus metrics. When missing or empty, no
Prometheus listener is started.
diff --git a/internal/connectioncounter/connectioncounter.go b/internal/connectioncounter/connectioncounter.go
new file mode 100644
index 000000000..0fbf3210b
--- /dev/null
+++ b/internal/connectioncounter/connectioncounter.go
@@ -0,0 +1,42 @@
+package connectioncounter
+
+import (
+ "net"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+ connTotal = prometheus.NewCounterVec(
+ prometheus.CounterOpts{
+ Name: "gitaly_connections_total",
+ Help: "Total number of connections accepted by this Gitaly process",
+ },
+ []string{"type"},
+ )
+)
+
+func init() {
+ prometheus.MustRegister(connTotal)
+}
+
+// New returns a listener which increments a prometheus counter on each
+// accepted connection. Use cType to specify the connection type, this is
+// a prometheus label.
+func New(cType string, l net.Listener) net.Listener {
+ return &countingListener{
+ cType: cType,
+ Listener: l,
+ }
+}
+
+type countingListener struct {
+ net.Listener
+ cType string
+}
+
+func (cl *countingListener) Accept() (net.Conn, error) {
+ conn, err := cl.Listener.Accept()
+ connTotal.WithLabelValues(cl.cType).Inc()
+ return conn, err
+}
diff --git a/internal/helper/command.go b/internal/helper/command.go
index 370fa4c50..812e52c48 100644
--- a/internal/helper/command.go
+++ b/internal/helper/command.go
@@ -22,11 +22,11 @@ func (c *Command) Kill() {
// GitCommandReader creates a git Command with the given args
func GitCommandReader(args ...string) (*Command, error) {
- return NewCommand(exec.Command("git", args...), nil, nil)
+ return NewCommand(exec.Command("git", args...), nil, nil, nil)
}
// NewCommand creates a Command from an exec.Cmd
-func NewCommand(cmd *exec.Cmd, stdin io.Reader, stdout io.Writer, env ...string) (*Command, error) {
+func NewCommand(cmd *exec.Cmd, stdin io.Reader, stdout, stderr io.Writer, env ...string) (*Command, error) {
command := &Command{Cmd: cmd}
// Explicitly set the environment for the command
@@ -56,8 +56,12 @@ func NewCommand(cmd *exec.Cmd, stdin io.Reader, stdout io.Writer, env ...string)
command.Reader = pipe
}
- // If we don't do something with cmd.Stderr, Git errors will be lost
- cmd.Stderr = os.Stderr
+ if stderr != nil {
+ cmd.Stderr = stderr
+ } else {
+ // If we don't do something with cmd.Stderr, Git errors will be lost
+ cmd.Stderr = os.Stderr
+ }
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("start %v: %v", cmd.Args, err)
diff --git a/internal/helper/debug.go b/internal/helper/debug.go
new file mode 100644
index 000000000..f016ece8c
--- /dev/null
+++ b/internal/helper/debug.go
@@ -0,0 +1,15 @@
+package helper
+
+import (
+ "log"
+ "os"
+)
+
+// Debugf behaves similarly to log.Printf. No-op unless GITALY_DEBUG=1.
+func Debugf(format string, args ...interface{}) {
+ if os.Getenv("GITALY_DEBUG") != "1" {
+ return
+ }
+
+ log.Printf("debug: "+format, args...)
+}
diff --git a/internal/helper/error.go b/internal/helper/error.go
new file mode 100644
index 000000000..1d7016f04
--- /dev/null
+++ b/internal/helper/error.go
@@ -0,0 +1,15 @@
+package helper
+
+import (
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+)
+
+// DecorateError unless it's already a grpc error.
+// If given nil it will return nil.
+func DecorateError(code codes.Code, err error) error {
+ if err != nil && grpc.Code(err) == codes.Unknown {
+ return grpc.Errorf(code, "%v", err)
+ }
+ return err
+}
diff --git a/internal/helper/repo.go b/internal/helper/repo.go
index c4c000f70..b8928a429 100644
--- a/internal/helper/repo.go
+++ b/internal/helper/repo.go
@@ -3,6 +3,7 @@ package helper
import (
"os"
"path"
+ "strings"
"gitlab.com/gitlab-org/gitaly/internal/config"
@@ -20,7 +21,15 @@ func GetRepoPath(repo *pb.Repository) (string, error) {
var repoPath string
if storagePath, ok := config.StoragePath(repo.GetStorageName()); ok {
- repoPath = path.Join(storagePath, repo.GetRelativePath())
+ relativePath := repo.GetRelativePath()
+ // Disallow directory traversal for security
+ separator := string(os.PathSeparator)
+ if strings.HasPrefix(relativePath, ".."+separator) ||
+ strings.Contains(relativePath, separator+".."+separator) ||
+ strings.HasSuffix(relativePath, separator+"..") {
+ return "", grpc.Errorf(codes.InvalidArgument, "GetRepoPath: relative path can't contain directory traversal")
+ }
+ repoPath = path.Join(storagePath, relativePath)
} else {
repoPath = repo.GetPath()
}
diff --git a/internal/helper/repo_test.go b/internal/helper/repo_test.go
index 07ea8b409..29e3daa7b 100644
--- a/internal/helper/repo_test.go
+++ b/internal/helper/repo_test.go
@@ -96,6 +96,42 @@ func TestGetRepoPath(t *testing.T) {
repo: &pb.Repository{Path: "/made/up/path.git"},
err: codes.NotFound,
},
+ {
+ desc: "relative path with directory traversal",
+ storages: exampleStorages,
+ repo: &pb.Repository{StorageName: "default", RelativePath: "../bazqux.git"},
+ err: codes.InvalidArgument,
+ },
+ {
+ desc: "valid path with ..",
+ storages: exampleStorages,
+ repo: &pb.Repository{StorageName: "default", RelativePath: "foo../bazqux.git"},
+ err: codes.NotFound, // Because the directory doesn't exist
+ },
+ {
+ desc: "relative path with sneaky directory traversal",
+ storages: exampleStorages,
+ repo: &pb.Repository{StorageName: "default", RelativePath: "/../bazqux.git"},
+ err: codes.InvalidArgument,
+ },
+ {
+ desc: "relative path with one level traversal at the end",
+ storages: exampleStorages,
+ repo: &pb.Repository{StorageName: "default", RelativePath: testhelper.TestRelativePath + "/.."},
+ err: codes.InvalidArgument,
+ },
+ {
+ desc: "relative path with one level dashed traversal at the end",
+ storages: exampleStorages,
+ repo: &pb.Repository{StorageName: "default", RelativePath: testhelper.TestRelativePath + "/../"},
+ err: codes.InvalidArgument,
+ },
+ {
+ desc: "relative path with deep traversal at the end",
+ storages: exampleStorages,
+ repo: &pb.Repository{StorageName: "default", RelativePath: "bazqux.git/../.."},
+ err: codes.InvalidArgument,
+ },
}
for _, tc := range testCases {
diff --git a/internal/service/commit/isancestor.go b/internal/service/commit/isancestor.go
index 999737941..7a84528b2 100644
--- a/internal/service/commit/isancestor.go
+++ b/internal/service/commit/isancestor.go
@@ -2,7 +2,6 @@ package commit
import (
"io/ioutil"
- "log"
"os/exec"
"google.golang.org/grpc"
@@ -20,14 +19,10 @@ func (s *server) CommitIsAncestor(ctx context.Context, in *pb.CommitIsAncestorRe
return nil, err
}
if in.AncestorId == "" {
- message := "bad request (empty ancestor sha)"
- log.Printf("CommitIsAncestor: %q", message)
- return nil, grpc.Errorf(codes.InvalidArgument, message)
+ return nil, grpc.Errorf(codes.InvalidArgument, "bad request (empty ancestor sha)")
}
if in.ChildId == "" {
- message := "bad request (empty child sha)"
- log.Printf("CommitIsAncestor: %q", message)
- return nil, grpc.Errorf(codes.InvalidArgument, message)
+ return nil, grpc.Errorf(codes.InvalidArgument, "bad request (empty child sha)")
}
ret, err := commitIsAncestorName(repoPath, in.AncestorId, in.ChildId)
@@ -37,13 +32,12 @@ func (s *server) CommitIsAncestor(ctx context.Context, in *pb.CommitIsAncestorRe
// Assumes that `path`, `ancestorID` and `childID` are populated :trollface:
func commitIsAncestorName(path, ancestorID, childID string) (bool, error) {
osCommand := exec.Command("git", "--git-dir", path, "merge-base", "--is-ancestor", ancestorID, childID)
- cmd, err := helper.NewCommand(osCommand, nil, ioutil.Discard)
+ cmd, err := helper.NewCommand(osCommand, nil, ioutil.Discard, nil)
if err != nil {
return false, grpc.Errorf(codes.Internal, err.Error())
}
defer cmd.Kill()
- log.Printf("commitIsAncestor: RepoPath=%q ancestorSha=%s childSha=%s", path, ancestorID, childID)
-
+ helper.Debugf("commitIsAncestor: RepoPath=%q ancestorSha=%s childSha=%s", path, ancestorID, childID)
return cmd.Wait() == nil, nil
}
diff --git a/internal/service/diff/commit.go b/internal/service/diff/commit.go
index 351f7e2f2..fa3801ca3 100644
--- a/internal/service/diff/commit.go
+++ b/internal/service/diff/commit.go
@@ -1,7 +1,7 @@
package diff
import (
- "log"
+ "fmt"
pb "gitlab.com/gitlab-org/gitaly-proto/go"
"gitlab.com/gitlab-org/gitaly/internal/diff"
@@ -11,9 +11,14 @@ import (
"google.golang.org/grpc/codes"
)
+type requestWithLeftRightCommitIds interface {
+ GetLeftCommitId() string
+ GetRightCommitId() string
+}
+
func (s *server) CommitDiff(in *pb.CommitDiffRequest, stream pb.Diff_CommitDiffServer) error {
if err := validateRequest(in); err != nil {
- return err
+ return grpc.Errorf(codes.InvalidArgument, "CommitDiff: %v", err)
}
repoPath, err := helper.GetRepoPath(in.Repository)
@@ -25,7 +30,7 @@ func (s *server) CommitDiff(in *pb.CommitDiffRequest, stream pb.Diff_CommitDiffS
ignoreWhitespaceChange := in.GetIgnoreWhitespaceChange()
paths := in.GetPaths()
- log.Printf(
+ helper.Debugf(
"CommitDiff: RepoPath=%q LeftCommitId=%q RightCommitId=%q IgnoreWhitespaceChange=%t Paths=%s",
repoPath,
leftSha,
@@ -54,17 +59,8 @@ func (s *server) CommitDiff(in *pb.CommitDiffRequest, stream pb.Diff_CommitDiffS
}
}
- cmd, err := helper.GitCommandReader(cmdArgs...)
- if err != nil {
- return grpc.Errorf(codes.Internal, "CommitDiff: cmd: %v", err)
- }
- defer cmd.Kill()
-
- diffParser := diff.NewDiffParser(cmd)
-
- for diffParser.Parse() {
- diff := diffParser.Diff()
- err = stream.Send(&pb.CommitDiffResponse{
+ err = eachDiff("CommitDiff", cmdArgs, func(diff *diff.Diff) error {
+ err := stream.Send(&pb.CommitDiffResponse{
FromPath: diff.FromPath,
ToPath: diff.ToPath,
FromId: diff.FromID,
@@ -78,27 +74,139 @@ func (s *server) CommitDiff(in *pb.CommitDiffRequest, stream pb.Diff_CommitDiffS
if err != nil {
return grpc.Errorf(codes.Unavailable, "CommitDiff: send: %v", err)
}
+
+ return nil
+ })
+
+ return err
+}
+
+func (s *server) CommitDelta(in *pb.CommitDeltaRequest, stream pb.Diff_CommitDeltaServer) error {
+ if err := validateRequest(in); err != nil {
+ return grpc.Errorf(codes.InvalidArgument, "CommitDelta: %v", err)
}
- if err := diffParser.Err(); err != nil {
- log.Printf("CommitDiff: Parsing diff in repo %q between %q and %q failed: %v", repoPath, leftSha, rightSha, err)
- return grpc.Errorf(codes.Internal, "CommitDiff: parse failure: %v", err)
+ repoPath, err := helper.GetRepoPath(in.Repository)
+ if err != nil {
+ return err
}
+ leftSha := in.LeftCommitId
+ rightSha := in.RightCommitId
+ paths := in.GetPaths()
- if err := cmd.Wait(); err != nil {
- return grpc.Errorf(codes.Unavailable, "CommitDiff: cmd wait for %v: %v", cmd.Args, err)
+ helper.Debugf(
+ "CommitDelta: RepoPath=%q LeftCommitId=%q RightCommitId=%q Paths=%s",
+ repoPath,
+ leftSha,
+ rightSha,
+ paths,
+ )
+
+ cmdArgs := []string{
+ "--git-dir", repoPath,
+ "diff",
+ "--raw",
+ "--abbrev=40",
+ "--full-index",
+ "--find-renames",
+ leftSha,
+ rightSha,
+ }
+ if len(paths) > 0 {
+ cmdArgs = append(cmdArgs, "--")
+ for _, path := range paths {
+ cmdArgs = append(cmdArgs, string(path))
+ }
+ }
+
+ var batch []*pb.CommitDelta
+ var batchSize int
+
+ flushFunc := func() error {
+ if len(batch) == 0 {
+ return nil
+ }
+
+ if err := stream.Send(&pb.CommitDeltaResponse{Deltas: batch}); err != nil {
+ return grpc.Errorf(codes.Unavailable, "CommitDelta: send: %v", err)
+ }
+
+ return nil
+ }
+
+ err = eachDiff("CommitDelta", cmdArgs, func(diff *diff.Diff) error {
+ delta := &pb.CommitDelta{
+ FromPath: diff.FromPath,
+ ToPath: diff.ToPath,
+ FromId: diff.FromID,
+ ToId: diff.ToID,
+ OldMode: diff.OldMode,
+ NewMode: diff.NewMode,
+ }
+
+ batch = append(batch, delta)
+ batchSize += deltaSize(diff)
+
+ if batchSize > s.MsgSizeThreshold {
+ if err := flushFunc(); err != nil {
+ return err
+ }
+
+ batch = nil
+ batchSize = 0
+ }
+
+ return nil
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return flushFunc()
+}
+
+func validateRequest(in requestWithLeftRightCommitIds) error {
+ if in.GetLeftCommitId() == "" {
+ return fmt.Errorf("empty LeftCommitId")
+ }
+ if in.GetRightCommitId() == "" {
+ return fmt.Errorf("empty RightCommitId")
}
return nil
}
-func validateRequest(in *pb.CommitDiffRequest) error {
- if in.LeftCommitId == "" {
- return grpc.Errorf(codes.InvalidArgument, "CommitDiff: empty LeftCommitId")
+func eachDiff(rpc string, cmdArgs []string, callback func(*diff.Diff) error) error {
+ cmd, err := helper.GitCommandReader(cmdArgs...)
+ if err != nil {
+ return grpc.Errorf(codes.Internal, "%s: cmd: %v", rpc, err)
}
- if in.RightCommitId == "" {
- return grpc.Errorf(codes.InvalidArgument, "CommitDiff: empty RightCommitId")
+ defer cmd.Kill()
+
+ diffParser := diff.NewDiffParser(cmd)
+
+ for diffParser.Parse() {
+ if err := callback(diffParser.Diff()); err != nil {
+ return err
+ }
+ }
+
+ if err := diffParser.Err(); err != nil {
+ return grpc.Errorf(codes.Internal, "%s: parse failure: %v", rpc, err)
+ }
+
+ if err := cmd.Wait(); err != nil {
+ return grpc.Errorf(codes.Unavailable, "%s: cmd wait for %v: %v", rpc, cmd.Args, err)
}
return nil
}
+
+func deltaSize(diff *diff.Diff) int {
+ size := len(diff.FromID) + len(diff.ToID) +
+ 4 + 4 + // OldMode and NewMode are int32 = 32/8 = 4 bytes
+ len(diff.FromPath) + len(diff.ToPath)
+
+ return size
+}
diff --git a/internal/service/diff/commit_test.go b/internal/service/diff/commit_test.go
index bc1c36922..24f573e5f 100644
--- a/internal/service/diff/commit_test.go
+++ b/internal/service/diff/commit_test.go
@@ -475,6 +475,233 @@ func TestFailedCommitDiffRequestWithNonExistentCommit(t *testing.T) {
testhelper.AssertGrpcError(t, err, codes.Unavailable, "")
}
+func TestSuccessfulCommitDeltaRequest(t *testing.T) {
+ server := runDiffServer(t)
+ defer server.Stop()
+
+ client := newDiffClient(t)
+ repo := &pb.Repository{Path: testRepoPath}
+ rightCommit := "742518b2be68fc750bb4c357c0df821a88113286"
+ leftCommit := "8a0f2ee90d940bfb0ba1e14e8214b0649056e4ab"
+ rpcRequest := &pb.CommitDeltaRequest{Repository: repo, RightCommitId: rightCommit, LeftCommitId: leftCommit}
+
+ c, err := client.CommitDelta(context.Background(), rpcRequest)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expectedDeltas := []diff.Diff{
+ {
+ FromID: "faaf198af3a36dbf41961466703cc1d47c61d051",
+ ToID: "877cee6ab11f9094e1bcdb7f1fd9c0001b572185",
+ OldMode: 0100644,
+ NewMode: 0100644,
+ FromPath: []byte("README.md"),
+ ToPath: []byte("README.md"),
+ },
+ {
+ FromID: "bdea48ee65c869eb0b86b1283069d76cce0a7254",
+ ToID: "0000000000000000000000000000000000000000",
+ OldMode: 0100644,
+ NewMode: 0,
+ FromPath: []byte("gitaly/deleted-file"),
+ ToPath: []byte("gitaly/deleted-file"),
+ },
+ {
+ FromID: "aa408b4556e594f7974390ad6b86210617fbda6e",
+ ToID: "1c69c4d2a65ad05c24ac3b6780b5748b97ffd3aa",
+ OldMode: 0100644,
+ NewMode: 0100644,
+ FromPath: []byte("gitaly/file-with-multiple-chunks"),
+ ToPath: []byte("gitaly/file-with-multiple-chunks"),
+ },
+ {
+ FromID: "0000000000000000000000000000000000000000",
+ ToID: "bc2ef601a538d69ef99d5bdafa605e63f902e8e4",
+ OldMode: 0,
+ NewMode: 0100644,
+ FromPath: []byte("gitaly/logo-white.png"),
+ ToPath: []byte("gitaly/logo-white.png"),
+ },
+ {
+ FromID: "ead5a0eee1391308803cfebd8a2a8530495645eb",
+ ToID: "ead5a0eee1391308803cfebd8a2a8530495645eb",
+ OldMode: 0100644,
+ NewMode: 0100755,
+ FromPath: []byte("gitaly/mode-file"),
+ ToPath: []byte("gitaly/mode-file"),
+ },
+ {
+ FromID: "357406f3075a57708d0163752905cc1576fceacc",
+ ToID: "8e5177d718c561d36efde08bad36b43687ee6bf0",
+ OldMode: 0100644,
+ NewMode: 0100755,
+ FromPath: []byte("gitaly/mode-file-with-mods"),
+ ToPath: []byte("gitaly/mode-file-with-mods"),
+ },
+ {
+ FromID: "43d24af4e22580f36b1ca52647c1aff75a766a33",
+ ToID: "0000000000000000000000000000000000000000",
+ OldMode: 0100644,
+ NewMode: 0,
+ FromPath: []byte("gitaly/named-file-with-mods"),
+ ToPath: []byte("gitaly/named-file-with-mods"),
+ },
+ {
+ FromID: "0000000000000000000000000000000000000000",
+ ToID: "b464dff7a75ccc92fbd920fd9ae66a84b9d2bf94",
+ OldMode: 0,
+ NewMode: 0100644,
+ FromPath: []byte("gitaly/no-newline-at-the-end"),
+ ToPath: []byte("gitaly/no-newline-at-the-end"),
+ },
+ {
+ FromID: "4e76e90b3c7e52390de9311a23c0a77575aed8a8",
+ ToID: "4e76e90b3c7e52390de9311a23c0a77575aed8a8",
+ OldMode: 0100644,
+ NewMode: 0100644,
+ FromPath: []byte("gitaly/named-file"),
+ ToPath: []byte("gitaly/renamed-file"),
+ },
+ {
+ FromID: "0000000000000000000000000000000000000000",
+ ToID: "3856c00e9450a51a62096327167fc43d3be62eef",
+ OldMode: 0,
+ NewMode: 0100644,
+ FromPath: []byte("gitaly/renamed-file-with-mods"),
+ ToPath: []byte("gitaly/renamed-file-with-mods"),
+ },
+ {
+ FromID: "0000000000000000000000000000000000000000",
+ ToID: "a135e3e0d4af177a902ca57dcc4c7fc6f30858b1",
+ OldMode: 0,
+ NewMode: 0100644,
+ FromPath: []byte("gitaly/tab\tnewline\n file"),
+ ToPath: []byte("gitaly/tab\tnewline\n file"),
+ },
+ {
+ FromID: "0000000000000000000000000000000000000000",
+ ToID: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
+ OldMode: 0,
+ NewMode: 0100755,
+ FromPath: []byte("gitaly/テスト.txt"),
+ ToPath: []byte("gitaly/テスト.txt"),
+ },
+ }
+
+ assertExactReceivedDeltas(t, c, expectedDeltas)
+}
+
+func TestSuccessfulCommitDeltaRequestWithPaths(t *testing.T) {
+ server := runDiffServer(t)
+ defer server.Stop()
+
+ client := newDiffClient(t)
+ repo := &pb.Repository{Path: testRepoPath}
+ rightCommit := "e4003da16c1c2c3fc4567700121b17bf8e591c6c"
+ leftCommit := "8a0f2ee90d940bfb0ba1e14e8214b0649056e4ab"
+ rpcRequest := &pb.CommitDeltaRequest{
+ Repository: repo,
+ RightCommitId: rightCommit,
+ LeftCommitId: leftCommit,
+ Paths: [][]byte{
+ []byte("CONTRIBUTING.md"),
+ []byte("README.md"),
+ []byte("gitaly/named-file-with-mods"),
+ []byte("gitaly/mode-file-with-mods"),
+ },
+ }
+
+ c, err := client.CommitDelta(context.Background(), rpcRequest)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expectedDeltas := []diff.Diff{
+ {
+ FromID: "c1788657b95998a2f177a4f86d68a60f2a80117f",
+ ToID: "b87f61fe2d7b2e208b340a1f3cafea916bd27f75",
+ OldMode: 0100644,
+ NewMode: 0100644,
+ FromPath: []byte("CONTRIBUTING.md"),
+ ToPath: []byte("CONTRIBUTING.md"),
+ },
+ {
+ FromID: "faaf198af3a36dbf41961466703cc1d47c61d051",
+ ToID: "877cee6ab11f9094e1bcdb7f1fd9c0001b572185",
+ OldMode: 0100644,
+ NewMode: 0100644,
+ FromPath: []byte("README.md"),
+ ToPath: []byte("README.md"),
+ },
+ {
+ FromID: "357406f3075a57708d0163752905cc1576fceacc",
+ ToID: "8e5177d718c561d36efde08bad36b43687ee6bf0",
+ OldMode: 0100644,
+ NewMode: 0100755,
+ FromPath: []byte("gitaly/mode-file-with-mods"),
+ ToPath: []byte("gitaly/mode-file-with-mods"),
+ },
+ {
+ FromID: "43d24af4e22580f36b1ca52647c1aff75a766a33",
+ ToID: "0000000000000000000000000000000000000000",
+ OldMode: 0100644,
+ NewMode: 0,
+ FromPath: []byte("gitaly/named-file-with-mods"),
+ ToPath: []byte("gitaly/named-file-with-mods"),
+ },
+ }
+
+ assertExactReceivedDeltas(t, c, expectedDeltas)
+}
+
+func TestFailedCommitDeltaRequestDueToValidationError(t *testing.T) {
+ server := runDiffServer(t)
+ defer server.Stop()
+
+ client := newDiffClient(t)
+ rightCommit := "d42783470dc29fde2cf459eb3199ee1d7e3f3a72"
+ leftCommit := rightCommit + "~" // Parent of rightCommit
+
+ rpcRequests := []pb.CommitDeltaRequest{
+ {Repository: &pb.Repository{Path: ""}, RightCommitId: rightCommit, LeftCommitId: leftCommit}, // Repository.Path is empty
+ {Repository: nil, RightCommitId: rightCommit, LeftCommitId: leftCommit}, // Repository is nil
+ {Repository: &pb.Repository{Path: testRepoPath}, RightCommitId: "", LeftCommitId: leftCommit}, // RightCommitId is empty
+ {Repository: &pb.Repository{Path: testRepoPath}, RightCommitId: rightCommit, LeftCommitId: ""}, // LeftCommitId is empty
+ }
+
+ for _, rpcRequest := range rpcRequests {
+ t.Logf("test case: %v", rpcRequest)
+
+ c, err := client.CommitDelta(context.Background(), &rpcRequest)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = drainCommitDeltaResponse(c)
+ testhelper.AssertGrpcError(t, err, codes.InvalidArgument, "")
+ }
+}
+
+func TestFailedCommitDeltaRequestWithNonExistentCommit(t *testing.T) {
+ server := runDiffServer(t)
+ defer server.Stop()
+
+ client := newDiffClient(t)
+ repo := &pb.Repository{Path: testRepoPath}
+ nonExistentCommitID := "deadfacedeadfacedeadfacedeadfacedeadface"
+ leftCommit := nonExistentCommitID + "~" // Parent of rightCommit
+ rpcRequest := &pb.CommitDeltaRequest{Repository: repo, RightCommitId: nonExistentCommitID, LeftCommitId: leftCommit}
+
+ c, err := client.CommitDelta(context.Background(), rpcRequest)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = drainCommitDeltaResponse(c)
+ testhelper.AssertGrpcError(t, err, codes.Unavailable, "")
+}
+
func runDiffServer(t *testing.T) *grpc.Server {
server := grpc.NewServer()
listener, err := net.Listen("unix", serverSocketPath)
@@ -516,6 +743,17 @@ func drainCommitDiffResponse(c pb.Diff_CommitDiffClient) error {
return nil
}
+func drainCommitDeltaResponse(c pb.Diff_CommitDeltaClient) error {
+ for {
+ _, err := c.Recv()
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
func assertExactReceivedDiffs(t *testing.T, client pb.Diff_CommitDiffClient, expectedDiffs []expectedDiff) {
i := 0
for {
@@ -550,11 +788,11 @@ func assertExactReceivedDiffs(t *testing.T, client pb.Diff_CommitDiffClient, exp
}
if !bytes.Equal(expectedDiff.FromPath, fetchedDiff.FromPath) {
- t.Errorf("Expected diff #%d FromPath to equal = %s, got %s", i, expectedDiff.FromPath, fetchedDiff.FromPath)
+ t.Errorf("Expected diff #%d FromPath to equal = %q, got %q", i, expectedDiff.FromPath, fetchedDiff.FromPath)
}
if !bytes.Equal(expectedDiff.ToPath, fetchedDiff.ToPath) {
- t.Errorf("Expected diff #%d ToPath to equal = %s, got %s", i, expectedDiff.ToPath, fetchedDiff.ToPath)
+ t.Errorf("Expected diff #%d ToPath to equal = %q, got %q", i, expectedDiff.ToPath, fetchedDiff.ToPath)
}
if expectedDiff.Binary != fetchedDiff.Binary {
@@ -573,3 +811,54 @@ func assertExactReceivedDiffs(t *testing.T, client pb.Diff_CommitDiffClient, exp
t.Errorf("Expected number of diffs to be %d, got %d", len(expectedDiffs), i)
}
}
+
+func assertExactReceivedDeltas(t *testing.T, client pb.Diff_CommitDeltaClient, expectedDeltas []diff.Diff) {
+ i := 0
+ for {
+ fetchedDeltas, err := client.Recv()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ t.Fatal(err)
+ }
+
+ for _, fetchedDelta := range fetchedDeltas.GetDeltas() {
+ if i >= len(expectedDeltas) {
+ t.Errorf("Unexpected delta #%d received: %v", i, fetchedDelta)
+ break
+ }
+
+ expectedDelta := expectedDeltas[i]
+
+ if expectedDelta.FromID != fetchedDelta.FromId {
+ t.Errorf("Expected delta #%d FromID to equal = %q, got %q", i, expectedDelta.FromID, fetchedDelta.FromId)
+ }
+
+ if expectedDelta.ToID != fetchedDelta.ToId {
+ t.Errorf("Expected delta #%d ToID to equal = %q, got %q", i, expectedDelta.ToID, fetchedDelta.ToId)
+ }
+
+ if expectedDelta.OldMode != fetchedDelta.OldMode {
+ t.Errorf("Expected delta #%d OldMode to equal = %o, got %o", i, expectedDelta.OldMode, fetchedDelta.OldMode)
+ }
+
+ if expectedDelta.NewMode != fetchedDelta.NewMode {
+ t.Errorf("Expected delta #%d NewMode to equal = %o, got %o", i, expectedDelta.NewMode, fetchedDelta.NewMode)
+ }
+
+ if !bytes.Equal(expectedDelta.FromPath, fetchedDelta.FromPath) {
+ t.Errorf("Expected delta #%d FromPath to equal = %q, got %q", i, expectedDelta.FromPath, fetchedDelta.FromPath)
+ }
+
+ if !bytes.Equal(expectedDelta.ToPath, fetchedDelta.ToPath) {
+ t.Errorf("Expected delta #%d ToPath to equal = %q, got %q", i, expectedDelta.ToPath, fetchedDelta.ToPath)
+ }
+
+ i++
+ }
+ }
+
+ if len(expectedDeltas) != i {
+ t.Errorf("Expected number of deltas to be %d, got %d", len(expectedDeltas), i)
+ }
+}
diff --git a/internal/service/diff/server.go b/internal/service/diff/server.go
index 945c66a1f..e75cbd386 100644
--- a/internal/service/diff/server.go
+++ b/internal/service/diff/server.go
@@ -4,9 +4,13 @@ import (
pb "gitlab.com/gitlab-org/gitaly-proto/go"
)
-type server struct{}
+const msgSizeThreshold = 1024
+
+type server struct {
+ MsgSizeThreshold int
+}
// NewServer creates a new instance of a gRPC DiffServer
func NewServer() pb.DiffServer {
- return &server{}
+ return &server{MsgSizeThreshold: msgSizeThreshold}
}
diff --git a/internal/service/middleware/loghandler/loghandler.go b/internal/service/middleware/loghandler/loghandler.go
new file mode 100644
index 000000000..8f4d17f5b
--- /dev/null
+++ b/internal/service/middleware/loghandler/loghandler.go
@@ -0,0 +1,32 @@
+package loghandler
+
+import (
+ "log"
+ "time"
+
+ "golang.org/x/net/context"
+ "google.golang.org/grpc"
+)
+
+// UnaryLogHandler handles access times and errors for unary RPC's
+func UnaryLogHandler(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
+ start := time.Now()
+ resp, err := handler(ctx, req)
+ logRequest(info.FullMethod, start, err)
+ return resp, err
+}
+
+// StreamLogHandler handles access times and errors for stream RPC's
+func StreamLogHandler(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
+ start := time.Now()
+ err := handler(srv, stream)
+ logRequest(info.FullMethod, start, err)
+ return err
+}
+
+func logRequest(method string, start time.Time, err error) {
+ if err != nil {
+ log.Printf("error: %s: %v", method, err)
+ }
+ log.Printf("%s %.3f", method, time.Since(start).Seconds())
+}
diff --git a/internal/service/notifications/post_receive.go b/internal/service/notifications/post_receive.go
index f63db6f9b..e8c809f31 100644
--- a/internal/service/notifications/post_receive.go
+++ b/internal/service/notifications/post_receive.go
@@ -1,8 +1,6 @@
package notifications
import (
- "log"
-
"gitlab.com/gitlab-org/gitaly/internal/helper"
pb "gitlab.com/gitlab-org/gitaly-proto/go"
@@ -11,12 +9,10 @@ import (
)
func (s *server) PostReceive(ctx context.Context, in *pb.PostReceiveRequest) (*pb.PostReceiveResponse, error) {
- // TODO: Invalidate InfoRefs cache
repoPath, err := helper.GetRepoPath(in.GetRepository())
if err != nil {
return nil, err
}
-
- log.Printf("PostReceive: RepoPath=%q", repoPath)
+ helper.Debugf("PostReceive: RepoPath=%q", repoPath)
return &pb.PostReceiveResponse{}, nil
}
diff --git a/internal/service/ref/refname.go b/internal/service/ref/refname.go
index d3b402b94..873974143 100644
--- a/internal/service/ref/refname.go
+++ b/internal/service/ref/refname.go
@@ -2,7 +2,6 @@ package ref
import (
"bufio"
- "log"
"strings"
"google.golang.org/grpc"
@@ -23,9 +22,7 @@ func (s *server) FindRefName(ctx context.Context, in *pb.FindRefNameRequest) (*p
return nil, err
}
if in.CommitId == "" {
- message := "Bad Request (empty commit sha)"
- log.Printf("FindRefName: %q", message)
- return nil, grpc.Errorf(codes.InvalidArgument, message)
+ return nil, grpc.Errorf(codes.InvalidArgument, "Bad Request (empty commit sha)")
}
ref, err := findRefName(repoPath, in.CommitId, string(in.Prefix))
@@ -44,7 +41,7 @@ func findRefName(path, commitID, prefix string) (string, error) {
}
defer cmd.Kill()
- log.Printf("findRefName: RepoPath=%q commitSha=%s prefix=%s", path, commitID, prefix)
+ helper.Debugf("findRefName: RepoPath=%q commitSha=%s prefix=%s", path, commitID, prefix)
scanner := bufio.NewScanner(cmd)
scanner.Scan()
diff --git a/internal/service/ref/refs.go b/internal/service/ref/refs.go
index 051e9fb5a..6fe12e34e 100644
--- a/internal/service/ref/refs.go
+++ b/internal/service/ref/refs.go
@@ -5,9 +5,11 @@ import (
"bytes"
"fmt"
"io"
- "log"
"strings"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+
pb "gitlab.com/gitlab-org/gitaly-proto/go"
"gitlab.com/gitlab-org/gitaly/internal/helper"
"golang.org/x/net/context"
@@ -39,7 +41,7 @@ func findRefs(writer refsWriter, repo *pb.Repository, pattern string, args ...st
return err
}
- log.Printf("FindRefs: RepoPath=%q Pattern=%q", repoPath, pattern)
+ helper.Debugf("FindRefs: RepoPath=%q Pattern=%q", repoPath, pattern)
baseArgs := []string{"--git-dir", repoPath, "for-each-ref", pattern}
@@ -165,11 +167,11 @@ func (s *server) FindDefaultBranchName(ctx context.Context, in *pb.FindDefaultBr
return nil, err
}
- log.Printf("FindDefaultBranchName: RepoPath=%q", repoPath)
+ helper.Debugf("FindDefaultBranchName: RepoPath=%q", repoPath)
defaultBranchName, err := defaultBranchName(repoPath)
if err != nil {
- return nil, err
+ return nil, grpc.Errorf(codes.Internal, err.Error())
}
return &pb.FindDefaultBranchNameResponse{Name: defaultBranchName}, nil
diff --git a/internal/service/register.go b/internal/service/register.go
index 54465d2fb..ae96cb1fd 100644
--- a/internal/service/register.go
+++ b/internal/service/register.go
@@ -7,6 +7,7 @@ import (
"gitlab.com/gitlab-org/gitaly/internal/service/notifications"
"gitlab.com/gitlab-org/gitaly/internal/service/ref"
"gitlab.com/gitlab-org/gitaly/internal/service/smarthttp"
+ "gitlab.com/gitlab-org/gitaly/internal/service/ssh"
"google.golang.org/grpc"
)
@@ -19,4 +20,5 @@ func RegisterAll(grpcServer *grpc.Server) {
pb.RegisterSmartHTTPServer(grpcServer, smarthttp.NewServer())
pb.RegisterDiffServer(grpcServer, diff.NewServer())
pb.RegisterCommitServer(grpcServer, commit.NewServer())
+ pb.RegisterSSHServer(grpcServer, ssh.NewServer())
}
diff --git a/internal/service/smarthttp/inforefs.go b/internal/service/smarthttp/inforefs.go
index 59026f7a5..b527d9019 100644
--- a/internal/service/smarthttp/inforefs.go
+++ b/internal/service/smarthttp/inforefs.go
@@ -3,7 +3,6 @@ package smarthttp
import (
"fmt"
"io"
- "log"
pb "gitlab.com/gitlab-org/gitaly-proto/go"
pbhelper "gitlab.com/gitlab-org/gitaly-proto/go/helper"
@@ -39,7 +38,7 @@ func handleInfoRefs(service string, repo *pb.Repository, w io.Writer) error {
}
defer cmd.Kill()
- log.Printf("handleInfoRefs: service=%q RepoPath=%q", service, repoPath)
+ helper.Debugf("handleInfoRefs: service=%q RepoPath=%q", service, repoPath)
if err := pktLine(w, fmt.Sprintf("# service=git-%s\n", service)); err != nil {
return grpc.Errorf(codes.Internal, "GetInfoRefs: pktLine: %v", err)
diff --git a/internal/service/smarthttp/receive_pack.go b/internal/service/smarthttp/receive_pack.go
index 6c4ddfefe..7d482d10a 100644
--- a/internal/service/smarthttp/receive_pack.go
+++ b/internal/service/smarthttp/receive_pack.go
@@ -2,7 +2,6 @@ package smarthttp
import (
"fmt"
- "log"
"os/exec"
"gitlab.com/gitlab-org/gitaly/internal/helper"
@@ -29,16 +28,19 @@ func (s *server) PostReceivePack(stream pb.SmartHTTP_PostReceivePackServer) erro
stdout := pbhelper.NewSendWriter(func(p []byte) error {
return stream.Send(&pb.PostReceivePackResponse{Data: p})
})
- glIDEnv := fmt.Sprintf("GL_ID=%s", req.GlId)
+ env := []string{fmt.Sprintf("GL_ID=%s", req.GlId)}
+ if req.GlRepository != "" {
+ env = append(env, fmt.Sprintf("GL_REPOSITORY=%s", req.GlRepository))
+ }
repoPath, err := helper.GetRepoPath(req.Repository)
if err != nil {
return err
}
- log.Printf("PostReceivePack: RepoPath=%q GlID=%q", repoPath, req.GlId)
+ helper.Debugf("PostReceivePack: RepoPath=%q GlID=%q GlRepository=%q", repoPath, req.GlId, req.GlRepository)
osCommand := exec.Command("git", "receive-pack", "--stateless-rpc", repoPath)
- cmd, err := helper.NewCommand(osCommand, stdin, stdout, glIDEnv)
+ cmd, err := helper.NewCommand(osCommand, stdin, stdout, nil, env...)
if err != nil {
return grpc.Errorf(codes.Unavailable, "PostReceivePack: cmd: %v", err)
diff --git a/internal/service/smarthttp/receive_pack_test.go b/internal/service/smarthttp/receive_pack_test.go
index 72228591a..ca27e4317 100644
--- a/internal/service/smarthttp/receive_pack_test.go
+++ b/internal/service/smarthttp/receive_pack_test.go
@@ -66,7 +66,7 @@ func TestSuccessfulReceivePackRequest(t *testing.T) {
client := newSmartHTTPClient(t)
repo := &pb.Repository{Path: remoteRepoPath}
- rpcRequest := &pb.PostReceivePackRequest{Repository: repo, GlId: "user-123"}
+ rpcRequest := &pb.PostReceivePackRequest{Repository: repo, GlId: "user-123", GlRepository: "project-123"}
stream, err := client.PostReceivePack(context.Background())
if err != nil {
t.Fatal(err)
diff --git a/internal/service/smarthttp/stream_reader.go b/internal/service/smarthttp/stream_reader.go
deleted file mode 100644
index 561e47f24..000000000
--- a/internal/service/smarthttp/stream_reader.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package smarthttp
-
-type bytesReceiver interface {
- ReceiveBytes() ([]byte, error)
-}
-
-type streamReader struct {
- br bytesReceiver
- buf []byte
-}
-
-func (rd *streamReader) Read(p []byte) (int, error) {
- var err error
-
- if len(rd.buf) == 0 {
- rd.buf, err = rd.br.ReceiveBytes()
- if err != nil {
- return 0, err
- }
- }
- n := copy(p, rd.buf)
- rd.buf = rd.buf[n:]
- return n, nil
-}
diff --git a/internal/service/smarthttp/upload_pack.go b/internal/service/smarthttp/upload_pack.go
index f34ee1b7f..a5ee5b15f 100644
--- a/internal/service/smarthttp/upload_pack.go
+++ b/internal/service/smarthttp/upload_pack.go
@@ -1,7 +1,6 @@
package smarthttp
import (
- "log"
"os/exec"
"gitlab.com/gitlab-org/gitaly/internal/helper"
@@ -33,10 +32,10 @@ func (s *server) PostUploadPack(stream pb.SmartHTTP_PostUploadPackServer) error
return err
}
- log.Printf("PostUploadPack: RepoPath=%q", repoPath)
+ helper.Debugf("PostUploadPack: RepoPath=%q", repoPath)
osCommand := exec.Command("git", "upload-pack", "--stateless-rpc", repoPath)
- cmd, err := helper.NewCommand(osCommand, stdin, stdout)
+ cmd, err := helper.NewCommand(osCommand, stdin, stdout, nil)
if err != nil {
return grpc.Errorf(codes.Unavailable, "PostUploadPack: cmd: %v", err)
diff --git a/internal/service/ssh/receive_pack.go b/internal/service/ssh/receive_pack.go
new file mode 100644
index 000000000..82e9c7e5b
--- /dev/null
+++ b/internal/service/ssh/receive_pack.go
@@ -0,0 +1,79 @@
+package ssh
+
+import (
+ "fmt"
+ "os/exec"
+
+ "gitlab.com/gitlab-org/gitaly/internal/helper"
+
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+ pbhelper "gitlab.com/gitlab-org/gitaly-proto/go/helper"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+)
+
+func (s *server) SSHReceivePack(stream pb.SSH_SSHReceivePackServer) error {
+ req, err := stream.Recv() // First request contains only Repository and GlId
+ if err != nil {
+ return err
+ }
+ if err = validateFirstReceivePackRequest(req); err != nil {
+ return err
+ }
+
+ stdin := pbhelper.NewReceiveReader(func() ([]byte, error) {
+ request, err := stream.Recv()
+ return request.GetStdin(), err
+ })
+ stdout := pbhelper.NewSendWriter(func(p []byte) error {
+ return stream.Send(&pb.SSHReceivePackResponse{Stdout: p})
+ })
+ stderr := pbhelper.NewSendWriter(func(p []byte) error {
+ return stream.Send(&pb.SSHReceivePackResponse{Stderr: p})
+ })
+ env := []string{
+ fmt.Sprintf("GL_ID=%s", req.GlId),
+ "GL_PROTOCOL=ssh",
+ }
+ if req.GlRepository != "" {
+ env = append(env, fmt.Sprintf("GL_REPOSITORY=%s", req.GlRepository))
+ }
+
+ repoPath, err := helper.GetRepoPath(req.Repository)
+ if err != nil {
+ return err
+ }
+
+ helper.Debugf("SSHReceivePack: RepoPath=%q GlID=%q GlRepository=%q", repoPath, req.GlId, req.GlRepository)
+
+ osCommand := exec.Command("git-receive-pack", repoPath)
+ cmd, err := helper.NewCommand(osCommand, stdin, stdout, stderr, env...)
+
+ if err != nil {
+ return grpc.Errorf(codes.Unavailable, "SSHReceivePack: cmd: %v", err)
+ }
+ defer cmd.Kill()
+
+ if err := cmd.Wait(); err != nil {
+ if status, ok := helper.ExitStatus(err); ok {
+ return helper.DecorateError(
+ codes.Internal,
+ stream.Send(&pb.SSHReceivePackResponse{ExitStatus: &pb.ExitStatus{Value: int32(status)}}),
+ )
+ }
+ return grpc.Errorf(codes.Unavailable, "SSHReceivePack: cmd wait for %v: %v", cmd.Args, err)
+ }
+
+ return nil
+}
+
+func validateFirstReceivePackRequest(req *pb.SSHReceivePackRequest) error {
+ if req.GlId == "" {
+ return grpc.Errorf(codes.InvalidArgument, "SSHReceivePack: empty GlId")
+ }
+ if req.Stdin != nil {
+ return grpc.Errorf(codes.InvalidArgument, "SSHReceivePack: non-empty data")
+ }
+
+ return nil
+}
diff --git a/internal/service/ssh/receive_pack_test.go b/internal/service/ssh/receive_pack_test.go
new file mode 100644
index 000000000..813e292c8
--- /dev/null
+++ b/internal/service/ssh/receive_pack_test.go
@@ -0,0 +1,50 @@
+package ssh
+
+import (
+ "testing"
+
+ "gitlab.com/gitlab-org/gitaly/internal/testhelper"
+
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+
+ "golang.org/x/net/context"
+ "google.golang.org/grpc/codes"
+)
+
+func TestFailedReceivePackRequestDueToValidationError(t *testing.T) {
+ server := runSSHServer(t)
+ defer server.Stop()
+
+ client := newSSHClient(t)
+
+ rpcRequests := []pb.SSHReceivePackRequest{
+ {Repository: &pb.Repository{Path: ""}, GlId: "user-123"}, // Repository.Path is empty
+ {Repository: nil, GlId: "user-123"}, // Repository is nil
+ {Repository: &pb.Repository{Path: "/path/to/repo"}, GlId: ""}, // Empty GlId
+ {Repository: &pb.Repository{Path: "/path/to/repo"}, GlId: "user-123", Stdin: []byte("Fail")}, // Data exists on first request
+ }
+
+ for _, rpcRequest := range rpcRequests {
+ t.Logf("test case: %v", rpcRequest)
+ stream, err := client.SSHReceivePack(context.Background())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err = stream.Send(&rpcRequest); err != nil {
+ t.Fatal(err)
+ }
+ stream.CloseSend()
+
+ err = drainPostReceivePackResponse(stream)
+ testhelper.AssertGrpcError(t, err, codes.InvalidArgument, "")
+ }
+}
+
+func drainPostReceivePackResponse(stream pb.SSH_SSHReceivePackClient) error {
+ var err error
+ for err == nil {
+ _, err = stream.Recv()
+ }
+ return err
+}
diff --git a/internal/service/ssh/server.go b/internal/service/ssh/server.go
new file mode 100644
index 000000000..5012f022f
--- /dev/null
+++ b/internal/service/ssh/server.go
@@ -0,0 +1,10 @@
+package ssh
+
+import pb "gitlab.com/gitlab-org/gitaly-proto/go"
+
+type server struct{}
+
+// NewServer creates a new instance of a grpc SSHServer
+func NewServer() pb.SSHServer {
+ return &server{}
+}
diff --git a/internal/service/ssh/testhelper_test.go b/internal/service/ssh/testhelper_test.go
new file mode 100644
index 000000000..84b037519
--- /dev/null
+++ b/internal/service/ssh/testhelper_test.go
@@ -0,0 +1,64 @@
+package ssh
+
+import (
+ "log"
+ "net"
+ "os"
+ "path"
+ "testing"
+ "time"
+
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/reflection"
+)
+
+const (
+ scratchDir = "testdata/scratch"
+)
+
+var (
+ serverSocketPath = path.Join(scratchDir, "gitaly.sock")
+)
+
+func TestMain(m *testing.M) {
+ if err := os.MkdirAll(scratchDir, 0755); err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(scratchDir)
+
+ os.Exit(func() int {
+ return m.Run()
+ }())
+}
+
+func runSSHServer(t *testing.T) *grpc.Server {
+ server := grpc.NewServer()
+ listener, err := net.Listen("unix", serverSocketPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ pb.RegisterSSHServer(server, NewServer())
+ reflection.Register(server)
+
+ go server.Serve(listener)
+
+ return server
+}
+
+func newSSHClient(t *testing.T) pb.SSHClient {
+ connOpts := []grpc.DialOption{
+ grpc.WithInsecure(),
+ grpc.WithDialer(func(addr string, _ time.Duration) (net.Conn, error) {
+ return net.Dial("unix", addr)
+ }),
+ }
+ conn, err := grpc.Dial(serverSocketPath, connOpts...)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return pb.NewSSHClient(conn)
+}
diff --git a/internal/service/ssh/upload_pack_test.go b/internal/service/ssh/upload_pack_test.go
new file mode 100644
index 000000000..da223e100
--- /dev/null
+++ b/internal/service/ssh/upload_pack_test.go
@@ -0,0 +1,49 @@
+package ssh
+
+import (
+ "testing"
+
+ "gitlab.com/gitlab-org/gitaly/internal/testhelper"
+
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+
+ "golang.org/x/net/context"
+ "google.golang.org/grpc/codes"
+)
+
+func TestFailedUploadPackRequestDueToValidationError(t *testing.T) {
+ server := runSSHServer(t)
+ defer server.Stop()
+
+ client := newSSHClient(t)
+
+ rpcRequests := []pb.SSHUploadPackRequest{
+ {Repository: &pb.Repository{Path: ""}}, // Repository.Path is empty
+ {Repository: nil}, // Repository is nil
+ {Repository: &pb.Repository{Path: "/path/to/repo"}, Stdin: []byte("Fail")}, // Data exists on first request
+ }
+
+ for _, rpcRequest := range rpcRequests {
+ t.Logf("test case: %v", rpcRequest)
+ stream, err := client.SSHUploadPack(context.Background())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err = stream.Send(&rpcRequest); err != nil {
+ t.Fatal(err)
+ }
+ stream.CloseSend()
+
+ err = drainPostUploadPackResponse(stream)
+ testhelper.AssertGrpcError(t, err, codes.InvalidArgument, "")
+ }
+}
+
+func drainPostUploadPackResponse(stream pb.SSH_SSHUploadPackClient) error {
+ var err error
+ for err == nil {
+ _, err = stream.Recv()
+ }
+ return err
+}
diff --git a/internal/service/ssh/uploadpack.go b/internal/service/ssh/uploadpack.go
new file mode 100644
index 000000000..2af4fd7f0
--- /dev/null
+++ b/internal/service/ssh/uploadpack.go
@@ -0,0 +1,66 @@
+package ssh
+
+import (
+ "os/exec"
+
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+ pbhelper "gitlab.com/gitlab-org/gitaly-proto/go/helper"
+ "gitlab.com/gitlab-org/gitaly/internal/helper"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+)
+
+func (s *server) SSHUploadPack(stream pb.SSH_SSHUploadPackServer) error {
+ req, err := stream.Recv() // First request contains Repository only
+ if err != nil {
+ return err
+ }
+ if err = validateFirstUploadPackRequest(req); err != nil {
+ return err
+ }
+
+ stdin := pbhelper.NewReceiveReader(func() ([]byte, error) {
+ request, err := stream.Recv()
+ return request.GetStdin(), err
+ })
+ stdout := pbhelper.NewSendWriter(func(p []byte) error {
+ return stream.Send(&pb.SSHUploadPackResponse{Stdout: p})
+ })
+ stderr := pbhelper.NewSendWriter(func(p []byte) error {
+ return stream.Send(&pb.SSHUploadPackResponse{Stderr: p})
+ })
+ repoPath, err := helper.GetRepoPath(req.Repository)
+ if err != nil {
+ return err
+ }
+
+ helper.Debugf("SSHUploadPack: RepoPath=%q", repoPath)
+
+ osCommand := exec.Command("git-upload-pack", repoPath)
+ cmd, err := helper.NewCommand(osCommand, stdin, stdout, stderr)
+
+ if err != nil {
+ return grpc.Errorf(codes.Unavailable, "SSHUploadPack: cmd: %v", err)
+ }
+ defer cmd.Kill()
+
+ if err := cmd.Wait(); err != nil {
+ if status, ok := helper.ExitStatus(err); ok {
+ return helper.DecorateError(
+ codes.Internal,
+ stream.Send(&pb.SSHUploadPackResponse{ExitStatus: &pb.ExitStatus{Value: int32(status)}}),
+ )
+ }
+ return grpc.Errorf(codes.Unavailable, "SSHUploadPack: cmd wait for %v: %v", cmd.Args, err)
+ }
+
+ return nil
+}
+
+func validateFirstUploadPackRequest(req *pb.SSHUploadPackRequest) error {
+ if req.Stdin != nil {
+ return grpc.Errorf(codes.InvalidArgument, "SSHUploadPack: non-empty stdin")
+ }
+
+ return nil
+}
diff --git a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION
index a918a2aa1..faef31a43 100644
--- a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION
+++ b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION
@@ -1 +1 @@
-0.6.0
+0.7.0
diff --git a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/commit.pb.go b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/commit.pb.go
index 9d984bee4..756c122cf 100644
--- a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/commit.pb.go
+++ b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/commit.pb.go
@@ -19,6 +19,9 @@ It has these top-level messages:
CommitIsAncestorResponse
CommitDiffRequest
CommitDiffResponse
+ CommitDeltaRequest
+ CommitDelta
+ CommitDeltaResponse
PostReceiveRequest
PostReceiveResponse
FindDefaultBranchNameRequest
diff --git a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/diff.pb.go b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/diff.pb.go
index 9e1f0bcd2..30a729285 100644
--- a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/diff.pb.go
+++ b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/diff.pb.go
@@ -140,9 +140,125 @@ func (m *CommitDiffResponse) GetRawChunks() [][]byte {
return nil
}
+type CommitDeltaRequest struct {
+ Repository *Repository `protobuf:"bytes,1,opt,name=repository" json:"repository,omitempty"`
+ LeftCommitId string `protobuf:"bytes,2,opt,name=left_commit_id,json=leftCommitId" json:"left_commit_id,omitempty"`
+ RightCommitId string `protobuf:"bytes,3,opt,name=right_commit_id,json=rightCommitId" json:"right_commit_id,omitempty"`
+ Paths [][]byte `protobuf:"bytes,4,rep,name=paths,proto3" json:"paths,omitempty"`
+}
+
+func (m *CommitDeltaRequest) Reset() { *m = CommitDeltaRequest{} }
+func (m *CommitDeltaRequest) String() string { return proto.CompactTextString(m) }
+func (*CommitDeltaRequest) ProtoMessage() {}
+func (*CommitDeltaRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} }
+
+func (m *CommitDeltaRequest) GetRepository() *Repository {
+ if m != nil {
+ return m.Repository
+ }
+ return nil
+}
+
+func (m *CommitDeltaRequest) GetLeftCommitId() string {
+ if m != nil {
+ return m.LeftCommitId
+ }
+ return ""
+}
+
+func (m *CommitDeltaRequest) GetRightCommitId() string {
+ if m != nil {
+ return m.RightCommitId
+ }
+ return ""
+}
+
+func (m *CommitDeltaRequest) GetPaths() [][]byte {
+ if m != nil {
+ return m.Paths
+ }
+ return nil
+}
+
+type CommitDelta struct {
+ FromPath []byte `protobuf:"bytes,1,opt,name=from_path,json=fromPath,proto3" json:"from_path,omitempty"`
+ ToPath []byte `protobuf:"bytes,2,opt,name=to_path,json=toPath,proto3" json:"to_path,omitempty"`
+ // Blob ID as returned via `git diff --full-index`
+ FromId string `protobuf:"bytes,3,opt,name=from_id,json=fromId" json:"from_id,omitempty"`
+ ToId string `protobuf:"bytes,4,opt,name=to_id,json=toId" json:"to_id,omitempty"`
+ OldMode int32 `protobuf:"varint,5,opt,name=old_mode,json=oldMode" json:"old_mode,omitempty"`
+ NewMode int32 `protobuf:"varint,6,opt,name=new_mode,json=newMode" json:"new_mode,omitempty"`
+}
+
+func (m *CommitDelta) Reset() { *m = CommitDelta{} }
+func (m *CommitDelta) String() string { return proto.CompactTextString(m) }
+func (*CommitDelta) ProtoMessage() {}
+func (*CommitDelta) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} }
+
+func (m *CommitDelta) GetFromPath() []byte {
+ if m != nil {
+ return m.FromPath
+ }
+ return nil
+}
+
+func (m *CommitDelta) GetToPath() []byte {
+ if m != nil {
+ return m.ToPath
+ }
+ return nil
+}
+
+func (m *CommitDelta) GetFromId() string {
+ if m != nil {
+ return m.FromId
+ }
+ return ""
+}
+
+func (m *CommitDelta) GetToId() string {
+ if m != nil {
+ return m.ToId
+ }
+ return ""
+}
+
+func (m *CommitDelta) GetOldMode() int32 {
+ if m != nil {
+ return m.OldMode
+ }
+ return 0
+}
+
+func (m *CommitDelta) GetNewMode() int32 {
+ if m != nil {
+ return m.NewMode
+ }
+ return 0
+}
+
+type CommitDeltaResponse struct {
+ Deltas []*CommitDelta `protobuf:"bytes,1,rep,name=deltas" json:"deltas,omitempty"`
+}
+
+func (m *CommitDeltaResponse) Reset() { *m = CommitDeltaResponse{} }
+func (m *CommitDeltaResponse) String() string { return proto.CompactTextString(m) }
+func (*CommitDeltaResponse) ProtoMessage() {}
+func (*CommitDeltaResponse) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{4} }
+
+func (m *CommitDeltaResponse) GetDeltas() []*CommitDelta {
+ if m != nil {
+ return m.Deltas
+ }
+ return nil
+}
+
func init() {
proto.RegisterType((*CommitDiffRequest)(nil), "gitaly.CommitDiffRequest")
proto.RegisterType((*CommitDiffResponse)(nil), "gitaly.CommitDiffResponse")
+ proto.RegisterType((*CommitDeltaRequest)(nil), "gitaly.CommitDeltaRequest")
+ proto.RegisterType((*CommitDelta)(nil), "gitaly.CommitDelta")
+ proto.RegisterType((*CommitDeltaResponse)(nil), "gitaly.CommitDeltaResponse")
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -158,6 +274,8 @@ const _ = grpc.SupportPackageIsVersion4
type DiffClient interface {
// Returns stream of CommitDiffResponse: 1 per changed file
CommitDiff(ctx context.Context, in *CommitDiffRequest, opts ...grpc.CallOption) (Diff_CommitDiffClient, error)
+ // Return a stream so we can divide the response in chunks of deltas
+ CommitDelta(ctx context.Context, in *CommitDeltaRequest, opts ...grpc.CallOption) (Diff_CommitDeltaClient, error)
}
type diffClient struct {
@@ -200,11 +318,45 @@ func (x *diffCommitDiffClient) Recv() (*CommitDiffResponse, error) {
return m, nil
}
+func (c *diffClient) CommitDelta(ctx context.Context, in *CommitDeltaRequest, opts ...grpc.CallOption) (Diff_CommitDeltaClient, error) {
+ stream, err := grpc.NewClientStream(ctx, &_Diff_serviceDesc.Streams[1], c.cc, "/gitaly.Diff/CommitDelta", opts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &diffCommitDeltaClient{stream}
+ if err := x.ClientStream.SendMsg(in); err != nil {
+ return nil, err
+ }
+ if err := x.ClientStream.CloseSend(); err != nil {
+ return nil, err
+ }
+ return x, nil
+}
+
+type Diff_CommitDeltaClient interface {
+ Recv() (*CommitDeltaResponse, error)
+ grpc.ClientStream
+}
+
+type diffCommitDeltaClient struct {
+ grpc.ClientStream
+}
+
+func (x *diffCommitDeltaClient) Recv() (*CommitDeltaResponse, error) {
+ m := new(CommitDeltaResponse)
+ if err := x.ClientStream.RecvMsg(m); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
// Server API for Diff service
type DiffServer interface {
// Returns stream of CommitDiffResponse: 1 per changed file
CommitDiff(*CommitDiffRequest, Diff_CommitDiffServer) error
+ // Return a stream so we can divide the response in chunks of deltas
+ CommitDelta(*CommitDeltaRequest, Diff_CommitDeltaServer) error
}
func RegisterDiffServer(s *grpc.Server, srv DiffServer) {
@@ -232,6 +384,27 @@ func (x *diffCommitDiffServer) Send(m *CommitDiffResponse) error {
return x.ServerStream.SendMsg(m)
}
+func _Diff_CommitDelta_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(CommitDeltaRequest)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(DiffServer).CommitDelta(m, &diffCommitDeltaServer{stream})
+}
+
+type Diff_CommitDeltaServer interface {
+ Send(*CommitDeltaResponse) error
+ grpc.ServerStream
+}
+
+type diffCommitDeltaServer struct {
+ grpc.ServerStream
+}
+
+func (x *diffCommitDeltaServer) Send(m *CommitDeltaResponse) error {
+ return x.ServerStream.SendMsg(m)
+}
+
var _Diff_serviceDesc = grpc.ServiceDesc{
ServiceName: "gitaly.Diff",
HandlerType: (*DiffServer)(nil),
@@ -242,6 +415,11 @@ var _Diff_serviceDesc = grpc.ServiceDesc{
Handler: _Diff_CommitDiff_Handler,
ServerStreams: true,
},
+ {
+ StreamName: "CommitDelta",
+ Handler: _Diff_CommitDelta_Handler,
+ ServerStreams: true,
+ },
},
Metadata: "diff.proto",
}
@@ -249,29 +427,33 @@ var _Diff_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("diff.proto", fileDescriptor1) }
var fileDescriptor1 = []byte{
- // 369 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0xc1, 0xae, 0x94, 0x30,
- 0x14, 0x86, 0xe5, 0x5e, 0x60, 0x98, 0x23, 0x6a, 0xac, 0xe6, 0xda, 0x3b, 0xc6, 0x84, 0xdc, 0x18,
- 0xc3, 0x6a, 0x62, 0xc6, 0x8d, 0xfb, 0x31, 0x31, 0xb3, 0x30, 0x9a, 0x6e, 0x5c, 0x92, 0x0e, 0x2d,
- 0xd0, 0x08, 0x1c, 0x6c, 0x3b, 0x21, 0xf3, 0xc0, 0xbe, 0x87, 0x69, 0xeb, 0xe0, 0x24, 0xba, 0x3c,
- 0xff, 0xf7, 0x53, 0xf8, 0x38, 0x05, 0x10, 0xaa, 0x69, 0xb6, 0x93, 0x46, 0x8b, 0x24, 0x6d, 0x95,
- 0xe5, 0xfd, 0x79, 0x93, 0x9b, 0x8e, 0x6b, 0x29, 0x42, 0xfa, 0xf0, 0x2b, 0x82, 0xe7, 0x7b, 0x1c,
- 0x06, 0x65, 0x3f, 0xa9, 0xa6, 0x61, 0xf2, 0xe7, 0x49, 0x1a, 0x4b, 0x76, 0x00, 0x5a, 0x4e, 0x68,
- 0x94, 0x45, 0x7d, 0xa6, 0x51, 0x11, 0x95, 0x8f, 0x77, 0x64, 0x1b, 0x0e, 0xd8, 0xb2, 0x85, 0xb0,
- 0xab, 0x16, 0x79, 0x0b, 0x4f, 0x7b, 0xd9, 0xd8, 0xaa, 0xf6, 0xa7, 0x55, 0x4a, 0xd0, 0x9b, 0x22,
- 0x2a, 0xd7, 0x2c, 0x77, 0x69, 0x78, 0xc5, 0x41, 0x90, 0x77, 0xf0, 0x4c, 0xab, 0xb6, 0xbb, 0xae,
- 0xdd, 0xfa, 0xda, 0x13, 0x1f, 0x2f, 0xbd, 0x8f, 0x40, 0x55, 0x3b, 0xa2, 0x96, 0xd5, 0xdc, 0x29,
- 0x2b, 0xcd, 0xc4, 0x6b, 0x59, 0xd5, 0x1d, 0x1f, 0x5b, 0x49, 0xe3, 0x22, 0x2a, 0x33, 0x76, 0x17,
- 0xf8, 0xf7, 0x05, 0xef, 0x3d, 0x25, 0x2f, 0x21, 0x99, 0xb8, 0xed, 0x0c, 0x4d, 0x8a, 0xdb, 0x32,
- 0x67, 0x61, 0x70, 0x9e, 0xe4, 0xda, 0xd3, 0x4c, 0x38, 0x1a, 0x49, 0x5e, 0xc3, 0xba, 0xd1, 0x38,
- 0x54, 0xae, 0xe4, 0x3d, 0x73, 0x96, 0xb9, 0xe0, 0x1b, 0xb7, 0x1d, 0x79, 0x05, 0x2b, 0x8b, 0x01,
- 0xdd, 0x78, 0x94, 0x5a, 0xbc, 0x00, 0xff, 0xd4, 0xf2, 0xf1, 0xa9, 0x1b, 0x0f, 0x82, 0xbc, 0x80,
- 0xc4, 0xa2, 0x8b, 0x63, 0x1f, 0xc7, 0x16, 0x0f, 0x82, 0xdc, 0x43, 0x86, 0xbd, 0xa8, 0x06, 0x14,
- 0x92, 0x26, 0x45, 0x54, 0x26, 0x6c, 0x85, 0xbd, 0xf8, 0x82, 0x42, 0x3a, 0x34, 0xca, 0x39, 0xa0,
- 0x34, 0xa0, 0x51, 0xce, 0x1e, 0xdd, 0x41, 0x7a, 0x54, 0x23, 0xd7, 0x67, 0xba, 0xf2, 0xba, 0x7f,
- 0x26, 0xf2, 0x06, 0x40, 0xf3, 0xb9, 0xaa, 0xbb, 0xd3, 0xf8, 0xc3, 0xd0, 0xcc, 0x3b, 0xae, 0x35,
- 0x9f, 0xf7, 0x3e, 0xd8, 0x7d, 0x85, 0xd8, 0x09, 0x92, 0xcf, 0x00, 0x7f, 0x75, 0xc9, 0xfd, 0x65,
- 0x77, 0xff, 0xac, 0x7a, 0xb3, 0xf9, 0x1f, 0x0a, 0x7f, 0xe7, 0xe1, 0xd1, 0xfb, 0xe8, 0x98, 0xfa,
- 0x7b, 0xf2, 0xe1, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x22, 0x00, 0x91, 0x7d, 0x4b, 0x02, 0x00,
- 0x00,
+ // 446 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x94, 0xd1, 0x8a, 0x13, 0x31,
+ 0x14, 0x86, 0xcd, 0x76, 0x66, 0xda, 0x9e, 0x56, 0xc5, 0x54, 0xd6, 0x6c, 0x17, 0x61, 0x28, 0x22,
+ 0x03, 0x42, 0x91, 0x7a, 0xe3, 0xb5, 0x15, 0xa4, 0x82, 0x20, 0xb9, 0xf1, 0x72, 0xc8, 0x36, 0x99,
+ 0x4e, 0x70, 0x3a, 0x19, 0x93, 0x2c, 0x43, 0x9f, 0xc5, 0x07, 0xf0, 0xc6, 0xd7, 0xf2, 0x3d, 0x24,
+ 0x49, 0x77, 0x3a, 0xbb, 0xf4, 0x01, 0xf6, 0x32, 0xff, 0xf7, 0xe7, 0x24, 0x7f, 0xce, 0x99, 0x01,
+ 0xe0, 0xb2, 0x28, 0x96, 0x8d, 0x56, 0x56, 0xe1, 0x64, 0x27, 0x2d, 0xab, 0x0e, 0xf3, 0xa9, 0x29,
+ 0x99, 0x16, 0x3c, 0xa8, 0x8b, 0x7f, 0x08, 0x5e, 0xac, 0xd5, 0x7e, 0x2f, 0xed, 0x67, 0x59, 0x14,
+ 0x54, 0xfc, 0xba, 0x15, 0xc6, 0xe2, 0x15, 0x80, 0x16, 0x8d, 0x32, 0xd2, 0x2a, 0x7d, 0x20, 0x28,
+ 0x45, 0xd9, 0x64, 0x85, 0x97, 0xa1, 0xc0, 0x92, 0x76, 0x84, 0xf6, 0x5c, 0xf8, 0x0d, 0x3c, 0xab,
+ 0x44, 0x61, 0xf3, 0xad, 0xaf, 0x96, 0x4b, 0x4e, 0x2e, 0x52, 0x94, 0x8d, 0xe9, 0xd4, 0xa9, 0xe1,
+ 0x88, 0x0d, 0xc7, 0x6f, 0xe1, 0xb9, 0x96, 0xbb, 0xb2, 0x6f, 0x1b, 0x78, 0xdb, 0x53, 0x2f, 0x77,
+ 0xbe, 0x8f, 0x40, 0xe4, 0xae, 0x56, 0x5a, 0xe4, 0x6d, 0x29, 0xad, 0x30, 0x0d, 0xdb, 0x8a, 0x7c,
+ 0x5b, 0xb2, 0x7a, 0x27, 0x48, 0x94, 0xa2, 0x6c, 0x44, 0x2f, 0x03, 0xff, 0xd1, 0xe1, 0xb5, 0xa7,
+ 0xf8, 0x25, 0xc4, 0x0d, 0xb3, 0xa5, 0x21, 0x71, 0x3a, 0xc8, 0xa6, 0x34, 0x2c, 0x5c, 0x4e, 0xdc,
+ 0xcf, 0x69, 0x1a, 0x55, 0x1b, 0x81, 0xaf, 0x61, 0x5c, 0x68, 0xb5, 0xcf, 0x9d, 0xc9, 0xe7, 0x9c,
+ 0xd2, 0x91, 0x13, 0xbe, 0x33, 0x5b, 0xe2, 0x57, 0x30, 0xb4, 0x2a, 0xa0, 0x0b, 0x8f, 0x12, 0xab,
+ 0xee, 0x80, 0xdf, 0xd5, 0x5d, 0x3e, 0x71, 0xcb, 0x0d, 0xc7, 0x33, 0x88, 0xad, 0x72, 0x72, 0xe4,
+ 0xe5, 0xc8, 0xaa, 0x0d, 0xc7, 0x57, 0x30, 0x52, 0x15, 0xcf, 0xf7, 0x8a, 0x0b, 0x12, 0xa7, 0x28,
+ 0x8b, 0xe9, 0x50, 0x55, 0xfc, 0x9b, 0xe2, 0xc2, 0xa1, 0x5a, 0xb4, 0x01, 0x25, 0x01, 0xd5, 0xa2,
+ 0xf5, 0xe8, 0x12, 0x92, 0x1b, 0x59, 0x33, 0x7d, 0x20, 0x43, 0x1f, 0xf7, 0xb8, 0xc2, 0xaf, 0x01,
+ 0x34, 0x6b, 0xf3, 0x6d, 0x79, 0x5b, 0xff, 0x34, 0x64, 0xe4, 0x33, 0x8e, 0x35, 0x6b, 0xd7, 0x5e,
+ 0x58, 0xfc, 0x3d, 0xe5, 0x14, 0x95, 0x65, 0x8f, 0xa7, 0xa1, 0x5d, 0x5b, 0xa2, 0x7e, 0x5b, 0xfe,
+ 0x20, 0x98, 0xf4, 0xae, 0xfb, 0x78, 0xfb, 0xb1, 0xf8, 0x04, 0xb3, 0x7b, 0xef, 0x7a, 0x1c, 0xa0,
+ 0x77, 0x90, 0x70, 0x27, 0x18, 0x82, 0xd2, 0x41, 0x36, 0x59, 0xcd, 0xee, 0x1e, 0xb5, 0x6f, 0x3e,
+ 0x5a, 0x56, 0xbf, 0x11, 0x44, 0x6e, 0xfc, 0xf0, 0x17, 0x80, 0xd3, 0x30, 0xe2, 0xab, 0x07, 0x7b,
+ 0x4e, 0x1f, 0xe2, 0x7c, 0x7e, 0x0e, 0x85, 0xa3, 0x17, 0x4f, 0xde, 0x23, 0xfc, 0xf5, 0xfe, 0xf3,
+ 0xcd, 0xcf, 0x9d, 0x7e, 0x2c, 0x75, 0x7d, 0x96, 0x9d, 0x6a, 0xdd, 0x24, 0xfe, 0x8f, 0xf0, 0xe1,
+ 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa2, 0xc7, 0x4a, 0x51, 0x35, 0x04, 0x00, 0x00,
}
diff --git a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/smarthttp.pb.go b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/smarthttp.pb.go
index 494118d6a..07fec0653 100644
--- a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/smarthttp.pb.go
+++ b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/smarthttp.pb.go
@@ -98,9 +98,10 @@ type PostReceivePackRequest struct {
Repository *Repository `protobuf:"bytes,1,opt,name=repository" json:"repository,omitempty"`
// Raw data to be copied to stdin of 'git receive-pack'
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
- // gl_id becomes env variable GL_ID, used by the Git {pre,post}-receive
- // hooks. Should only be present in the first message of the stream.
- GlId string `protobuf:"bytes,3,opt,name=gl_id,json=glId" json:"gl_id,omitempty"`
+ // gl_id and gl_repository becomes env variables, used by the Git {pre,post}-receive
+ // hooks. They should only be present in the first message of the stream.
+ GlId string `protobuf:"bytes,3,opt,name=gl_id,json=glId" json:"gl_id,omitempty"`
+ GlRepository string `protobuf:"bytes,4,opt,name=gl_repository,json=glRepository" json:"gl_repository,omitempty"`
}
func (m *PostReceivePackRequest) Reset() { *m = PostReceivePackRequest{} }
@@ -129,6 +130,13 @@ func (m *PostReceivePackRequest) GetGlId() string {
return ""
}
+func (m *PostReceivePackRequest) GetGlRepository() string {
+ if m != nil {
+ return m.GlRepository
+ }
+ return ""
+}
+
type PostReceivePackResponse struct {
// Raw data from stdout of 'git receive-pack'
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
@@ -455,24 +463,26 @@ var _SmartHTTP_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("smarthttp.proto", fileDescriptor5) }
var fileDescriptor5 = []byte{
- // 304 bytes of a gzipped FileDescriptorProto
+ // 321 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x4d, 0x4b, 0xc3, 0x40,
- 0x14, 0x74, 0x6b, 0x2d, 0xf4, 0x59, 0xac, 0xbc, 0xa2, 0x0d, 0x01, 0xb5, 0xe4, 0x20, 0x39, 0x68,
- 0x28, 0xf1, 0x37, 0x08, 0x16, 0x3d, 0x84, 0xb5, 0x05, 0x6f, 0x65, 0x6d, 0xb6, 0x69, 0x30, 0x76,
- 0xe3, 0xee, 0x56, 0xe8, 0x2f, 0xf5, 0xef, 0x88, 0x09, 0xf9, 0x68, 0x62, 0x3c, 0x28, 0xde, 0xc2,
- 0x9b, 0xf7, 0x66, 0x26, 0x33, 0x2c, 0xf4, 0xd5, 0x2b, 0x93, 0x7a, 0xa5, 0x75, 0xec, 0xc4, 0x52,
- 0x68, 0x81, 0x9d, 0x20, 0xd4, 0x2c, 0xda, 0x9a, 0x3d, 0xb5, 0x62, 0x92, 0xfb, 0xe9, 0xd4, 0xba,
- 0x85, 0xfe, 0x64, 0xbd, 0x14, 0x94, 0x2f, 0x15, 0xe5, 0x6f, 0x1b, 0xae, 0x34, 0xba, 0x00, 0x92,
- 0xc7, 0x42, 0x85, 0x5a, 0xc8, 0xad, 0x41, 0x46, 0xc4, 0x3e, 0x74, 0xd1, 0x49, 0xaf, 0x1d, 0x9a,
- 0x23, 0xb4, 0xb4, 0x65, 0x5d, 0xc2, 0x71, 0x41, 0xa3, 0x62, 0xb1, 0x56, 0x1c, 0x11, 0xda, 0x3e,
- 0xd3, 0x2c, 0x61, 0xe8, 0xd1, 0xe4, 0xdb, 0x9a, 0xc3, 0x89, 0x27, 0x94, 0x9e, 0xc5, 0x91, 0x60,
- 0xbe, 0xc7, 0x16, 0x2f, 0x7f, 0x10, 0xcd, 0x05, 0x5a, 0x25, 0x81, 0x2b, 0x38, 0xad, 0x0a, 0xfc,
- 0x60, 0x67, 0x93, 0x6e, 0x53, 0xbe, 0xe0, 0xe1, 0x3b, 0xff, 0x07, 0x3f, 0x38, 0x80, 0x83, 0x20,
- 0x9a, 0x87, 0xbe, 0xb1, 0x3f, 0x22, 0x76, 0x97, 0xb6, 0x83, 0x68, 0xe2, 0x5b, 0xd7, 0x30, 0xac,
- 0xc9, 0x36, 0xbb, 0x74, 0x3f, 0x5a, 0xd0, 0x7d, 0xfc, 0x6a, 0xf3, 0x6e, 0x3a, 0xf5, 0xf0, 0x1e,
- 0x30, 0x8b, 0xba, 0xf8, 0x4b, 0x1c, 0x66, 0xde, 0x2a, 0x6d, 0x9a, 0x46, 0x1d, 0x48, 0xa5, 0xac,
- 0xbd, 0x31, 0xc1, 0x07, 0x18, 0x14, 0xf3, 0xdc, 0xcd, 0x6f, 0xd9, 0x66, 0x70, 0xb4, 0x1b, 0x3e,
- 0x9e, 0x65, 0xfb, 0xdf, 0xb6, 0x6e, 0x9e, 0x37, 0xc1, 0x19, 0xa9, 0x4d, 0xc6, 0x04, 0x9f, 0xa0,
- 0x5f, 0x89, 0x0b, 0x77, 0x0e, 0xeb, 0xf5, 0x99, 0x17, 0x8d, 0x78, 0x99, 0xf9, 0xb9, 0x93, 0x3c,
- 0x82, 0x9b, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x16, 0x3e, 0x9b, 0xd1, 0x2d, 0x03, 0x00, 0x00,
+ 0x10, 0x75, 0x6b, 0x2d, 0x74, 0xac, 0x56, 0xa6, 0x68, 0x4b, 0x40, 0x2d, 0x11, 0xa4, 0x07, 0x0d,
+ 0x25, 0xfe, 0x06, 0xc1, 0xa2, 0x87, 0xb0, 0xb6, 0xe0, 0x2d, 0xac, 0xcd, 0x36, 0x0d, 0xae, 0xdd,
+ 0x98, 0x5d, 0x85, 0xfe, 0x15, 0xff, 0x98, 0x7f, 0x47, 0x4c, 0xc8, 0x47, 0x13, 0xe3, 0x41, 0xf1,
+ 0x16, 0xe6, 0xcd, 0xbc, 0xf7, 0x66, 0x5e, 0x16, 0xba, 0xea, 0x99, 0x45, 0x7a, 0xa9, 0x75, 0x68,
+ 0x85, 0x91, 0xd4, 0x12, 0x5b, 0x7e, 0xa0, 0x99, 0x58, 0x1b, 0x1d, 0xb5, 0x64, 0x11, 0xf7, 0x92,
+ 0xaa, 0x79, 0x0d, 0xdd, 0xc9, 0x6a, 0x21, 0x29, 0x5f, 0x28, 0xca, 0x5f, 0x5e, 0xb9, 0xd2, 0x68,
+ 0x03, 0x44, 0x3c, 0x94, 0x2a, 0xd0, 0x32, 0x5a, 0x0f, 0xc8, 0x90, 0x8c, 0x76, 0x6d, 0xb4, 0x92,
+ 0x69, 0x8b, 0x66, 0x08, 0x2d, 0x74, 0x99, 0xe7, 0x70, 0x90, 0xd3, 0xa8, 0x50, 0xae, 0x14, 0x47,
+ 0x84, 0xa6, 0xc7, 0x34, 0x8b, 0x19, 0x3a, 0x34, 0xfe, 0x36, 0x5d, 0x38, 0x74, 0xa4, 0xd2, 0xb3,
+ 0x50, 0x48, 0xe6, 0x39, 0x6c, 0xfe, 0xf4, 0x07, 0xd1, 0x4c, 0xa0, 0x51, 0x10, 0xb8, 0x80, 0xa3,
+ 0xb2, 0xc0, 0x0f, 0x76, 0xde, 0x49, 0xd2, 0x4e, 0xf9, 0x9c, 0x07, 0x6f, 0xfc, 0x1f, 0x0c, 0x61,
+ 0x0f, 0x76, 0x7c, 0xe1, 0x06, 0xde, 0x60, 0x7b, 0x48, 0x46, 0x6d, 0xda, 0xf4, 0xc5, 0xc4, 0xc3,
+ 0x33, 0xd8, 0xf3, 0x85, 0x5b, 0xe0, 0x6f, 0xc6, 0x60, 0xc7, 0x17, 0x39, 0xb3, 0x79, 0x09, 0xfd,
+ 0x8a, 0xb7, 0xfa, 0x5d, 0xec, 0x8f, 0x06, 0xb4, 0xef, 0xbf, 0x32, 0xbf, 0x99, 0x4e, 0x1d, 0xbc,
+ 0x05, 0x4c, 0x03, 0xc9, 0x6f, 0x81, 0xfd, 0x74, 0x81, 0x52, 0xe6, 0xc6, 0xa0, 0x0a, 0x24, 0x52,
+ 0xe6, 0xd6, 0x98, 0xe0, 0x1d, 0xf4, 0xf2, 0x7a, 0xe6, 0xe6, 0xb7, 0x6c, 0x33, 0xd8, 0xdf, 0x8c,
+ 0x08, 0x8f, 0xd3, 0xfe, 0x6f, 0xff, 0x0d, 0xe3, 0xa4, 0x0e, 0x4e, 0x49, 0x47, 0x64, 0x4c, 0xf0,
+ 0x01, 0xba, 0xa5, 0x73, 0xe1, 0xc6, 0x60, 0x35, 0x63, 0xe3, 0xb4, 0x16, 0x2f, 0x32, 0x3f, 0xb6,
+ 0xe2, 0xa7, 0x72, 0xf5, 0x19, 0x00, 0x00, 0xff, 0xff, 0x4c, 0x33, 0x8a, 0x1a, 0x53, 0x03, 0x00,
+ 0x00,
}
diff --git a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/ssh.pb.go b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/ssh.pb.go
index 842b88e5f..2fe41d027 100644
--- a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/ssh.pb.go
+++ b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/ssh.pb.go
@@ -85,8 +85,10 @@ type SSHReceivePackRequest struct {
Repository *Repository `protobuf:"bytes,1,opt,name=repository" json:"repository,omitempty"`
// A chunk of raw data to be copied to 'git upload-pack' standard input
Stdin []byte `protobuf:"bytes,2,opt,name=stdin,proto3" json:"stdin,omitempty"`
- // Contents of GL_ID environment variable for 'git receive-pack'
- GlId string `protobuf:"bytes,3,opt,name=gl_id,json=glId" json:"gl_id,omitempty"`
+ // Contents of GL_ID and GL_REPOSITORY environment variables for
+ // 'git receive-pack'
+ GlId string `protobuf:"bytes,3,opt,name=gl_id,json=glId" json:"gl_id,omitempty"`
+ GlRepository string `protobuf:"bytes,4,opt,name=gl_repository,json=glRepository" json:"gl_repository,omitempty"`
}
func (m *SSHReceivePackRequest) Reset() { *m = SSHReceivePackRequest{} }
@@ -115,6 +117,13 @@ func (m *SSHReceivePackRequest) GetGlId() string {
return ""
}
+func (m *SSHReceivePackRequest) GetGlRepository() string {
+ if m != nil {
+ return m.GlRepository
+ }
+ return ""
+}
+
type SSHReceivePackResponse struct {
// A chunk of raw data from 'git receive-pack' standard output
Stdout []byte `protobuf:"bytes,1,opt,name=stdout,proto3" json:"stdout,omitempty"`
@@ -334,23 +343,24 @@ var _SSH_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("ssh.proto", fileDescriptor6) }
var fileDescriptor6 = []byte{
- // 284 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x52, 0xcd, 0x4a, 0xc3, 0x40,
- 0x10, 0x76, 0xad, 0x0d, 0x74, 0x1a, 0x3d, 0xac, 0xb5, 0x84, 0xa0, 0x52, 0x72, 0xca, 0x29, 0x48,
- 0xfa, 0x0c, 0x42, 0xbd, 0xc9, 0x86, 0x9e, 0x6b, 0xec, 0x2e, 0xe9, 0x62, 0xe8, 0xc6, 0x9d, 0x49,
- 0x69, 0x41, 0xdf, 0xc9, 0x47, 0x14, 0x92, 0x58, 0x92, 0x6a, 0x8f, 0xf6, 0xb6, 0x33, 0xdf, 0xce,
- 0xf7, 0x33, 0xbb, 0x30, 0x40, 0x5c, 0x45, 0x85, 0x35, 0x64, 0xb8, 0x93, 0x69, 0x4a, 0xf3, 0x9d,
- 0xef, 0xe2, 0x2a, 0xb5, 0x4a, 0xd6, 0xdd, 0xe0, 0x05, 0x46, 0x49, 0x32, 0x9b, 0x17, 0xb9, 0x49,
- 0xe5, 0x73, 0xba, 0x7c, 0x13, 0xea, 0xbd, 0x54, 0x48, 0x3c, 0x06, 0xb0, 0xaa, 0x30, 0xa8, 0xc9,
- 0xd8, 0x9d, 0xc7, 0x26, 0x2c, 0x1c, 0xc6, 0x3c, 0xaa, 0x29, 0x22, 0xb1, 0x47, 0x44, 0xeb, 0x16,
- 0x1f, 0x41, 0x1f, 0x49, 0xea, 0xb5, 0x77, 0x3e, 0x61, 0xa1, 0x2b, 0xea, 0x22, 0xf8, 0x80, 0x9b,
- 0x03, 0x05, 0x2c, 0xcc, 0x1a, 0x15, 0x1f, 0x83, 0x83, 0x24, 0x4d, 0x49, 0x15, 0xbd, 0x2b, 0x9a,
- 0xaa, 0xe9, 0x2b, 0x6b, 0x1b, 0x9e, 0xa6, 0xe2, 0x53, 0x18, 0xaa, 0xad, 0xa6, 0x05, 0x52, 0x4a,
- 0x25, 0x7a, 0xbd, 0xae, 0xa7, 0xc7, 0xad, 0xa6, 0xa4, 0x42, 0x04, 0xa8, 0xfd, 0x39, 0xd8, 0x54,
- 0xea, 0x42, 0x2d, 0x95, 0xde, 0xa8, 0x7f, 0x09, 0xc8, 0xaf, 0xa1, 0x9f, 0xe5, 0x0b, 0x2d, 0x2b,
- 0x47, 0x03, 0x71, 0x91, 0xe5, 0x4f, 0x32, 0xf8, 0x84, 0xf1, 0xa1, 0xee, 0x09, 0x63, 0xc7, 0x5f,
- 0x0c, 0x7a, 0x49, 0x32, 0xe3, 0x02, 0x2e, 0x3b, 0xcb, 0xe7, 0xb7, 0x3f, 0x83, 0x7f, 0xbd, 0xba,
- 0x7f, 0x77, 0x04, 0xad, 0xad, 0x07, 0x67, 0x21, 0x7b, 0x60, 0x7c, 0x0e, 0x57, 0xdd, 0x68, 0xbc,
- 0x3d, 0xf6, 0x7b, 0xd5, 0xfe, 0xfd, 0x31, 0xb8, 0x4d, 0xfb, 0xea, 0x54, 0x1f, 0x72, 0xfa, 0x1d,
- 0x00, 0x00, 0xff, 0xff, 0x71, 0xde, 0xae, 0x4f, 0xb3, 0x02, 0x00, 0x00,
+ // 304 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x52, 0xcd, 0x4e, 0xf3, 0x30,
+ 0x10, 0xfc, 0xfc, 0xf5, 0x47, 0xea, 0x36, 0xe5, 0xb0, 0x94, 0xaa, 0x8a, 0x00, 0x55, 0xe1, 0x92,
+ 0x53, 0x84, 0xd2, 0x67, 0x40, 0x2a, 0x37, 0xe4, 0xa8, 0xe7, 0x10, 0x6a, 0x2b, 0xb5, 0xb0, 0xea,
+ 0x60, 0x3b, 0xa8, 0x95, 0xe0, 0x49, 0x78, 0x09, 0x1e, 0x11, 0xc9, 0x09, 0x25, 0x29, 0xf4, 0x08,
+ 0xb7, 0xcc, 0x4e, 0x76, 0x66, 0xd6, 0xbb, 0x30, 0x30, 0x66, 0x1d, 0x15, 0x5a, 0x59, 0x85, 0xfd,
+ 0x5c, 0xd8, 0x4c, 0xee, 0x7c, 0xcf, 0xac, 0x33, 0xcd, 0x59, 0x55, 0x0d, 0xee, 0x61, 0x9c, 0x24,
+ 0x8b, 0x65, 0x21, 0x55, 0xc6, 0xee, 0xb2, 0xd5, 0x23, 0xe5, 0x4f, 0x25, 0x37, 0x16, 0x63, 0x00,
+ 0xcd, 0x0b, 0x65, 0x84, 0x55, 0x7a, 0x37, 0x25, 0x33, 0x12, 0x0e, 0x63, 0x8c, 0x2a, 0x89, 0x88,
+ 0xee, 0x19, 0xda, 0xf8, 0x0b, 0xc7, 0xd0, 0x33, 0x96, 0x89, 0xcd, 0xf4, 0xff, 0x8c, 0x84, 0x1e,
+ 0xad, 0x40, 0xf0, 0x02, 0x67, 0x07, 0x0e, 0xa6, 0x50, 0x1b, 0xc3, 0x71, 0x02, 0x7d, 0x63, 0x99,
+ 0x2a, 0xad, 0x93, 0xf7, 0x68, 0x8d, 0xea, 0x3a, 0xd7, 0xba, 0xd6, 0xa9, 0x11, 0xce, 0x61, 0xc8,
+ 0xb7, 0xc2, 0xa6, 0xc6, 0x66, 0xb6, 0x34, 0xd3, 0x4e, 0x3b, 0xd3, 0xcd, 0x56, 0xd8, 0xc4, 0x31,
+ 0x14, 0xf8, 0xfe, 0x3b, 0x78, 0x23, 0xce, 0x9e, 0xf2, 0x15, 0x17, 0xcf, 0xfc, 0x57, 0x26, 0xc4,
+ 0x53, 0xe8, 0xe5, 0x32, 0x15, 0xcc, 0x45, 0x1a, 0xd0, 0x6e, 0x2e, 0x6f, 0x19, 0x5e, 0xc1, 0x28,
+ 0x97, 0x69, 0xc3, 0xa1, 0xeb, 0x48, 0x2f, 0x97, 0x5f, 0xda, 0xc1, 0x2b, 0x4c, 0x0e, 0xc3, 0xfd,
+ 0xe1, 0xe3, 0xc4, 0xef, 0x04, 0x3a, 0x49, 0xb2, 0x40, 0x0a, 0xa3, 0xd6, 0x8a, 0xf0, 0xfc, 0xb3,
+ 0xf1, 0xa7, 0xdb, 0xf0, 0x2f, 0x8e, 0xb0, 0x55, 0xf4, 0xe0, 0x5f, 0x48, 0xae, 0x09, 0x2e, 0xe1,
+ 0xa4, 0x3d, 0x1a, 0x36, 0xdb, 0xbe, 0xef, 0xc3, 0xbf, 0x3c, 0x46, 0x37, 0x65, 0x1f, 0xfa, 0xee,
+ 0x6c, 0xe7, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x3d, 0xb9, 0xce, 0xd9, 0x02, 0x00, 0x00,
}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index 181c38ef9..1fe7449b2 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -117,20 +117,20 @@
"revisionTime": "2017-01-30T11:31:45Z"
},
{
- "checksumSHA1": "aHVxlXMV5xCeI9Tnhg2TfMJtDmE=",
+ "checksumSHA1": "xoChRi6dWPR0Bt78+zius0y/ur4=",
"path": "gitlab.com/gitlab-org/gitaly-proto/go",
- "revision": "1ec5c4d277421304d15f8a1b96365d67c30602c0",
- "revisionTime": "2017-04-26T12:18:56Z",
- "version": "v0.6.0",
- "versionExact": "v0.6.0"
+ "revision": "8967f31f8d73482228a357acba0f1ce3744ceae2",
+ "revisionTime": "2017-05-05T12:14:06Z",
+ "version": "v0.7.0",
+ "versionExact": "v0.7.0"
},
{
"checksumSHA1": "GkeSZfXVbtAkBZOrswot19GJZqQ=",
"path": "gitlab.com/gitlab-org/gitaly-proto/go/helper",
- "revision": "1ec5c4d277421304d15f8a1b96365d67c30602c0",
- "revisionTime": "2017-04-26T12:18:56Z",
- "version": "v0.6.0",
- "versionExact": "v0.6.0"
+ "revision": "8967f31f8d73482228a357acba0f1ce3744ceae2",
+ "revisionTime": "2017-05-05T12:14:06Z",
+ "version": "v0.7.0",
+ "versionExact": "v0.7.0"
},
{
"checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=",