From 11175e2e84dd0dbeecbaf1eb759c2e02cf3930bb Mon Sep 17 00:00:00 2001 From: Damian Szymanski Date: Thu, 18 Mar 2021 18:54:16 +0100 Subject: [PATCH 01/46] Update OS for enterprise ship:docker --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 5e052443a9..cdddd541a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,8 @@ LABEL maintainer Travis CI GmbH # packages required for bundle install RUN ( \ apt-get update ; \ + # update to deb 10.8 + apt-get upgrade -y ; \ apt-get install -y --no-install-recommends git make gcc g++ libpq-dev libjemalloc-dev \ && rm -rf /var/lib/apt/lists/* \ ) From c73e9ee401cf2082effa5854e1d47af31f5eb16a Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Wed, 21 Apr 2021 14:55:12 +0200 Subject: [PATCH 02/46] gem updates (#1192) --- Dockerfile | 7 ++- Gemfile | 1 + Gemfile.lock | 87 ++++++++++++++++------------- spec/v3/services/build/find_spec.rb | 4 +- spec/v3/services/job/find_spec.rb | 4 +- 5 files changed, 59 insertions(+), 44 deletions(-) diff --git a/Dockerfile b/Dockerfile index cdddd541a3..7eeb16271e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,6 @@ ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 # throw errors if Gemfile has been modified since Gemfile.lock RUN bundle config --global frozen 1 RUN bundle config set deployment 'true' -RUN bundle config set without 'development test' RUN mkdir -p /app WORKDIR /app @@ -25,9 +24,15 @@ COPY Gemfile /app COPY Gemfile.lock /app RUN gem install bundler -v '2.1.4' +RUN bundle config set without 'development test' RUN bundler install --verbose --retry=3 RUN gem install --user-install executable-hooks COPY . /app +RUN bundle config unset frozen +RUN cd /usr/local/bundle/bundler/gems/s3-386361c1b0ed && bundle update +RUN cd /usr/local/bundle/bundler/gems/travis-lock-b418401c79e0 && sed "s/'activerecord'/'activerecord','~>4.2'/g" Gemfile -i && bundle update activerecord && bundle update redlock +RUN cd /usr/local/bundle/bundler/gems/travis-settings-debef595a6a5 && echo "gem 'activesupport','~> 5.2'" >> Gemfile && bundle update activemodel +RUN bundle config set frozen true CMD ./script/server-buildpacks diff --git a/Gemfile b/Gemfile index f15950eeee..30f9d5e05b 100644 --- a/Gemfile +++ b/Gemfile @@ -31,6 +31,7 @@ gem 'gh', git: 'https://github.com/travis-ci/gh' gem 'bunny', '~> 2.9.2' gem 'dalli' gem 'pry' +gem 'http', '~> 4' gem 'metriks', '0.9.9.6' gem 'metriks-librato_metrics', git: 'https://github.com/eric/metriks-librato_metrics' gem 'librato-metrics' diff --git a/Gemfile.lock b/Gemfile.lock index d468feea56..51d077bc21 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,7 +7,7 @@ GIT GIT remote: https://github.com/rkh/yard-sinatra - revision: 00774d355123617ff0faa7e0ebd54c4cdcfcdf93 + revision: b0d84033056dabdba08e7eee9438a3796d0d087d specs: yard-sinatra (1.0.0) yard (~> 0.7) @@ -95,14 +95,14 @@ GEM specs: active_model_serializers (0.9.5) activemodel (>= 3.2) - activemodel (4.2.11.1) - activesupport (= 4.2.11.1) + activemodel (4.2.11.3) + activesupport (= 4.2.11.3) builder (~> 3.1) - activerecord (4.2.11.1) - activemodel (= 4.2.11.1) - activesupport (= 4.2.11.1) + activerecord (4.2.11.3) + activemodel (= 4.2.11.3) + activesupport (= 4.2.11.3) arel (~> 6.0) - activesupport (4.2.11.1) + activesupport (4.2.11.3) i18n (~> 0.7) minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) @@ -119,12 +119,12 @@ GEM descendants_tracker (~> 0.0.4) ice_nine (~> 0.11.0) thread_safe (~> 0.3, >= 0.3.1) - backports (3.8.0) + backports (3.21.0) builder (3.2.4) bunny (2.9.2) amq-protocol (~> 2.3.0) byebug (10.0.2) - closeio (3.5.1) + closeio (3.6.1) faraday faraday_middleware json @@ -134,27 +134,30 @@ GEM descendants_tracker (~> 0.0.1) composite_primary_keys (8.1.8) activerecord (~> 4.2.0) - concurrent-ruby (1.1.6) + concurrent-ruby (1.1.8) connection_pool (2.2.1) crack (0.4.3) safe_yaml (~> 1.0.0) dalli (2.7.6) - database_cleaner (1.8.2) + database_cleaner (1.99.0) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.3) docile (1.1.5) - domain_name (0.5.20170404) + domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) equalizer (0.0.11) excon (0.72.0) factory_bot (5.1.1) activesupport (>= 4.2.0) - faraday (0.17.3) + faraday (0.17.4) multipart-post (>= 1.2, < 3) faraday_middleware (0.14.0) faraday (>= 0.7.4, < 1.0) - ffi (1.9.25) + ffi (1.15.0) + ffi-compiler (1.0.1) + ffi (>= 1.0.0) + rake fog-aws (0.12.0) fog-core (~> 1.38) fog-json (~> 1.0) @@ -221,28 +224,31 @@ GEM hashdiff (1.0.0) hashr (2.0.0) hitimes (1.2.4) - http (2.2.2) + http (4.4.1) addressable (~> 2.3) http-cookie (~> 1.0) - http-form_data (~> 1.0.1) - http_parser.rb (~> 0.6.0) + http-form_data (~> 2.2) + http-parser (~> 1.2.0) http-cookie (1.0.3) domain_name (~> 0.5) - http-form_data (1.0.3) - http_parser.rb (0.6.0) + http-form_data (2.3.0) + http-parser (1.2.3) + ffi-compiler (>= 1.0, < 2.0) httpclient (2.8.3) hurley (0.2) i18n (0.9.5) concurrent-ruby (~> 1.0) ice_nine (0.11.2) ipaddress (0.8.3) - json (2.1.0) + json (2.5.1) jwt (2.2.1) kgio (2.11.3) knapsack (1.14.0) rake - libhoney (1.3.2) - http (~> 2.0) + libhoney (1.18.0) + addressable (~> 2.0) + excon + http (>= 2.0, < 5.0) librato-metrics (2.1.2) aggregate (~> 0.2.2) faraday @@ -262,12 +268,13 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) mini_portile2 (2.4.0) - minitest (5.14.0) + minitest (5.14.4) mocha (1.11.2) - msgpack (1.2.4) + msgpack (1.4.2) multi_json (1.13.1) multipart-post (2.1.1) - mustermann (1.0.0.beta2) + mustermann (1.1.1) + ruby2_keywords (~> 0.0.1) nakayoshi_fork (0.0.3) net-http-persistent (2.9.4) net-http-pipeline (1.0.1) @@ -278,9 +285,10 @@ GEM concurrent-ruby (~> 1.0) google-cloud-trace (~> 0.31) opencensus (~> 0.3) - os (1.0.0) + optimist (3.0.1) + os (1.1.1) pg (0.21.0) - proxies (0.2.1) + proxies (0.2.3) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -288,13 +296,13 @@ GEM pry-byebug (3.6.0) byebug (~> 10.0) pry (~> 0.10) - public_suffix (4.0.3) + public_suffix (4.0.6) pusher (0.14.6) httpclient (~> 2.5) multi_json (~> 1.0) pusher-signature (~> 0.1.8) pusher-signature (0.1.8) - rack (1.6.12) + rack (1.6.13) rack-attack (5.4.2) rack (>= 1.0, < 3) rack-contrib (1.4.0) @@ -311,16 +319,16 @@ GEM rb-fsevent (0.9.8) rb-inotify (0.9.7) ffi (>= 0.5.0) - rbtrace (0.4.10) + rbtrace (0.4.14) ffi (>= 1.0.6) msgpack (>= 0.4.3) - trollop (>= 1.16.2) + optimist (>= 3.0.0) redcarpet (3.4.0) redis (3.3.5) redis-namespace (1.5.2) redis (~> 3.0, >= 3.0.4) - redlock (0.1.8) - redis (~> 3, >= 3.0.0) + redlock (1.2.1) + redis (>= 3.0.0, < 5.0) representable (2.3.0) uber (~> 0.0.7) rerun (0.11.0) @@ -344,6 +352,7 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.9.0) rspec-support (3.9.2) + ruby2_keywords (0.0.4) ruby_dep (1.5.0) safe_yaml (1.0.5) sentry-raven (2.11.3) @@ -379,20 +388,19 @@ GEM slop (3.6.0) stackdriver-core (1.3.3) google-cloud-core (~> 1.2) - stackprof (0.2.10) + stackprof (0.2.16) thor (0.19.1) thread_safe (0.3.6) - tilt (2.0.8) + tilt (2.0.10) timecop (0.9.1) tool (0.2.3) travis-rollout (0.0.2) - trollop (2.1.2) - tzinfo (1.2.7) + tzinfo (1.2.9) thread_safe (~> 0.1) uber (0.0.15) unf (0.1.4) unf_ext - unf_ext (0.0.7.4) + unf_ext (0.0.7.7) unicorn (5.5.3) kgio (~> 2.6) raindrops (~> 0.7) @@ -406,7 +414,7 @@ GEM addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - yard (0.9.20) + yard (0.9.26) PLATFORMS ruby @@ -431,6 +439,7 @@ DEPENDENCIES google-api-client (~> 0.9.4) hashdiff hashr + http (~> 4) ipaddress (~> 0.8.3) knapsack libhoney diff --git a/spec/v3/services/build/find_spec.rb b/spec/v3/services/build/find_spec.rb index 03a1bd8d7f..d309ae2aac 100644 --- a/spec/v3/services/build/find_spec.rb +++ b/spec/v3/services/build/find_spec.rb @@ -389,7 +389,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v0.17.3' + 'User-Agent'=>'Faraday v0.17.4' }). to_return(status: 200, body: "{}", headers: {}) end @@ -413,7 +413,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v0.17.3' + 'User-Agent'=>'Faraday v0.17.4' }). to_return(status: 200, body: "{}", headers: {}) end diff --git a/spec/v3/services/job/find_spec.rb b/spec/v3/services/job/find_spec.rb index bddf4525f0..a94c8cc31d 100644 --- a/spec/v3/services/job/find_spec.rb +++ b/spec/v3/services/job/find_spec.rb @@ -324,7 +324,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v0.17.3' + 'User-Agent'=>'Faraday v0.17.4' }). to_return(status: 200, body: "{}", headers: {}) end @@ -346,7 +346,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v0.17.3' + 'User-Agent'=>'Faraday v0.17.4' }). to_return(status: 200, body: "{}", headers: {}) From 4a759cafe52db4b163e112b3696348e00bd75f77 Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Tue, 6 Jul 2021 13:45:36 +0200 Subject: [PATCH 03/46] trivy scan added, docker fix (#1196) --- .travis.yml | 8 ++++---- Makefile | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a6689f06c..c4c6ae5781 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,6 @@ rvm: 2.6.5 script: "bundle exec rake knapsack:rspec" -addons: - - snaps: - - name: docker - channel: latest/beta env: global: @@ -35,6 +31,10 @@ before_install: jobs: include: - stage: ":ship: it to Quay.io" + addons: + - snaps: + - name: docker + channel: latest/stable install: echo skip before_script: echo skip script: make ship diff --git a/Makefile b/Makefile index 8c6814bfaf..9058db211b 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ docker-push-latest-master: docker-push-branch: $(DOCKER) tag $(DOCKER_DEST) $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) $(DOCKER) push $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) + $(DOCKER) run --rm -v /tmp:/root/.cache/ aquasec/trivy --ignore-unfixed $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) .PHONY: ship ship: docker-build docker-login From 5ee50d2386938cc6d81ef524712e4cb87d9dec0e Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Wed, 7 Jul 2021 09:20:25 +0200 Subject: [PATCH 04/46] trivy fix --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9058db211b..378bf2d88f 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ docker-push-latest-master: docker-push-branch: $(DOCKER) tag $(DOCKER_DEST) $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) $(DOCKER) push $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) - $(DOCKER) run --rm -v /tmp:/root/.cache/ aquasec/trivy --ignore-unfixed $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) + $(DOCKER) run --rm -v /tmp:/root/.cache/ -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy --ignore-unfixed $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) .PHONY: ship ship: docker-build docker-login From ba2c4dc4103a7f9c8c1f40a7141235e2da8e82ba Mon Sep 17 00:00:00 2001 From: gbarc80 <73236040+gbarc80@users.noreply.github.com> Date: Mon, 2 Aug 2021 12:35:34 +0200 Subject: [PATCH 05/46] security updates [ship:docker] (#1200) Co-authored-by: gabriel-arc --- Gemfile.lock | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 51d077bc21..71e8913c47 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -107,7 +107,7 @@ GEM minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.7.0) + addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) aggregate (0.2.2) allocation_tracer (0.6.3) @@ -267,7 +267,7 @@ GEM mime-types (3.1) mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) - mini_portile2 (2.4.0) + mini_portile2 (2.5.3) minitest (5.14.4) mocha (1.11.2) msgpack (1.4.2) @@ -278,8 +278,9 @@ GEM nakayoshi_fork (0.0.3) net-http-persistent (2.9.4) net-http-pipeline (1.0.1) - nokogiri (1.10.8) - mini_portile2 (~> 2.4.0) + nokogiri (1.11.7) + mini_portile2 (~> 2.5.0) + racc (~> 1.4) opencensus (0.3.1) opencensus-stackdriver (0.1.2) concurrent-ruby (~> 1.0) @@ -302,6 +303,7 @@ GEM multi_json (~> 1.0) pusher-signature (~> 0.1.8) pusher-signature (0.1.8) + racc (1.5.2) rack (1.6.13) rack-attack (5.4.2) rack (>= 1.0, < 3) From 26be255ef105fea1e139707ab6411dd48fa33684 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Mon, 2 Aug 2021 14:09:48 +0200 Subject: [PATCH 06/46] gh update --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 71e8913c47..f1b1bae30d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -21,7 +21,7 @@ GIT GIT remote: https://github.com/travis-ci/gh - revision: 38fb339510ff9ae67cb08c6df7698f4c393f5a44 + revision: 49d4ed2bda65892e1080111ca437bf52b47a5a4b specs: gh (0.15.1) addressable (~> 2.4) From a89750cfe195d6a0692fec97c7604d0352bf83e3 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Thu, 21 Oct 2021 11:55:26 +0200 Subject: [PATCH 07/46] update to use latest docker --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index c4c6ae5781..e0361e2980 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: ruby +group: edge import: - travis-ci/build-configs:db-setup.yml@bionic @@ -31,10 +32,6 @@ before_install: jobs: include: - stage: ":ship: it to Quay.io" - addons: - - snaps: - - name: docker - channel: latest/stable install: echo skip before_script: echo skip script: make ship From 82d519824aaae3a7267200123d607d711edbea6c Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Tue, 23 Nov 2021 13:31:56 +0100 Subject: [PATCH 08/46] added region to s3 query --- lib/travis/api/v3/remote_query.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/travis/api/v3/remote_query.rb b/lib/travis/api/v3/remote_query.rb index 1bba0def5a..a83f87e613 100644 --- a/lib/travis/api/v3/remote_query.rb +++ b/lib/travis/api/v3/remote_query.rb @@ -75,6 +75,7 @@ def s3_connection aws_access_key_id: s3_config[:access_key_id], aws_secret_access_key: s3_config[:secret_access_key], provider: 'AWS', + region: s3_config[:region], instrumentor: ActiveSupport::Notifications, connection_options: { instrumentor: ActiveSupport::Notifications } ) From 52adedb2bc46e4c2d0d483cead4cd79708e117ea Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Tue, 8 Feb 2022 12:36:37 +0100 Subject: [PATCH 09/46] gh update - gh token fix (#1223) --- Gemfile | 2 +- Gemfile.lock | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index 30f9d5e05b..e6c96129a9 100644 --- a/Gemfile +++ b/Gemfile @@ -27,7 +27,7 @@ gem 'yard-sinatra', git: 'https://github.com/rkh/yard-sinatra' gem 'rack-contrib' gem 'rack-cache', git: 'https://github.com/rtomayko/rack-cache' gem 'rack-attack', '~> 5.0' -gem 'gh', git: 'https://github.com/travis-ci/gh' +gem 'gh', git: 'https://github.com/travis-ci/gh', branch: 'tcie30-0_15_1' gem 'bunny', '~> 2.9.2' gem 'dalli' gem 'pry' diff --git a/Gemfile.lock b/Gemfile.lock index f1b1bae30d..bc3d9c05e3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -21,10 +21,11 @@ GIT GIT remote: https://github.com/travis-ci/gh - revision: 49d4ed2bda65892e1080111ca437bf52b47a5a4b + revision: 482ccbc8159c73fd5e651476692c6ea3d9f416a8 + branch: tcie30-0_15_1 specs: gh (0.15.1) - addressable (~> 2.4) + addressable (~> 2.4.0) backports faraday (~> 0.8) multi_json (~> 1.0) @@ -107,8 +108,7 @@ GEM minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.4.0) aggregate (0.2.2) allocation_tracer (0.6.3) amq-protocol (2.3.0) @@ -119,7 +119,7 @@ GEM descendants_tracker (~> 0.0.4) ice_nine (~> 0.11.0) thread_safe (~> 0.3, >= 0.3.1) - backports (3.21.0) + backports (3.23.0) builder (3.2.4) bunny (2.9.2) amq-protocol (~> 2.3.0) @@ -271,7 +271,7 @@ GEM minitest (5.14.4) mocha (1.11.2) msgpack (1.4.2) - multi_json (1.13.1) + multi_json (1.15.0) multipart-post (2.1.1) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) @@ -297,7 +297,6 @@ GEM pry-byebug (3.6.0) byebug (~> 10.0) pry (~> 0.10) - public_suffix (4.0.6) pusher (0.14.6) httpclient (~> 2.5) multi_json (~> 1.0) From b968fac4a90895fd9e8282fe828b7bb0488b9b7a Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Wed, 16 Mar 2022 12:12:24 +0100 Subject: [PATCH 10/46] share envs to forks (#1232) * repo settings merge from master --- lib/travis/api/v3/models/user_settings.rb | 8 +++ lib/travis/api/v3/renderer/user_settings.rb | 2 + .../api/v3/services/user_setting/update.rb | 4 +- lib/travis/model/repository.rb | 1 + lib/travis/model/repository/settings.rb | 13 +++++ spec/lib/model/repository_spec.rb | 15 ----- spec/v3/services/user_setting/find_spec.rb | 58 +++++++++++++++++++ .../user_settings/for_repository_spec.rb | 6 +- 8 files changed, 89 insertions(+), 18 deletions(-) diff --git a/lib/travis/api/v3/models/user_settings.rb b/lib/travis/api/v3/models/user_settings.rb index 2e093a749c..8485f94a18 100644 --- a/lib/travis/api/v3/models/user_settings.rb +++ b/lib/travis/api/v3/models/user_settings.rb @@ -10,6 +10,8 @@ class Models::UserSettings < Models::JsonSlice attribute :auto_cancel_pull_requests, Boolean, default: lambda { |us, _| us.auto_cancel_default? } attribute :allow_config_imports, Boolean, default: false attribute :config_validation, Boolean, default: lambda { |us, _| us.config_validation? } + attribute :share_encrypted_env_with_forks, Boolean, default: false + attribute :share_ssh_keys_with_forks, Boolean, default: lambda { |us, _| us.share_ssh_keys_with_forks? } attr_reader :repo @@ -34,6 +36,12 @@ def config_validation? new_repo? || old_repo? end + def share_ssh_keys_with_forks? + return false unless ENV['IBM_REPO_SWITCHES_DATE'] + + repo.created_at <= Date.parse(ENV['IBM_REPO_SWITCHES_DATE']) + end + def new_repo? repo.created_at >= NOV_15 end diff --git a/lib/travis/api/v3/renderer/user_settings.rb b/lib/travis/api/v3/renderer/user_settings.rb index 298a6acacc..7622fc6397 100644 --- a/lib/travis/api/v3/renderer/user_settings.rb +++ b/lib/travis/api/v3/renderer/user_settings.rb @@ -12,6 +12,8 @@ def render end def allow?(setting) + return unless setting + case setting[:name] when :allow_config_imports then repo.private? else true diff --git a/lib/travis/api/v3/services/user_setting/update.rb b/lib/travis/api/v3/services/user_setting/update.rb index 415de2356b..b99aabf51f 100644 --- a/lib/travis/api/v3/services/user_setting/update.rb +++ b/lib/travis/api/v3/services/user_setting/update.rb @@ -8,9 +8,9 @@ def run! return repo_migrated if migrated?(repository) user_setting = query.find(repository) - access_control.permissions(user_setting).write! + access_control.permissions(user_setting).write! if user_setting - user_setting = query.update(repository) + user_setting = query.update(repository) result user_setting end end diff --git a/lib/travis/model/repository.rb b/lib/travis/model/repository.rb index 71b951a1c5..b8ddc7fb12 100644 --- a/lib/travis/model/repository.rb +++ b/lib/travis/model/repository.rb @@ -183,6 +183,7 @@ def regenerate_key! def settings @settings ||= begin instance = Repository::Settings.load(super, repository_id: id) + instance.handle_ssh_share(id) instance.on_save do self.settings = instance.to_json self.save! diff --git a/lib/travis/model/repository/settings.rb b/lib/travis/model/repository/settings.rb index 119d02efe1..03e4726889 100644 --- a/lib/travis/model/repository/settings.rb +++ b/lib/travis/model/repository/settings.rb @@ -100,6 +100,8 @@ def custom_timeouts?(settings) attribute :auto_cancel_pushes, Boolean, default: lambda { |s, _| s.auto_cancel_default? } attribute :auto_cancel_pull_requests, Boolean, default: lambda { |s, _| s.auto_cancel_default? } attribute :allow_config_imports, Boolean, default: false + attribute :share_encrypted_env_with_forks, Boolean, default: false + attribute :share_ssh_keys_with_forks, Boolean, default: nil validates :maximum_number_of_builds, numericality: true @@ -148,6 +150,17 @@ def repository_id def repository Repository.find(repository_id) end + + def handle_ssh_share(id) + if self.share_ssh_keys_with_forks.nil? + self.share_ssh_keys_with_forks = false + return unless ENV['IBM_REPO_SWITCHES_DATE'] + + repo = Repository.find(id) + self.share_ssh_keys_with_forks = repo.created_at <= Date.parse(ENV['IBM_REPO_SWITCHES_DATE']) if repo + + end + end end class Repository::DefaultSettings < Repository::Settings diff --git a/spec/lib/model/repository_spec.rb b/spec/lib/model/repository_spec.rb index 3b943563ee..861806fb07 100644 --- a/spec/lib/model/repository_spec.rb +++ b/spec/lib/model/repository_spec.rb @@ -358,21 +358,6 @@ expect(repo.settings.build_pushes?).to be true end - it "allows to set nil for settings" do - repo.settings = nil - expect(repo.settings.to_hash).to eq(Repository::Settings.new.to_hash) - end - - it "allows to set settings as JSON string" do - repo.settings = '{"maximum_number_of_builds": 44}' - expect(repo.settings.to_hash).to eq(Repository::Settings.new(maximum_number_of_builds: 44).to_hash) - end - - it "allows to set settings as a Hash" do - repo.settings = { maximum_number_of_builds: 44} - expect(repo.settings.to_hash).to eq(Repository::Settings.new(maximum_number_of_builds: 44).to_hash) - end - it 'updates settings in the DB' do repo.settings = {'build_pushes' => false} repo.save diff --git a/spec/v3/services/user_setting/find_spec.rb b/spec/v3/services/user_setting/find_spec.rb index b60853181a..a8b75b7053 100644 --- a/spec/v3/services/user_setting/find_spec.rb +++ b/spec/v3/services/user_setting/find_spec.rb @@ -99,4 +99,62 @@ ) end end + + describe 'authenticated, existing repo, default share_encrypted_env_with_forks setting' do + before do + get("/v3/repo/#{repo.id}/setting/share_encrypted_env_with_forks", {}, auth_headers) + end + + example { expect(last_response.status).to eq(200) } + example do + expect(JSON.load(body)).to eq( + '@type' => 'setting', + '@representation' => 'standard', + '@permissions' => { 'read' => true, 'write' => false }, + '@href' => "/v3/repo/#{repo.id}/setting/share_encrypted_env_with_forks", + 'name' => 'share_encrypted_env_with_forks', + 'value' => false + ) + end + end + + describe 'authenticated, existing repo, default share_ssh_keys_with_forks setting' do + let(:created_at) { Date.parse('2021-09-01') } + + before do + ENV['IBM_REPO_SWITCHES_DATE'] = '2021-10-01' + repo.update(created_at: created_at) + get("/v3/repo/#{repo.id}/setting/share_ssh_keys_with_forks", {}, auth_headers) + end + + after { ENV['IBM_REPO_SWITCHES_DATE'] = nil } + + example { expect(last_response.status).to eq(200) } + example do + expect(JSON.load(body)).to eq( + '@type' => 'setting', + '@representation' => 'standard', + '@permissions' => { 'read' => true, 'write' => false }, + '@href' => "/v3/repo/#{repo.id}/setting/share_ssh_keys_with_forks", + 'name' => 'share_ssh_keys_with_forks', + 'value' => true + ) + end + + context 'when repo is new' do + let(:created_at) { Date.parse('2021-11-01') } + + example { expect(last_response.status).to eq(200) } + example do + expect(JSON.load(body)).to eq( + '@type' => 'setting', + '@representation' => 'standard', + '@permissions' => { 'read' => true, 'write' => false }, + '@href' => "/v3/repo/#{repo.id}/setting/share_ssh_keys_with_forks", + 'name' => 'share_ssh_keys_with_forks', + 'value' => false + ) + end + end + end end diff --git a/spec/v3/services/user_settings/for_repository_spec.rb b/spec/v3/services/user_settings/for_repository_spec.rb index 4c825f03aa..a8479e42ed 100644 --- a/spec/v3/services/user_settings/for_repository_spec.rb +++ b/spec/v3/services/user_settings/for_repository_spec.rb @@ -49,6 +49,8 @@ { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pushes', 'value' => false }, { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pull_requests', 'value' => false }, { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/config_validation", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'config_validation', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_encrypted_env_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_encrypted_env_with_forks', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_ssh_keys_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_ssh_keys_with_forks', 'value' => false }, ] ) end @@ -86,6 +88,8 @@ { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pushes', 'value' => false }, { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pull_requests', 'value' => false }, { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/config_validation", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'config_validation', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_encrypted_env_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_encrypted_env_with_forks', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_ssh_keys_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_ssh_keys_with_forks', 'value' => false }, ] ) end @@ -110,4 +114,4 @@ ) end end -end \ No newline at end of file +end From 40153e7db727f6a69acbb8ce4c0e91f83ad7ce9e Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Wed, 4 May 2022 07:18:15 +0200 Subject: [PATCH 11/46] extended default timeouts for db, temp workaround for tcie --- lib/travis/config/defaults.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/travis/config/defaults.rb b/lib/travis/config/defaults.rb index 72128f5c53..70c16c8f84 100644 --- a/lib/travis/config/defaults.rb +++ b/lib/travis/config/defaults.rb @@ -45,10 +45,10 @@ def fallback_logs_api_auth_token closeio: { key: 'key' }, gdpr: {}, insights: { endpoint: 'https://insights.travis-ci.dev/', auth_token: 'secret' }, - database: { adapter: 'postgresql', database: "travis_#{Travis.env}", encoding: 'unicode', min_messages: 'warning', variables: { statement_timeout: 10_000 } }, + database: { adapter: 'postgresql', database: "travis_#{Travis.env}", encoding: 'unicode', min_messages: 'warning', variables: { statement_timeout: 45_000 } }, fallback_logs_api: { url: fallback_logs_api_auth_url, token: fallback_logs_api_auth_token }, logs_api: { url: logs_api_url, token: logs_api_auth_token }, - db: { max_statement_timeout_in_seconds: 15, slow_host_max_statement_timeout_in_seconds: 60}, + db: { max_statement_timeout_in_seconds: 45, slow_host_max_statement_timeout_in_seconds: 60}, log_options: { s3: { access_key_id: '', secret_access_key: ''}}, s3: { access_key_id: '', secret_access_key: ''}, pusher: { app_id: 'app-id', key: 'key', secret: 'secret' }, From 95b0da0cc490db74d33f6cc407f5079c32b66d47 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Wed, 4 May 2022 07:25:02 +0200 Subject: [PATCH 12/46] timeout spec fix --- spec/lib/travis/config_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/travis/config_spec.rb b/spec/lib/travis/config_spec.rb index c052278878..0f969c8402 100644 --- a/spec/lib/travis/config_spec.rb +++ b/spec/lib/travis/config_spec.rb @@ -79,7 +79,7 @@ :database => 'travis_test', :encoding => 'unicode', :min_messages => 'warning', - :variables => { :statement_timeout => 10000 } + :variables => { :statement_timeout => 45000 } }) end end From 2bce53f95d69640b3a2f1eae6511d70590aac073 Mon Sep 17 00:00:00 2001 From: Maciej Kempin Date: Tue, 17 May 2022 12:22:33 +0100 Subject: [PATCH 13/46] Upgrade gems (#1233) * Rspec are loading & some deprecation fixes * some Arel and handling string as hash * No more composite keys * fixing deprecations for rake - parsing json * fixing deprecations * further cleanup * Some fixex including repo - but logic must be discussed * cleanup with composite keys * Revert "cleanup with composite keys" This reverts commit c9c796050481693018ef2ac19da6e4abe8c23eef. * Revert "No more composite keys" This reverts commit 8fb395ef7c7e69d40104ed7db3ac5bb9a1d547c3. * further changes and fixes * More spohisticated changes * ruby, ar upgrade && annoying bug fix for composite keys * Cleanup after not proper fixes * sentry & openssl upgrade * add root to serialized json * Proper gems are used * USing old Metrics * Next fixes * almost there * All green * Further gems update * problems with simple states * removing s3 step 1 * moving s3 to fog * s3 totally removed * some Gemfile changes * docker fix * sidekiq update * better regexp * Nicely usage of Mustermann * guard for AR patch * clear active connections * nokogiri bump * Parse config if string * Ensure Hash is saved into Json settings/preferences * next approach to make settings an actual hash * Ensure settings/preferences are hash Co-authored-by: Maciej Co-authored-by: gabriel-arc --- .ruby-version | 2 +- .travis.yml | 2 +- Dockerfile | 8 +- Gemfile | 40 +- Gemfile.lock | 458 +++++++++--------- bin/migrate-hooks | 3 - bin/suspend | 2 +- bin/unsuspend | 2 +- .../active_record/predicate_builder.rb | 179 +++++++ lib/tasks/correct_next_runs_for_crons.rake | 2 +- lib/travis.rb | 3 +- lib/travis/api/app.rb | 41 +- lib/travis/api/app/base.rb | 2 +- lib/travis/api/app/cors.rb | 2 +- lib/travis/api/app/endpoint/authorization.rb | 6 +- lib/travis/api/app/endpoint/env_vars.rb | 1 - lib/travis/api/app/endpoint/repos.rb | 14 +- .../api/app/extensions/smart_constants.rb | 2 +- lib/travis/api/app/responders/json.rb | 2 +- lib/travis/api/serialize/serializer.rb | 1 - lib/travis/api/serialize/v2/http/env_var.rb | 4 +- .../api/serialize/v2/http/validation_error.rb | 13 +- lib/travis/api/v3/billing_client.rb | 2 +- lib/travis/api/v3/extensions/belongs_to.rb | 6 +- lib/travis/api/v3/extensions/preferences.rb | 2 + lib/travis/api/v3/gdpr_client.rb | 2 +- lib/travis/api/v3/model.rb | 3 +- lib/travis/api/v3/models/build.rb | 2 +- lib/travis/api/v3/models/cron.rb | 2 +- lib/travis/api/v3/models/fingerprint.rb | 2 + lib/travis/api/v3/models/job.rb | 2 +- lib/travis/api/v3/models/json_sync.rb | 2 +- lib/travis/api/v3/models/key_pair.rb | 2 + lib/travis/api/v3/models/message.rb | 4 +- lib/travis/api/v3/models/organization.rb | 13 + lib/travis/api/v3/models/repository.rb | 16 +- lib/travis/api/v3/models/request.rb | 10 +- lib/travis/api/v3/models/user.rb | 13 + lib/travis/api/v3/models/user_settings.rb | 2 + lib/travis/api/v3/proxy_service.rb | 2 +- lib/travis/api/v3/queries/builds.rb | 2 +- lib/travis/api/v3/queries/env_vars.rb | 13 +- lib/travis/api/v3/queries/key_pair.rb | 12 +- lib/travis/api/v3/queries/lint.rb | 2 +- lib/travis/api/v3/queries/repositories.rb | 8 +- lib/travis/api/v3/queries/repository.rb | 2 +- lib/travis/api/v3/query.rb | 2 +- lib/travis/api/v3/renderer/request.rb | 3 +- lib/travis/api/v3/routes.rb | 5 - lib/travis/api/v3/service.rb | 2 +- lib/travis/api/v3/services/leads/create.rb | 66 --- .../api/v3/services/repository/activate.rb | 2 +- .../api/v3/services/repository/deactivate.rb | 2 +- lib/travis/config/defaults.rb | 1 - lib/travis/event/handler/metrics.rb | 1 + lib/travis/model/build.rb | 11 +- lib/travis/model/build/denormalize.rb | 2 +- lib/travis/model/build/update_branch.rb | 2 +- lib/travis/model/job.rb | 2 +- lib/travis/model/job/test.rb | 2 +- lib/travis/model/organization.rb | 13 + lib/travis/model/repository.rb | 25 +- lib/travis/model/request.rb | 2 +- lib/travis/model/user.rb | 9 + lib/travis/model/user/oauth.rb | 2 +- lib/travis/services/find_admin.rb | 4 +- lib/travis/services/find_caches.rb | 15 +- lib/travis/services/update_user.rb | 2 +- lib/travis/testing/factories.rb | 3 + lib/travis/testing/scenario.rb | 4 +- spec/auth/helpers.rb | 1 + spec/auth/v1/builds_spec.rb | 10 +- spec/auth/v2.1/builds_spec.rb | 10 +- spec/auth/v2/builds_spec.rb | 10 +- spec/integration/error_handling_spec.rb | 19 +- spec/integration/settings_endpoint_spec.rb | 12 +- .../singleton_settings_endpoint_spec.rb | 8 +- spec/integration/v2/builds_spec.rb | 6 +- spec/integration/v2/hooks_spec.rb | 4 +- spec/integration/v2/jobs_spec.rb | 4 +- spec/integration/v2/pusher_spec.rb | 16 +- spec/integration/v2/repositories_spec.rb | 18 +- spec/integration/v2/requests_spec.rb | 4 +- spec/integration/v2/settings/env_vars_spec.rb | 8 +- spec/integration/v2/settings/ssh_key_spec.rb | 4 +- spec/integration/visibility_spec.rb | 14 +- spec/lib/model/broadcast_spec.rb | 8 +- spec/lib/model/build/denormalize_spec.rb | 2 +- spec/lib/model/build/matrix_spec.rb | 60 +-- spec/lib/model/organization_spec.rb | 16 +- .../model/repository/settings/ssh_key_spec.rb | 9 +- spec/lib/model/repository/settings_spec.rb | 2 +- .../lib/model/repository/status_image_spec.rb | 16 +- spec/lib/model/repository_spec.rb | 24 +- spec/lib/model/user_spec.rb | 14 + spec/lib/services/find_admin_spec.rb | 4 +- spec/lib/services/update_job_spec.rb | 8 +- spec/lib/services/update_user_spec.rb | 6 +- spec/spec_helper.rb | 1 - spec/support/active_record.rb | 1 + spec/support/s3.rb | 41 +- .../authorization/user_manager_spec.rb | 4 +- spec/unit/endpoint/authorization_spec.rb | 4 +- spec/unit/endpoint/repos_spec.rb | 5 +- spec/unit/serialize/v2/http/builds_spec.rb | 10 +- spec/v3/models/build_spec.rb | 2 +- spec/v3/services/build/find_spec.rb | 10 +- spec/v3/services/build/restart_spec.rb | 6 +- spec/v3/services/builds/find_spec.rb | 6 +- .../services/builds/for_current_user_spec.rb | 6 +- spec/v3/services/caches/delete_spec.rb | 4 +- spec/v3/services/cron/create_spec.rb | 4 +- spec/v3/services/cron/delete_spec.rb | 4 +- .../email_subscription/resubscribe_spec.rb | 4 +- .../email_subscription/unsubscribe_spec.rb | 4 +- spec/v3/services/env_var/delete_spec.rb | 8 +- spec/v3/services/env_var/find_spec.rb | 2 +- spec/v3/services/env_var/update_spec.rb | 8 +- spec/v3/services/env_vars/create_spec.rb | 8 +- .../services/env_vars/for_repository_spec.rb | 2 +- spec/v3/services/job/debug_spec.rb | 6 +- spec/v3/services/job/find_spec.rb | 10 +- spec/v3/services/job/restart_spec.rb | 4 +- .../jobs/find_for_current_user_spec.rb | 2 +- spec/v3/services/jobs/find_spec.rb | 4 +- spec/v3/services/key_pair/create_spec.rb | 8 +- spec/v3/services/key_pair/delete_spec.rb | 12 +- spec/v3/services/key_pair/find_spec.rb | 4 +- spec/v3/services/key_pair/update_spec.rb | 8 +- spec/v3/services/leads/create_spec.rb | 229 --------- spec/v3/services/log/delete_spec.rb | 4 +- spec/v3/services/log/find_spec.rb | 8 +- .../services/repositories/for_owner_spec.rb | 2 +- spec/v3/services/repository/activate_spec.rb | 6 +- .../v3/services/repository/deactivate_spec.rb | 6 +- spec/v3/services/repository/migrate_spec.rb | 4 +- spec/v3/services/repository/star_spec.rb | 4 +- spec/v3/services/repository/unstar_spec.rb | 4 +- spec/v3/services/repository/update_spec.rb | 4 +- spec/v3/services/request/find_spec.rb | 4 +- spec/v3/services/request/preview_spec.rb | 2 +- spec/v3/services/requests/create_spec.rb | 6 +- spec/v3/services/ssl_key/create_spec.rb | 4 +- spec/v3/services/stages/find_spec.rb | 4 +- spec/v3/services/user_setting/find_spec.rb | 4 +- spec/v3/services/user_setting/update_spec.rb | 4 +- .../user_settings/for_repository_spec.rb | 6 +- 147 files changed, 1001 insertions(+), 920 deletions(-) create mode 100644 lib/patches/active_record/predicate_builder.rb delete mode 100644 lib/travis/api/v3/services/leads/create.rb delete mode 100644 spec/v3/services/leads/create_spec.rb diff --git a/.ruby-version b/.ruby-version index 57cf282ebb..a603bb50a2 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.6.5 +2.7.5 diff --git a/.travis.yml b/.travis.yml index e0361e2980..6ef65f5535 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ group: edge import: - travis-ci/build-configs:db-setup.yml@bionic -rvm: 2.6.5 +rvm: 2.7.5 script: "bundle exec rake knapsack:rspec" diff --git a/Dockerfile b/Dockerfile index 7eeb16271e..6cb858bb73 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.6.5-slim +FROM ruby:2.7.5-slim LABEL maintainer Travis CI GmbH @@ -23,16 +23,12 @@ WORKDIR /app COPY Gemfile /app COPY Gemfile.lock /app -RUN gem install bundler -v '2.1.4' +RUN gem install bundler -v '2.3.6' RUN bundle config set without 'development test' RUN bundler install --verbose --retry=3 RUN gem install --user-install executable-hooks COPY . /app -RUN bundle config unset frozen -RUN cd /usr/local/bundle/bundler/gems/s3-386361c1b0ed && bundle update -RUN cd /usr/local/bundle/bundler/gems/travis-lock-b418401c79e0 && sed "s/'activerecord'/'activerecord','~>4.2'/g" Gemfile -i && bundle update activerecord && bundle update redlock -RUN cd /usr/local/bundle/bundler/gems/travis-settings-debef595a6a5 && echo "gem 'activesupport','~> 5.2'" >> Gemfile && bundle update activemodel RUN bundle config set frozen true CMD ./script/server-buildpacks diff --git a/Gemfile b/Gemfile index e6c96129a9..b41962778e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,33 +1,29 @@ source 'https://rubygems.org' -ruby '2.6.5' - -gem 's3', git: 'https://github.com/travis-ci/s3' +ruby '2.7.5' gem 'mime-types' -gem 'travis-support', git: 'https://github.com/travis-ci/travis-support' +gem 'travis-support', git: 'https://github.com/travis-ci/travis-support', ref: '4dda53ffa96b804db22c261551256caa18c4a2cc' gem 'travis-amqp', git: 'https://github.com/travis-ci/travis-amqp' gem 'travis-config', git: 'https://github.com/travis-ci/travis-config', branch: 'fix-docker-redis-url' gem 'travis-settings', git: 'https://github.com/travis-ci/travis-settings' -gem 'travis-lock', git: 'https://github.com/travis-ci/travis-lock' +gem 'travis-lock', git: 'https://github.com/travis-ci/travis-lock/', branch: '6.1' gem 'travis-github_apps', git: 'https://github.com/travis-ci/travis-github_apps' gem 'travis-rollout', '~> 0.0.2' -gem 'mustermann' gem 'sinatra' gem 'sinatra-contrib', require: nil #git: 'https://github.com/sinatra/sinatra-contrib', require: nil +gem 'simple_states', git: 'https://github.com/travis-ci/simple_states', branch: '6.1' -gem 'simple_states', '1.0.2' - -gem 'active_model_serializers' +gem 'active_model_serializers', "~> 0.9.8" gem 'unicorn' gem 'sentry-raven' gem 'yard-sinatra', git: 'https://github.com/rkh/yard-sinatra' -gem 'rack-contrib' +gem 'rack-contrib', '= 2.3.0' gem 'rack-cache', git: 'https://github.com/rtomayko/rack-cache' gem 'rack-attack', '~> 5.0' -gem 'gh', git: 'https://github.com/travis-ci/gh', branch: 'tcie30-0_15_1' +gem 'gh', git: 'https://github.com/travis-ci/gh', branch: '6.1' gem 'bunny', '~> 2.9.2' gem 'dalli' gem 'pry' @@ -39,16 +35,16 @@ gem 'simplecov' gem 'stackprof' gem "ipaddress", "~> 0.8.3" gem 'nakayoshi_fork' -gem 'sidekiq' +gem 'sidekiq', '~> 6.4.0' gem 'redis-namespace' -gem 'marginalia', git: 'https://github.com/travis-ci/marginalia' +gem 'marginalia', git: 'https://github.com/travis-ci/marginalia', branch: '6.1' gem 'rbtrace' gem 'memory_profiler' gem 'allocation_tracer' -gem 'redlock' -gem 'rake', '~> 12.3.3' +gem 'redlock', '~> 1.2.2' +gem 'rake', '~> 13.0.6' gem 'libhoney' gem 'opencensus' @@ -59,8 +55,8 @@ gem 'faraday_middleware' gem 'knapsack' -gem 'pg', '~> 0.21' -gem 'composite_primary_keys', '~> 8.0' +gem 'pg', '~> 1.3' +gem 'composite_primary_keys', '~> 13.0.3' gem 'redcarpet', '>= 3.2.3' gem 'rack-ssl', '~> 1.3', '>= 1.3.3' gem 'memcachier' @@ -69,15 +65,17 @@ gem 'tool' gem 'google-api-client', '~> 0.9.4' gem 'fog-aws', '~> 0.12.0' gem 'fog-google', '~> 0.4.2' -gem 'activerecord', '~> 4.2' +gem 'activerecord', '~> 6.1.4.5' gem 'rollout', '~> 1.1.0' gem 'coder', '~> 0.4.0' gem 'virtus', '~> 1.0.0' -gem 'redis', '~> 3.0' +gem 'redis', '~> 4.2.0' gem 'hashr' gem 'pusher', '~> 0.14.0' gem 'multi_json' -gem 'closeio', '~> 3.5' +gem 'addressable', '~> 2.8.0' +gem 'rack', '~> 2.2.3' +gem 'os', '~> 1.1.4' group :test do gem 'rspec' @@ -89,6 +87,7 @@ group :test do gem 'webmock' gem 'hashdiff' gem 'pry-byebug' + gem 'rack-test' end group :development do @@ -96,4 +95,3 @@ group :development do gem 'rerun' gem 'rb-fsevent', '~> 0.9.1' end - diff --git a/Gemfile.lock b/Gemfile.lock index bc3d9c05e3..5ffba8cd80 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,37 +14,40 @@ GIT GIT remote: https://github.com/rtomayko/rack-cache - revision: 2d6618172c39c53dceab2e2946d87496154f3e52 + revision: 1ab44995cfb57b9b49567cd0fafb7d88c41fbdc0 specs: - rack-cache (1.6.1) + rack-cache (1.13.0) rack (>= 0.4) GIT remote: https://github.com/travis-ci/gh - revision: 482ccbc8159c73fd5e651476692c6ea3d9f416a8 - branch: tcie30-0_15_1 + revision: 490fbc2a663613f98a19060de7b128eb07014b2f + branch: 6.1 specs: - gh (0.15.1) - addressable (~> 2.4.0) - backports - faraday (~> 0.8) + gh (0.18.0) + activesupport (>= 5, < 6.2) + addressable (~> 2.8) + faraday (~> 1.0) + faraday_middleware (~> 1.0) multi_json (~> 1.0) net-http-persistent (~> 2.9) net-http-pipeline GIT remote: https://github.com/travis-ci/marginalia - revision: 46bbe301640efb5ea81828cb7deeaf874516de78 + revision: 7f74ee15d34be5009b5c82734d5b6fd601ab25f6 + branch: 6.1 specs: - marginalia (1.5.0) - pg (~> 0.21) + marginalia (1.6.0) + pg (~> 1.3) GIT - remote: https://github.com/travis-ci/s3 - revision: 386361c1b0ede19cde0ddaf86e41a16308575f5d + remote: https://github.com/travis-ci/simple_states + revision: 68e3087763e5e345c0949268169cb0f74a54ef6a + branch: 6.1 specs: - s3 (0.3.21) - proxies (~> 0.2.0) + simple_states (1.0.2) + activesupport (~> 6.1.4.5) GIT remote: https://github.com/travis-ci/travis-amqp @@ -72,8 +75,9 @@ GIT redis GIT - remote: https://github.com/travis-ci/travis-lock - revision: b418401c79e082aa53a62364f7b01a9be6f0d768 + remote: https://github.com/travis-ci/travis-lock/ + revision: 1dbed2874330d5d24c1dcdb9143ecf9a5eb041a9 + branch: 6.1 specs: travis-lock (0.1.1) @@ -88,73 +92,95 @@ GIT GIT remote: https://github.com/travis-ci/travis-support revision: 4dda53ffa96b804db22c261551256caa18c4a2cc + ref: 4dda53ffa96b804db22c261551256caa18c4a2cc specs: travis-support (0.0.1) GEM remote: https://rubygems.org/ specs: - active_model_serializers (0.9.5) + active_model_serializers (0.9.8) activemodel (>= 3.2) - activemodel (4.2.11.3) - activesupport (= 4.2.11.3) - builder (~> 3.1) - activerecord (4.2.11.3) - activemodel (= 4.2.11.3) - activesupport (= 4.2.11.3) - arel (~> 6.0) - activesupport (4.2.11.3) - i18n (~> 0.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.4.0) - aggregate (0.2.2) + concurrent-ruby (~> 1.0) + activemodel (6.1.4.6) + activesupport (= 6.1.4.6) + activerecord (6.1.4.6) + activemodel (= 6.1.4.6) + activesupport (= 6.1.4.6) + activesupport (6.1.4.6) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + aggregate (0.2.3) allocation_tracer (0.6.3) - amq-protocol (2.3.0) - arel (6.0.4) - atomic (1.1.99) + amq-protocol (2.3.2) + atomic (1.1.101) avl_tree (1.1.3) axiom-types (0.1.1) descendants_tracker (~> 0.0.4) ice_nine (~> 0.11.0) thread_safe (~> 0.3, >= 0.3.1) - backports (3.23.0) builder (3.2.4) bunny (2.9.2) amq-protocol (~> 2.3.0) - byebug (10.0.2) - closeio (3.6.1) - faraday - faraday_middleware - json + byebug (11.1.3) coder (0.4.0) - coderay (1.1.1) + coderay (1.1.3) coercible (1.0.0) descendants_tracker (~> 0.0.1) - composite_primary_keys (8.1.8) - activerecord (~> 4.2.0) - concurrent-ruby (1.1.8) - connection_pool (2.2.1) - crack (0.4.3) - safe_yaml (~> 1.0.0) - dalli (2.7.6) - database_cleaner (1.99.0) + composite_primary_keys (13.0.3) + activerecord (~> 6.1.0) + concurrent-ruby (1.1.9) + connection_pool (2.2.5) + crack (0.4.5) + rexml + dalli (3.2.1) + database_cleaner (2.0.1) + database_cleaner-active_record (~> 2.0.0) + database_cleaner-active_record (2.0.1) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) - diff-lcs (1.3) - docile (1.1.5) + diff-lcs (1.5.0) + docile (1.4.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) equalizer (0.0.11) - excon (0.72.0) - factory_bot (5.1.1) - activesupport (>= 4.2.0) - faraday (0.17.4) + excon (0.91.0) + factory_bot (6.2.0) + activesupport (>= 5.0.0) + faraday (1.9.3) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.3) multipart-post (>= 1.2, < 3) - faraday_middleware (0.14.0) - faraday (>= 0.7.4, < 1.0) - ffi (1.15.0) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + ffi (1.15.5) ffi-compiler (1.0.1) ffi (>= 1.0.0) rake @@ -171,16 +197,21 @@ GEM fog-core fog-json fog-xml - fog-json (1.0.2) - fog-core (~> 1.0) + fog-json (1.2.0) + fog-core multi_json (~> 1.10) - fog-xml (0.1.3) + fog-xml (0.1.4) fog-core nokogiri (>= 1.5.11, < 2.0.0) - foreman (0.82.0) - thor (~> 0.19.1) - formatador (0.2.5) - git-version-bump (0.15.1) + foreman (0.87.2) + formatador (0.3.0) + gapic-common (0.8.0) + faraday (~> 1.3) + google-protobuf (~> 3.14) + googleapis-common-protos (>= 1.3.11, < 2.a) + googleapis-common-protos-types (>= 1.0.6, < 2.a) + googleauth (>= 0.17.0, < 2.a) + grpc (~> 1.36) google-api-client (0.9.28) addressable (~> 2.3) googleauth (~> 0.5) @@ -190,65 +221,59 @@ GEM mime-types (>= 1.6) representable (~> 2.3.0) retriable (~> 2.0) - google-cloud-core (1.2.7) - google-cloud-env (~> 1.0) - google-cloud-env (1.0.5) - faraday (~> 0.11) - google-cloud-trace (0.33.5) - google-cloud-core (~> 1.2) - google-gax (~> 1.3) - stackdriver-core (~> 1.3) - google-gax (1.3.0) - google-protobuf (~> 3.2) - googleapis-common-protos (>= 1.3.5, < 2.0) - googleauth (~> 0.6.2) - grpc (>= 1.7.2, < 2.0) - rly (~> 0.2.3) - google-protobuf (3.11.2) - googleapis-common-protos (1.3.7) - google-protobuf (~> 3.0) - googleapis-common-protos-types (~> 1.0) - grpc (~> 1.0) - googleapis-common-protos-types (1.0.4) - google-protobuf (~> 3.0) - googleauth (0.6.6) - faraday (~> 0.12) + google-cloud-env (1.5.0) + faraday (>= 0.17.3, < 2.0) + google-cloud-errors (1.2.0) + google-cloud-monitoring-v3 (0.7.1) + gapic-common (>= 0.7, < 2.a) + google-cloud-errors (~> 1.0) + google-cloud-trace-v2 (0.3.5) + gapic-common (>= 0.7, < 2.a) + google-cloud-errors (~> 1.0) + google-protobuf (3.19.4) + googleapis-common-protos (1.3.12) + google-protobuf (~> 3.14) + googleapis-common-protos-types (~> 1.2) + grpc (~> 1.27) + googleapis-common-protos-types (1.3.0) + google-protobuf (~> 3.14) + googleauth (0.17.1) + faraday (>= 0.17.3, < 2.0) jwt (>= 1.4, < 3.0) - memoist (~> 0.12) + memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) - signet (~> 0.7) - grpc (1.26.0) - google-protobuf (~> 3.8) + signet (~> 0.15) + grpc (1.43.1) + google-protobuf (~> 3.18) googleapis-common-protos-types (~> 1.0) - hashdiff (1.0.0) - hashr (2.0.0) - hitimes (1.2.4) + hashdiff (1.0.1) + hashr (2.0.1) + hitimes (1.3.1) http (4.4.1) addressable (~> 2.3) http-cookie (~> 1.0) http-form_data (~> 2.2) http-parser (~> 1.2.0) - http-cookie (1.0.3) + http-cookie (1.0.4) domain_name (~> 0.5) http-form_data (2.3.0) http-parser (1.2.3) ffi-compiler (>= 1.0, < 2.0) httpclient (2.8.3) hurley (0.2) - i18n (0.9.5) + i18n (1.10.0) concurrent-ruby (~> 1.0) ice_nine (0.11.2) ipaddress (0.8.3) - json (2.5.1) - jwt (2.2.1) - kgio (2.11.3) - knapsack (1.14.0) + jwt (2.3.0) + kgio (2.11.4) + knapsack (4.0.0) rake - libhoney (1.18.0) + libhoney (2.1.0) addressable (~> 2.0) excon - http (>= 2.0, < 5.0) + http (>= 2.0, < 6.0) librato-metrics (2.1.2) aggregate (~> 0.2.2) faraday @@ -257,177 +282,173 @@ GEM rb-inotify (~> 0.9, >= 0.9.7) ruby_dep (~> 1.2) memcachier (0.0.2) - memoist (0.16.0) - memory_profiler (0.9.10) - method_source (0.8.2) + memoist (0.16.2) + memory_profiler (1.0.0) + method_source (1.0.0) metriks (0.9.9.6) atomic (~> 1.0) avl_tree (~> 1.1.2) hitimes (~> 1.1) - mime-types (3.1) + mime-types (3.4.1) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0521) - mini_portile2 (2.5.3) - minitest (5.14.4) - mocha (1.11.2) - msgpack (1.4.2) + mime-types-data (3.2022.0105) + mini_portile2 (2.8.0) + minitest (5.15.0) + mocha (1.13.0) + msgpack (1.4.5) multi_json (1.15.0) multipart-post (2.1.1) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) - nakayoshi_fork (0.0.3) + nakayoshi_fork (0.0.4) net-http-persistent (2.9.4) net-http-pipeline (1.0.1) - nokogiri (1.11.7) - mini_portile2 (~> 2.5.0) + nokogiri (1.13.3) + mini_portile2 (~> 2.8.0) racc (~> 1.4) - opencensus (0.3.1) - opencensus-stackdriver (0.1.2) + opencensus (0.5.0) + opencensus-stackdriver (0.4.1) concurrent-ruby (~> 1.0) - google-cloud-trace (~> 0.31) - opencensus (~> 0.3) + google-cloud-env (~> 1.3) + google-cloud-monitoring-v3 (~> 0.1) + google-cloud-trace-v2 (~> 0.1) + opencensus (~> 0.5) optimist (3.0.1) - os (1.1.1) - pg (0.21.0) - proxies (0.2.3) - pry (0.10.4) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-byebug (3.6.0) - byebug (~> 10.0) - pry (~> 0.10) + os (1.1.4) + pg (1.3.4) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.9.0) + byebug (~> 11.0) + pry (~> 0.13.0) + public_suffix (4.0.6) pusher (0.14.6) httpclient (~> 2.5) multi_json (~> 1.0) pusher-signature (~> 0.1.8) pusher-signature (0.1.8) - racc (1.5.2) - rack (1.6.13) + racc (1.6.0) + rack (2.2.3) rack-attack (5.4.2) rack (>= 1.0, < 3) - rack-contrib (1.4.0) - git-version-bump (~> 0.15) - rack (~> 1.4) - rack-protection (1.5.5) + rack-contrib (2.3.0) + rack (~> 2.0) + rack-protection (2.2.0) rack rack-ssl (1.4.1) rack - rack-test (0.6.3) - rack (>= 1.0) - raindrops (0.19.1) - rake (12.3.3) + rack-test (1.1.0) + rack (>= 1.0, < 3) + raindrops (0.20.0) + rake (13.0.6) rb-fsevent (0.9.8) - rb-inotify (0.9.7) - ffi (>= 0.5.0) + rb-inotify (0.10.1) + ffi (~> 1.0) rbtrace (0.4.14) ffi (>= 1.0.6) msgpack (>= 0.4.3) optimist (>= 3.0.0) - redcarpet (3.4.0) - redis (3.3.5) - redis-namespace (1.5.2) - redis (~> 3.0, >= 3.0.4) - redlock (1.2.1) + redcarpet (3.5.1) + redis (4.2.5) + redis-namespace (1.8.1) + redis (>= 3.0.4) + redlock (1.2.2) redis (>= 3.0.0, < 5.0) representable (2.3.0) uber (~> 0.0.7) - rerun (0.11.0) + rerun (0.13.1) listen (~> 3.0) retriable (2.1.0) - rly (0.2.3) + rexml (3.2.5) rollout (1.1.0) - rspec (3.9.0) - rspec-core (~> 3.9.0) - rspec-expectations (~> 3.9.0) - rspec-mocks (~> 3.9.0) - rspec-core (3.9.1) - rspec-support (~> 3.9.1) - rspec-expectations (3.9.0) + rspec (3.11.0) + rspec-core (~> 3.11.0) + rspec-expectations (~> 3.11.0) + rspec-mocks (~> 3.11.0) + rspec-core (3.11.0) + rspec-support (~> 3.11.0) + rspec-expectations (3.11.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) + rspec-support (~> 3.11.0) rspec-its (1.3.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.9.1) + rspec-mocks (3.11.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) - rspec-support (3.9.2) - ruby2_keywords (0.0.4) + rspec-support (~> 3.11.0) + rspec-support (3.11.0) + ruby2_keywords (0.0.5) ruby_dep (1.5.0) - safe_yaml (1.0.5) - sentry-raven (2.11.3) - faraday (>= 0.7.6, < 1.0) - sidekiq (4.2.6) - concurrent-ruby (~> 1.0) - connection_pool (~> 2.2, >= 2.2.0) - rack-protection (>= 1.5.0) - redis (~> 3.2, >= 3.2.1) - signet (0.9.2) - addressable (~> 2.3) - faraday (~> 0.9) + sentry-raven (3.1.2) + faraday (>= 1.0) + sidekiq (6.4.1) + connection_pool (>= 2.2.2) + rack (~> 2.0) + redis (>= 4.2.0) + signet (0.16.0) + addressable (~> 2.8) + faraday (>= 0.17.3, < 2.0) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simple_states (1.0.2) - activesupport - simplecov (0.15.1) - docile (~> 1.1.0) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.2) - sinatra (1.4.8) - rack (~> 1.5) - rack-protection (~> 1.4) - tilt (>= 1.3, < 3) - sinatra-contrib (1.4.7) - backports (>= 2.0) + simplecov (0.21.2) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.4) + sinatra (2.2.0) + mustermann (~> 1.0) + rack (~> 2.2) + rack-protection (= 2.2.0) + tilt (~> 2.0) + sinatra-contrib (2.2.0) multi_json - rack-protection - rack-test - sinatra (~> 1.4.0) - tilt (>= 1.3, < 3) - slop (3.6.0) - stackdriver-core (1.3.3) - google-cloud-core (~> 1.2) - stackprof (0.2.16) - thor (0.19.1) + mustermann (~> 1.0) + rack-protection (= 2.2.0) + sinatra (= 2.2.0) + tilt (~> 2.0) + stackprof (0.2.17) thread_safe (0.3.6) tilt (2.0.10) - timecop (0.9.1) + timecop (0.9.4) tool (0.2.3) travis-rollout (0.0.2) - tzinfo (1.2.9) - thread_safe (~> 0.1) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) uber (0.0.15) unf (0.1.4) unf_ext - unf_ext (0.0.7.7) - unicorn (5.5.3) + unf_ext (0.0.8) + unicorn (6.1.0) kgio (~> 2.6) raindrops (~> 0.7) - useragent (0.16.8) + useragent (0.16.10) virtus (1.0.5) axiom-types (~> 0.1) coercible (~> 1.0) descendants_tracker (~> 0.0, >= 0.0.3) equalizer (~> 0.0, >= 0.0.9) - webmock (3.8.2) - addressable (>= 2.3.6) + webmock (3.14.0) + addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - yard (0.9.26) + webrick (1.7.0) + yard (0.9.27) + webrick (~> 1.7.0) + zeitwerk (2.5.4) PLATFORMS ruby DEPENDENCIES - active_model_serializers - activerecord (~> 4.2) + active_model_serializers (~> 0.9.8) + activerecord (~> 6.1.4.5) + addressable (~> 2.8.0) allocation_tracer bunny (~> 2.9.2) - closeio (~> 3.5) coder (~> 0.4.0) - composite_primary_keys (~> 8.0) + composite_primary_keys (~> 13.0.3) dalli database_cleaner factory_bot @@ -453,33 +474,34 @@ DEPENDENCIES mime-types mocha multi_json - mustermann nakayoshi_fork opencensus opencensus-stackdriver - pg (~> 0.21) + os (~> 1.1.4) + pg (~> 1.3) pry pry-byebug pusher (~> 0.14.0) + rack (~> 2.2.3) rack-attack (~> 5.0) rack-cache! - rack-contrib + rack-contrib (= 2.3.0) rack-ssl (~> 1.3, >= 1.3.3) - rake (~> 12.3.3) + rack-test + rake (~> 13.0.6) rb-fsevent (~> 0.9.1) rbtrace redcarpet (>= 3.2.3) - redis (~> 3.0) + redis (~> 4.2.0) redis-namespace - redlock + redlock (~> 1.2.2) rerun rollout (~> 1.1.0) rspec rspec-its - s3! sentry-raven - sidekiq - simple_states (= 1.0.2) + sidekiq (~> 6.4.0) + simple_states! simplecov sinatra sinatra-contrib @@ -500,7 +522,7 @@ DEPENDENCIES yard-sinatra! RUBY VERSION - ruby 2.6.5p114 + ruby 2.7.5p203 BUNDLED WITH - 2.1.4 + 2.3.6 diff --git a/bin/migrate-hooks b/bin/migrate-hooks index 21e1020f5c..32ec3ff7d3 100755 --- a/bin/migrate-hooks +++ b/bin/migrate-hooks @@ -6,9 +6,6 @@ $stdout.sync = true require 'bundler/setup' require 'active_record' -# To silence deprecation warning -ActiveRecord::Base.raise_in_transactional_callbacks = true - require 'date' require 'stringio' require 'thread' diff --git a/bin/suspend b/bin/suspend index 357b5ded25..23f59826dc 100755 --- a/bin/suspend +++ b/bin/suspend @@ -8,7 +8,7 @@ unless login = ARGV.first end if user = User.find_by_login(login) - user.update_attributes!(suspended: true, suspended_at: Time.now.utc) + user.update!(suspended: true, suspended_at: Time.now.utc) puts "Suspending user id=#{user.id} login=#{login}" exit 0 else diff --git a/bin/unsuspend b/bin/unsuspend index d3c775e816..281862faf3 100755 --- a/bin/unsuspend +++ b/bin/unsuspend @@ -8,7 +8,7 @@ unless login = ARGV.first end if user = User.find_by_login(login) - user.update_attributes!(suspended: false, suspended_at: nil) + user.update!(suspended: false, suspended_at: nil) puts "Unsuspending user id=#{user.id} login=#{login}" exit 0 else diff --git a/lib/patches/active_record/predicate_builder.rb b/lib/patches/active_record/predicate_builder.rb new file mode 100644 index 0000000000..91da25af3b --- /dev/null +++ b/lib/patches/active_record/predicate_builder.rb @@ -0,0 +1,179 @@ +# frozen_string_literal: true + +EXPECTED_AR_VERSION = '6.1.4.6'.freeze +ACTUAL_AR_VERSION = "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}.#{ActiveRecord::VERSION::TINY}.#{ActiveRecord::VERSION::PRE}" + +if EXPECTED_AR_VERSION != ACTUAL_AR_VERSION + raise 'The version of ActiveRecord has been changed. + Patch "&& !table.has_column?(key)" (line 98) introduced in this file might not be needed + or needs to be applied to changed version of ActiveRecord::PredicateBuilder. + You can check need by commented the code in this file running all specs.' +end + +module ActiveRecord + class PredicateBuilder # :nodoc: + require "active_record/relation/predicate_builder/array_handler" + require "active_record/relation/predicate_builder/basic_object_handler" + require "active_record/relation/predicate_builder/range_handler" + require "active_record/relation/predicate_builder/relation_handler" + require "active_record/relation/predicate_builder/association_query_value" + require "active_record/relation/predicate_builder/polymorphic_array_value" + + # No-op BaseHandler to work Mashal.load(File.read("legacy_relation.dump")). + # TODO: Remove the constant alias once Rails 6.1 has released. + BaseHandler = BasicObjectHandler + + def initialize(table) + @table = table + @handlers = [] + + register_handler(BasicObject, BasicObjectHandler.new(self)) + register_handler(Range, RangeHandler.new(self)) + register_handler(Relation, RelationHandler.new) + register_handler(Array, ArrayHandler.new(self)) + register_handler(Set, ArrayHandler.new(self)) + end + + def build_from_hash(attributes, &block) + attributes = convert_dot_notation_to_hash(attributes) + expand_from_hash(attributes, &block) + end + + def self.references(attributes) + attributes.each_with_object([]) do |(key, value), result| + if value.is_a?(Hash) + result << Arel.sql(key) + elsif key.include?(".") + result << Arel.sql(key.split(".").first) + end + end + end + + # Define how a class is converted to Arel nodes when passed to +where+. + # The handler can be any object that responds to +call+, and will be used + # for any value that +===+ the class given. For example: + # + # MyCustomDateRange = Struct.new(:start, :end) + # handler = proc do |column, range| + # Arel::Nodes::Between.new(column, + # Arel::Nodes::And.new([range.start, range.end]) + # ) + # end + # ActiveRecord::PredicateBuilder.new("users").register_handler(MyCustomDateRange, handler) + def register_handler(klass, handler) + @handlers.unshift([klass, handler]) + end + + def [](attr_name, value, operator = nil) + build(table.arel_table[attr_name], value, operator) + end + + def build(attribute, value, operator = nil) + value = value.id if value.respond_to?(:id) + if operator ||= table.type(attribute.name).force_equality?(value) && :eq + bind = build_bind_attribute(attribute.name, value) + attribute.public_send(operator, bind) + else + handler_for(value).call(attribute, value) + end + end + + def build_bind_attribute(column_name, value) + attr = Relation::QueryAttribute.new(column_name, value, table.type(column_name)) + Arel::Nodes::BindParam.new(attr) + end + + def resolve_arel_attribute(table_name, column_name, &block) + table.associated_table(table_name, &block).arel_table[column_name] + end + + protected + def expand_from_hash(attributes, &block) + return ["1=0"] if attributes.empty? + + attributes.flat_map do |key, value| + if value.is_a?(Hash) && !table.has_column?(key) + table.associated_table(key, &block) + .predicate_builder.expand_from_hash(value.stringify_keys) + elsif table.associated_with?(key) && !table.has_column?(key) # && !table.has_column?(key) is important to make Composite Primary keys work when key is same as relation (i.e. branch) + # Find the foreign key when using queries such as: + # Post.where(author: author) + # + # For polymorphic relationships, find the foreign key and type: + # PriceEstimate.where(estimate_of: treasure) + associated_table = table.associated_table(key) + if associated_table.polymorphic_association? + value = [value] unless value.is_a?(Array) + klass = PolymorphicArrayValue + elsif associated_table.through_association? + next associated_table.predicate_builder.expand_from_hash( + associated_table.primary_key => value + ) + end + + klass ||= AssociationQueryValue + queries = klass.new(associated_table, value).queries.map! do |query| + # If the query produced is identical to attributes don't go any deeper. + # Prevents stack level too deep errors when association and foreign_key are identical. + query == attributes ? self[key, value] : expand_from_hash(query) + end + + grouping_queries(queries) + elsif table.aggregated_with?(key) + mapping = table.reflect_on_aggregation(key).mapping + values = value.nil? ? [nil] : Array.wrap(value) + if mapping.length == 1 || values.empty? + column_name, aggr_attr = mapping.first + values = values.map do |object| + object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object + end + self[column_name, values] + else + queries = values.map do |object| + mapping.map do |field_attr, aggregate_attr| + self[field_attr, object.try!(aggregate_attr)] + end + end + + grouping_queries(queries) + end + else + self[key, value] + end + end + end + + private + attr_reader :table + + def grouping_queries(queries) + if queries.one? + queries.first + else + queries.map! { |query| query.reduce(&:and) } + queries = queries.reduce { |result, query| Arel::Nodes::Or.new(result, query) } + Arel::Nodes::Grouping.new(queries) + end + end + + def convert_dot_notation_to_hash(attributes) + dot_notation = attributes.select do |k, v| + k.include?(".") && !v.is_a?(Hash) + end + + dot_notation.each_key do |key| + table_name, column_name = key.split(".") + value = attributes.delete(key) + attributes[table_name] ||= {} + + attributes[table_name] = attributes[table_name].merge(column_name => value) + end + + attributes + end + + def handler_for(object) + @handlers.detect { |klass, _| klass === object }.last + end + end +end \ No newline at end of file diff --git a/lib/tasks/correct_next_runs_for_crons.rake b/lib/tasks/correct_next_runs_for_crons.rake index de3047f1c1..6fecc2e82c 100644 --- a/lib/tasks/correct_next_runs_for_crons.rake +++ b/lib/tasks/correct_next_runs_for_crons.rake @@ -20,7 +20,7 @@ task :correct_next_runs_for_crons do crons.all.each do |cron| corrected = send("corrected_#{interval}_next_run", cron) puts "#{interval} cron #{cron.id}. Set next_run to #{corrected}" - cron.update_attributes!(next_run: corrected) + cron.update!(next_run: corrected) end end end diff --git a/lib/travis.rb b/lib/travis.rb index bcc7f6a25b..d68ebbe680 100644 --- a/lib/travis.rb +++ b/lib/travis.rb @@ -1,6 +1,6 @@ require 'pusher' require 'travis/support' -require 'travis/support/database' +#require 'travis/support/database' require 'travis/errors' module Travis @@ -45,6 +45,7 @@ def setup(options = {}) Github.setup Services.register Github::Services.register + require 'patches/active_record/predicate_builder' end def redis diff --git a/lib/travis/api/app.rb b/lib/travis/api/app.rb index 587ed4026c..3afd26c0cc 100644 --- a/lib/travis/api/app.rb +++ b/lib/travis/api/app.rb @@ -10,6 +10,7 @@ require 'rack/protection' require 'rack/contrib/config' require 'rack/contrib/jsonp' +require 'rack/contrib/json_body_parser' require 'rack/contrib/post_body_content_type_parser' require 'dalli' require 'memcachier' @@ -39,6 +40,7 @@ module Travis::Api require 'travis/api/v3' require 'travis/api/app/error_handling' require 'travis/api/sidekiq' +require 'travis/support/database' # Rack class implementing the HTTP API. # Instances respond to #call. @@ -77,10 +79,6 @@ def self.setup(options = {}) FileUtils.touch('/tmp/app-initialized') if ENV['DYNO'] # Heroku end - def self.new(options = {}) - setup(options) - super() - end def self.deploy_sha @deploy_sha ||= ENV['HEROKU_SLUG_COMMIT'] || SecureRandom.hex(5) @@ -88,7 +86,8 @@ def self.deploy_sha attr_accessor :app - def initialize + def initialize(options = {}) + self.class.setup(options) @app = Rack::Builder.app do # if stackprof = ENV['STACKPROF'] # require 'stackprof' @@ -118,7 +117,7 @@ def initialize if Travis::Api::App.use_monitoring? use Rack::Config do |env| if env['HTTP_X_REQUEST_ID'] - Raven.tags_context(request_id: env['HTTP_X_REQUEST_ID']) + Raven.set_tags(request_id: env['HTTP_X_REQUEST_ID']) end end use Raven::Rack @@ -137,8 +136,7 @@ def initialize end use Rack::SSL if Endpoint.production? && !ENV['DOCKER'] - use ActiveRecord::ConnectionAdapters::ConnectionManagement - use ActiveRecord::QueryCache + use ConnectionManagement memcache_servers = ENV['MEMCACHIER_SERVERS'] if Travis::Features.feature_active?(:use_rack_cache) && memcache_servers @@ -148,7 +146,7 @@ def initialize end use Rack::Deflater - use Rack::PostBodyContentTypeParser + use Rack::JSONBodyParser use Rack::JSONP use Rack::Config do |env| @@ -178,15 +176,15 @@ def initialize end Endpoint.subclasses.each do |e| - next if e == SettingsEndpoint # TODO: add something like abstract? method to check if - # class should be registered - map(e.prefix) { run(e.new) } + next if e == SettingsEndpoint # TODO: add something like abstract? method to check if class should be registered + map(e.prefix) { run e } end end end # Rack protocol def call(env) + #app.after { ActiveRecord::Base.clear_active_connections! } app.call(env) rescue if Endpoint.production? @@ -290,4 +288,23 @@ def self.setup_endpoints Base.subclasses.each(&:setup) end end + + class ConnectionManagement + def initialize(app) + @app = app + end + + def call(env) + testing = ENV['RACK_ENV'] == 'test' + + status, headers, body = @app.call(env) + proxy = ::Rack::BodyProxy.new(body) do + ActiveRecord::Base.clear_active_connections! unless testing + end + [status, headers, proxy] + rescue Exception + ActiveRecord::Base.clear_active_connections! unless testing + raise + end + end end diff --git a/lib/travis/api/app/base.rb b/lib/travis/api/app/base.rb index 729fdae81a..94fcfa9d8b 100644 --- a/lib/travis/api/app/base.rb +++ b/lib/travis/api/app/base.rb @@ -8,8 +8,8 @@ class Travis::Api::App # Superclass for any endpoint and middleware. # Pulls in relevant helpers and extensions. class Base < Sinatra::Base + register Travis::Api::App::Extensions::Scoping register Extensions::SmartConstants - register Mustermann error NotImplementedError do content_type :txt diff --git a/lib/travis/api/app/cors.rb b/lib/travis/api/app/cors.rb index f01ae3fe77..4f735123ca 100644 --- a/lib/travis/api/app/cors.rb +++ b/lib/travis/api/app/cors.rb @@ -12,7 +12,7 @@ class Cors < Base headers['Access-Control-Expose-Headers'] = "Content-Type, Cache-Control, Expires, Etag, Last-Modified, X-Request-ID" end - options // do + options '/' do # make sure to update nginx.conf.erb when you update this headers['Access-Control-Allow-Methods'] = "HEAD, GET, POST, PATCH, PUT, DELETE" headers['Access-Control-Allow-Headers'] = "Content-Type, Authorization, Accept, If-None-Match, If-Modified-Since, X-User-Agent, X-Client-Release, Travis-API-Version, Trace" diff --git a/lib/travis/api/app/endpoint/authorization.rb b/lib/travis/api/app/endpoint/authorization.rb index 7acfc35ebb..f1aea98b8a 100644 --- a/lib/travis/api/app/endpoint/authorization.rb +++ b/lib/travis/api/app/endpoint/authorization.rb @@ -124,7 +124,7 @@ class Authorization < Endpoint erb(:container, locals: data) end - error Faraday::Error::ClientError do + error Faraday::ClientError do halt 401, 'could not resolve github token' end @@ -133,7 +133,7 @@ class Authorization < Endpoint # update first login date if not set def update_first_login(user) unless user.first_logged_in_at - user.update_attributes(first_logged_in_at: Time.now) + user.update(first_logged_in_at: Time.now) end end @@ -318,7 +318,7 @@ def fetch if user ensure_token_is_available rename_repos_owner(user.login, info['login']) - user.update_attributes info + user.update info else self.user = ::User.create! info end diff --git a/lib/travis/api/app/endpoint/env_vars.rb b/lib/travis/api/app/endpoint/env_vars.rb index d779e39f7f..dbab2034dd 100644 --- a/lib/travis/api/app/endpoint/env_vars.rb +++ b/lib/travis/api/app/endpoint/env_vars.rb @@ -27,7 +27,6 @@ def update respond_with(record, type: :validation_error, version: :v2) end end - end end end diff --git a/lib/travis/api/app/endpoint/repos.rb b/lib/travis/api/app/endpoint/repos.rb index ab5ae7f33f..eb65ba7874 100644 --- a/lib/travis/api/app/endpoint/repos.rb +++ b/lib/travis/api/app/endpoint/repos.rb @@ -7,9 +7,7 @@ class RepoStatus < Endpoint halt 401 if private_mode? && !org? && !authenticated? end - set :pattern, capture: { id: /\d+/ } - - get '/:id/cc', scope: [:public, :travis_token] do + get Mustermann.new('/:id/cc', capture: { id: /\d+/ }), scope: [:public, :travis_token] do respond_with service(:find_repo, params.merge(schema: 'cc')), responder: :xml end @@ -33,8 +31,6 @@ class RepoStatus < Endpoint class Repos < Endpoint before { authenticate_by_mode! } - set :pattern, capture: { id: /\d+/ } - # Endpoint for getting all repositories. # # You can filter the repositories by adding parameters to the request. For example, you can get all repositories @@ -57,10 +53,10 @@ class Repos < Endpoint # ### Response # # json(:repository) - get '/:id' do - prefer_follower do - respond_with service(:find_repo, params) - end + get Mustermann.new('/:id', capture: { id: /\d+/ }) do + prefer_follower do + respond_with service(:find_repo, params) + end end # Retrieves repositories for a given owner. diff --git a/lib/travis/api/app/extensions/smart_constants.rb b/lib/travis/api/app/extensions/smart_constants.rb index e4991d2dc2..f4a9dd74f4 100644 --- a/lib/travis/api/app/extensions/smart_constants.rb +++ b/lib/travis/api/app/extensions/smart_constants.rb @@ -15,7 +15,7 @@ def helpers(*list, &block) end def register(*list, &block) - super(*resolve_constants(list, Extensions), &block) + super(*resolve_constants(list, Extensions), &block) end private diff --git a/lib/travis/api/app/responders/json.rb b/lib/travis/api/app/responders/json.rb index 2103419178..29014f83b8 100644 --- a/lib/travis/api/app/responders/json.rb +++ b/lib/travis/api/app/responders/json.rb @@ -33,8 +33,8 @@ def accepts_log? end def result + p ||= {} if builder - p = params p[:root] = options[:root] if options[:root] p[:root] = options[:type] if options[:type] && !p[:root] builder_instance = builder.new(resource, p) diff --git a/lib/travis/api/serialize/serializer.rb b/lib/travis/api/serialize/serializer.rb index 933d523c5a..0257239a5b 100644 --- a/lib/travis/api/serialize/serializer.rb +++ b/lib/travis/api/serialize/serializer.rb @@ -1,5 +1,4 @@ require 'active_model_serializers' - # This hideousness courtesy of http://stackoverflow.com/a/8339255 module ActiveSupport::JSON::Encoding def self.escape(string) diff --git a/lib/travis/api/serialize/v2/http/env_var.rb b/lib/travis/api/serialize/v2/http/env_var.rb index 25799ff9ac..101f399ef6 100644 --- a/lib/travis/api/serialize/v2/http/env_var.rb +++ b/lib/travis/api/serialize/v2/http/env_var.rb @@ -12,8 +12,8 @@ def value end end - def serializable_hash - hash = super + def serializable_hash(adapter_options) + hash = super(adapter_options) hash.delete :value unless object.public? hash end diff --git a/lib/travis/api/serialize/v2/http/validation_error.rb b/lib/travis/api/serialize/v2/http/validation_error.rb index 22b882a110..529ec82800 100644 --- a/lib/travis/api/serialize/v2/http/validation_error.rb +++ b/lib/travis/api/serialize/v2/http/validation_error.rb @@ -6,14 +6,19 @@ module Http class ValidationError attr_reader :resource - def initialize(resource, options = {}) + def initialize(resource, _options = {}) @resource = resource + current_class_name = resource.class.name + resource.class.define_singleton_method(:name) do + current_class_name || 'ValidationError' + end end def data response = { message: 'Validation failed' } + resource.errors.to_hash.each do |name, errors| response['errors'] ||= [] errors.each do |error_code| @@ -25,9 +30,11 @@ def data end def code(error_code) - case error_code - when :blank + case error_code.to_s + when /blank/ 'missing_field' + when /is not a number/ + 'not_a_number' else error_code.to_s end diff --git a/lib/travis/api/v3/billing_client.rb b/lib/travis/api/v3/billing_client.rb index def9b79a35..56de2738bd 100644 --- a/lib/travis/api/v3/billing_client.rb +++ b/lib/travis/api/v3/billing_client.rb @@ -126,7 +126,7 @@ def handle_errors_and_respond(response) def connection @connection ||= Faraday.new(url: billing_url, ssl: { ca_path: '/usr/lib/ssl/certs' }) do |conn| - conn.basic_auth '_', billing_auth_key + conn.request(:basic_auth, '_', billing_auth_key) conn.headers['X-Travis-User-Id'] = @user_id.to_s conn.headers['Content-Type'] = 'application/json' conn.request :json diff --git a/lib/travis/api/v3/extensions/belongs_to.rb b/lib/travis/api/v3/extensions/belongs_to.rb index b1921e570b..6c5543927c 100644 --- a/lib/travis/api/v3/extensions/belongs_to.rb +++ b/lib/travis/api/v3/extensions/belongs_to.rb @@ -41,7 +41,7 @@ def base_class end def polymorphic_name - @polymorfic_name ||= name.sub("#{parent}::", ''.freeze) + @polymorfic_name ||= name.sub("#{module_parent}::", ''.freeze) end end @@ -52,12 +52,12 @@ def self.included(base) def [](key) value = super - value &&= "#{self.class.parent}::#{value}" if self.class.polymorfic_foreign_types.include?(key) + value &&= "#{self.class.module_parent}::#{value}" if self.class.polymorfic_foreign_types.include?(key) value end def []=(key, value) - value &&= value.sub("#{self.class.parent}::", ''.freeze) if self.class.polymorfic_foreign_types.include?(key) + value &&= value.sub("#{self.class.module_parent}::", ''.freeze) if self.class.polymorfic_foreign_types.include?(key) super(key, value) end end diff --git a/lib/travis/api/v3/extensions/preferences.rb b/lib/travis/api/v3/extensions/preferences.rb index 7c317c9127..617523ebb1 100644 --- a/lib/travis/api/v3/extensions/preferences.rb +++ b/lib/travis/api/v3/extensions/preferences.rb @@ -1,3 +1,5 @@ +require 'active_support/all' + module Travis::API::V3 module Extensions module Preferences diff --git a/lib/travis/api/v3/gdpr_client.rb b/lib/travis/api/v3/gdpr_client.rb index ad727dff9f..c9e8f6ed6a 100644 --- a/lib/travis/api/v3/gdpr_client.rb +++ b/lib/travis/api/v3/gdpr_client.rb @@ -27,7 +27,7 @@ def handle_errors_and_respond(response) def connection @connection ||= Faraday.new(url: gdpr_url, ssl: { ca_path: '/usr/lib/ssl/certs' }) do |conn| - conn.token_auth gdpr_auth_token + conn.request(:token_auth, gdpr_auth_token) conn.headers['X-Travis-User-Id'] = @user_id.to_s conn.headers['X-Travis-Source'] = 'travis-api' conn.use OpenCensus::Trace::Integrations::FaradayMiddleware if Travis::Api::App::Middleware::OpenCensus.enabled? diff --git a/lib/travis/api/v3/model.rb b/lib/travis/api/v3/model.rb index fa42f05070..5d3fee8faf 100644 --- a/lib/travis/api/v3/model.rb +++ b/lib/travis/api/v3/model.rb @@ -6,7 +6,8 @@ class Model < ActiveRecord::Base self.abstract_class = true def self.===(other) - super or (self == Model and other.class.parent == Models) + super or (self == Model and other.class.module_parent == Models) end + end end diff --git a/lib/travis/api/v3/models/build.rb b/lib/travis/api/v3/models/build.rb index 5a83ed1f48..0db1a49cd6 100644 --- a/lib/travis/api/v3/models/build.rb +++ b/lib/travis/api/v3/models/build.rb @@ -13,7 +13,7 @@ class Models::Build < Model belongs_to :repository, autosave: true belongs_to :owner, polymorphic: true belongs_to :sender, polymorphic: true - belongs_to :config, foreign_key: :config_id, class_name: Models::BuildConfig + belongs_to :config, foreign_key: :config_id, class_name: 'Models::BuildConfig' has_many :stages diff --git a/lib/travis/api/v3/models/cron.rb b/lib/travis/api/v3/models/cron.rb index 2552cccada..3b5163cc3d 100644 --- a/lib/travis/api/v3/models/cron.rb +++ b/lib/travis/api/v3/models/cron.rb @@ -82,7 +82,7 @@ def last_non_cron_build_time end def deactivate - update_attributes!(active: false) + update!(active: false) end def deactivate_and_log_reason(reason) diff --git a/lib/travis/api/v3/models/fingerprint.rb b/lib/travis/api/v3/models/fingerprint.rb index 2879439a9e..de6ab66515 100644 --- a/lib/travis/api/v3/models/fingerprint.rb +++ b/lib/travis/api/v3/models/fingerprint.rb @@ -13,6 +13,8 @@ def calculate(source) rsa_key = OpenSSL::PKey::RSA.new(source) public_ssh_rsa = "\x00\x00\x00\x07ssh-rsa" + rsa_key.e.to_s(0) + rsa_key.n.to_s(0) OpenSSL::Digest::MD5.new(public_ssh_rsa).hexdigest.scan(/../).join(':') + rescue OpenSSL::PKey::RSAError + nil end module_function :calculate diff --git a/lib/travis/api/v3/models/job.rb b/lib/travis/api/v3/models/job.rb index ba016e8990..26b96676fb 100644 --- a/lib/travis/api/v3/models/job.rb +++ b/lib/travis/api/v3/models/job.rb @@ -13,7 +13,7 @@ class Models::Job < Model belongs_to :build, autosave: true, foreign_key: 'source_id' belongs_to :stage belongs_to :owner, polymorphic: true - belongs_to :config, foreign_key: :config_id, class_name: Models::JobConfig + belongs_to :config, foreign_key: :config_id, class_name: 'Models::JobConfig' serialize :config serialize :debug_options diff --git a/lib/travis/api/v3/models/json_sync.rb b/lib/travis/api/v3/models/json_sync.rb index 1a160f153f..e913f45237 100644 --- a/lib/travis/api/v3/models/json_sync.rb +++ b/lib/travis/api/v3/models/json_sync.rb @@ -6,7 +6,7 @@ def sync(parent, attr) @parent, @attr = parent, attr @sync = -> do previous = @parent[@attr] || {} - @parent[@attr] = previous.merge(to_h).to_json + @parent[@attr] = previous.merge(to_h) @parent.save! end end diff --git a/lib/travis/api/v3/models/key_pair.rb b/lib/travis/api/v3/models/key_pair.rb index 316ed672aa..be957a31d1 100644 --- a/lib/travis/api/v3/models/key_pair.rb +++ b/lib/travis/api/v3/models/key_pair.rb @@ -18,6 +18,8 @@ def fingerprint_source def public_key return unless value.decrypt OpenSSL::PKey::RSA.new(value.decrypt).public_key.to_s + rescue OpenSSL::PKey::RSAError + nil end def to_h diff --git a/lib/travis/api/v3/models/message.rb b/lib/travis/api/v3/models/message.rb index 3fc6439668..060a07214e 100644 --- a/lib/travis/api/v3/models/message.rb +++ b/lib/travis/api/v3/models/message.rb @@ -5,7 +5,7 @@ class Models::Message < Model belongs_to :subject, polymorphic: true scope :ordered, -> do - order(%Q{ + order(Arel.sql(%Q{ CASE WHEN level = 'alert' THEN '0' WHEN level = 'error' THEN '1' @@ -13,7 +13,7 @@ class Models::Message < Model WHEN level = 'info' THEN '3' WHEN level IS NULL THEN '4' END - }.strip) + }.strip)) end end end diff --git a/lib/travis/api/v3/models/organization.rb b/lib/travis/api/v3/models/organization.rb index f1530db96a..3ca8e22f36 100644 --- a/lib/travis/api/v3/models/organization.rb +++ b/lib/travis/api/v3/models/organization.rb @@ -8,6 +8,14 @@ class Models::Organization < Model has_preferences Models::OrganizationPreferences + after_initialize do + ensure_preferences + end + + before_save do + ensure_preferences + end + def repositories Models::Repository.where(owner_type: 'Organization', owner_id: id) end @@ -29,6 +37,11 @@ def build_priorities_enabled? Travis::Features.owner_active?(:build_priorities_org, self) end + def ensure_preferences + return if attributes['preferences'].nil? + self.preferences = self['preferences'].is_a?(String) ? JSON.parse(self['preferences']) : self['preferences'] + end + alias members users end end diff --git a/lib/travis/api/v3/models/repository.rb b/lib/travis/api/v3/models/repository.rb index 6b1ece977c..df15abc7a1 100644 --- a/lib/travis/api/v3/models/repository.rb +++ b/lib/travis/api/v3/models/repository.rb @@ -24,7 +24,12 @@ class Models::Repository < Model alias last_started_build current_build after_initialize do - update_attributes! default_branch_name: 'master'.freeze unless default_branch_name + ensure_settings + update! default_branch_name: 'master'.freeze unless default_branch_name + end + + before_save do + ensure_settings end def migrating? @@ -87,7 +92,7 @@ def find_or_create_branch(name:, create_without_build: false) new_branch = true end - branch = branches.where(name: name).first + branch = branches.includes(:builds).where(name: name).first return branch unless new_branch return nil unless create_without_build or branch.builds.any? branch.last_build = branch.builds.order("number::int desc").first @@ -96,7 +101,7 @@ def find_or_create_branch(name:, create_without_build: false) end def legacy_find_or_create_branch(name, create_without_build: false) - return nil unless branch = branches.where(name: name).first_or_initialize + return nil unless branch = branches.includes(:builds).where(name: name).first_or_initialize return branch unless branch.new_record? return nil unless create_without_build or branch.builds.any? branch.last_build = branch.builds.order("number::int desc").first @@ -198,5 +203,10 @@ def admin def allow_migration? Travis::Features.owner_active?(:allow_migration, self.owner) end + + def ensure_settings + return if attributes['settings'].nil? + self.settings = self['settings'].is_a?(String) ? JSON.parse(self['settings']) : self['settings'] + end end end diff --git a/lib/travis/api/v3/models/request.rb b/lib/travis/api/v3/models/request.rb index 8e80115a8e..16badaaafd 100644 --- a/lib/travis/api/v3/models/request.rb +++ b/lib/travis/api/v3/models/request.rb @@ -36,7 +36,7 @@ class RequestRawConfig < Model class RequestRawConfiguration < Model belongs_to :request - belongs_to :raw_config, foreign_key: :request_raw_config_id, class_name: RequestRawConfig + belongs_to :raw_config, foreign_key: :request_raw_config_id, class_name: 'RequestRawConfig' end class Request < Model @@ -48,10 +48,10 @@ def self.columns belongs_to :pull_request belongs_to :repository belongs_to :owner, polymorphic: true - belongs_to :config, foreign_key: :config_id, class_name: RequestConfig - belongs_to :yaml_config, foreign_key: :yaml_config_id, class_name: RequestYamlConfig - has_many :raw_configurations, -> { order 'request_raw_configurations.id' }, class_name: RequestRawConfiguration - has_many :raw_configs, through: :raw_configurations, class_name: RequestRawConfig + belongs_to :config, foreign_key: :config_id, class_name: 'RequestConfig' + belongs_to :yaml_config, foreign_key: :yaml_config_id, class_name: 'RequestYamlConfig' + has_many :raw_configurations, -> { order 'request_raw_configurations.id' }, class_name: 'RequestRawConfiguration' + has_many :raw_configs, through: :raw_configurations, class_name: 'RequestRawConfig' has_many :builds serialize :config serialize :payload diff --git a/lib/travis/api/v3/models/user.rb b/lib/travis/api/v3/models/user.rb index dcc936b13c..116a64e689 100644 --- a/lib/travis/api/v3/models/user.rb +++ b/lib/travis/api/v3/models/user.rb @@ -15,6 +15,14 @@ class Models::User < Model has_preferences Models::UserPreferences + after_initialize do + ensure_preferences + end + + before_save do + ensure_preferences + end + serialize :github_oauth_token, Travis::Model::EncryptedColumn.new scope :with_github_token, -> { where('github_oauth_token IS NOT NULL')} @@ -82,5 +90,10 @@ def installation def github? vcs_type == 'GithubUser' end + + def ensure_preferences + return if attributes['preferences'].nil? + self.preferences = self['preferences'].is_a?(String) ? JSON.parse(self['preferences']) : self['preferences'] + end end end diff --git a/lib/travis/api/v3/models/user_settings.rb b/lib/travis/api/v3/models/user_settings.rb index 8485f94a18..3f6d77b241 100644 --- a/lib/travis/api/v3/models/user_settings.rb +++ b/lib/travis/api/v3/models/user_settings.rb @@ -1,3 +1,5 @@ +require 'json' + module Travis::API::V3 class Models::UserSettings < Models::JsonSlice child Models::UserSetting diff --git a/lib/travis/api/v3/proxy_service.rb b/lib/travis/api/v3/proxy_service.rb index e33364d9e6..c57fb34423 100644 --- a/lib/travis/api/v3/proxy_service.rb +++ b/lib/travis/api/v3/proxy_service.rb @@ -30,7 +30,7 @@ def proxy! class ProxyClient def initialize(endpoint, auth_token) @connection = Faraday::Connection.new(URI(endpoint)) do |conn| - conn.token_auth auth_token + conn.request(:token_auth, auth_token) conn.response :json, content_type: 'application/json' conn.use OpenCensus::Trace::Integrations::FaradayMiddleware if Travis::Api::App::Middleware::OpenCensus.enabled? conn.adapter Faraday.default_adapter diff --git a/lib/travis/api/v3/queries/builds.rb b/lib/travis/api/v3/queries/builds.rb index f776ccb830..98fac498e5 100644 --- a/lib/travis/api/v3/queries/builds.rb +++ b/lib/travis/api/v3/queries/builds.rb @@ -4,7 +4,7 @@ class Queries::Builds < Query params :name, prefix: :branch, method_name: :branch_name sortable_by :id, :created_at, :started_at, :finished_at, - number: "number::int %{order}" + number: "number::int %{order}" default_sort "number:desc,id:desc" def find(repository) diff --git a/lib/travis/api/v3/queries/env_vars.rb b/lib/travis/api/v3/queries/env_vars.rb index dc9da39c56..35c0fe0720 100644 --- a/lib/travis/api/v3/queries/env_vars.rb +++ b/lib/travis/api/v3/queries/env_vars.rb @@ -8,6 +8,7 @@ def find(repository) def create(repository) env_var = repository.env_vars.create(env_var_params) + unless env_var.valid? repository.env_vars.destroy(env_var.id) handle_errors(env_var) @@ -19,12 +20,14 @@ def create(repository) private def handle_errors(env_var) - base = env_var.errors[:base] - name = env_var.errors[:name] - raise WrongParams if base.include?(:format) - raise DuplicateResource if base.include?(:duplicate_resource) - raise UnprocessableEntity, 'Variable name is required' if name.include?(:blank) + raise WrongParams if errors_(env_var, 'format') + raise DuplicateResource if errors_(env_var, 'duplicate_resource') + raise UnprocessableEntity, 'Variable name is required' if errors_(env_var, 'blank') raise ServerError end + + def errors_(env_var, what) + env_var.errors.errors.any? { |e| e.type.to_s == what} + end end end diff --git a/lib/travis/api/v3/queries/key_pair.rb b/lib/travis/api/v3/queries/key_pair.rb index 6db9c1d5ce..0d5cf9d366 100644 --- a/lib/travis/api/v3/queries/key_pair.rb +++ b/lib/travis/api/v3/queries/key_pair.rb @@ -27,8 +27,16 @@ def delete(repository) def handle_errors(key_pair) value = key_pair.errors[:value] - raise UnprocessableEntity if value.include?(:invalid_pem) - raise WrongParams if value.include?(:missing_attr) + if value.is_a?(Array) + return value.each { |v| check_error(v) } + end + check_error(value) + end + + def check_error(value) + value = value.to_s + raise UnprocessableEntity if value[/invalid_pem/] + raise WrongParams if value[/missing_attr/] end end end diff --git a/lib/travis/api/v3/queries/lint.rb b/lib/travis/api/v3/queries/lint.rb index 845a124b6f..ef15d1eb1d 100644 --- a/lib/travis/api/v3/queries/lint.rb +++ b/lib/travis/api/v3/queries/lint.rb @@ -38,7 +38,7 @@ def post(content) def client @client ||= Faraday.new(config[:url], ssl: ssl) do |client| - client.basic_auth 'admin', config[:auth_key] + client.request(:basic_auth, 'admin', config[:auth_key]) client.headers['Accept'] = 'application/json' client.adapter :net_http end diff --git a/lib/travis/api/v3/queries/repositories.rb b/lib/travis/api/v3/queries/repositories.rb index 398f7b453e..908d348668 100644 --- a/lib/travis/api/v3/queries/repositories.rb +++ b/lib/travis/api/v3/queries/repositories.rb @@ -55,22 +55,22 @@ def filter(list, user: nil) query = name_filter.strip.downcase sql_phrase = query.empty? ? '%' : "%#{query.split('').join('%')}%" - query = ActiveRecord::Base.sanitize(query) + query = ActiveRecord::Base.sanitize_sql(query) list = list.where(["(lower(repositories.name)) LIKE ?", sql_phrase]) - list = list.select("repositories.*, similarity(lower(repositories.name), #{query}) as name_filter") + list = list.select("repositories.*, similarity(lower(repositories.name), '#{query}') as name_filter") end if slug_filter query = slug_filter.strip.downcase sql_phrase = query.empty? ? '%' : "%#{query.split('').join('%')}%" - query = ActiveRecord::Base.sanitize(query) + query = ActiveRecord::Base.sanitize_sql(query) list = list.where(["(lower(repositories.owner_name) || '/' || lower(repositories.name)) LIKE ?", sql_phrase]) list = list.select("repositories.*, similarity(lower(repositories.owner_name) || '/' - || lower(repositories.name), #{query}) as slug_filter") + || lower(repositories.name), '#{query}') as slug_filter") end list = list.includes(default_branch: :last_build) list = list.includes(current_build: [:repository, :branch, :commit, :stages]) if includes? 'repository.current_build'.freeze diff --git a/lib/travis/api/v3/queries/repository.rb b/lib/travis/api/v3/queries/repository.rb index 6bb931391f..a871685ed0 100644 --- a/lib/travis/api/v3/queries/repository.rb +++ b/lib/travis/api/v3/queries/repository.rb @@ -29,7 +29,7 @@ def sync(current_user) def update(attrs) repository = find - repository.update_attributes!(attrs) + repository.update!(attrs) repository end diff --git a/lib/travis/api/v3/query.rb b/lib/travis/api/v3/query.rb index 6ada02d663..fa87a6b279 100644 --- a/lib/travis/api/v3/query.rb +++ b/lib/travis/api/v3/query.rb @@ -205,7 +205,7 @@ def sort_by(collection, field, order: nil, first: false, sql: nil, **) collection = collection.joins(field.to_sym) end - first ? collection.reorder(line) : collection.order(line) + first ? collection.reorder(Arel.sql(line)) : collection.order(Arel.sql(line)) end def sort_join?(collection, field) diff --git a/lib/travis/api/v3/renderer/request.rb b/lib/travis/api/v3/renderer/request.rb index 6b6faf651b..e8b29176f5 100644 --- a/lib/travis/api/v3/renderer/request.rb +++ b/lib/travis/api/v3/renderer/request.rb @@ -8,7 +8,8 @@ def self.available_attributes end def config - model.config.reject { |key, _| key == :'.result' } + config_ = model.config.is_a?(String) ? JSON.parse(model.config) : model.config + config_.deep_symbolize_keys.reject { |key, _| key == :'.result' } end def yaml_config diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb index aeb18acc3b..16c48cc83b 100644 --- a/lib/travis/api/v3/routes.rb +++ b/lib/travis/api/v3/routes.rb @@ -344,10 +344,5 @@ module Routes route '/queues/{queue.name}' get :stats, '/stats' end - - hidden_resource :leads do - route '/leads' - post :create - end end end diff --git a/lib/travis/api/v3/service.rb b/lib/travis/api/v3/service.rb index 28b0eb56a5..9cd9057e77 100644 --- a/lib/travis/api/v3/service.rb +++ b/lib/travis/api/v3/service.rb @@ -7,7 +7,7 @@ class Service def self.result_type(rt = nil) @result_type = rt if rt - @result_type ||= parent.result_type if parent and parent.respond_to? :result_type + @result_type ||= module_parent.result_type if module_parent and module_parent.respond_to? :result_type raise 'result type not set' unless defined? @result_type @result_type end diff --git a/lib/travis/api/v3/services/leads/create.rb b/lib/travis/api/v3/services/leads/create.rb deleted file mode 100644 index c6ee4dd985..0000000000 --- a/lib/travis/api/v3/services/leads/create.rb +++ /dev/null @@ -1,66 +0,0 @@ -require 'uri' -require 'closeio' - -module Travis::API::V3 - class Services::Leads::Create < Service - result_type :leads - params :name, :email, :team_size, :phone, :message, :referral_source, :utm_fields - - def run! - # Get params - name, email, team_size, phone, message, referral_source, utm_fields = params.values_at('name', 'email', 'team_size', 'phone', 'message', 'referral_source', 'utm_fields') - team_size = team_size.to_i unless team_size.nil? - name = name.strip unless name.nil? - message = message.strip unless message.nil? - - # Validation - raise WrongParams, 'missing name' unless name && name.length > 0 - raise WrongParams, 'invalid email' unless email && email.length > 0 && email.match(URI::MailTo::EMAIL_REGEXP).present? - raise WrongParams, 'missing message' unless message && message.length > 0 - raise WrongParams, 'invalid team size' if team_size && team_size <= 0 - - # Prep data for request - api_client = Closeio::Client.new(Travis.config.closeio.key, ENV['RACK_ENV'] != 'test') - custom_fields = api_client.list_custom_fields - team_size_field = fetch_custom_field(custom_fields, 'team_size') - referral_source_field = fetch_custom_field(custom_fields, 'referral_source') - - phones = [] - phones.push({ type: "office", phone: phone }) unless phone.nil? - - lead_data = { - name: name, - contacts: [{ - name: name, - emails: [{ type: "office", email: email }], - phones: phones - }], - } - - lead_data["custom.#{team_size_field['id']}"] = team_size if team_size_field && team_size - lead_data["custom.#{referral_source_field['id']}"] = referral_source || 'Travis API' if referral_source_field - - # Handle UTM fields - supported_utm_fields = ['utm_source', 'utm_campaign', 'utm_medium', 'utm_term', 'utm_content'] - supported_utm_fields.each do |field_name| - field = fetch_custom_field(custom_fields, field_name) - field_data = utm_fields[field_name] if utm_fields - lead_data["custom.#{field['id']}"] = field_data if field && field_data - end - - # Send request - lead = api_client.create_lead(lead_data) - note = api_client.create_note({ lead_id: lead['id'], note: message }) - - # Return result - model = Travis::API::V3::Models::Leads.new(lead) - result model - end - - private - - def fetch_custom_field(custom_fields, field_name) - custom_fields['data'].find { |field| field['name'] == field_name } - end - end -end \ No newline at end of file diff --git a/lib/travis/api/v3/services/repository/activate.rb b/lib/travis/api/v3/services/repository/activate.rb index 2263d58de2..616174920e 100644 --- a/lib/travis/api/v3/services/repository/activate.rb +++ b/lib/travis/api/v3/services/repository/activate.rb @@ -17,7 +17,7 @@ def run! else github(admin).set_hook(repository, true) end - repository.update_attributes(active: true) + repository.update(active: true) if repository.private? || access_control.enterprise? if Travis::Features.deactivate_owner(:use_vcs, admin) || !admin.github? diff --git a/lib/travis/api/v3/services/repository/deactivate.rb b/lib/travis/api/v3/services/repository/deactivate.rb index 86d3b24368..6a366d67d4 100644 --- a/lib/travis/api/v3/services/repository/deactivate.rb +++ b/lib/travis/api/v3/services/repository/deactivate.rb @@ -16,7 +16,7 @@ def run!(activate = false) else github(admin).set_hook(repository, activate) end - repository.update_attributes(active: activate) + repository.update(active: activate) result repository end diff --git a/lib/travis/config/defaults.rb b/lib/travis/config/defaults.rb index 70c16c8f84..381fcb11d0 100644 --- a/lib/travis/config/defaults.rb +++ b/lib/travis/config/defaults.rb @@ -42,7 +42,6 @@ def fallback_logs_api_auth_token assets: { host: HOSTS[Travis.env.to_sym] }, amqp: { username: 'guest', password: 'guest', host: 'localhost', prefetch: 1 }, billing: {}, - closeio: { key: 'key' }, gdpr: {}, insights: { endpoint: 'https://insights.travis-ci.dev/', auth_token: 'secret' }, database: { adapter: 'postgresql', database: "travis_#{Travis.env}", encoding: 'unicode', min_messages: 'warning', variables: { statement_timeout: 45_000 } }, diff --git a/lib/travis/event/handler/metrics.rb b/lib/travis/event/handler/metrics.rb index 2cbce9f9af..9a6212aa1b 100644 --- a/lib/travis/event/handler/metrics.rb +++ b/lib/travis/event/handler/metrics.rb @@ -1,4 +1,5 @@ require 'travis/support/metrics' +require 'travis/support' module Travis module Event diff --git a/lib/travis/model/build.rb b/lib/travis/model/build.rb index ba21121028..e5773c13fa 100644 --- a/lib/travis/model/build.rb +++ b/lib/travis/model/build.rb @@ -24,7 +24,7 @@ class Build < Travis::Model belongs_to :pull_request belongs_to :repository, autosave: true belongs_to :owner, polymorphic: true - belongs_to :config, foreign_key: :config_id, class_name: BuildConfig + belongs_to :config, foreign_key: :config_id, class_name: 'BuildConfig' has_many :matrix, -> { order('id') }, as: :source, class_name: 'Job::Test', dependent: :destroy has_many :events, as: :source @@ -148,15 +148,6 @@ def state (super || :created).to_sym end - # AR 3.2 does not handle pg arrays and the plugins supporting them - # do not work well with jdbc drivers - # TODO: remove this once we're on >= 4.0 - def cached_matrix_ids - if (value = super) && value =~ /^{/ - value.gsub(/^{|}$/, '').split(',').map(&:to_i) - end - end - def matrix_ids matrix.map(&:id) end diff --git a/lib/travis/model/build/denormalize.rb b/lib/travis/model/build/denormalize.rb index d01a51275f..6d55ba5245 100644 --- a/lib/travis/model/build/denormalize.rb +++ b/lib/travis/model/build/denormalize.rb @@ -11,7 +11,7 @@ class Build # These attributes are used in the repositories list and thus read frequently. module Denormalize def denormalize(event, *args) - repository.update_attributes!(denormalize_attributes_for(event)) if denormalize?(event) + repository.update!(denormalize_attributes_for(event)) if denormalize?(event) end DENORMALIZE = { diff --git a/lib/travis/model/build/update_branch.rb b/lib/travis/model/build/update_branch.rb index 9ed8e936d9..df78b1fcbf 100644 --- a/lib/travis/model/build/update_branch.rb +++ b/lib/travis/model/build/update_branch.rb @@ -7,7 +7,7 @@ class UpdateBranch < Struct.new(:build) def update_last_build logger.info MSGS[:update] % [build.id, branch_name, repository.slug] - branch.update_attributes!(last_build_id: build.id) + branch.update!(last_build_id: build.id) validate_branch_last_build_id # TODO double check and remove after a few days end diff --git a/lib/travis/model/job.rb b/lib/travis/model/job.rb index d520cd459c..d784de08da 100644 --- a/lib/travis/model/job.rb +++ b/lib/travis/model/job.rb @@ -65,7 +65,7 @@ def owned_by(owner) belongs_to :commit belongs_to :source, polymorphic: true, autosave: true belongs_to :owner, polymorphic: true - belongs_to :config, foreign_key: :config_id, class_name: JobConfig + belongs_to :config, foreign_key: :config_id, class_name: 'JobConfig' validates :repository_id, :commit_id, :source_id, :source_type, :owner_id, :owner_type, presence: true diff --git a/lib/travis/model/job/test.rb b/lib/travis/model/job/test.rb index e85ffd849c..8849a698d8 100644 --- a/lib/travis/model/job/test.rb +++ b/lib/travis/model/job/test.rb @@ -28,7 +28,7 @@ class Test < Job event :all, after: [:propagate] def enqueue # TODO rename to queue and make it an event, simple_states should support that now - update_attributes!(state: :queued, queued_at: Time.now.utc) + update!(state: :queued, queued_at: Time.now.utc) end def receive(data = {}) diff --git a/lib/travis/model/organization.rb b/lib/travis/model/organization.rb index dc3f12ffd5..dda84cefcf 100644 --- a/lib/travis/model/organization.rb +++ b/lib/travis/model/organization.rb @@ -6,6 +6,14 @@ class Organization < Travis::Model has_many :users, :through => :memberships has_many :repositories, :as => :owner + after_initialize do + ensure_preferences + end + + before_save do + ensure_preferences + end + def education? Travis::Features.owner_active?(:educational_org, self) end @@ -20,5 +28,10 @@ def subscription records = Subscription.where(owner_id: id, owner_type: "Organization") @subscription = records.where(status: 'subscribed').last || records.last end + + def ensure_preferences + return if attributes['preferences'].nil? + self.preferences = self['preferences'].is_a?(String) ? JSON.parse(self['preferences']) : self['preferences'] + end end diff --git a/lib/travis/model/repository.rb b/lib/travis/model/repository.rb index b8ddc7fb12..321c3d32f2 100644 --- a/lib/travis/model/repository.rb +++ b/lib/travis/model/repository.rb @@ -30,6 +30,14 @@ class Repository < Travis::Model validates :name, presence: true validates :owner_name, presence: true + after_initialize do + ensure_settings + end + + before_save do + ensure_settings + end + # before_create do # build_key # end @@ -37,7 +45,7 @@ class Repository < Travis::Model delegate :public_key, to: :key scope :by_params, ->(params) { - if id = params[:repository_id] || params[:id] + if (id = params[:repository_id] || params[:id]) where(id: id) elsif params[:github_id] where('vcs_id = :id OR github_id = :id_i', id: params[:github_id].to_s, id_i: params[:github_id].to_i) @@ -54,7 +62,8 @@ class Repository < Travis::Model end } scope :timeline, -> { - active.order('last_build_finished_at IS NULL AND last_build_started_at IS NOT NULL DESC, last_build_started_at DESC NULLS LAST, id DESC') + s = 'last_build_finished_at IS NULL AND last_build_started_at IS NOT NULL DESC, last_build_started_at DESC NULLS LAST, id DESC' + active.order(Arel.sql(s)) } scope :with_builds, -> { where(arel_table[:last_build_id].not_eq(nil)) @@ -193,11 +202,8 @@ def settings end def settings=(value) - if value.is_a?(String) || value.nil? - super(value) - else - super(value.to_json) - end + value = value.is_a?(String) ? JSON.parse(value) : value + super(value) end def users_with_permission(permission) @@ -228,4 +234,9 @@ def migrated? def github? vcs_type == 'GithubRepository' end + + def ensure_settings + return if attributes['settings'].nil? + self.settings = self['settings'].is_a?(String) ? JSON.parse(self['settings']) : self['settings'] + end end diff --git a/lib/travis/model/request.rb b/lib/travis/model/request.rb index 68e5d68055..cdb0df786a 100644 --- a/lib/travis/model/request.rb +++ b/lib/travis/model/request.rb @@ -44,7 +44,7 @@ def with_build_id belongs_to :pull_request belongs_to :repository belongs_to :owner, polymorphic: true - belongs_to :config, foreign_key: :config_id, class_name: RequestConfig + belongs_to :config, foreign_key: :config_id, class_name: 'RequestConfig' has_many :builds has_many :events, as: :source diff --git a/lib/travis/model/user.rb b/lib/travis/model/user.rb index a4363e389c..3ce965d903 100644 --- a/lib/travis/model/user.rb +++ b/lib/travis/model/user.rb @@ -21,6 +21,10 @@ class User < Travis::Model serialize :github_oauth_token, Travis::Model::EncryptedColumn.new + before_save do + ensure_preferences + end + class << self def with_permissions(permissions) where(:permissions => permissions).includes(:permissions) @@ -170,6 +174,11 @@ def github? vcs_type == 'GithubUser' end + def ensure_preferences + return if attributes['preferences'].nil? + self.preferences = self['preferences'].is_a?(String) ? JSON.parse(self['preferences']) : self['preferences'] + end + protected def track_previous_changes diff --git a/lib/travis/model/user/oauth.rb b/lib/travis/model/user/oauth.rb index d8a9e5ab82..f1ef703649 100644 --- a/lib/travis/model/user/oauth.rb +++ b/lib/travis/model/user/oauth.rb @@ -4,7 +4,7 @@ class << self def find_or_create_by(payload) attrs = attributes_from(payload) user = User.find_by_github_id(attrs['github_id']) - user ? user.update_attributes(attrs) : user = User.create!(attrs) + user ? user.update(attrs) : user = User.create!(attrs) user end diff --git a/lib/travis/services/find_admin.rb b/lib/travis/services/find_admin.rb index ea4eac4f77..f6695d1812 100644 --- a/lib/travis/services/find_admin.rb +++ b/lib/travis/services/find_admin.rb @@ -56,7 +56,7 @@ def handle_error(user, error) case status when 401 error "[github-admin] token for #{user.login} no longer valid" - user.update_attributes!(:github_oauth_token => "") + user.update!(:github_oauth_token => "") when 404 info "[github-admin] #{user.login} no longer has any access to #{repository.slug}" update(user, {}) @@ -73,7 +73,7 @@ def repository_data end def update(user, permissions) - user.update_attributes!(:permissions => permissions) + user.update!(:permissions => permissions) end def raise_admin_missing diff --git a/lib/travis/services/find_caches.rb b/lib/travis/services/find_caches.rb index 9f37b1284a..e38adcf921 100644 --- a/lib/travis/services/find_caches.rb +++ b/lib/travis/services/find_caches.rb @@ -1,4 +1,3 @@ -require 's3' require 'travis/services/base' require 'google/apis/storage_v1' @@ -142,12 +141,18 @@ def caches(options = {}) end def fetch_s3(cache_objects, options) - config = cache_options[:s3] - svc = ::S3::Service.new(config.to_h.slice(:secret_access_key, :access_key_id)) - bucket = svc.buckets.find(config.to_h[:bucket_name]) + config = cache_options[:s3].to_h + + svc = Fog::Storage.new( + aws_access_key_id: config[:access_key_id], + aws_secret_access_key: config[:secret_access_key], + provider: 'AWS', + instrumentor: ActiveSupport::Notifications, + connection_options: { instrumentor: ActiveSupport::Notifications }) + bucket = svc.directories.get(config[:bucket_name], options) if bucket - bucket.objects(options).each { |object| cache_objects << S3Wrapper.new(repo, object) } + bucket.files.each { |object| cache_objects << S3Wrapper.new(repo, object) } end end diff --git a/lib/travis/services/update_user.rb b/lib/travis/services/update_user.rb index c0a12ac5b0..f589ba262f 100644 --- a/lib/travis/services/update_user.rb +++ b/lib/travis/services/update_user.rb @@ -10,7 +10,7 @@ class UpdateUser < Base attr_reader :result def run - @result = current_user.update_attributes!(attributes) if valid_locale? + @result = current_user.update!(attributes) if valid_locale? true end diff --git a/lib/travis/testing/factories.rb b/lib/travis/testing/factories.rb index b4da9712fc..56965f09cd 100644 --- a/lib/travis/testing/factories.rb +++ b/lib/travis/testing/factories.rb @@ -68,6 +68,9 @@ end end + factory :v3_repository, class: Travis::API::V3::Models::Repository do + end + factory :minimal, :parent => :repository_without_last_build do end diff --git a/lib/travis/testing/scenario.rb b/lib/travis/testing/scenario.rb index cee054127b..14da13b404 100644 --- a/lib/travis/testing/scenario.rb +++ b/lib/travis/testing/scenario.rb @@ -133,13 +133,13 @@ def build(attributes) build = FactoryBot.create(:build, attributes.merge(:commit => commit)) build.matrix.each_with_index do |job, ix| - job.update_attributes!(jobs[ix] || {}) + job.update!(jobs[ix] || {}) end if build.finished? keys = %w(id number state finished_at started_at) attributes = keys.inject({}) { |result, key| result.merge(:"last_build_#{key}" => build.send(key)) } - build.repository.update_attributes!(attributes) + build.repository.update!(attributes) end end end diff --git a/spec/auth/helpers.rb b/spec/auth/helpers.rb index b7709c2b83..5dd3426668 100644 --- a/spec/auth/helpers.rb +++ b/spec/auth/helpers.rb @@ -1,5 +1,6 @@ require 'auth/helpers/faraday' require 'auth/helpers/rack_test' +require 'active_support/all' RSpec.shared_context 'cache setup' do include Support::S3 diff --git a/spec/auth/v1/builds_spec.rb b/spec/auth/v1/builds_spec.rb index 62d44e558d..c0654f1308 100644 --- a/spec/auth/v1/builds_spec.rb +++ b/spec/auth/v1/builds_spec.rb @@ -12,7 +12,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -50,7 +50,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -88,7 +88,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -136,7 +136,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -174,7 +174,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: false } it(:invalid_token) { should auth status: 403 } diff --git a/spec/auth/v2.1/builds_spec.rb b/spec/auth/v2.1/builds_spec.rb index 3830d2eee9..aa4db6542f 100644 --- a/spec/auth/v2.1/builds_spec.rb +++ b/spec/auth/v2.1/builds_spec.rb @@ -16,7 +16,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -54,7 +54,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -92,7 +92,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -136,7 +136,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -174,7 +174,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: false } it(:invalid_token) { should auth status: 403 } diff --git a/spec/auth/v2/builds_spec.rb b/spec/auth/v2/builds_spec.rb index 6232fb8e2f..f86c431ed0 100644 --- a/spec/auth/v2/builds_spec.rb +++ b/spec/auth/v2/builds_spec.rb @@ -16,7 +16,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -54,7 +54,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -92,7 +92,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -136,7 +136,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: true } it(:invalid_token) { should auth status: 403 } @@ -174,7 +174,7 @@ end describe 'GET /builds?running=true' do - before { build.update_attributes(state: :started) } + before { build.update(state: :started) } it(:with_permission) { should auth status: 200, type: :json, empty: false } it(:without_permission) { should auth status: 200, type: :json, empty: false } it(:invalid_token) { should auth status: 403 } diff --git a/spec/integration/error_handling_spec.rb b/spec/integration/error_handling_spec.rb index 62591bb545..8f41189735 100644 --- a/spec/integration/error_handling_spec.rb +++ b/spec/integration/error_handling_spec.rb @@ -46,11 +46,28 @@ class TestError < StandardError end end + before do + stub_request(:post, "https://app.getsentry.com/api/12345/store/"). + with( + body: "eJztfYt72zay778Cy/er5a1ES/Iz2s06OY3b5OvmcW13Hzf2x6VISGJNkSoftlXb52+/MwBIgdSDdCrHjjs+Z1MRxHPmh5nBYADe1Lh/6YaBP+J+XOvWYh7FtUaNX8Kj6TqQcrDXtvZeWPsvdq3WzsH2Qc/mB539XYv3d1/0246Nua/j0Kp1b2oRDy95iL+CCP/1rRGHKt5Y4ZXrQ0Z4GbmBnyWxn3noc4/9U6azTtvoGK0uO0l89iG4ZJ0D1ml1Owfd3R326eQUHjrtv7IwCOLutZ80D1rtF8Ze29j93/bW8dE/jl6fHJn/Ptgz93agrV7ieth/WSckXIi2zJk+/NDq/LTb+s/b92/2jlUP2AN3j13LXt41amHixy5SKaNWmPQmOVphAusY+8buuNPaZnVsptluNzs7LOSXruhaH1jEewfb7Z1N9lnW3nTEIDrt89rdHbTkAVM9qI6HYRBCA14wGCCz0gZHgZN4XPAttC6wJ+1to2XswSs78O0kDAETTZEZXhlt4wW8cdsHvnxsCSKPXN8VGOrWdo32rkiLf3f9foCsgOqQNb9zN77i4YVI2hVJlh27lzxKxuMgxMJ7UP+OaFu+gc6JzhfTTfHCBOC5luf+DjSDTC3jhXGQZQm5HYROruw46XmubUZJv+9ew5sdNU7LcUIeRVbP46JvB6L/1mAQ8oEVc1F1x9jGNM8LbCsG0puAfVvQEeqQ70a/NcdhEAd24Ilqto0OJsfByLUV7dqtNiZdelCcc5WIheNhyC3HjKy+bG5bdMzhkc19x/LjSLR3oRqU9HRtbvquLwu027K1azcYNePJmEuKQP3ppBBloU+GnCa+44mUjmoLUvyJeH4haupNeC8ZYBfTPvat0HKsSZOPzGEcj0XvJfu1N9HEt4cgWCbzXl/bgYJNLh1rsz1XiiIshH0eJV7sjq0wbo4DAayOGkxaKsugCuld9Hms97E955U5xpkWxWmrnVyXxlYcqr7mx4BcmJfM43CidQTnS8e84JMrAGGkmLY7LSCyvtD7bI5cB1hyZYVc68+vkehFBzCGg7C9IOJuIBi5LzLYgaNAsTN9tiYatOyAh7YrsZ122w5GQFWYsuY4dEdWOMGuRuncl6V8n9sC6eNAAbojRhDy65GnoITPtiIJ9gCfHZgkrnrfFs+x1bMibtoet3weNmFeciUW5r5XUzybwIsy6q/cfr/p2WIEhhQ/TmC7asySMonfN0FlKV4cyBQ1SXZEgZHl+qYSx8AtowOSvLUvpiz/LZGCRhVvi0SFZxA8KaDtOABi9gIpzBSm+q5kx65EQN9tIv1dOf8yfAbhCAboBKESAKJoMEjJBZ2UAxO4NxUw2qm0xZxZmmwX+CLlzp549IOLYOCGqi/bqtFBU3IzpQLMKCkNRdqBRCjksq6UQOlkzQ2CYOBxxfmOHAIfWZIiB/siSeaRcrGX9AUsQD3uZK+ssRshOUaBL3NFmfRqKyIMwrEcx47s9KKCqkgb2/31KlayTZAMFIkbSda390THVHY56MgdgFhIX7embSTxUKbuy5ahUVs1qugjKMtjIcOaOZGCgnQn99Ydc0/K65TpA1W9rCcnBzuK+MMk9PhE6iChaUdcUqiJ80HOs1YHuNJu7ebei1c7opmkNwWunMJjYDG0k6k8SSeUYm6W1tYo0YSRN7O+oabtHExfglhKnCaYlNr8y79C4yPSsJl7C9R0Yd64/qB5uS2q39cYrTIJfdu87KjZgcMYWtEQZ75GUEzSBcPQRTMrg4YiMrAwuHBTRuykqTgFTUXVlCSSc1YYqckq7QClW3YUfS8GrjR02hJPF741jqRU3FES13N7w8DnE42ykBSCddAcIdWF7MI3yOSw1+xHwhjXzBpIdP0gdvsSDG05QFQ0psPHGuU9AUE51QSdxgM1fgEgKxy4PggzS5MNMEFsyx66GUw6ataAMIPJ1ddklcweDwOwVoIktHk+PXQvUlvshbArVFpTjdacjratzK9RYA+tVCqJaqLBOFWzO4KgowSGBPLRT80HHLpvXViTIBq6JjDuQjOMgjH3wW6KkkgJ8lYusRnFULsTupeZ5myLDAAVKSW2FXpg6NeusqQk48ehov62yjBpZobSNoy4JczMaAhqDIWKFSehss8ED+UrmSBtUqU8O6p+fGxacSxTd5VgFanIIK6TSaYGPtCzp09iTEaJKNW3BjjxJoo8Rdh2mqQs93aWzfWdMBircUvWhj0xAVN67Qhp4dhWOOaSYruyPu64UvJsK2MBnpuoU6OxpbBykOYEW/pCTSoxSg6rIp26YQDmdpLrWjTmdnO6XtjGGTd9oVRlIZVfw7+xsNqj2beAvovZ5Nl8bqzrpGhbyaEOdhRFaYi24aWady2lVhx+4f4mGNkR66bIHY09bgIAY55OgU6WbgeXoClSdSwBkb0RGt+UVkKcYkg1o7JIfkkRErtenMpB0WGY82K5nqFBpeQQpN4g/HDaK+C390WFI2hjrOY2thtLuzCdGlAXrEqbsAwap7pmmgqN9N1BKqi17AM3HiY90xqncNNLKYCkyxiVOoVFKqku3TBOUnruTnNGPI5Bq0Sz/ZlCKH2R+C7Ax6/JBaMwGEHmW4NUCINhIAh5xXsj2a1tnMMqCUSahLK0yieWsFyFntxXz80pC6S8hMX52LNiZGktW46HHMyOSCjg3ouDF9y2kCHOhe4pQJg1Z/wFEnV3DeWOSQ1Z3c+B47eQHDd3kqEmQBvH15KPwPgRMg8Nimar02zvnrba3fZ2d7sjSedHVipUtsCICKKttiIU9s8dm1Pjsd3ZNyRt74SlzMey4E3t0vISRP/nmxoaKpD3FFo+Uv4J8RbSLIZiiaVuC+mmgPQUn0oc3dT6oTVS1Vm9yISVGxpVW79Ap6Kt95bt8l+NnznY2/6WEV6OtgZ8FG0h9ZrCubLVgxdCi/JrbifCJDKHYB9EaNEmfjrev+Hq4O9CvfrcB3Xf6YC17CNya92+5UUc1QEsTmA6iWXG5xpj0NMwNrEEe8miC3c85o7M4ceGHSR+XD+rnZ35Z7VN9j1rn6G3jDEONGAqV4NB/xwAcYP9n1ZDq1Dk5dAs/DgX6zVs1lQG5pJKREFcU+td5b6D6X7ieeKfc6H8fgW5aaJjaxFBP8k80VY6+ccuUg3MBYW+VbDhrvGwnEVKEV+/Nb4KLV0yQ7fLOKnIUxP/uH32Ex8ZIL/Gge+YcXBY7wpfBChrE9oUHd2cyxYvsBxReCZ/fWNqmmw0mHyCH0pub87nmmQ/rID4iJ1pxs1ZLSsp3mftZs0Vc6tnraAawWPAQPBs1WxHGhDTnyvT5XM2uqa0yrdAmMwVAXEwZvWQ/5a4sL7Y1IXBThks1te2kigUfeb+JcM+TGGiqlSs3BKMnQuK4xN43+3+ABm63ePE93louP5lcMHnMT2Ty48knEupu2q+eW5va0pCKCAIFPbybJQE05m3W66T8W+dof/bUPoW/xzeZxH3+joTmPqDpalQR1YSB9CTtQUaV/7hmi2JQN1Dzvrr45/+CTo3ih2wT+UPWJFsGnFgunMnd1oLv3bjuqxqk4HsUbWuvWQtrWuahFoVJuYS/XG4i6v8KWv329VYy5BcgVhERIb67+eubOI8x1a2MJthW55XV6kNJniHfMsVX2J7pX8+v0pr2TQQD/maFjJfsfXPx+SDF1WZDEv2ZFyfz5kQ3oU+eyWdCUkoXDoGrkPDGLqAc8vkVuhN6uInigIxyYRMNq6C0HOMK7mZGpggz2ON/gt4DcPANbId1V/J8kEIUx6MfX5tCVfOIAySMaAgtsbMCZaynzG1P5AVlrOfR3n8zUHJ8wSIpKwGk3a7spxnrG/BuJyirJ8yrMChPI3lu8gUazUQ6oq7aRm5hJutYTFQshrHVhRxB6tcAFP5o57vwiaAh92meW5LcFSo+sqNh2aU4HauWFmlQGTaH0yD4qBB57DvvitWhmQ13b7pBylMo5nKFk1FLJsAv7Lp961DN+NZEbziha7FSs3LDKAp+9EprQkSCQON1MIlUCFfjw9cfyk2Jy73HGEFLcEVbo2Eefuo7/puNPwqwkgj9OOIox76mpnrs/lyaa+aXHp4CTSnhlVJnGUWT0WJs1hkPaIEypf89hVqgcsFIBdZo7tGWnsHVe2wVKroxJN2lAoJNCM7GKP7s9vjGPihtVkoJibEtEP1s5rF/isL1bvixeZ/mShXa7BXM7WVKF4l3koM7xnZtnA0Vh+mw70G47P/ikJzBlOsLFqlH2YZJB5TiNY7TASd4gp3gTztVF70rWKyl9j4mjBVgtYYgTV/w24Ht2wg1nepmNxkdwYsIQ9LhF3ehH/uSz0gFvH2mfJWzehtmtHPkus5IpX4cPZa+w9nPKSMXKBx5+SK6uiF20jtCPVqU+jejU3pXB0GieeYWEGuZAl2Qh4lXoyhNmY8dCNJHOn4zQzSKX5KgCMri0RtWjg/VCc8Sa4/MCNARMwHE+lbqttD13OASJspZkXCLRP/WYzdsv6Dnb2gLwUfW2QnnH3iYl+52z25cMdvuO1ZIXfe+Udy+Ozl32F+PQz2ZyD52FMg47k+F3ZKgwQ0qq6zV+NQ7BDO25hYCKvFGF0EHaBorHsnI4khXOiplDLPkg8p5S7TaX7Xj2LLt3Eq43RUrRiQjG4LM0jicdGLK3y8JpAjjOpp8QYrzHDx+oGM5aeFsLz1RMAiYK0IWDmP1lwZVtGp9VTZt1CBR4ltc+4In1jaMurNaa1VtTeMeG1am1ChyqcmnFR9K8LmR2Csjnhc1MNsMbWgY3GYFK3bB3NNPRIwSwzKzm7lXUHBCRVnN0tmZayASAovzLF8WBMysCEKFcnsRchXZZDm1h9OOEFz8bB0dSG8bBaQ03dMC/4XQZMej4OCpVnFLzrfXJZ/mu2raDo32wLbelrk4TD1iGiqyAMNcbvtiqtU1KEVq88xZEEe+DeKp8JIzkMzFUeGVsqzouo1GguXRvMbWi439fGm5SWIb9QO0t39to9Kuy69o1V7/uCbUE8L0TkW6KFQ5T78gjG4sNYct5avz/VyS1EkKhbatiubbGRyqCFE8mYlOKll6Ik8ptHtvva8o/QMQSR/ffR59C/+PoniD0F8LPPjujSPQY7RFqpg/bnhSBF7qZbdObiHmceYbUWcibPhabhpTu0NuZ9igsX4oBmXanrDu2wWB6GcyI20EPwIOcakAqQse1i0ANMWhGRg92xBFGowwJuquUSFy5YESKctzZsncxushmMdarOmXtGf+ABgzCDyWFBcSFF9KdK5jyXoAzYtD8+l2tEEZJRySnW7n0SKoS04ikya1iL76/pIyHq+SrkzLn83mOo+5r+dQavMZFyFwlOnZTXkaQduovCtZwIwbeCuBJ0ABxGrWCmcMNcrFyNMtFj2gm2xiYuYQpqBGjaKgxDpYXuJww/rxWLfNjgX6VsksQbD7d0KR3/k3zr7AcpGKDcEUxlYiMwPYo5JVizSVatsaEVg4oN8UZjIxaxJFS3iUv9ihYOowb4TC/eiZHyVFp4uHZfGa2CnjEXVVgtQZQxPiUcoFlkGxuepMhdtXFeSXfexxx5fgC1Xin9EoJXsn00F2hwB9g0Ll/mI0smli5gXraoRrnNcu0IWs9eCK2+hWfY39ra4YYbiZCmvylTP1FUnll7i3F49BVMVKZJt7oIuUnhKhVfRd5Pz3Cj/zlrW47m+juLfWW39BlkgdrRCVxj6d8xxhThOKaHL47PaM9VmOY7pK4Dd0o3bKnsKeUDMaJXFmHq1wO1RUuFiT0PB7Jl295vWTMTWb5Gt6jqIprwMQvBUJUneVjI1lhxb3K4QdFEgnXRpG1J51+VquLhVN5+t2mbJQk79i/fewwjwxCyP11STaQ/uVsitGTLSIoEWCY+/SLjPyqDU8zYTuSPsJmnwg/Uk+wHDiSeHgCaMimPigBuLA2ZdBq6jMATUY9O7SUECRDEL+uy/hZXFf6uEzv2R5clik/Dx/S0F91u6HPmGDcFymJIfmPzAT2NxkqGS9rhoj+vBAEVhABQG8IygXYiX2iu92ojl/r5KXNESzYp/1bwEMlbruyzzkmXI3I6ip1G6Emejw+RfztPYd6+5s5aeiH6WGFrkNSIQPVcQzal6S1TmwrAHMsBxS1ynaQ5BkXkizHsFHqqdUmWqS21sH9if3fgpVpMb+mWfG7qUx0XtFejdScZ0M+jXT8UIwWIau/jPuNs98p1xAAPtdo/xWlK8iQnsK5u7l3jGmIeXLmgPA/V3aLkRr4uWlilCMM6gmwMes430ptONBvNdr8E23p6efjL/bR4f/d9fjk5OzXdvNtAo2+hs7zpO66DfbLec3eZO37abL6wdp7nXO+B7Vmen/2J/d2Oh7lTWYEaYop0nL4Koc2OEnyoZcDFE/ttC2mWaeFXIrACjyrIOxJzLc9JOiDV43MLH1hZIlSsrdPB6rhl8AlN0gbZd8c4YfakFv/+ac13OwiDNPld0rLMTYdX8OO0mrJh9EJYswbsYgDXiIiOwID38hgw6ZZTDL+ghmeXcYlbErrjnSV/f+gqZVaDfH1RC6SXhTXEPt+QVpG1hWgl7diveOLCeuZlymxZMTMGz2tZZccUH6fUkdBtsbIXWCCfrzV2D4c198leVLQwbFlbByESxBiOpb/x0dAqTXKtVVPhFuxfY+XdRBDPaYp8+npwy1QgDzggcDEA0+eyX43cGO+GcrcN4VqlGdPZ8Te7nSVrTTwhXjPESru48Yy552MvxZQm3p3ob8sNb8e0GE35LtECRwjUqog74V3h30jwgZcMBr8sPHXTxFs0eXu4XGckYPWNpP7rqv5vLcYZuSJDa2XjSVr4YWScwKSw25JbDQxQ2IHdU6JbDUNR4HouSXoTN+XEKPdx1APtpMET8PQesFcias3IrOjvnUBfxt4hhJTui2FUTN63MCErLO3hmKygxR0UEXxxOhCvbdNwBlMcrKoeH9RnwgoEEL8wMwwq20kJ5/cvp24/H7/7f69N3Hz8IE0WrzJTgaXxjOMgTd+ZWrhkcVJI58lqueYzKRMRnSdIfPn78+d3Rxjm7vX3J5EdkzF+t0FCiQy/0ysPDYanUf8mOoftonYpnuYeyHE/ycsCGmuXwoxc4uB3zCkYjN+1yTRhV0JWWwADRCJdhuJV7rB5Fp+a22pAkQA4Y8lM+G+dG30uinOMecxriC2WIYfGUC0UVr1YaezMPESsAnvgYyxRzwJU5eq6wK1zJzFlfZ68FEBhk9Fy1W+dGIMuP8WuPyjasY+SSxVTALm4VZ1SGGhRNI5T732M3vp9uFWfbxFIiwHJlGcKcZGyYafbFOmhGRmIruXIrZWhK7q/ESLPAyd2KAXo4I45f//CzeXR8/PH45Bw3SnFq/CuEojxMZ3guz+aMJl8XMQFy3xdg4LPXYWhNcO8WVv92jDu9wxDMQ/nNjO4SZlphXjgsZSlkj4Cc+JWCTBis30AV6QndO0SlgGHaJZAESawyCWTe4ccNbvKhAPDuwoX5HvQPZTHt9SpjQ1YIFP3bPU3xDRUFGHjWXScSUmVyYLfizsIxVm+oZEP7soqBn4gSwDmrfXp9+tZ89+HHj2e1c3GhyWxyEVDll0Fqwr8yWJRvQuA7x3DhTAF79E3gb8Qgecb4vSs5OOmQ0Hcx0lrSrarUw7E6UCxk2Vf1nxUgUUkz6IJ7M0czody5Y1qxNPFADWtpG+dFOyX/dn4ZsZRRgDIu+OSwns+wTGlUw8wiXi/vqp6gE0Gg7Kn6ssiOIDuC7Ig/iR0xT0kgLuTjFj4i5UpmeftAi+rFQM35s1xO8bH6pvjcyanrinVsWUZM3bDX4iPKx+Ibyt3u/1iwvMPPJoem+rqynX3fOVpbehzxPvJe6wwol3RPxoAROIloK7+x9nm31Wqwm40fsC4/bp5OxlxupWhibQu/e7hx12CfBfjN46OTTx8/nBydn68QB/NZuHrJoUKzy+BR6rUoxcIr4Vc0CsJ1LoMrTvXp9kn6a8URGHn6/EGjXn3bspN5j1TKFn5AvJz+LyqZ8XMVWiWSiy8Y3oPouRaUaF0h7YvEeUzid6rctb7Ootj1PPR7i7033O1N/NR+kcfkjq5BqDjcEUL0b+wE5KwtHW9dqHvz3kyTtyc2RN4e1vkyLxuVk8yKJr4MqsdMyj5ftKwS4d6yYpb4HoduZ9WjQheVHdb/IrPkNsZF0FSmdG+ycqLptE497llsSJrCCVcXew9arU8TSPMkKPolS+dvpRMaXzx7yx2zVVyxajmfBhG8Pzp9+/HNOd6J//bo9Zu8nly1mE2JuHr24GfMTC8YDObcJVzkUvW4kUVaLrOL//Hxp5+OjtF2nobjrELZFeRuP8CDsAMkpVwVZRt4f111POIcYq7OPq0kiLfbFWzUL59ECSxuytwHJ1KcdLsfgvhHjEjVeP95p7Uz33jEirbGnuVKs3HjlINA/DkQ8UOx66Oy6LvXDO/GXds4nzpQVsvBJVR/TPX6onxLbOokkAsQoVDQYxL2LZvPdxKUuQcw39oXzLlpOehN1w+cwO4+WX31BZxZ01mzXTFC4pXmw9U377TZEUNfPfwkqW3ZQ7X0E3coqi+iGyHHz4iaab4oJf0iJsrPJ4Kd4bgRUMceri2NA8+yS++aEJJr9bTfRvoFxLvU6nklbCdFLrnHuDHj3E7zptV8zk/+VS4IHxUYM5+/bLdb1ZUlzNrEFyFGMpATwwhAKA7D4Ip1h5YXb6DwxSMn0sSEpfYktRdBNGLBjE8F/ae+oLk8ZtJGdNRFS2XnYPKbA1D2M/znHHH6Dh20PARz6KV4FYRowANy05S8JSVdS2lmHFahAqPvhtEzWjIBiQkfhI8F+MgOkJAkIaRUQwoZI2SMzEVIRuKcFOlU+t6lwIeMkP18wSe4Pu8HIZ7X8e0AT9LULy1v9lBfFd6XXKyNPHXttRzKZNoh3oBYT4PmBjw+ZLe36c6zgZ6Rw3yMpfz2wVp23H3m46qvgN4+d/SwurWFsDB81zt8Ltgg9ULqhQxVwgcZqoSUr4WUBfZI5QukH0adz7nBZVH8ZZDEfG2J8aKfU1R+8G43F0jXC4KRDobUvBUxbHx6F8haHXNurjRi5lFBIGmnM77VKT3OrkfICDkhaolwfkMtDmJKbEbIu7Dzk0z0QnubO88g61l+JCjd4hUdrxeqw1NkUbTsnPqMVZzJDqzQ5GA+17/TKhFn2LNHYjux/ZmxveInSP8Y6eZrelF+5EZ4n031TSyJPUsWV+aJJS4ay4wTaa4oIwRMEuORGfhH9pBzVNJY1ykLeNQINgzivnt9OFWr4nxegfzLNvjZIVPn31mXIYXrO62dL9h4XHVY8lPZElbE0b191S4HXGfqwgOFVnm2UVnQTnDlR3HIrREa2KzZZCPXAXsE8nMW+N4kb1qrTmgzFD+px85qhXoweDji8Vkt87iJ6MypRGbd6U2OXxavg3EkS+RwZvwpTyFGmYgfWt+neVTl+J+571Uv5EndtbRTz0VmUyTl0yE+RVJSJCVFUuYW5xRJSZGUFElJkZQUSUmRlDmznIIXnmXwAm0r0bYSbVATPmiDmpBCkZRkjFAkJUVSPklskHoh9UKGKuGDDFVCCkVS6iYMRVJSSJ1kIIXUEduJ7cR2YjsF0FIALQXQUgAtBdA+lQDailN+ylD92vHyCK8XFQKI1gWIokTEljBowsLPy41c3x1Z4ktzwJzIxQ/CZWRV4Z3Yk7eyI8vCO6vHqVS9Nbj8nvj08ndQMqeClAZ+FShVIA8rWpYxa/XxfkBb3LEphcJOpf2CxwjJlBWoglDkl9j1om73rUh4a0XDz+rdoh2gaBgknmMqShzK2Nq5HVr5ZfE69VfAW6RK6PYgfVv/epVKFldamzgOU3ydrpTne5V9MuqTcC/ZDatyrXYurDmzutNPVWmfhZJfgdrB+7plE5sGrALcaDiz5bTqeNFx6F4CZ1bN8GWs+DoAKL0lvtq+ccmXQ5Z9eWzp7uDMvNO8ePeOzz45fX36y4n5r3enb80PH82jD6fvTv9j/s/HN/8x1HcLD9WXxzbnAXJhXx4SFXQFPF0BTweX6OASHVyig0t0cIkOLtHBJTq49G26K+ng0lM2fChWmGKFKR6UURQXxYMSPigelJBCB5fIGHlSCKGDS3RwiQxVUi9kqBI+yFAlpDw2UujgEh1coqMMf/qjDMR2Yjux/c/Cdjq49GROMdDBpW81EoAOLtHBJQqgpQBaCqDFPwqgpQBaCqClAFoKoKUAWgqgfRr6igJoKWaF4hJoN5HiEggfT2O3mSQJIYUCaMkYoQBaCqAlQ5XUCxmqhI+nhA8yVAkpFEBLAbQUUkchdcR2YjuxndhOAbQUQEsBtBRASwG0347MpgDap0N8CqClAFoKoM35ZCiAlgJoKYCWAmgpgJYCaHNmOcWsPMuYFdpNpN1EiksgfFBcAiGFAmjJGKEAWgqgfZLYIPVC6oUMVcIHGaqEFAqg1U0YCqClkDrJQAqpI7YT24ntxHYKoKUAWgqgpQBaCqB9KgG0Fab85fZWMI5N1y+N2yyb6qmSPBWVd7tvA59P7GDUM1Qmw3Kc+gY0al5CV6GRjQbbuNzeuKeDWK3rX6Y/bm+ZxweWPTGrRt0yNnbti3oa8Kmkz7Qb+U48hIzIUZ1CoRe2QKHQFApNodAUCk2h0BQKTaHQFApNodBPRF9RKDRFH1GECe0LU4QJ4eNpxA2QJCGkUCg0GSMUCk2h0GSoknohQ5Xw8ZTwQYYqIYVCoSkUmoIjKTiS2E5sJ7YT2ykU+snGRVIo9LccCUCh0BQKTQG0FEBLAbT4RwG0FEBLAbQUQEsBtBRASwG0T0NfUQAtxaxQXALtJlJcAuHjaew2kyQhpFAALRkjFEBLAbRkqJJ6IUOV8PGU8EGGKiGFAmgpgJZC6iikjthObCe2E9spgJYCaCmAlgJoKYD2iYXeJaE3ssZlASa7B/dQ0W5kDpH4Fz5wH3kjfoi0yHB920scfsiGcTwWaWW+4VfQPxjXwOCWPQRkslss1WAgfi3sbYONcOnYQITdLvUfZ8GYEbdH48N61gXAE/y7yc7OCstGhm7kLD8Q+5KHJvJmeYn6Gr5FnzTQIoLspiyq8q80nmzKwK8GDmQEgYPAMRccuc1HDSX7lTeXcKPu5Ifjd59OzQ+v3x/hBlM9skN3HAvqsu8z7ub3dLDcp9enb813H378eC7vHS8FUGbfV4shnWuOqqhF9sPHD6dHH07N0/98OkKXzlltGrV4VmvA87+bP1iRDVoCVKDIgOYq/MaQxrPaB1CPIiKyy9ZvkFF3Z7XzVe45rhQTf/A4xu5OpYDuuQSvGqQI9sLEt8E6993f0ZcGRIyDeDLmU04v3WOe0/Q6+4d7wdnPPPS5t47V8JD1kpjxa5Rd6Nm1eRgDx0HyDFwb6ohDVzlzcXEAtu+TNRDuyVKNuDpn9/cq+21hwYbi4rAgJ1+9GsEK4drQGqh/p62xsxkPdS9lP5Nu+6WCn+cikB/gkwJPw8VO8+/ZzT864fZ0iE8n3OiEG51wy2lnOuFGJ9zohBudcKMTbnTCTQgxCip/1kHlFO5H4X4UOEz4oMBhQgqdcCNjhE640Qm3J4kNUi+kXshQJXyQoUpIoRNuuglDJ9y+0uGHVmnM5FRAFA67BFJkyN1iIRc8Tzv+wqO8LNDOrYh9JmlV6udW5J7QZn6eqkZfyvMz8unzq9TeVP81RzweBs55OXKiaYAmkByQ7DcY5HdcJBHuRWJHlgdo6oHXDvc4LMzkVmY9D+7NbI1TmBHFpZBEKu5lQ6YcOQByNtRgiq7X53R4U4zkL1Y4iG6fC0oLUb2EUcLok8Nopk7niNTyjfkv5fbKubssYHE13F4GURmAkDmKRJUb6OQ4q63fLJg+dzIiGVu9OysCVD+QB/pc9Pmz6Mp5LpQnZ2d8+2DM8SQHxd3KZh1QDKjMvgcOC3+TIROMvofE9u/nY1L2PAJns8zTNEWOnAc37Na+TU8yYg0oYG2j5/pOHYNTNmWAFtjoYkAFvkqYHirWY/6GGto568qFRV1PnXWePQtEzPgNCAl/UiRkimqxkNir7iiYz9BVMnCxRvoyhlZdI2oDmbN9YcipIJSTcsg/L4DUO8zjl9wDpi4wau5zN8IqzYcVmwvLLJ5y82GxLTPnhAD+rcNw/A08jT/mDCrXVxK5yyKeC5ymFMzBZ7s0pLjgjLz35QbFU/3YhSX81mprlJzNmXP9wru+XFYmYQjGdnZoXRzxBN2pECe6rZvyfYy5f5biY5vEB4mPlcZTBFCxl0fR3v5uVSNWn3Wvpg+ovvVXn89zBL8KoWoesuLfS8lMwwrdeMLWXrIWK54URGSiwWM12PgWlt09DLdWKJIWjyXNnfpfxhgq0S0BU+X6yvdJGPvM5noW0uHqRHhGpm/xvATB588An4onOKCj48D1462Qw9gXy6G/CfHaPcZcf9fQtNepcLoDBfivUeDXu6IVNw7Cib7OHPCYbWx1XWejuJQSF0iJuB94e/556+zM+X7rHKrz+RW7hFHjVlbQZ++TCBgzsnwfagDLAy+2EVZIKT54n4dmP/C84Ap4WLI0x7/0dhxhe+FNEa7N690+YMnE0TVUhzcLyM6fataPSj/UMZFZ1q4QN0PujbGw08uIN8cflyOuhpqyC6sYGwVO4nH2VjaTUU4lv+n9qCrVaIo2b6HJpdwvO4muc2z6+8FP9yyg7Nee8/mV8MLpv11p+j/sBG+UTegSa/U+E7rcdC1McL1zwZUPfUvJX5/W++SkwJLTmnhovDkCiETNbaOdWiAieUskb1n+xHTFMTmbQ7N2EDpzpEOmWoKeuG9HN3E7exXvQpD8ky1MT23mdoguxC2TphkBJUyz3pVbosoGaDD5X3GRjbZoEgcyZ3abpm0ZY8+a4DHpNeVr06spRVzWGa1Ug2kN3xdrc4aJfOuYF3xyBR2OCuOEWacK5G/fLJTBGV280melp1OrgObB4aoo4wRJz6vmF1QQAhpcTxSQdJlYOaY5si65GYTuAOw7z3RHY4+PuB+Lq5RMtErxUoK1HANE08LyNGPAC48NIZlNfs3tWSiC1Z5VDxxwe66HpvftLZs+SdTniFCoY5q3OCFyc6m+ZCqprdvl0yLPCJ26poxNSh3buXrvP1fyMK8XZ8Z7YWNA++4lHjZIeyUjKWZmSdHOy2bglGrzpMPK588Mih953sxjn24BVoplgYWDRt519koxZcbqmwMVM+j9OgcqiyH4SlRjjHgUWQMOut/m7iV32AIhLW+0vddNOVr3nwcEJMWKrC9SUGP7dvkmW8qO4xNop9t9jw0Z0RiPjOs6wkx1RGT2w2BkYloUhxMz6NeB80C0zWlASZT08MK6Hg+LEmz6xgCT0u1Psl6bahiqNpzE4rnBJATmXX9VErO5/LKCOaB5WLxk3Ht6OOm0KytRsYao82u8y8iSoa1MGO+WN0Iqi1WC6w9MLUs946WYz5tFIQ6smGY2LAdIyesyaxpKpGeQv6eQibIhFf1bZQjBE0dJz5AyrC5uBrmHsgP7BK+Dmfas2LrW58RXw8r6DO1Ad6J4xnOhlVIdw07Ol63fMEhTOOrjLT2ptLPfqn6N5py9jenpAFwOgvFnLqbtQszICkA02qEwIBHtlh0nYPWhFRmZvUm9Lc15sZpd0kz5tXwLum+qu9zyvciEqR0kcsW7fIgPoBPnMvUJgWkp2/RlRbuy256h2Q+q0RyEQTI2VDy/TLLxApvQcv14ulouTHiQIfm1CNjCHKza+LDUhC+Uk576e1nrQoRpOJmRzNq7Mjk5R+7+qQBWvPF3t6JSteI4BCTiFnMQsq5YcAIoLVve4NzFINpw+oiOObHElClFSGX3+9xDpsmaImNkjYUBJ5/LAmllroWo08BgwKI5frD9mm8FH0BdggfBYxE8Ft4cvluqiSrxt1GBn8vUTQk/lxgy8/m70kuGvzkmW7jfYcGKQI8VOKhoc6wjO3DLpW5b4aaB96hKy6/eHQSbRlZ3/WMSf+z/ZEXiAtUOSIfg99zqC9EyzS2XXDmoiBewtgu55UxSZ48pb+Rw+6bPUSxZ4aRupg4hs+RGZLCCjExGFZywEmKwogR+29hndsP0rpUENIFh8vgoO7+D/2/UVERXrXtTUzeO4s/0nMw/uD8QKGxBA/9uHsvMzXcOJHW2dx2nddBvtlvObnOnb9vNF9aO09zrHfA9q7PTf7G/C6XeBlh7jV9bSEMjCAeA8Br3L7Gdk6Pjfx4di+8HFPI00nefPh6fwrsD7MHx0fuPp0fm6zdvjiGp3dk3WvB/bazQDoILl2Pn4SEJPXiPn4bobm1ptcrdrq02VKX8893aT0en8AjjCidgPeKJaEiEFMeKrVoXL8m8u/v/tZOELw==", + headers: { + 'Accept'=>'*/*', + 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type'=>'application/octet-stream', + 'User-Agent'=>'sentry-ruby/3.0.4', + 'X-Sentry-Auth'=>'Sentry sentry_version=5, sentry_client=raven-ruby/3.0.4, sentry_timestamp=1644887612, sentry_key=fake, sentry_secret=token' + }). + to_return(status: 200, body: "", headers: {}) + end + it 'enqueues error into a thread' do error = TestError.new('Konstantin broke all the thingz!') allow_any_instance_of(Travis::Api::App::Endpoint::Repos).to receive(:service).and_raise(error) expect(Raven).to receive(:send_event).with( - satisfy { |event| event['logentry']['message'] == "#{error.class}: #{error.message}" } + satisfy do |event| + event_error = event['exception']['values'].first + event_error['type'] == error.class.to_s && event_error['value'] == error.message + end ) res = get '/repos/1' expect(res.status).to eq(500) diff --git a/spec/integration/settings_endpoint_spec.rb b/spec/integration/settings_endpoint_spec.rb index 2c83e82aa8..b1f729148d 100644 --- a/spec/integration/settings_endpoint_spec.rb +++ b/spec/integration/settings_endpoint_spec.rb @@ -77,7 +77,7 @@ describe 'POST /items' do context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } it "responds with 403" do body = { item: { name: 'foo', secret: 'TEH SECRET' } }.to_json @@ -87,7 +87,7 @@ end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } it "responds with 403" do body = { item: { name: 'foo', secret: 'TEH SECRET' } }.to_json @@ -130,7 +130,7 @@ describe 'PATCH /items/:id' do context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } it "responds with 403" do settings = repo.settings @@ -145,7 +145,7 @@ end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } it "responds with 403" do settings = repo.settings @@ -201,7 +201,7 @@ describe 'DELETE /items/:id' do context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } it "responds with 403" do settings = repo.settings @@ -217,7 +217,7 @@ end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } it "responds with 403" do settings = repo.settings diff --git a/spec/integration/singleton_settings_endpoint_spec.rb b/spec/integration/singleton_settings_endpoint_spec.rb index df0f683ffc..c520def2d7 100644 --- a/spec/integration/singleton_settings_endpoint_spec.rb +++ b/spec/integration/singleton_settings_endpoint_spec.rb @@ -54,7 +54,7 @@ describe 'PATCH /item' do context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } it "responds with 403" do body = { item: { name: 'a name', secret: 'a secret' } }.to_json @@ -64,7 +64,7 @@ end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } it "responds with 403" do body = { item: { name: 'a name', secret: 'a secret' } }.to_json @@ -124,7 +124,7 @@ describe 'DELETE /item' do context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } it "responds with 403" do response = delete "/settings/item/#{repo.id}", {}, headers @@ -133,7 +133,7 @@ end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } it "responds with 403" do response = delete "/settings/item/#{repo.id}", {}, headers diff --git a/spec/integration/v2/builds_spec.rb b/spec/integration/v2/builds_spec.rb index f8952eaee6..4670e29286 100644 --- a/spec/integration/v2/builds_spec.rb +++ b/spec/integration/v2/builds_spec.rb @@ -138,20 +138,20 @@ end context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post "/builds/#{build.id}/restart", {}, headers } it { expect(last_response.status).to eq(403) } end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post "/builds/#{build.id}/restart", {}, headers } it { expect(last_response.status).to eq(403) } end context 'when the repo is migrated on .com' do before { Travis.config.host = 'travis-ci.com' } - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post "/builds/#{build.id}/restart", {}, headers } it { expect(last_response.status).to eq(202) } end diff --git a/spec/integration/v2/hooks_spec.rb b/spec/integration/v2/hooks_spec.rb index 6005db6d52..a0c0f72125 100644 --- a/spec/integration/v2/hooks_spec.rb +++ b/spec/integration/v2/hooks_spec.rb @@ -41,13 +41,13 @@ end context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { put 'hooks', { hook: { id: hook.id, active: 'true' } }, headers } it { expect(last_response.status).to eq(403) } end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { put 'hooks', { hook: { id: hook.id, active: 'true' } }, headers } it { expect(last_response.status).to eq(403) } end diff --git a/spec/integration/v2/jobs_spec.rb b/spec/integration/v2/jobs_spec.rb index 93e540ad3f..355265a289 100644 --- a/spec/integration/v2/jobs_spec.rb +++ b/spec/integration/v2/jobs_spec.rb @@ -360,13 +360,13 @@ end context 'when the repo is migrating' do - before { job.repository.update_attributes(migration_status: "migrating") } + before { job.repository.update(migration_status: "migrating") } before { post "/jobs/#{job.id}/restart", {}, headers } it { expect(last_response.status).to eq(403) } end context 'when the repo is migrated' do - before { job.repository.update_attributes(migration_status: "migrated") } + before { job.repository.update(migration_status: "migrated") } before { post "/jobs/#{job.id}/restart", {}, headers } it { expect(last_response.status).to eq(403) } end diff --git a/spec/integration/v2/pusher_spec.rb b/spec/integration/v2/pusher_spec.rb index 096b0dc9a4..9bbed113de 100644 --- a/spec/integration/v2/pusher_spec.rb +++ b/spec/integration/v2/pusher_spec.rb @@ -26,7 +26,7 @@ after { Travis.config.public_mode = false } describe 'for a private repo' do - before { job.update_attributes!(private: true) } + before { job.update!(private: true) } it 'does not authorize a channel for a job that belongs to a repository that i do not have permissions on' do post '/pusher/auth', { channels: ["private-job-1"], socket_id: '123.456' }, headers @@ -38,7 +38,7 @@ describe 'for a public repo (org)' do before { Travis.config.host = 'travis-ci.org' } before { Travis.config.public_mode = false } - before { job.update_attributes!(private: false) } + before { job.update!(private: false) } it 'authorizes a channel for a job that belongs to a repository that i do not have permissions on' do Permission.delete_all @@ -51,7 +51,7 @@ describe 'for a public repo (public mode)' do before { Travis.config.host = 'travis-ci.com' } before { Travis.config.public_mode = true } - before { job.update_attributes!(private: false) } + before { job.update!(private: false) } it 'authorizes a channel for a job that belongs to a repository that i do not have permissions on' do Permission.delete_all @@ -64,7 +64,7 @@ describe 'for a public repo (private mode)' do before { Travis.config.host = 'enterprise.travis-ci.com' } before { Travis.config.public_mode = false } - before { job.update_attributes!(private: false) } + before { job.update!(private: false) } it 'does not authorize a channel for a job that belongs to a repository that i do not have permissions on' do Permission.delete_all @@ -111,7 +111,7 @@ after { Travis.config.public_mode = false } describe 'for a private repo' do - before { job.update_attributes!(private: true) } + before { job.update!(private: true) } it 'authorizes a channel for a job that belongs to a repository that i have permissions on' do post '/pusher/auth', { channels: ["private-job-#{job.id}"], socket_id: '123.456' }, headers @@ -129,7 +129,7 @@ describe 'for a public repo (org)' do before { Travis.config.host = 'travis-ci.org' } before { Travis.config.public_mode = false } - before { job.update_attributes!(private: false) } + before { job.update!(private: false) } it 'authorizes a channel for a job that belongs to a repository that i have permissions on' do post '/pusher/auth', { channels: ["private-job-#{job.id}"], socket_id: '123.456' }, headers @@ -148,7 +148,7 @@ describe 'for a public repo (public mode)' do before { Travis.config.host = 'travis-ci.com' } before { Travis.config.public_mode = true } - before { job.update_attributes!(private: false) } + before { job.update!(private: false) } it 'authorizes a channel for a job that belongs to a repository that i have permissions on' do post '/pusher/auth', { channels: ["private-job-#{job.id}"], socket_id: '123.456' }, headers @@ -167,7 +167,7 @@ describe 'for a public repo (private mode)' do before { Travis.config.host = 'enterprise.travis-ci.com' } before { Travis.config.public_mode = false } - before { job.update_attributes!(private: false) } + before { job.update!(private: false) } it 'authorizes a channel for a job that belongs to a repository that i have permissions on' do post '/pusher/auth', { channels: ["private-job-#{job.id}"], socket_id: '123.456' }, headers diff --git a/spec/integration/v2/repositories_spec.rb b/spec/integration/v2/repositories_spec.rb index 01a563ca97..3c64dbd7a9 100644 --- a/spec/integration/v2/repositories_spec.rb +++ b/spec/integration/v2/repositories_spec.rb @@ -18,7 +18,7 @@ let(:headers) { { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json', 'HTTP_AUTHORIZATION' => "token #{token}" } } context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } it "responds with 403" do response = post "/repos/#{repo.id}/key", {}, headers @@ -30,7 +30,7 @@ end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } it "responds with 403" do response = post "/repos/#{repo.id}/key", {}, headers @@ -193,7 +193,7 @@ it 'does not proxy to .com if a user agent is set to PROXY_USER_AGENT' do Travis.config.host = 'travis-ci.org' Travis.config.public_mode = true - repo.update_attributes(migration_status: 'migrated', migrated_at: Time.now) + repo.update(migration_status: 'migrated', migrated_at: Time.now) FactoryBot.create(:build, repository: repo, state: :passed) headers = { @@ -209,7 +209,7 @@ it 'proxies to .com if a repo has been migrated' do Travis.config.host = 'travis-ci.org' Travis.config.public_mode = true - repo.update_attributes(migration_status: 'migrated', migrated_at: Time.now) + repo.update(migration_status: 'migrated', migrated_at: Time.now) FactoryBot.create(:build, repository: repo, state: :passed) stub_request(:get, "https://api.travis-ci.com/svenfuchs/minimal.svg?branch=master"). @@ -224,7 +224,7 @@ it 'proxies to .com and an image if a repo has been migrated and with browser-like accept header' do Travis.config.host = 'travis-ci.org' Travis.config.public_mode = true - repo.update_attributes(migration_status: 'migrated', migrated_at: Time.now) + repo.update(migration_status: 'migrated', migrated_at: Time.now) FactoryBot.create(:build, repository: repo, state: :passed) stub_request(:get, "https://api.travis-ci.com/svenfuchs/minimal.svg?branch=master"). @@ -239,7 +239,7 @@ it 'proxies to .com to .com if a repo has been migrated, slug without format' do Travis.config.host = 'travis-ci.org' Travis.config.public_mode = true - repo.update_attributes(migration_status: 'migrated', migrated_at: Time.now) + repo.update(migration_status: 'migrated', migrated_at: Time.now) FactoryBot.create(:build, repository: repo, state: :passed) stub_request(:get, "https://api.travis-ci.com/svenfuchs/minimal?branch=master"). @@ -254,7 +254,7 @@ it 'does not proxy to .org if a user agent is set to PROXY_USER_AGENT' do Travis.config.host = 'travis-ci.com' Travis.config.public_mode = true - repo.update_attributes(migration_status: 'migrated', migrated_at: Time.now) + repo.update(migration_status: 'migrated', migrated_at: Time.now) FactoryBot.create(:build, repository: repo, state: :passed) headers = { @@ -270,7 +270,7 @@ it 'proxies to .org if a repo has not been migrated and is not active' do Travis.config.host = 'travis-ci.com' Travis.config.public_mode = true - repo.update_attributes(migration_status: nil, migrated_at: Time.now, active: false) + repo.update(migration_status: nil, migrated_at: Time.now, active: false) FactoryBot.create(:build, repository: repo, state: :passed) stub_request(:get, "https://api.travis-ci.org/svenfuchs/minimal.svg?branch=master"). @@ -491,7 +491,7 @@ FactoryBot.create(:build, repository: repo, state: :passed, commit: on_foo) FactoryBot.create(:build, repository: repo, state: :passed, commit: on_bar) FactoryBot.create(:build, repository: repo, state: :started, commit: on_bar) - repo.update_attributes!(last_build_state: nil) + repo.update!(last_build_state: nil) result = get('/repos/svenfuchs/minimal.png?branch=foo,bar', {}, headers) expect(result).to deliver_result_image_for('passing') end diff --git a/spec/integration/v2/requests_spec.rb b/spec/integration/v2/requests_spec.rb index 3d8b6a7cb7..fd3132d030 100644 --- a/spec/integration/v2/requests_spec.rb +++ b/spec/integration/v2/requests_spec.rb @@ -34,13 +34,13 @@ end context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post "/requests", { build_id: build.id }, headers } it { expect(last_response.status).to eq(403) } end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post "/requests", { build_id: build.id }, headers } it { expect(last_response.status).to eq(403) } end diff --git a/spec/integration/v2/settings/env_vars_spec.rb b/spec/integration/v2/settings/env_vars_spec.rb index b7d1b41678..668e31b795 100644 --- a/spec/integration/v2/settings/env_vars_spec.rb +++ b/spec/integration/v2/settings/env_vars_spec.rb @@ -85,13 +85,13 @@ end context 'when the repo is migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post "/settings/env_vars?repository_id=#{repo.id}", '{}', headers } it { expect(last_response.status).to eq(403) } end context 'when the repo is migrated' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post "/settings/env_vars?repository_id=#{repo.id}", '{}', headers } it { expect(last_response.status).to eq(403) } end @@ -169,14 +169,14 @@ context 'when the repo is migrating' do let(:env_var) { repo.settings.env_vars.create(name: 'FOO', value: 'bar').tap { repo.settings.save } } - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { patch "/settings/env_vars/#{env_var.id}?repository_id=#{repo.id}", '{}', headers } it { expect(last_response.status).to eq(403) } end context 'when the repo is migrated' do let(:env_var) { repo.settings.env_vars.create(name: 'FOO', value: 'bar').tap { repo.settings.save } } - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { patch "/settings/env_vars/#{env_var.id}?repository_id=#{repo.id}", '{}', headers } it { expect(last_response.status).to eq(403) } end diff --git a/spec/integration/v2/settings/ssh_key_spec.rb b/spec/integration/v2/settings/ssh_key_spec.rb index 531d59ea4d..1b348bd1f3 100644 --- a/spec/integration/v2/settings/ssh_key_spec.rb +++ b/spec/integration/v2/settings/ssh_key_spec.rb @@ -103,14 +103,14 @@ context 'when the repo is migrating' do let(:env_var) { repo.settings.create(:ssh_key, description: 'foo', value: TEST_PRIVATE_KEY).tap { repo.settings.save } } - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { patch "/settings/ssh_key/#{repo.id}", '{"settings": {}}', headers } it { expect(last_response.status).to eq(403) } end context 'when the repo is migrated' do let(:env_var) { repo.settings.create(:ssh_key, description: 'foo', value: TEST_PRIVATE_KEY).tap { repo.settings.save } } - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { patch "/settings/ssh_key/#{repo.id}", '{}', headers } it { expect(JSON.parse(last_response.body)["error_type"]).to eq("migrated_repository") } it { expect(last_response.status).to eq(403) } diff --git a/spec/integration/visibility_spec.rb b/spec/integration/visibility_spec.rb index ae6afb023a..3c9fd50e56 100644 --- a/spec/integration/visibility_spec.rb +++ b/spec/integration/visibility_spec.rb @@ -9,13 +9,13 @@ let(:job_id) { 42864 } let(:archived_content) { 'hello world!'} - before { repo.update_attributes(private: false) } + before { repo.update(private: false) } before { requests.update_all(private: true) } before { builds.update_all(private: true) } before { jobs.update_all(private: true) } - before { requests[0].update_attributes(private: false) } - before { builds[0].update_attributes(private: false) } - before { jobs[0].update_attributes(private: false) } + before { requests[0].update(private: false) } + before { builds[0].update(private: false) } + before { jobs[0].update(private: false) } before :each do Fog.mock! storage = Fog::Storage.new({ @@ -178,17 +178,17 @@ end describe 'GET /repos/%{repo.id}' do - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } it { expect(status).to eq 404 } end describe 'GET /repos/%{repo.id}/caches' do - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } it { expect(status).to eq 404 } end describe 'GET /repos/%{repo.slug}' do - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } it { expect(status).to eq 404 } end diff --git a/spec/lib/model/broadcast_spec.rb b/spec/lib/model/broadcast_spec.rb index 165d01d245..444b8ba857 100644 --- a/spec/lib/model/broadcast_spec.rb +++ b/spec/lib/model/broadcast_spec.rb @@ -76,25 +76,25 @@ end it 'finds a broadcast for an org this repo belongs to' do - repo.update_attributes(owner: org) + repo.update(owner: org) to_org = Broadcast.create!(recipient: org) expect(broadcasts).to include(to_org) end it 'does not find a broadcast for a different org' do - repo.update_attributes(owner: org) + repo.update(owner: org) to_org = Broadcast.create!(recipient: FactoryBot.create(:org, login: 'sinatra')) expect(broadcasts).not_to include(to_org) end it 'finds a broadcast for a user this repo belongs to' do - repo.update_attributes(owner: user) + repo.update(owner: user) to_org = Broadcast.create!(recipient: user) expect(broadcasts).to include(to_org) end it 'does not find a broadcast for a different user' do - repo.update_attributes(owner: org) + repo.update(owner: org) to_org = Broadcast.create!(recipient: FactoryBot.create(:user, login: 'rkh')) expect(broadcasts).not_to include(to_org) end diff --git a/spec/lib/model/build/denormalize_spec.rb b/spec/lib/model/build/denormalize_spec.rb index 675779883a..9eda377a30 100644 --- a/spec/lib/model/build/denormalize_spec.rb +++ b/spec/lib/model/build/denormalize_spec.rb @@ -34,7 +34,7 @@ describe 'on build:finished' do before :each do - build.update_attributes(state: :errored) + build.update(state: :errored) build.denormalize(:finish) build.reload end diff --git a/spec/lib/model/build/matrix_spec.rb b/spec/lib/model/build/matrix_spec.rb index 0feef4b043..d984da30cd 100644 --- a/spec/lib/model/build/matrix_spec.rb +++ b/spec/lib/model/build/matrix_spec.rb @@ -4,8 +4,8 @@ context 'if at least one job has not finished and is not allowed to fail' do it 'returns false' do build = FactoryBot.create(:build, config: { rvm: ['1.8.7', '1.9.2'] }) - build.matrix[0].update_attributes(state: :passed) - build.matrix[1].update_attributes(state: :started) + build.matrix[0].update(state: :passed) + build.matrix[1].update(state: :started) expect(build.matrix_finished?).not_to be true end @@ -14,8 +14,8 @@ context 'if at least one job has not finished and is allowed to fail' do it 'returns false' do build = FactoryBot.create(:build, config: { rvm: ['1.8.7', '1.9.2'] }) - build.matrix[0].update_attributes(state: :passed) - build.matrix[1].update_attributes(state: :started, allow_failure: true) + build.matrix[0].update(state: :passed) + build.matrix[1].update(state: :started, allow_failure: true) expect(build.matrix_finished?).not_to be true end @@ -24,8 +24,8 @@ context 'if all jobs have finished' do it 'returns true' do build = FactoryBot.create(:build, config: { rvm: ['1.8.7', '1.9.2'] }) - build.matrix[0].update_attributes!(state: :passed) - build.matrix[1].update_attributes!(state: :passed) + build.matrix[0].update!(state: :passed) + build.matrix[1].update!(state: :passed) expect(build.matrix_finished?).to be true end @@ -35,8 +35,8 @@ context 'if at least one job has not finished and is not allowed to fail' do it 'returns false' do build = FactoryBot.create(:build, config: { rvm: ['1.8.7', '1.9.2'], matrix: {fast_finish: true} }) - build.matrix[0].update_attributes(state: :passed) - build.matrix[1].update_attributes(state: :started) + build.matrix[0].update(state: :passed) + build.matrix[1].update(state: :started) expect(build.matrix_finished?).to be false end @@ -45,8 +45,8 @@ context 'if at least one job has not finished and is allowed to fail' do it 'returns true' do build = FactoryBot.create(:build, config: { rvm: ['1.8.7', '1.9.2'], matrix: {fast_finish: true} }) - build.matrix[0].update_attributes(state: :passed) - build.matrix[1].update_attributes(state: :started, allow_failure: true) + build.matrix[0].update(state: :passed) + build.matrix[1].update(state: :started, allow_failure: true) expect(build.matrix_finished?).to be true end @@ -55,8 +55,8 @@ context 'if all jobs have finished' do it 'returns true' do build = FactoryBot.create(:build, config: { rvm: ['1.8.7', '1.9.2'], matrix: {fast_finish: true} }) - build.matrix[0].update_attributes!(state: :passed) - build.matrix[1].update_attributes!(state: :passed) + build.matrix[0].update!(state: :passed) + build.matrix[1].update!(state: :passed) expect(build.matrix_finished?).to be true end @@ -68,56 +68,56 @@ let(:build) { FactoryBot.create(:build, config: { rvm: ['1.8.7', '1.9.2'] }) } it 'returns :passed if all jobs have passed' do - build.matrix[0].update_attributes!(state: "passed") - build.matrix[1].update_attributes!(state: "passed") + build.matrix[0].update!(state: "passed") + build.matrix[1].update!(state: "passed") expect(build.matrix_state).to eq(:passed) end it 'returns :failed if one job has failed' do - build.matrix[0].update_attributes!(state: "passed") - build.matrix[1].update_attributes!(state: "failed") + build.matrix[0].update!(state: "passed") + build.matrix[1].update!(state: "failed") expect(build.matrix_state).to eq(:failed) end it 'returns :failed if one job has failed and one job has errored' do - build.matrix[0].update_attributes!(state: "errored") - build.matrix[1].update_attributes!(state: "failed") + build.matrix[0].update!(state: "errored") + build.matrix[1].update!(state: "failed") expect(build.matrix_state).to eq(:errored) end it 'returns :errored if one job has errored' do - build.matrix[0].update_attributes!(state: "passed") - build.matrix[1].update_attributes!(state: "errored") + build.matrix[0].update!(state: "passed") + build.matrix[1].update!(state: "errored") expect(build.matrix_state).to eq(:errored) end it 'returns :passed if a errored job is allowed to fail' do - build.matrix[0].update_attributes!(state: "passed") - build.matrix[1].update_attributes!(state: "errored", allow_failure: true) + build.matrix[0].update!(state: "passed") + build.matrix[1].update!(state: "errored", allow_failure: true) expect(build.matrix_state).to eq(:passed) end it 'returns :passed if a failed job is allowed to fail' do - build.matrix[0].update_attributes!(state: "passed") - build.matrix[1].update_attributes!(state: "failed", allow_failure: true) + build.matrix[0].update!(state: "passed") + build.matrix[1].update!(state: "failed", allow_failure: true) expect(build.matrix_state).to eq(:passed) end it 'returns :failed if all jobs have failed and only one is allowed to fail' do - build.matrix[0].update_attributes!(state: "failed") - build.matrix[1].update_attributes!(state: "failed", allow_failure: true) + build.matrix[0].update!(state: "failed") + build.matrix[1].update!(state: "failed", allow_failure: true) expect(build.matrix_state).to eq(:failed) end it 'returns :failed if all jobs have failed and only one is allowed to fail' do - build.matrix[0].update_attributes!(state: "finished") + build.matrix[0].update!(state: "finished") expect { build.matrix_state }.to raise_error(StandardError) end it 'returns :passed if all jobs have passed except a job that is allowed to fail, and config[:matrix][:finish_fast] is set' do build.config.update(finish_fast: true) - build.matrix[0].update_attributes!(state: "passed") - build.matrix[1].update_attributes!(state: "failed", allow_failure: true) + build.matrix[0].update!(state: "passed") + build.matrix[1].update!(state: "failed", allow_failure: true) expect(build.matrix_state).to eq(:passed) end end @@ -126,7 +126,7 @@ let(:build) { FactoryBot.create(:build, config: { rvm: ['1.9.3'] }) } it 'returns :passed' do - build.matrix[0].update_attributes!(state: "failed", allow_failure: true) + build.matrix[0].update!(state: "failed", allow_failure: true) expect(build.matrix_state).to eq(:passed) end end diff --git a/spec/lib/model/organization_spec.rb b/spec/lib/model/organization_spec.rb index f54ef3ab69..7ba1f8d889 100644 --- a/spec/lib/model/organization_spec.rb +++ b/spec/lib/model/organization_spec.rb @@ -1,4 +1,4 @@ -describe User do +describe Organization do let(:org) { FactoryBot.create(:org, :login => 'travis-organization') } describe 'educational_org' do @@ -15,4 +15,18 @@ expect(org.education?).to be false end end + + describe '#preferences' do + it 'keeps them as ruby hash' do + org.preferences = { 'a' => 'b', 'c' => 'd' }.to_json + org.save! + + expect(org.reload.preferences).to be_a(Hash) + + org.preferences = { 'a' => 'b', 'c' => 'd' } + org.save! + + expect(org.reload.preferences).to be_a(Hash) + end + end end diff --git a/spec/lib/model/repository/settings/ssh_key_spec.rb b/spec/lib/model/repository/settings/ssh_key_spec.rb index 156a73ae66..8b533b822a 100644 --- a/spec/lib/model/repository/settings/ssh_key_spec.rb +++ b/spec/lib/model/repository/settings/ssh_key_spec.rb @@ -38,7 +38,8 @@ ssh_key.value = 'foo' expect(ssh_key).not_to be_valid - expect(ssh_key.errors[:value]).to eq([:not_a_private_key]) + + expect(ssh_key.errors[:value].to_s).to match('not_a_private_key') end it 'allows only private key' do @@ -46,14 +47,14 @@ ssh_key = described_class.new(value: public_key) expect(ssh_key).not_to be_valid - expect(ssh_key.errors[:value]).to eq([:not_a_private_key]) + expect(ssh_key.errors[:value].to_s).to match('not_a_private_key') end it 'does not check key if a value is nil' do ssh_key = described_class.new({}) expect(ssh_key).not_to be_valid - expect(ssh_key.errors[:value]).to eq([:blank]) + expect(ssh_key.errors[:value].to_s).to match('blank') end describe 'with a passphrase' do @@ -96,7 +97,7 @@ expect(ssh_key).not_to be_valid - expect(ssh_key.errors[:value]).to eq([:key_with_a_passphrase]) + expect(ssh_key.errors[:value].to_s).to match('key_with_a_passphrase') end end end diff --git a/spec/lib/model/repository/settings_spec.rb b/spec/lib/model/repository/settings_spec.rb index 52be399718..77f86764cb 100644 --- a/spec/lib/model/repository/settings_spec.rb +++ b/spec/lib/model/repository/settings_spec.rb @@ -38,7 +38,7 @@ settings.maximum_number_of_builds = 'foo' expect(settings).not_to be_valid - expect(settings.errors[:maximum_number_of_builds]).to eq([:not_a_number]) + expect(settings.errors[:maximum_number_of_builds].first.to_s).to eq('is not a number') settings.maximum_number_of_builds = 0 expect(settings).to be_valid diff --git a/spec/lib/model/repository/status_image_spec.rb b/spec/lib/model/repository/status_image_spec.rb index ad093998c6..c3f8126a9e 100644 --- a/spec/lib/model/repository/status_image_spec.rb +++ b/spec/lib/model/repository/status_image_spec.rb @@ -49,25 +49,25 @@ end it 'returns :failing if the status of the last finished build is failed' do - build.update_attributes(state: :failed) + build.update(state: :failed) image = described_class.new(repo, nil) expect(image.result).to eq(:failing) end it 'returns :error if the status of the last finished build is errored' do - build.update_attributes(state: :errored) + build.update(state: :errored) image = described_class.new(repo, nil) expect(image.result).to eq(:error) end it 'returns :canceled if the status of the last finished build is canceled' do - build.update_attributes(state: 'canceled') + build.update(state: 'canceled') image = described_class.new(repo, nil) expect(image.result).to eq(:canceled) end it 'returns :unknown if the status of the last finished build is unknown' do - build.update_attributes(state: :created) + build.update(state: :created) image = described_class.new(repo, nil) expect(image.result).to eq(:unknown) end @@ -75,25 +75,25 @@ describe 'given a branch' do it 'returns :passed if the last build on that branch has passed' do - build.update_attributes(state: :passed, branch: 'master') + build.update(state: :passed, branch: 'master') image = described_class.new(repo, 'master') expect(image.result).to eq(:passing) end it 'returns :failed if the last build on that branch has failed' do - build.update_attributes(state: :failed, branch: 'develop') + build.update(state: :failed, branch: 'develop') image = described_class.new(repo, 'develop') expect(image.result).to eq(:failing) end it 'returns :error if the last build on that branch has errored' do - build.update_attributes(state: :errored, branch: 'develop') + build.update(state: :errored, branch: 'develop') image = described_class.new(repo, 'develop') expect(image.result).to eq(:error) end it 'returns :canceled if the last build on that branch was canceled' do - build.update_attributes(state: :canceled, branch: 'develop') + build.update(state: :canceled, branch: 'develop') image = described_class.new(repo, 'develop') expect(image.result).to eq(:canceled) end diff --git a/spec/lib/model/repository_spec.rb b/spec/lib/model/repository_spec.rb index 861806fb07..d0e91978d0 100644 --- a/spec/lib/model/repository_spec.rb +++ b/spec/lib/model/repository_spec.rb @@ -7,8 +7,8 @@ let(:build2) { FactoryBot.create(:build, repository: repo, finished_at: Time.now, state: :failed) } before do - build1.update_attributes(branch: 'master') - build2.update_attributes(branch: 'development') + build1.update(branch: 'master') + build2.update(branch: 'development') end it 'returns last completed build' do @@ -258,7 +258,7 @@ end it 'returns the most recent build' do - expect(repo.last_build('master').id).to eq(@build.id) + expect(repo.reload.last_build.id).to eq(@build.id) end end @@ -268,7 +268,7 @@ end it 'returns the most recent build' do - expect(repo.last_build('master').id).to eq(@build.id) + expect(repo.reload.last_build.id).to eq(@build.id) end end end @@ -420,4 +420,20 @@ expect(repo.users_with_permission(:admin)).not_to include(user_wrong_permission) end end + + describe '#settings' do + let(:repo) { FactoryBot.create(:repository, name: 'foobarbaz') } + + it 'ensures settings are always a hash' do + repo.settings = {'build_pushes' => false}.to_json + repo.save + + expect(repo.reload.attributes['settings']).to be_a(Hash) + + repo.settings = {'build_pushes' => false} + repo.save + + expect(repo.reload.attributes['settings']).to be_a(Hash) + end + end end diff --git a/spec/lib/model/user_spec.rb b/spec/lib/model/user_spec.rb index ab5ad84984..c92b755dd8 100644 --- a/spec/lib/model/user_spec.rb +++ b/spec/lib/model/user_spec.rb @@ -182,4 +182,18 @@ def user(payload) end end end + + describe '#preferences' do + it 'keeps them as ruby hash' do + user.preferences = { 'a' => 'b', 'c' => 'd' }.to_json + user.save! + + expect(user.reload.preferences).to be_a(Hash) + + user.preferences = { 'a' => 'b', 'c' => 'd' } + user.save! + + expect(user.reload.preferences).to be_a(Hash) + end + end end diff --git a/spec/lib/services/find_admin_spec.rb b/spec/lib/services/find_admin_spec.rb index 3d83b89645..0b5527f0ca 100644 --- a/spec/lib/services/find_admin_spec.rb +++ b/spec/lib/services/find_admin_spec.rb @@ -21,7 +21,7 @@ describe 'given a user does not have access to a repository' do before :each do allow(GH).to receive(:[]).with("repos/#{repository.slug}").and_return('permissions' => { 'admin' => false }) - allow(user).to receive(:update_attributes!) + allow(user).to receive(:update!) end xit 'raises an exception' do @@ -29,7 +29,7 @@ end xit 'revokes admin permissions for that user on our side' do - expect(user).to receive(:update_attributes!).with(:permissions => { 'admin' => false }) + expect(user).to receive(:update!).with(:permissions => { 'admin' => false }) ignore_exception { result } end end diff --git a/spec/lib/services/update_job_spec.rb b/spec/lib/services/update_job_spec.rb index a07dbade36..fabc30206d 100644 --- a/spec/lib/services/update_job_spec.rb +++ b/spec/lib/services/update_job_spec.rb @@ -32,7 +32,7 @@ let(:event) { :receive } before :each do - job.repository.update_attributes(last_build_state: :passed) + job.repository.update(last_build_state: :passed) end context 'when job is canceled' do @@ -82,7 +82,7 @@ let(:event) { :start } before :each do - job.repository.update_attributes(last_build_state: :passed) + job.repository.update(last_build_state: :passed) end context 'when job is canceled' do @@ -136,7 +136,7 @@ let(:event) { :finish } before :each do - job.repository.update_attributes(last_build_state: :started) + job.repository.update(last_build_state: :started) end context 'when job is canceled' do @@ -201,7 +201,7 @@ let(:event) { :reset } before :each do - job.repository.update_attributes(last_build_state: :passed) + job.repository.update(last_build_state: :passed) end it 'sets the job state to created' do diff --git a/spec/lib/services/update_user_spec.rb b/spec/lib/services/update_user_spec.rb index cb5c39a2fc..6ba4a118b2 100644 --- a/spec/lib/services/update_user_spec.rb +++ b/spec/lib/services/update_user_spec.rb @@ -4,20 +4,20 @@ let(:service) { described_class.new(user, params) } before :each do - allow(user).to receive(:update_attributes!) + allow(user).to receive(:update!) end attr_reader :params it 'updates the locale if valid' do @params = { :locale => 'en' } - expect(user).to receive(:update_attributes!).with(params) + expect(user).to receive(:update!).with(params) service.run end it 'does not update the locale if invalid' do @params = { :locale => 'foo' } - expect(user).not_to receive(:update_attributes!) + expect(user).not_to receive(:update!) service.run end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ccf1ddc656..6969736af0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -21,7 +21,6 @@ require 'webmock/rspec' require 'active_record' -ActiveRecord::Base.raise_in_transactional_callbacks = true require 'travis/api/app' require 'travis/testing' diff --git a/spec/support/active_record.rb b/spec/support/active_record.rb index 6e4c376359..1cd611ed78 100644 --- a/spec/support/active_record.rb +++ b/spec/support/active_record.rb @@ -12,6 +12,7 @@ DatabaseCleaner.clean_with :truncation DatabaseCleaner.strategy = :transaction +DatabaseCleaner.allow_remote_database_url = true module Support module ActiveRecord diff --git a/spec/support/s3.rb b/spec/support/s3.rb index fb3c476a08..830f95e9b2 100644 --- a/spec/support/s3.rb +++ b/spec/support/s3.rb @@ -1,48 +1,57 @@ -require 's3' +require 'fog/aws' module Support module S3 class FakeObject attr_accessor :key, :size, :last_modified - def initialize(key, options = {}) + def initialize(key) @key = key - @size = options[:size] || "0" + @size = "0" end end class FakeService - attr_reader :buckets - def initialize(bucket) - @buckets = [bucket] + class GetClass + + def initialize(something) + @something = something + end + + def get(_bucket_name, params) + raise "'prefix' is required" if params.empty? || !params[:prefix] + @something.params = params + @something + end + end + attr_reader :directories + def initialize(directory) + @directories = GetClass.new(directory) end end class FakeBucket + attr_accessor :params def initialize(objects) @objects = Array(objects) end - def objects(params = {}) - params.each_key { |key| raise "cannot fake #{key}" unless key == :prefix } - prefix = params[:prefix] || "" - @objects.select { |o| o.key.start_with? prefix } + def files + @objects.select { |o| o.key.start_with? params[:prefix] } end - def add(key, options = {}) - @objects << FakeObject.new(key, options) + def create(key) + @objects << FakeObject.new(key) end - alias_method :<<, :add + alias_method :<<, :create end extend ActiveSupport::Concern included do - before(:each) { allow(::S3::Service).to receive(:new).and_return(s3_service) } - before(:each) { allow(::S3::Service).to receive(:new).and_return(s3_service) } + before(:each) { allow(::Fog::Storage).to receive(:new).and_return(s3_service) } let(:s3_service) { service = FakeService.new(s3_bucket) - allow(service.buckets).to receive(:find).and_return(s3_bucket) service } let(:s3_bucket) { FakeBucket.new(s3_objects) } diff --git a/spec/unit/endpoint/authorization/user_manager_spec.rb b/spec/unit/endpoint/authorization/user_manager_spec.rb index 5ff45ff3ce..9cfc5dec72 100644 --- a/spec/unit/endpoint/authorization/user_manager_spec.rb +++ b/spec/unit/endpoint/authorization/user_manager_spec.rb @@ -43,7 +43,7 @@ attributes = { login: 'drogus', github_id: 456, education: false, vcs_id: 456 }.stringify_keys - expect(user).to receive(:update_attributes).with(attributes) + expect(user).to receive(:update).with(attributes) expect(manager.fetch).to eq(user) end @@ -70,7 +70,7 @@ it 'updates user data' do attributes = { login: 'drogus', github_id: 456, github_oauth_token: 'abc123', education: false, vcs_id: 456 }.stringify_keys - expect_any_instance_of(User).to receive(:update_attributes).with(attributes) + expect_any_instance_of(User).to receive(:update).with(attributes) expect(manager.fetch).to eq(user) end end diff --git a/spec/unit/endpoint/authorization_spec.rb b/spec/unit/endpoint/authorization_spec.rb index 6103f23f09..b1f25a14ab 100644 --- a/spec/unit/endpoint/authorization_spec.rb +++ b/spec/unit/endpoint/authorization_spec.rb @@ -46,7 +46,7 @@ after do ENV['TRAVIS_SITE'] = nil end - + describe 'evil hackers messing with the state' do it 'does not succeed if state cookie mismatches' do Travis.redis.sadd('github:states', 'github-state') @@ -226,7 +226,7 @@ allow(GH).to receive(:with).with(token: 'private repos', client_id: nil).and_return double(:[] => user.login, :headers => {'x-oauth-scopes' => 'repo'}, :to_hash => data) allow(GH).to receive(:with).with(token: 'public repos', client_id: nil).and_return double(:[] => user.login, :headers => {'x-oauth-scopes' => 'public_repo'}, :to_hash => data) allow(GH).to receive(:with).with(token: 'no repos', client_id: nil).and_return double(:[] => user.login, :headers => {'x-oauth-scopes' => 'user'}, :to_hash => data) - allow(GH).to receive(:with).with(token: 'invalid token', client_id: nil).and_raise(Faraday::Error::ClientError, 'CLIENT ERROR!') + allow(GH).to receive(:with).with(token: 'invalid token', client_id: nil).and_raise(Faraday::ClientError, 'CLIENT ERROR!') end def get_token(github_token) diff --git a/spec/unit/endpoint/repos_spec.rb b/spec/unit/endpoint/repos_spec.rb index 36d3fb5650..32e16d8c3e 100644 --- a/spec/unit/endpoint/repos_spec.rb +++ b/spec/unit/endpoint/repos_spec.rb @@ -11,7 +11,10 @@ expect(get('/repos/spec/match/123').body).to eq("id") end - it 'does not match :id with non-digits' do + # we tested same thing here ./spec/integration/visibility_spec.rb + # and after gem upgrade Mustermann does not prevent :id + # to be not be digit-only so solution for that is manual change in the code + xit 'does not match :id with non-digits' do expect(get('/repos/spec/match/f123').body).to eq("name") end end diff --git a/spec/unit/serialize/v2/http/builds_spec.rb b/spec/unit/serialize/v2/http/builds_spec.rb index 05bfbe72b0..c8c37470b0 100644 --- a/spec/unit/serialize/v2/http/builds_spec.rb +++ b/spec/unit/serialize/v2/http/builds_spec.rb @@ -79,7 +79,13 @@ 3.times { FactoryBot.create(:build, :repository => repo) } end - it 'queries' do - expect { data }.to issue_queries(12) + # checking actual data not how ActiveRecord behaves underneath :| It can be changed on every version + + it 'builds field' do + expect(data['builds'].size).to eq(3) + end + + it 'commits field' do + expect(data['commits'].size).to eq(3) end end diff --git a/spec/v3/models/build_spec.rb b/spec/v3/models/build_spec.rb index 6eb6b702aa..f1845d1e0b 100644 --- a/spec/v3/models/build_spec.rb +++ b/spec/v3/models/build_spec.rb @@ -8,7 +8,7 @@ let(:sender) { FactoryBot.create(:user) } before do - subject.update_attributes(sender_type: 'User', sender_id: sender.id) + subject.update(sender_type: 'User', sender_id: sender.id) end it 'always returns a V3 namespaced sender instance' do diff --git a/spec/v3/services/build/find_spec.rb b/spec/v3/services/build/find_spec.rb index d309ae2aac..120723376b 100644 --- a/spec/v3/services/build/find_spec.rb +++ b/spec/v3/services/build/find_spec.rb @@ -8,11 +8,11 @@ let(:org) { Travis::API::V3::Models::Organization.new(login: 'example-org') } before do - build.update_attributes(sender_id: repo.owner.id, sender_type: 'User') + build.update(sender_id: repo.owner.id, sender_type: 'User') test = build.stages.create(number: 1, name: 'test') deploy = build.stages.create(number: 2, name: 'deploy') - build.jobs[0, 2].each { |job| job.update_attributes!(stage: test) } - build.jobs[2, 2].each { |job| job.update_attributes!(stage: deploy) } + build.jobs[0, 2].each { |job| job.update!(stage: test) } + build.jobs[2, 2].each { |job| job.update!(stage: deploy) } build.reload end @@ -389,7 +389,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v0.17.4' + 'User-Agent'=>'Faraday v1.9.3' }). to_return(status: 200, body: "{}", headers: {}) end @@ -413,7 +413,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v0.17.4' + 'User-Agent'=>'Faraday v1.9.3' }). to_return(status: 200, body: "{}", headers: {}) end diff --git a/spec/v3/services/build/restart_spec.rb b/spec/v3/services/build/restart_spec.rb index ee3948511f..da50ad9323 100644 --- a/spec/v3/services/build/restart_spec.rb +++ b/spec/v3/services/build/restart_spec.rb @@ -48,14 +48,14 @@ describe "repo migrating on .com" do before { Travis.config.host = "travis-ci.com" } - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/build/#{build.id}/restart", {}, headers) } example { expect(last_response.status).to be == 202 } end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/build/#{build.id}/restart", {}, headers) } example { expect(last_response.status).to be == 403 } @@ -67,7 +67,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/build/#{build.id}/restart", {}, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/builds/find_spec.rb b/spec/v3/services/builds/find_spec.rb index ec738b2b7b..86ba3b5f28 100644 --- a/spec/v3/services/builds/find_spec.rb +++ b/spec/v3/services/builds/find_spec.rb @@ -8,11 +8,11 @@ before do # TODO should this go into the scenario? is it ok to keep it here? - build.update_attributes!(sender_id: repo.owner.id, sender_type: 'User') + build.update!(sender_id: repo.owner.id, sender_type: 'User') test = build.stages.create(number: 1, name: 'test') deploy = build.stages.create(number: 2, name: 'deploy') - build.jobs[0, 2].each { |job| job.update_attributes!(stage: test) } - build.jobs[2, 2].each { |job| job.update_attributes!(stage: deploy) } + build.jobs[0, 2].each { |job| job.update!(stage: test) } + build.jobs[2, 2].each { |job| job.update!(stage: deploy) } build.reload build.jobs.each(&:reload) end diff --git a/spec/v3/services/builds/for_current_user_spec.rb b/spec/v3/services/builds/for_current_user_spec.rb index 6501c3309f..59565471d4 100644 --- a/spec/v3/services/builds/for_current_user_spec.rb +++ b/spec/v3/services/builds/for_current_user_spec.rb @@ -8,11 +8,11 @@ before do # TODO should this go into the scenario? is it ok to keep it here? - build.update_attributes!(sender_id: repo.owner.id, sender_type: 'User') + build.update!(sender_id: repo.owner.id, sender_type: 'User') test = build.stages.create(number: 1, name: 'test') deploy = build.stages.create(number: 2, name: 'deploy') - build.jobs[0, 2].each { |job| job.update_attributes!(stage: test) } - build.jobs[2, 2].each { |job| job.update_attributes!(stage: deploy) } + build.jobs[0, 2].each { |job| job.update!(stage: test) } + build.jobs[2, 2].each { |job| job.update!(stage: deploy) } end diff --git a/spec/v3/services/caches/delete_spec.rb b/spec/v3/services/caches/delete_spec.rb index 164c15639e..96970b7eac 100644 --- a/spec/v3/services/caches/delete_spec.rb +++ b/spec/v3/services/caches/delete_spec.rb @@ -245,7 +245,7 @@ context do describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { delete("/v3/repo/#{repo.id}/caches", {}, headers) } example { expect(last_response.status).to be == 403 } @@ -257,7 +257,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { delete("/v3/repo/#{repo.id}/caches", {}, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/cron/create_spec.rb b/spec/v3/services/cron/create_spec.rb index 23921d8d18..4ceeafdb79 100644 --- a/spec/v3/services/cron/create_spec.rb +++ b/spec/v3/services/cron/create_spec.rb @@ -169,7 +169,7 @@ context do describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } before { post("/v3/repo/#{repo.id}/branch/#{branch.name}/cron", options, headers) } @@ -182,7 +182,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } before { post("/v3/repo/#{repo.id}/branch/#{branch.name}/cron", options, headers) } diff --git a/spec/v3/services/cron/delete_spec.rb b/spec/v3/services/cron/delete_spec.rb index 8caa92a4cb..9a43e5cec3 100644 --- a/spec/v3/services/cron/delete_spec.rb +++ b/spec/v3/services/cron/delete_spec.rb @@ -55,7 +55,7 @@ context do describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } before { delete("/v3/cron/#{cron.id}", {}, headers) } @@ -68,7 +68,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } before { delete("/v3/cron/#{cron.id}", {}, headers) } diff --git a/spec/v3/services/email_subscription/resubscribe_spec.rb b/spec/v3/services/email_subscription/resubscribe_spec.rb index 81a159f14e..1eb712d5f4 100644 --- a/spec/v3/services/email_subscription/resubscribe_spec.rb +++ b/spec/v3/services/email_subscription/resubscribe_spec.rb @@ -56,7 +56,7 @@ before { delete("/v3/repo/#{repo.id}/email_subscription", {}, auth_headers) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/email_subscription", {}, auth_headers) } example { expect(last_response.status).to be == 403 } @@ -68,7 +68,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/email_subscription", {}, auth_headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/email_subscription/unsubscribe_spec.rb b/spec/v3/services/email_subscription/unsubscribe_spec.rb index db72efdca5..6d42ad0787 100644 --- a/spec/v3/services/email_subscription/unsubscribe_spec.rb +++ b/spec/v3/services/email_subscription/unsubscribe_spec.rb @@ -51,7 +51,7 @@ context do describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { delete("/v3/repo/#{repo.id}/email_subscription", {}, auth_headers) } example { expect(last_response.status).to be == 403 } @@ -63,7 +63,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { delete("/v3/repo/#{repo.id}/email_subscription", {}, auth_headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/env_var/delete_spec.rb b/spec/v3/services/env_var/delete_spec.rb index 98a87a0635..436ef20396 100644 --- a/spec/v3/services/env_var/delete_spec.rb +++ b/spec/v3/services/env_var/delete_spec.rb @@ -13,7 +13,7 @@ describe 'authenticated, wrong permissions' do before do - repo.update_attributes(settings: { env_vars: [env_var] }) + repo.update(settings: { env_vars: [env_var] }) Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true) delete("/v3/repo/#{repo.id}/env_var/#{env_var[:id]}", {}, auth_headers) end @@ -53,7 +53,7 @@ describe 'existing repo, existing env var' do before do - repo.update_attributes(settings: { env_vars: [env_var], foo: 'bar' }) + repo.update(settings: { env_vars: [env_var], foo: 'bar' }) delete("/v3/repo/#{repo.id}/env_var/#{env_var[:id]}", {}, auth_headers) end @@ -70,7 +70,7 @@ context do describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } before { delete("/v3/repo/#{repo.id}/env_var/#{env_var[:id]}", {}, auth_headers) } @@ -83,7 +83,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } before { delete("/v3/repo/#{repo.id}/env_var/#{env_var[:id]}", {}, auth_headers) } diff --git a/spec/v3/services/env_var/find_spec.rb b/spec/v3/services/env_var/find_spec.rb index 9e7c1115d6..e0cb2a8b0c 100644 --- a/spec/v3/services/env_var/find_spec.rb +++ b/spec/v3/services/env_var/find_spec.rb @@ -23,7 +23,7 @@ describe 'authenticated, existing repo, existing env var' do before do - repo.update_attributes(settings: { env_vars: [env_var]} ) + repo.update(settings: { env_vars: [env_var]} ) get("/v3/repo/#{repo.id}/env_var/#{env_var[:id]}", {}, auth_headers) end diff --git a/spec/v3/services/env_var/update_spec.rb b/spec/v3/services/env_var/update_spec.rb index d03c00b40c..9271fa67c0 100644 --- a/spec/v3/services/env_var/update_spec.rb +++ b/spec/v3/services/env_var/update_spec.rb @@ -31,7 +31,7 @@ before do Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true) - repo.update_attributes(settings: { env_vars: [env_var], foo: 'bar' }) + repo.update(settings: { env_vars: [env_var], foo: 'bar' }) patch("/v3/repo/#{repo.id}/env_var/#{env_var[:id]}", JSON.generate(params), auth_headers.merge(json_headers)) end @@ -65,7 +65,7 @@ before do Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) - repo.update_attributes(settings: { env_vars: [env_var], foo: 'bar' }) + repo.update(settings: { env_vars: [env_var], foo: 'bar' }) patch("/v3/repo/#{repo.id}/env_var/#{env_var[:id]}", JSON.generate(params), auth_headers.merge(json_headers)) end @@ -96,7 +96,7 @@ before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { patch("/v3/repo/#{repo.id}/env_var/#{env_var[:id]}", JSON.generate(params), auth_headers.merge(json_headers)) } example { expect(last_response.status).to be == 403 } @@ -108,7 +108,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { patch("/v3/repo/#{repo.id}/env_var/#{env_var[:id]}", JSON.generate(params), auth_headers.merge(json_headers)) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/env_vars/create_spec.rb b/spec/v3/services/env_vars/create_spec.rb index 11716d37f7..20a70193cc 100644 --- a/spec/v3/services/env_vars/create_spec.rb +++ b/spec/v3/services/env_vars/create_spec.rb @@ -19,7 +19,7 @@ describe 'authenticated, existing repo, wrong permissions' do before do Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true) - repo.update_attributes(settings: { env_vars: [{ id: 'abc', name: 'FOO', value: Travis::Settings::EncryptedValue.new('bar'), public: false }] }) + repo.update(settings: { env_vars: [{ id: 'abc', name: 'FOO', value: Travis::Settings::EncryptedValue.new('bar'), public: false }] }) post("/v3/repo/#{repo.id}/env_vars", JSON.generate({}), auth_headers.merge(json_headers)) end @@ -79,7 +79,7 @@ before do Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) - repo.update_attributes(settings: { env_vars: [{ id: 'abc', name: 'FOO', value: Travis::Settings::EncryptedValue.new('bar'), public: false }] }) + repo.update(settings: { env_vars: [{ id: 'abc', name: 'FOO', value: Travis::Settings::EncryptedValue.new('bar'), public: false }] }) post("/v3/repo/#{repo.id}/env_vars", JSON.generate(params), auth_headers.merge(json_headers)) end @@ -162,7 +162,7 @@ before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/env_vars", JSON.generate(params), auth_headers.merge(json_headers)) } example { expect(last_response.status).to be == 403 } @@ -174,7 +174,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/env_vars", JSON.generate(params), auth_headers.merge(json_headers)) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/env_vars/for_repository_spec.rb b/spec/v3/services/env_vars/for_repository_spec.rb index 23c2a31468..e459826682 100644 --- a/spec/v3/services/env_vars/for_repository_spec.rb +++ b/spec/v3/services/env_vars/for_repository_spec.rb @@ -33,7 +33,7 @@ describe 'authenticated, existing repo, existing env vars' do before do - repo.update_attributes(settings: { env_vars: [env_var] }) + repo.update(settings: { env_vars: [env_var] }) get("/v3/repo/#{repo.id}/env_vars", {}, auth_headers) end example { expect(last_response.status).to eq(200) } diff --git a/spec/v3/services/job/debug_spec.rb b/spec/v3/services/job/debug_spec.rb index 58ff11d64a..be72468fdc 100644 --- a/spec/v3/services/job/debug_spec.rb +++ b/spec/v3/services/job/debug_spec.rb @@ -86,7 +86,7 @@ context "for a private repo" do before do - job.repository.update_attributes!(private: true) + job.repository.update!(private: true) post("/v3/job/#{job.id}/debug", {}, headers) end @@ -102,7 +102,7 @@ before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/job/#{job.id}/debug", {}, headers) } example { expect(last_response.status).to be == 403 } @@ -114,7 +114,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/job/#{job.id}/debug", {}, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/job/find_spec.rb b/spec/v3/services/job/find_spec.rb index a94c8cc31d..f572403447 100644 --- a/spec/v3/services/job/find_spec.rb +++ b/spec/v3/services/job/find_spec.rb @@ -27,9 +27,9 @@ before do # TODO should this go into the scenario? is it ok to keep it here? - job.update_attributes!(stage: stage) - job2.update_attributes!(config: config, stage: stage) - # for some reason update_attributes! doesn't update updated_at + job.update!(stage: stage) + job2.update!(config: config, stage: stage) + # for some reason update! doesn't update updated_at # and it doesn't play well with out triggers (as triggers will update # updated_at and instance variable in tests will have a different value) job.reload @@ -324,7 +324,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v0.17.4' + 'User-Agent'=>'Faraday v1.9.3' }). to_return(status: 200, body: "{}", headers: {}) end @@ -346,7 +346,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v0.17.4' + 'User-Agent'=>'Faraday v1.9.3' }). to_return(status: 200, body: "{}", headers: {}) diff --git a/spec/v3/services/job/restart_spec.rb b/spec/v3/services/job/restart_spec.rb index 4e6299ef25..e1c0b9188a 100644 --- a/spec/v3/services/job/restart_spec.rb +++ b/spec/v3/services/job/restart_spec.rb @@ -300,7 +300,7 @@ before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/job/#{job.id}/restart", {}, headers) } example { expect(last_response.status).to be == 403 } @@ -312,7 +312,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/job/#{job.id}/restart", {}, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/jobs/find_for_current_user_spec.rb b/spec/v3/services/jobs/find_for_current_user_spec.rb index b1c41d6681..24a19dd72c 100644 --- a/spec/v3/services/jobs/find_for_current_user_spec.rb +++ b/spec/v3/services/jobs/find_for_current_user_spec.rb @@ -37,7 +37,7 @@ def create(type, attributes = {}) context "with active jobs" do before do - build1.matrix.first.update_attributes(state: 'started') + build1.matrix.first.update(state: 'started') end it "returns only active jobs when active=true is passed" do diff --git a/spec/v3/services/jobs/find_spec.rb b/spec/v3/services/jobs/find_spec.rb index a0501a0fd0..cfa8845edc 100644 --- a/spec/v3/services/jobs/find_spec.rb +++ b/spec/v3/services/jobs/find_spec.rb @@ -11,8 +11,8 @@ # TODO should this go into the scenario? is it ok to keep it here? test = build.stages.create(number: 1, name: 'test') deploy = build.stages.create(number: 2, name: 'deploy') - jobs[0, 2].each { |job| job.update_attributes!(stage: test) } - jobs[2, 2].each { |job| job.update_attributes!(stage: deploy) } + jobs[0, 2].each { |job| job.update!(stage: test) } + jobs[2, 2].each { |job| job.update!(stage: deploy) } jobs.each(&:reload) end diff --git a/spec/v3/services/key_pair/create_spec.rb b/spec/v3/services/key_pair/create_spec.rb index b0328264e8..7ca26837fb 100644 --- a/spec/v3/services/key_pair/create_spec.rb +++ b/spec/v3/services/key_pair/create_spec.rb @@ -133,7 +133,7 @@ end context 'private repo' do - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } include_examples 'paid' end @@ -146,10 +146,10 @@ context do before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true, pull: true) } - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/key_pair", JSON.generate({}), auth_headers.merge(json_headers)) } example { expect(last_response.status).to be == 403 } @@ -161,7 +161,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/key_pair", JSON.generate({}), auth_headers.merge(json_headers)) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/key_pair/delete_spec.rb b/spec/v3/services/key_pair/delete_spec.rb index 28e652bfd8..2c2a771df8 100644 --- a/spec/v3/services/key_pair/delete_spec.rb +++ b/spec/v3/services/key_pair/delete_spec.rb @@ -24,7 +24,7 @@ describe 'authenticated user with wrong permissions' do before do Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true) - repo.update_attributes(settings: { ssh_key: key_pair, foo: 'bar' }) + repo.update(settings: { ssh_key: key_pair, foo: 'bar' }) delete("/v3/repo/#{repo.id}/key_pair", {}, { 'HTTP_AUTHORIZATION' => "token #{token}" }) end include_examples 'insufficient access to repo', 'delete_key_pair' @@ -49,7 +49,7 @@ describe 'existing repo, deletes key pair' do before do - repo.update_attributes(settings: { ssh_key: key_pair, foo: 'bar' }) + repo.update(settings: { ssh_key: key_pair, foo: 'bar' }) delete("/v3/repo/#{repo.id}/key_pair", {}, auth_headers) end @@ -77,7 +77,7 @@ end context 'private repo' do - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } include_examples 'paid' end @@ -90,10 +90,10 @@ context do before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true, pull: true) } - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { delete("/v3/repo/#{repo.id}/key_pair", {}, auth_headers) } example { expect(last_response.status).to be == 403 } @@ -105,7 +105,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { delete("/v3/repo/#{repo.id}/key_pair", {}, auth_headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/key_pair/find_spec.rb b/spec/v3/services/key_pair/find_spec.rb index 7b89147c79..bee324ecfc 100644 --- a/spec/v3/services/key_pair/find_spec.rb +++ b/spec/v3/services/key_pair/find_spec.rb @@ -40,7 +40,7 @@ describe 'existing repo, existing key pair' do before do Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true) - repo.update_attributes(settings: { ssh_key: key_pair }) + repo.update(settings: { ssh_key: key_pair }) get("/v3/repo/#{repo.id}/key_pair", {}, auth_headers) end @@ -71,7 +71,7 @@ end context 'private repo' do - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } include_examples 'paid' end diff --git a/spec/v3/services/key_pair/update_spec.rb b/spec/v3/services/key_pair/update_spec.rb index 1f8734762b..aceb9f979e 100644 --- a/spec/v3/services/key_pair/update_spec.rb +++ b/spec/v3/services/key_pair/update_spec.rb @@ -170,7 +170,7 @@ end context 'private repo' do - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } include_examples 'paid' end @@ -183,10 +183,10 @@ context do before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true, pull: true) } - before { repo.update_attributes(private: true) } + before { repo.update(private: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { patch("/v3/repo/#{repo.id}/key_pair", JSON.generate({}), auth_headers.merge(json_headers)) } example { expect(last_response.status).to be == 403 } @@ -198,7 +198,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { patch("/v3/repo/#{repo.id}/key_pair", JSON.generate({}), auth_headers.merge(json_headers)) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/leads/create_spec.rb b/spec/v3/services/leads/create_spec.rb deleted file mode 100644 index 1c1c05463b..0000000000 --- a/spec/v3/services/leads/create_spec.rb +++ /dev/null @@ -1,229 +0,0 @@ -describe Travis::API::V3::Services::Leads::Create, set_app: true do - let(:user) { FactoryBot.create(:user) } - let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } - let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} - let(:endpoint) { "/v3/leads" } - let(:parsed_body) { JSON.load(body) } - let(:full_options) {{ - "name" => "Test Name", - "email" => "test@email.example.com", - "team_size" => "123", - "phone" => "+1 123-456-7890", - "message" => "Interested in CI", - "referral_source" => "Custom Source", - "utm_fields" => { - "utm_source" => "Custom UTM source", - "utm_campaign" => "Custom UTM campaign", - "utm_medium" => "Custom UTM medium", - "utm_term" => "Custom UTM term", - "utm_content" => "Custom UTM content" - } - }} - let(:options) { full_options } - let(:expected_lead_data) {{ - "@type" => "leads", - "@representation" => "standard", - "id" => "lead_12345", - "name" => options['name'], - "status_label" => "Potential", - "contacts" => [{ - "display_name" => options['name'], - "name" => options['name'], - "phones" => [{ "type" => "office", "phone" => options['phone'] }], - "emails" => [{ "type" => "office", "email" => options['email'] }] - }], - - "custom" => { - "referral_source" => options['referral_source'], - "team_size" => options['team_size'], - "utm_source" => options['utm_fields']['utm_source'], - "utm_campaign" => options['utm_fields']['utm_campaign'], - "utm_medium" => options['utm_fields']['utm_medium'], - "utm_term" => options['utm_fields']['utm_term'], - "utm_content" => options['utm_fields']['utm_content'] - } - }} - - let(:close_url) { "https://api.close.com/api/v1/" } - let(:close_lead_url) { "#{close_url}lead/" } - let(:stubbed_response_status) { 200 } - let(:stubbed_response_body) { JSON.dump(expected_lead_data) } - let(:stubbed_response_headers) {{ content_type: 'application/json' }} - let!(:stubbed_request) do - stub_request(:post, close_lead_url).to_return( - status: stubbed_response_status, - body: stubbed_response_body, - headers: stubbed_response_headers - ) - end - - let(:close_note_url) { "#{close_url}activity/note/" } - let!(:stubbed_note_request) do - stub_request(:post, close_note_url).to_return( - status: stubbed_response_status, - body: JSON.dump([{ "note" => options['message'] }]), - headers: stubbed_response_headers - ) - end - - let(:close_list_custom_url) { "#{close_url}custom_fields/lead/" } - let!(:stubbed_list_custom_request) do - stub_request(:get, close_list_custom_url).to_return( - status: stubbed_response_status, - body: JSON.dump({ "data" => [ - { "name" => "team_size", "id" => "23456" }, - { "name" => "referral_source", "id" => "34567" }, - ]}), - headers: stubbed_response_headers - ) - end - - subject(:response) { post(endpoint, options, headers) } - - it 'sends a contact request' do - expect(response.status).to eq(200) - response_data = JSON.parse(response.body) - expect(response_data).to eq(expected_lead_data) - end - - context 'when name is missing' do - let(:options) {{ - "email" => full_options['email'], - "team_size" => full_options['team_size'], - "phone" => full_options['phone'], - "message" => full_options['message'], - "referral_source" => full_options['referral_source'] - }} - let(:expected_lead_data) {{ - "@type" => "error", - "error_type" => "wrong_params", - "error_message" => "missing name", - }} - - it 'rejects the request' do - expect(response.status).to eq(400) - response_data = JSON.parse(response.body) - expect(response_data).to eq(expected_lead_data) - expect(stubbed_request).to_not have_been_made - expect(stubbed_note_request).to_not have_been_made - end - end - - context 'when message is missing' do - let(:options) {{ - "name" => full_options['name'], - "email" => full_options['email'], - "team_size" => full_options['team_size'], - "phone" => full_options['phone'], - "referral_source" => full_options['referral_source'] - }} - let(:expected_lead_data) {{ - "@type" => "error", - "error_type" => "wrong_params", - "error_message" => "missing message", - }} - - it 'rejects the request' do - expect(response.status).to eq(400) - response_data = JSON.parse(response.body) - expect(response_data).to eq(expected_lead_data) - expect(stubbed_request).to_not have_been_made - expect(stubbed_note_request).to_not have_been_made - end - end - - context 'when email is missing' do - let(:options) {{ - "name" => full_options['name'], - "team_size" => full_options['team_size'], - "phone" => full_options['phone'], - "message" => full_options['message'], - "referral_source" => full_options['referral_source'] - }} - let(:expected_lead_data) {{ - "@type" => "error", - "error_type" => "wrong_params", - "error_message" => "invalid email", - }} - - it 'rejects the request' do - expect(response.status).to eq(400) - response_data = JSON.parse(response.body) - expect(response_data).to eq(expected_lead_data) - expect(stubbed_request).to_not have_been_made - expect(stubbed_note_request).to_not have_been_made - end - end - - context 'when email is invalid' do - let(:options) {{ - "name" => full_options['name'], - "email" => "incorrect-email", - "team_size" => full_options['team_size'], - "phone" => full_options['phone'], - "message" => full_options['message'], - "referral_source" => full_options['referral_source'] - }} - let(:expected_lead_data) {{ - "@type" => "error", - "error_type" => "wrong_params", - "error_message" => "invalid email", - }} - - it 'rejects the request' do - expect(response.status).to eq(400) - response_data = JSON.parse(response.body) - expect(response_data).to eq(expected_lead_data) - expect(stubbed_request).to_not have_been_made - expect(stubbed_note_request).to_not have_been_made - end - end - - context 'when team_size is string' do - let(:options) {{ - "name" => full_options['name'], - "email" => full_options['email'], - "team_size" => 'invalid team size', - "phone" => full_options['phone'], - "message" => full_options['message'], - "referral_source" => full_options['referral_source'] - }} - let(:expected_lead_data) {{ - "@type" => "error", - "error_type" => "wrong_params", - "error_message" => "invalid team size", - }} - - it 'rejects the request' do - expect(response.status).to eq(400) - response_data = JSON.parse(response.body) - expect(response_data).to eq(expected_lead_data) - expect(stubbed_request).to_not have_been_made - expect(stubbed_note_request).to_not have_been_made - end - end - - context 'when team_size is invalid' do - let(:options) {{ - "name" => full_options['name'], - "email" => full_options['email'], - "team_size" => -5, - "phone" => full_options['phone'], - "message" => full_options['message'], - "referral_source" => full_options['referral_source'] - }} - let(:expected_lead_data) {{ - "@type" => "error", - "error_type" => "wrong_params", - "error_message" => "invalid team size", - }} - - it 'rejects the request' do - expect(response.status).to eq(400) - response_data = JSON.parse(response.body) - expect(response_data).to eq(expected_lead_data) - expect(stubbed_request).to_not have_been_made - expect(stubbed_note_request).to_not have_been_made - end - end -end diff --git a/spec/v3/services/log/delete_spec.rb b/spec/v3/services/log/delete_spec.rb index 77370c23b2..841922aaae 100644 --- a/spec/v3/services/log/delete_spec.rb +++ b/spec/v3/services/log/delete_spec.rb @@ -65,7 +65,7 @@ end describe "missing log, authenticated" do - before { job3.update_attributes(finished_at: Time.now, state: "passed")} + before { job3.update(finished_at: Time.now, state: "passed")} example do stub_request( @@ -83,7 +83,7 @@ end describe "sucessfully delete log" do - before { job.update_attributes(finished_at: Time.now, state: "passed")} + before { job.update(finished_at: Time.now, state: "passed")} let(:remote_log_response) { JSON.dump(job_id: job.id, log_parts: [ diff --git a/spec/v3/services/log/find_spec.rb b/spec/v3/services/log/find_spec.rb index 682e09e50b..1558bb4bf6 100644 --- a/spec/v3/services/log/find_spec.rb +++ b/spec/v3/services/log/find_spec.rb @@ -98,8 +98,8 @@ let(:headers) { {} } describe 'when repo is public' do - before { repo.update_attributes(private: false) } - before { s3log.job.update_attributes(private: false) } + before { repo.update(private: false) } + before { s3log.job.update(private: false) } it 'returns the log' do get("/v3/job/#{s3log.job.id}/log", {}, headers) @@ -130,8 +130,8 @@ end describe 'when repo is private' do - before { repo.update_attributes(private: true) } - before { s3log.job.update_attributes(private: true) } + before { repo.update(private: true) } + before { s3log.job.update(private: true) } it 'returns the text version of the log with log token supplied' do get("/job/#{s3log.job.id}/log", {}, headers.merge('HTTP_AUTHORIZATION' => "token #{token}", 'HTTP_TRAVIS_API_VERSION' => '3')) diff --git a/spec/v3/services/repositories/for_owner_spec.rb b/spec/v3/services/repositories/for_owner_spec.rb index a243d6fa49..14e223b362 100644 --- a/spec/v3/services/repositories/for_owner_spec.rb +++ b/spec/v3/services/repositories/for_owner_spec.rb @@ -22,7 +22,7 @@ let!(:build) { Travis::API::V3::Models::Build.create(repository: repo2, branch_id: branch.id, branch_name: 'other-branch') } before do - branch.update_attributes!(last_build_id: build.id) + branch.update!(last_build_id: build.id) Travis::API::V3::Models::Permission.create(repository: repo2, user: repo2.owner, pull: true) get("/v3/owner/svenfuchs/repos?sort_by=default_branch.last_build:desc&include=repository.default_branch", {}, headers) end diff --git a/spec/v3/services/repository/activate_spec.rb b/spec/v3/services/repository/activate_spec.rb index aa2aafe0c8..4a04e64b14 100644 --- a/spec/v3/services/repository/activate_spec.rb +++ b/spec/v3/services/repository/activate_spec.rb @@ -3,7 +3,7 @@ let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } before do - repo.update_attributes!(active: false) + repo.update!(active: false) @original_sidekiq = Sidekiq::Client Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = [] @@ -267,7 +267,7 @@ before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, admin: true, push: true, pull: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/activate", {}, headers) } example { expect(last_response.status).to be == 403 } @@ -279,7 +279,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/activate", {}, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/repository/deactivate_spec.rb b/spec/v3/services/repository/deactivate_spec.rb index a7479dc285..5cfa365290 100644 --- a/spec/v3/services/repository/deactivate_spec.rb +++ b/spec/v3/services/repository/deactivate_spec.rb @@ -2,7 +2,7 @@ let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } before do - repo.update_attributes!(active: true) + repo.update!(active: true) end describe "not authenticated" do @@ -233,7 +233,7 @@ before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, admin: true, push: true, pull: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/deactivate", {}, headers) } example { expect(last_response.status).to be == 403 } @@ -245,7 +245,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/deactivate", {}, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/repository/migrate_spec.rb b/spec/v3/services/repository/migrate_spec.rb index 7120a2a4ec..e395ffe299 100644 --- a/spec/v3/services/repository/migrate_spec.rb +++ b/spec/v3/services/repository/migrate_spec.rb @@ -23,7 +23,7 @@ end context "when repo is migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/migrate", {}, headers) } example { expect(last_response.status).to be == 403 } @@ -35,7 +35,7 @@ end context "when repo has been migrated" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/migrate", {}, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/repository/star_spec.rb b/spec/v3/services/repository/star_spec.rb index 0658656c67..ebb05e84ec 100644 --- a/spec/v3/services/repository/star_spec.rb +++ b/spec/v3/services/repository/star_spec.rb @@ -79,7 +79,7 @@ before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, admin: true, push: true, pull: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/star", {}, headers) } example { expect(last_response.status).to be == 403 } @@ -91,7 +91,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/star", {}, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/repository/unstar_spec.rb b/spec/v3/services/repository/unstar_spec.rb index 101e9be97f..06c4752208 100644 --- a/spec/v3/services/repository/unstar_spec.rb +++ b/spec/v3/services/repository/unstar_spec.rb @@ -79,7 +79,7 @@ before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, admin: true, push: true, pull: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/unstar", {}, headers) } example { expect(last_response.status).to be == 403 } @@ -91,7 +91,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/unstar", {}, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/repository/update_spec.rb b/spec/v3/services/repository/update_spec.rb index acec9d55f8..d250845e13 100644 --- a/spec/v3/services/repository/update_spec.rb +++ b/spec/v3/services/repository/update_spec.rb @@ -53,7 +53,7 @@ let(:headers) { { 'HTTP_AUTHORIZATION' => "internal app:12345" } } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { patch("/v3/repo/#{repo.id}", { com_id: 1 }, headers) } example { expect(last_response.status).to be == 403 } @@ -65,7 +65,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { patch("/v3/repo/#{repo.id}", { com_id: 1 }, headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/request/find_spec.rb b/spec/v3/services/request/find_spec.rb index 29cb30c743..77a2d9bbda 100644 --- a/spec/v3/services/request/find_spec.rb +++ b/spec/v3/services/request/find_spec.rb @@ -30,7 +30,7 @@ end describe "include config" do - before { request.update_attributes!(config: { language: :ruby }) } + before { request.update!(config: { language: :ruby }) } before { get("/v3/repo/#{repo.id}/request/#{request.id}?include=request.config") } subject { JSON.load(body)['config'] } it { should eq 'language' => 'ruby' } @@ -73,7 +73,7 @@ describe "include yaml config" do subject { JSON.load(body)['yaml_config'] } let(:yaml_config) { Travis::API::V3::Models::RequestYamlConfig.new(key: '123', yaml: 'rvm: 2.5.1') } - before { request.update_attributes!(yaml_config: yaml_config) } + before { request.update!(yaml_config: yaml_config) } before { get("/v3/repo/#{repo.id}/request/#{request.id}?include=request.yaml_config") } it { should eq 'rvm: 2.5.1' } diff --git a/spec/v3/services/request/preview_spec.rb b/spec/v3/services/request/preview_spec.rb index 4b2bc63cb3..84d4b0d896 100644 --- a/spec/v3/services/request/preview_spec.rb +++ b/spec/v3/services/request/preview_spec.rb @@ -16,7 +16,7 @@ } end - before { repo.update_attributes(settings: { env_vars: [env_var] }) } + before { repo.update(settings: { env_vars: [env_var] }) } before { stub_request(:post, 'https://yml.travis-ci.org/configs').to_return(status: 200, body: JSON.dump(configs)) } def parse(str) diff --git a/spec/v3/services/requests/create_spec.rb b/spec/v3/services/requests/create_spec.rb index 601993b6d2..35c277eeec 100644 --- a/spec/v3/services/requests/create_spec.rb +++ b/spec/v3/services/requests/create_spec.rb @@ -265,7 +265,7 @@ def compact(hash) end describe 'when the repository is inactive' do - before { repo.update_attributes!(active: false) } + before { repo.update!(active: false) } before { post("/v3/repo/#{repo.id}/requests", {}, headers) } it { expect(last_response.status).to be == 406 } @@ -329,7 +329,7 @@ def compact(hash) before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } describe 'repo migrating' do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/requests", {}, headers) } it { expect(last_response.status).to be == 403 } @@ -337,7 +337,7 @@ def compact(hash) end describe 'repo migrating' do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/deactivate", {}, headers) } it { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/ssl_key/create_spec.rb b/spec/v3/services/ssl_key/create_spec.rb index c228fac1cb..2429e8e0db 100644 --- a/spec/v3/services/ssl_key/create_spec.rb +++ b/spec/v3/services/ssl_key/create_spec.rb @@ -66,7 +66,7 @@ before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/key_pair/generated", {}, auth_headers) } example { expect(last_response.status).to be == 403 } @@ -78,7 +78,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrated") } + before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/key_pair/generated", {}, auth_headers) } example { expect(last_response.status).to be == 403 } diff --git a/spec/v3/services/stages/find_spec.rb b/spec/v3/services/stages/find_spec.rb index 638aaf5d3c..42ba15af64 100644 --- a/spec/v3/services/stages/find_spec.rb +++ b/spec/v3/services/stages/find_spec.rb @@ -10,8 +10,8 @@ # TODO should this go into the scenario? is it ok to keep it here? test = build.stages.create(number: 1, name: 'test') deploy = build.stages.create(number: 2, name: 'deploy') - jobs[0, 2].each { |job| job.update_attributes!(stage: test) } - jobs[2, 2].each { |job| job.update_attributes!(stage: deploy) } + jobs[0, 2].each { |job| job.update!(stage: test) } + jobs[2, 2].each { |job| job.update!(stage: deploy) } end describe "stages on public repository" do diff --git a/spec/v3/services/user_setting/find_spec.rb b/spec/v3/services/user_setting/find_spec.rb index a8b75b7053..c2086ccc36 100644 --- a/spec/v3/services/user_setting/find_spec.rb +++ b/spec/v3/services/user_setting/find_spec.rb @@ -14,7 +14,7 @@ let(:other_token) { Travis::Api::App::AccessToken.create(user: other_user, app_id: 1) } before do - repo.update_attributes(private: true) + repo.update(private: true) get("/v3/repo/#{repo.id}/setting/build_pushes", {}, { 'HTTP_AUTHORIZATION' => "token #{other_token}" }) end @@ -61,7 +61,7 @@ describe 'authenticated, existing repo, setting found' do before do - repo.update_attributes(settings: { 'build_pushes' => false }) + repo.update(settings: { 'build_pushes' => false }) get("/v3/repo/#{repo.id}/setting/build_pushes", {}, auth_headers) end diff --git a/spec/v3/services/user_setting/update_spec.rb b/spec/v3/services/user_setting/update_spec.rb index 118fd287cb..d4e2c127a2 100644 --- a/spec/v3/services/user_setting/update_spec.rb +++ b/spec/v3/services/user_setting/update_spec.rb @@ -109,7 +109,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { patch("/v3/repo/#{repo.id}/setting/build_pushes", new_params, json_headers.merge(auth_headers)) } @@ -123,7 +123,7 @@ end describe "repo migrating" do - before { repo.update_attributes(migration_status: "migrating") } + before { repo.update(migration_status: "migrating") } before { patch("/v3/repo/#{repo.id}/setting/build_pushes", new_params, json_headers.merge(auth_headers)) } diff --git a/spec/v3/services/user_settings/for_repository_spec.rb b/spec/v3/services/user_settings/for_repository_spec.rb index a8479e42ed..ae34bd0d79 100644 --- a/spec/v3/services/user_settings/for_repository_spec.rb +++ b/spec/v3/services/user_settings/for_repository_spec.rb @@ -57,7 +57,7 @@ end describe 'a private repo' do - before { repo.update_attributes!(private: true) } + before { repo.update!(private: true) } before { get("/v3/repo/#{repo.id}/settings", {}, auth_headers) } example do @@ -70,7 +70,7 @@ describe 'authenticated, existing repo, repo has some settings' do before do - repo.update_attributes(settings: { 'build_pushes' => false }) + repo.update(settings: { 'build_pushes' => false }) get("/v3/repo/#{repo.id}/settings", {}, auth_headers) end @@ -97,7 +97,7 @@ describe 'authenticated, existing repo, update one setting' do before do - repo.update_attributes(settings: { 'build_pushes' => true }) + repo.update(settings: { 'build_pushes' => true }) patch("/v3/repo/#{repo.id}/setting/build_pushes", JSON.dump('setting.value' => false), json_headers.merge(auth_headers)) get("/v3/repo/#{repo.id}/setting/build_pushes", {}, auth_headers) end From 41af8871212ddde4eca36ffd52e767c8bc71cfd2 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Tue, 17 May 2022 13:48:02 +0200 Subject: [PATCH 14/46] removed trivy --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 378bf2d88f..8c6814bfaf 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,6 @@ docker-push-latest-master: docker-push-branch: $(DOCKER) tag $(DOCKER_DEST) $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) $(DOCKER) push $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) - $(DOCKER) run --rm -v /tmp:/root/.cache/ -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy --ignore-unfixed $(QUAY_IMAGE):$(VERSION_VALUE)-$(BRANCH) .PHONY: ship ship: docker-build docker-login From 6e817ccfb25f3fafe9de24bcbd56c59dbb141706 Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Tue, 17 May 2022 15:33:14 +0200 Subject: [PATCH 15/46] gem updates (#1237) --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5ffba8cd80..4d6f2bd5e5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -303,7 +303,7 @@ GEM nakayoshi_fork (0.0.4) net-http-persistent (2.9.4) net-http-pipeline (1.0.1) - nokogiri (1.13.3) + nokogiri (1.13.6) mini_portile2 (~> 2.8.0) racc (~> 1.4) opencensus (0.5.0) @@ -525,4 +525,4 @@ RUBY VERSION ruby 2.7.5p203 BUNDLED WITH - 2.3.6 + 2.3.7 From d8b682fffc47c1db238d4847f6225c3d38a82d33 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Wed, 1 Jun 2022 15:33:30 +0200 Subject: [PATCH 16/46] w/a: removed set_tags call for raven, todo - migrate to new api' --- lib/travis/api/app.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/travis/api/app.rb b/lib/travis/api/app.rb index 3afd26c0cc..cba3ef9eaf 100644 --- a/lib/travis/api/app.rb +++ b/lib/travis/api/app.rb @@ -117,7 +117,7 @@ def initialize(options = {}) if Travis::Api::App.use_monitoring? use Rack::Config do |env| if env['HTTP_X_REQUEST_ID'] - Raven.set_tags(request_id: env['HTTP_X_REQUEST_ID']) + #Raven.set_tags(request_id: env['HTTP_X_REQUEST_ID']) end end use Raven::Rack From eaefc8a87739eb750ccec33928d0c27db3d6fd08 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Wed, 8 Jun 2022 11:13:27 +0200 Subject: [PATCH 17/46] rack update -> 2.2.3.1 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4d6f2bd5e5..6bcb57e84f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -329,7 +329,7 @@ GEM pusher-signature (~> 0.1.8) pusher-signature (0.1.8) racc (1.6.0) - rack (2.2.3) + rack (2.2.3.1) rack-attack (5.4.2) rack (>= 1.0, < 3) rack-contrib (2.3.0) From c12eb153d8cc861b6d1d6cb5b225e20dfbed8280 Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Tue, 14 Jun 2022 10:21:52 +0200 Subject: [PATCH 18/46] job query optimization ship:docker (#1240) --- lib/travis/api/v3/queries/jobs.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/travis/api/v3/queries/jobs.rb b/lib/travis/api/v3/queries/jobs.rb index e018987c27..b00f8b2951 100644 --- a/lib/travis/api/v3/queries/jobs.rb +++ b/lib/travis/api/v3/queries/jobs.rb @@ -34,7 +34,14 @@ def for_owner(relation) def for_user(user) set_custom_timeout(host_timeout) - jobs = V3::Models::Job.where("jobs.id in (select id from most_recent_job_ids_for_user_repositories_by_states(#{user.id}, ?))", states) + if ENV['TCIE_BETA_MOST_RECENT_JOBS_LW'] == 'true' + puts "USING LW JOBS!!\n\n" + jobs = V3::Models::Job.where("jobs.id in (select id from most_recent_job_ids_for_user_repositories_by_states_lw(#{user.id}, ?))", states) + else + puts "USING REGULAR JOBS!!!\n\n" + jobs = V3::Models::Job.where("jobs.id in (select id from most_recent_job_ids_for_user_repositories_by_states(#{user.id}, ?))", states) + end + puts jobs.inspect sort filter(jobs) end From 8d8d693e71a18c2c490df84a3c35c1319b0d94eb Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Wed, 29 Jun 2022 11:22:47 +0200 Subject: [PATCH 19/46] console fix after pry update --- script/console | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/console b/script/console index 474dc883ca..ea0ec352fb 100755 --- a/script/console +++ b/script/console @@ -29,7 +29,7 @@ methods = Travis::Console.instance_methods - Object.instance_methods if $stdin.tty? require 'pry' - console.pry(quiet: true, prompt: Pry::SIMPLE_PROMPT) + console.pry(quiet: true, prompt: Pry::Prompt[:simple]) else console.instance_eval $stdin.read end From 978635fbcb31155362d3e2aedf1233755d5fe8e0 Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Fri, 26 Aug 2022 11:32:05 +0200 Subject: [PATCH 20/46] gem updates + extended access rights for tokens (#1246) * github_apps update * activerecord bump to 6.1.6.1 * permit symbol in yaml deserializer for debug --- Gemfile | 4 +- Gemfile.lock | 41 ++++++++++--------- .../active_record/predicate_builder.rb | 4 +- lib/travis/api/v3/services/job/debug.rb | 4 ++ spec/v3/services/build/find_spec.rb | 4 +- spec/v3/services/job/find_spec.rb | 4 +- 6 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Gemfile b/Gemfile index b41962778e..1fa0b7428b 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,7 @@ gem 'travis-amqp', git: 'https://github.com/travis-ci/travis-amqp' gem 'travis-config', git: 'https://github.com/travis-ci/travis-config', branch: 'fix-docker-redis-url' gem 'travis-settings', git: 'https://github.com/travis-ci/travis-settings' gem 'travis-lock', git: 'https://github.com/travis-ci/travis-lock/', branch: '6.1' -gem 'travis-github_apps', git: 'https://github.com/travis-ci/travis-github_apps' +gem 'travis-github_apps', git: 'https://github.com/travis-ci/travis-github_apps', branch: 'ga-ext_access' gem 'travis-rollout', '~> 0.0.2' gem 'sinatra' @@ -65,7 +65,7 @@ gem 'tool' gem 'google-api-client', '~> 0.9.4' gem 'fog-aws', '~> 0.12.0' gem 'fog-google', '~> 0.4.2' -gem 'activerecord', '~> 6.1.4.5' +gem 'activerecord', '~> 6.1.6.1' gem 'rollout', '~> 1.1.0' gem 'coder', '~> 0.4.0' gem 'virtus', '~> 1.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 6bcb57e84f..e331e1d71f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -43,11 +43,11 @@ GIT GIT remote: https://github.com/travis-ci/simple_states - revision: 68e3087763e5e345c0949268169cb0f74a54ef6a + revision: b7dffc715181e54313784b315f6b7df795d01db4 branch: 6.1 specs: simple_states (1.0.2) - activesupport (~> 6.1.4.5) + activesupport (~> 6.1.6.1) GIT remote: https://github.com/travis-ci/travis-amqp @@ -65,7 +65,8 @@ GIT GIT remote: https://github.com/travis-ci/travis-github_apps - revision: c96dc9330849ff3e2ccd7c9d00005a1a96c1a4b6 + revision: 929dadf0b4f60ca4240d52a11fc032917ff3f83a + branch: ga-ext_access specs: travis-github_apps (0.2.1) activesupport (>= 3.2) @@ -102,12 +103,12 @@ GEM active_model_serializers (0.9.8) activemodel (>= 3.2) concurrent-ruby (~> 1.0) - activemodel (6.1.4.6) - activesupport (= 6.1.4.6) - activerecord (6.1.4.6) - activemodel (= 6.1.4.6) - activesupport (= 6.1.4.6) - activesupport (6.1.4.6) + activemodel (6.1.6.1) + activesupport (= 6.1.6.1) + activerecord (6.1.6.1) + activemodel (= 6.1.6.1) + activesupport (= 6.1.6.1) + activesupport (6.1.6.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -134,7 +135,7 @@ GEM descendants_tracker (~> 0.0.1) composite_primary_keys (13.0.3) activerecord (~> 6.1.0) - concurrent-ruby (1.1.9) + concurrent-ruby (1.1.10) connection_pool (2.2.5) crack (0.4.5) rexml @@ -155,7 +156,7 @@ GEM excon (0.91.0) factory_bot (6.2.0) activesupport (>= 5.0.0) - faraday (1.9.3) + faraday (1.10.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -171,8 +172,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.3) - multipart-post (>= 1.2, < 3) + faraday-multipart (1.0.4) + multipart-post (~> 2) faraday-net_http (1.0.1) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) @@ -262,11 +263,11 @@ GEM ffi-compiler (>= 1.0, < 2.0) httpclient (2.8.3) hurley (0.2) - i18n (1.10.0) + i18n (1.12.0) concurrent-ruby (~> 1.0) ice_nine (0.11.2) ipaddress (0.8.3) - jwt (2.3.0) + jwt (2.4.1) kgio (2.11.4) knapsack (4.0.0) rake @@ -293,11 +294,11 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2022.0105) mini_portile2 (2.8.0) - minitest (5.15.0) + minitest (5.16.3) mocha (1.13.0) msgpack (1.4.5) multi_json (1.15.0) - multipart-post (2.1.1) + multipart-post (2.2.3) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) nakayoshi_fork (0.0.4) @@ -414,7 +415,7 @@ GEM timecop (0.9.4) tool (0.2.3) travis-rollout (0.0.2) - tzinfo (2.0.4) + tzinfo (2.0.5) concurrent-ruby (~> 1.0) uber (0.0.15) unf (0.1.4) @@ -436,14 +437,14 @@ GEM webrick (1.7.0) yard (0.9.27) webrick (~> 1.7.0) - zeitwerk (2.5.4) + zeitwerk (2.6.0) PLATFORMS ruby DEPENDENCIES active_model_serializers (~> 0.9.8) - activerecord (~> 6.1.4.5) + activerecord (~> 6.1.6.1) addressable (~> 2.8.0) allocation_tracer bunny (~> 2.9.2) diff --git a/lib/patches/active_record/predicate_builder.rb b/lib/patches/active_record/predicate_builder.rb index 91da25af3b..134a213a6b 100644 --- a/lib/patches/active_record/predicate_builder.rb +++ b/lib/patches/active_record/predicate_builder.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -EXPECTED_AR_VERSION = '6.1.4.6'.freeze +EXPECTED_AR_VERSION = '6.1.6.1'.freeze ACTUAL_AR_VERSION = "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}.#{ActiveRecord::VERSION::TINY}.#{ActiveRecord::VERSION::PRE}" if EXPECTED_AR_VERSION != ACTUAL_AR_VERSION @@ -176,4 +176,4 @@ def handler_for(object) @handlers.detect { |klass, _| klass === object }.last end end -end \ No newline at end of file +end diff --git a/lib/travis/api/v3/services/job/debug.rb b/lib/travis/api/v3/services/job/debug.rb index 66f1f5ca24..6c2fb893c6 100644 --- a/lib/travis/api/v3/services/job/debug.rb +++ b/lib/travis/api/v3/services/job/debug.rb @@ -5,6 +5,10 @@ class Services::Job::Debug < Service attr_reader :job def run + if ActiveRecord::Base.respond_to?(:yaml_column_permitted_classes) + ActiveRecord::Base.yaml_column_permitted_classes |= [Symbol] + end + @job = check_login_and_find(:job) raise WrongCredentials unless job.repository.debug_tools_enabled? diff --git a/spec/v3/services/build/find_spec.rb b/spec/v3/services/build/find_spec.rb index 120723376b..6000c02d0d 100644 --- a/spec/v3/services/build/find_spec.rb +++ b/spec/v3/services/build/find_spec.rb @@ -389,7 +389,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v1.9.3' + 'User-Agent'=>'Faraday v1.10.0' }). to_return(status: 200, body: "{}", headers: {}) end @@ -413,7 +413,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v1.9.3' + 'User-Agent'=>'Faraday v1.10.0' }). to_return(status: 200, body: "{}", headers: {}) end diff --git a/spec/v3/services/job/find_spec.rb b/spec/v3/services/job/find_spec.rb index f572403447..a08d7e717a 100644 --- a/spec/v3/services/job/find_spec.rb +++ b/spec/v3/services/job/find_spec.rb @@ -324,7 +324,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v1.9.3' + 'User-Agent'=>'Faraday v1.10.0' }). to_return(status: 200, body: "{}", headers: {}) end @@ -346,7 +346,7 @@ 'Authorization'=>'token notset', 'Connection'=>'keep-alive', 'Keep-Alive'=>'30', - 'User-Agent'=>'Faraday v1.9.3' + 'User-Agent'=>'Faraday v1.10.0' }). to_return(status: 200, body: "{}", headers: {}) From e036f1b63d5e48bf75e238e9795f3d106f20457d Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Wed, 7 Sep 2022 14:23:08 +0200 Subject: [PATCH 21/46] restarted_by feature - merge from master (#1248) * BSFY-141 merge - add restarted by --- lib/travis/api/app/endpoint/builds.rb | 2 +- lib/travis/api/app/endpoint/jobs.rb | 2 +- .../api/app/extensions/smart_constants.rb | 2 +- lib/travis/api/v3/models/job.rb | 5 ++++ lib/travis/api/v3/queries/build.rb | 2 +- lib/travis/api/v3/queries/builds.rb | 2 +- lib/travis/api/v3/queries/job.rb | 2 +- lib/travis/api/v3/renderer/job.rb | 14 +++++++++-- spec/v3/services/job/find_spec.rb | 6 +++++ spec/v3/services/jobs/find_spec.rb | 24 +++++++++++++++++++ 10 files changed, 53 insertions(+), 8 deletions(-) diff --git a/lib/travis/api/app/endpoint/builds.rb b/lib/travis/api/app/endpoint/builds.rb index 423b6c298f..6f573d5a2e 100644 --- a/lib/travis/api/app/endpoint/builds.rb +++ b/lib/travis/api/app/endpoint/builds.rb @@ -60,7 +60,7 @@ class Builds < Endpoint status 400 false else - payload = { id: params[:id], user_id: current_user.id } + payload = { id: params[:id], user_id: current_user.id, restarted_by: current_user.id } service.push("build:restart", payload) status 202 true diff --git a/lib/travis/api/app/endpoint/jobs.rb b/lib/travis/api/app/endpoint/jobs.rb index 4b58820377..a5a4efc925 100644 --- a/lib/travis/api/app/endpoint/jobs.rb +++ b/lib/travis/api/app/endpoint/jobs.rb @@ -68,7 +68,7 @@ class Jobs < Endpoint status 400 false else - payload = {id: params[:id], user_id: current_user.id} + payload = {id: params[:id], user_id: current_user.id, restarted_by: current_user.id} service.push("job:restart", payload) status 202 true diff --git a/lib/travis/api/app/extensions/smart_constants.rb b/lib/travis/api/app/extensions/smart_constants.rb index f4a9dd74f4..e4991d2dc2 100644 --- a/lib/travis/api/app/extensions/smart_constants.rb +++ b/lib/travis/api/app/extensions/smart_constants.rb @@ -15,7 +15,7 @@ def helpers(*list, &block) end def register(*list, &block) - super(*resolve_constants(list, Extensions), &block) + super(*resolve_constants(list, Extensions), &block) end private diff --git a/lib/travis/api/v3/models/job.rb b/lib/travis/api/v3/models/job.rb index 26b96676fb..716be30b3c 100644 --- a/lib/travis/api/v3/models/job.rb +++ b/lib/travis/api/v3/models/job.rb @@ -1,4 +1,5 @@ require 'travis/config/defaults' +require 'travis/api/v3/models/user' module Travis::API::V3 class Models::JobConfig < Model @@ -66,6 +67,10 @@ def migrated? !!org_id end + def restarter + @restarter ||= Travis::API::V3::Models::User.find(restarted_by) if restarted_by + end + private def enterprise? !!Travis.config.enterprise end diff --git a/lib/travis/api/v3/queries/build.rb b/lib/travis/api/v3/queries/build.rb index b0b7a98425..3ae579e044 100644 --- a/lib/travis/api/v3/queries/build.rb +++ b/lib/travis/api/v3/queries/build.rb @@ -25,7 +25,7 @@ def restart(user) raise BuildAlreadyRunning if %w(received queued started).include? find.state service = Travis::Enqueue::Services::RestartModel.new(user, { build_id: id }) - payload = { id: id, user_id: user.id } + payload = { id: id, user_id: user.id, restarted_by: user.id } restart_status = service.push("build:restart", payload) diff --git a/lib/travis/api/v3/queries/builds.rb b/lib/travis/api/v3/queries/builds.rb index 98fac498e5..f776ccb830 100644 --- a/lib/travis/api/v3/queries/builds.rb +++ b/lib/travis/api/v3/queries/builds.rb @@ -4,7 +4,7 @@ class Queries::Builds < Query params :name, prefix: :branch, method_name: :branch_name sortable_by :id, :created_at, :started_at, :finished_at, - number: "number::int %{order}" + number: "number::int %{order}" default_sort "number:desc,id:desc" def find(repository) diff --git a/lib/travis/api/v3/queries/job.rb b/lib/travis/api/v3/queries/job.rb index ad841d5dae..631d96fde6 100644 --- a/lib/travis/api/v3/queries/job.rb +++ b/lib/travis/api/v3/queries/job.rb @@ -23,7 +23,7 @@ def restart(user) raise JobAlreadyRunning if %w(received queued started).include? find.state service = Travis::Enqueue::Services::RestartModel.new(user, { job_id: id }) - payload = { id: id, user_id: user.id } + payload = { id: id, user_id: user.id, restarted_by: user.id } restart_status = service.push("job:restart", payload) diff --git a/lib/travis/api/v3/renderer/job.rb b/lib/travis/api/v3/renderer/job.rb index f4ca4b0b9f..fbd5ace1b5 100644 --- a/lib/travis/api/v3/renderer/job.rb +++ b/lib/travis/api/v3/renderer/job.rb @@ -3,13 +3,13 @@ module Travis::API::V3 class Renderer::Job < ModelRenderer representation(:minimal, :id) - representation(:standard, *representations[:minimal], :allow_failure, :number, :state, :started_at, :finished_at, :build, :queue, :repository, :commit, :owner, :stage, :created_at, :updated_at, :private) + representation(:standard, *representations[:minimal], :allow_failure, :number, :state, :started_at, :finished_at, :build, :queue, :repository, :commit, :owner, :stage, :created_at, :updated_at, :private, :restarted_at, :restarted_by) representation(:active, *representations[:standard]) # TODO: I don't want to config be visible in the regular representation # as I want it to be visible only after adding include=job.config # we probably need to have a better way of doing this - representation(:with_config, *representations[:minimal], :allow_failure, :number, :state, :started_at, :finished_at, :build, :queue, :repository, :commit, :owner, :stage, :created_at, :updated_at, :config) + representation(:with_config, *representations[:minimal], :allow_failure, :number, :state, :started_at, :finished_at, :build, :queue, :repository, :commit, :owner, :stage, :created_at, :updated_at, :restarted_at, :restarted_by, :config) hidden_representations(:with_config) hidden_representations(:active) @@ -26,6 +26,16 @@ def updated_at json_format_time_with_ms(model.updated_at) end + def restarted_by + return nil unless restarter = model.restarter + { + '@type' => 'user', + '@representation' => 'minimal'.freeze, + 'id' => restarter.id, + 'login' => restarter.login + } + end + def config if include_config? ConfigObfuscator.new(model.config, model.repository.key).obfuscate diff --git a/spec/v3/services/job/find_spec.rb b/spec/v3/services/job/find_spec.rb index a08d7e717a..bb793207a0 100644 --- a/spec/v3/services/job/find_spec.rb +++ b/spec/v3/services/job/find_spec.rb @@ -60,6 +60,8 @@ "created_at" => json_format_time_with_ms(job.created_at), "updated_at" => json_format_time_with_ms(job.updated_at), "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "build" => { "@type" => "build", "@href" => "/v3/build/#{build.id}", @@ -175,6 +177,8 @@ "created_at" => json_format_time_with_ms(job.created_at), "updated_at" => json_format_time_with_ms(job.updated_at), "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "build" => { "@type" => "build", "@href" => "/v3/build/#{build.id}", @@ -252,6 +256,8 @@ "created_at" => json_format_time_with_ms(job2.created_at), "updated_at" => json_format_time_with_ms(job2.updated_at), "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "build" => { "@type" => "build", "@href" => "/v3/build/#{build.id}", diff --git a/spec/v3/services/jobs/find_spec.rb b/spec/v3/services/jobs/find_spec.rb index cfa8845edc..6cc364b6d1 100644 --- a/spec/v3/services/jobs/find_spec.rb +++ b/spec/v3/services/jobs/find_spec.rb @@ -36,6 +36,8 @@ "prioritize" => false }, "id" => jobs[0].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[0].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -111,6 +113,8 @@ "prioritize" => false}, "id" => jobs[1].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[1].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -186,6 +190,8 @@ "prioritize" => false}, "id" => jobs[2].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[2].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -261,6 +267,8 @@ "prioritize" => false}, "id" => jobs[3].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[3].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -354,6 +362,8 @@ "prioritize" => false }, "id" => jobs[0].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[0].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -429,6 +439,8 @@ "prioritize" => false }, "id" => jobs[1].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[1].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -504,6 +516,8 @@ "prioritize" => false }, "id" => jobs[2].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[2].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -579,6 +593,8 @@ "prioritize" => false }, "id" => jobs[3].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[3].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -675,6 +691,8 @@ "prioritize" => true }, "id" => jobs[0].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[0].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -750,6 +768,8 @@ "prioritize" => true }, "id" => jobs[1].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[1].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -825,6 +845,8 @@ "prioritize" => true }, "id" => jobs[2].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[2].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", @@ -900,6 +922,8 @@ "prioritize" => true }, "id" => jobs[3].id, "private" => false, + "restarted_at" => nil, + "restarted_by" => nil, "number" => "#{jobs[3].number}", "state" => "configured", "started_at" => "2010-11-12T13:00:00Z", From 0bd55667ab10dfb7b288efc310da4e81fd1ecc15 Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Wed, 5 Oct 2022 14:09:01 +0200 Subject: [PATCH 22/46] putting api on a diet (ship:docker) (#1250) --- Dockerfile | 38 +++++++++++++++++++------------------- Makefile | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6cb858bb73..a6350f3ff9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,33 +2,33 @@ FROM ruby:2.7.5-slim LABEL maintainer Travis CI GmbH -# packages required for bundle install +RUN ( \ + bundle config set no-cache 'true'; \ + bundle config --global frozen 1; \ + bundle config set deployment 'true'; \ + mkdir -p /app; \ +) + +WORKDIR /app + +COPY Gemfile* /app/ + RUN ( \ apt-get update ; \ - # update to deb 10.8 apt-get upgrade -y ; \ apt-get install -y --no-install-recommends git make gcc g++ libpq-dev libjemalloc-dev \ && rm -rf /var/lib/apt/lists/* \ + gem install bundler -v '2.3.6'; \ + bundle config set without 'development test'; \ + bundler install --verbose --retry=3; \ + bundle config set frozen true; \ + apt-get remove -y gcc g++ make git perl && apt-get -y autoremove; \ + bundle clean && rm -rf /app/vendor/bundle/ruby/2.7.0/cache/*; \ + for i in `find /app/vendor/ -name \*.o -o -name \*.c -o -name \*.h`; do rm -f $i; done; \ ) ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 -# throw errors if Gemfile has been modified since Gemfile.lock -RUN bundle config --global frozen 1 -RUN bundle config set deployment 'true' - -RUN mkdir -p /app -WORKDIR /app - -COPY Gemfile /app -COPY Gemfile.lock /app - -RUN gem install bundler -v '2.3.6' -RUN bundle config set without 'development test' -RUN bundler install --verbose --retry=3 -RUN gem install --user-install executable-hooks - COPY . /app -RUN bundle config set frozen true -CMD ./script/server-buildpacks +CMD ["./script/server-buildpacks"] diff --git a/Makefile b/Makefile index 8c6814bfaf..2ba2048f5d 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ DOCKER ?= docker .PHONY: docker-build docker-build: - $(DOCKER) build -t $(DOCKER_DEST) . + $(DOCKER) build --no-cache --pull -t $(DOCKER_DEST) . .PHONY: docker-login docker-login: From ef4b8f87797521d8ca75b9e6450a45a3d093f200 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Fri, 14 Oct 2022 09:41:04 +0200 Subject: [PATCH 23/46] bump google-protobuf to 3.19.6 --- Gemfile | 1 + Gemfile.lock | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 1fa0b7428b..9620afa0a5 100644 --- a/Gemfile +++ b/Gemfile @@ -63,6 +63,7 @@ gem 'memcachier' gem 'useragent' gem 'tool' gem 'google-api-client', '~> 0.9.4' +gem 'google-protobuf', '~> 3.19.6' gem 'fog-aws', '~> 0.12.0' gem 'fog-google', '~> 0.4.2' gem 'activerecord', '~> 6.1.6.1' diff --git a/Gemfile.lock b/Gemfile.lock index e331e1d71f..cf64baa08c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -231,7 +231,7 @@ GEM google-cloud-trace-v2 (0.3.5) gapic-common (>= 0.7, < 2.a) google-cloud-errors (~> 1.0) - google-protobuf (3.19.4) + google-protobuf (3.19.6) googleapis-common-protos (1.3.12) google-protobuf (~> 3.14) googleapis-common-protos-types (~> 1.2) @@ -460,6 +460,7 @@ DEPENDENCIES foreman gh! google-api-client (~> 0.9.4) + google-protobuf (~> 3.19.6) hashdiff hashr http (~> 4) From a6be27093c98b6a9fc791b45b1f2fe91c7496682 Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Wed, 14 Dec 2022 15:24:45 +0100 Subject: [PATCH 24/46] merge from master (#1260) * bundler update * merge from master 31.10.22 * usr/group update * ship:docker --- .travis.yml | 2 - Dockerfile | 28 +- Gemfile.lock | 2 +- README.md | 2 + lib/travis.rb | 2 + lib/travis/api/app/endpoint.rb | 1 + lib/travis/api/app/endpoint/authorization.rb | 38 +- lib/travis/api/app/endpoint/build_backups.rb | 18 + lib/travis/api/app/endpoint/env_vars.rb | 1 + lib/travis/api/app/endpoint/jobs.rb | 11 +- lib/travis/api/app/endpoint/logs.rb | 15 +- .../api/enqueue/services/restart_model.rb | 109 ++++- lib/travis/api/serialize/serializer.rb | 1 + lib/travis/api/v3.rb | 2 + lib/travis/api/v3/access_control/log_token.rb | 3 +- lib/travis/api/v3/billing_client.rb | 160 +++++++- lib/travis/api/v3/log_token.rb | 15 +- lib/travis/api/v3/model.rb | 5 + lib/travis/api/v3/models/allowance.rb | 16 + lib/travis/api/v3/models/audit.rb | 6 + lib/travis/api/v3/models/auto_refill.rb | 13 + lib/travis/api/v3/models/build_backup.rb | 7 + lib/travis/api/v3/models/build_permission.rb | 11 + .../v3/models/credits_calculator_config.rb | 11 + lib/travis/api/v3/models/credits_result.rb | 11 + lib/travis/api/v3/models/env_var.rb | 2 +- lib/travis/api/v3/models/executions.rb | 43 ++ lib/travis/api/v3/models/invoice.rb | 4 +- lib/travis/api/v3/models/json_slice.rb | 11 +- lib/travis/api/v3/models/json_sync.rb | 2 +- lib/travis/api/v3/models/leads.rb | 13 - lib/travis/api/v3/models/log.rb | 4 + .../api/v3/models/organization_preferences.rb | 2 + lib/travis/api/v3/models/subscription.rb | 3 +- lib/travis/api/v3/models/user_preferences.rb | 2 + lib/travis/api/v3/models/user_settings.rb | 30 ++ lib/travis/api/v3/models/v2_addon.rb | 13 + lib/travis/api/v3/models/v2_addon_usage.rb | 17 + lib/travis/api/v3/models/v2_plan_config.rb | 25 ++ lib/travis/api/v3/models/v2_subscription.rb | 67 ++++ lib/travis/api/v3/queries/allowance.rb | 16 + lib/travis/api/v3/queries/build.rb | 8 +- lib/travis/api/v3/queries/build_backup.rb | 21 + lib/travis/api/v3/queries/build_backups.rb | 10 + .../api/v3/queries/build_permissions.rb | 19 + .../api/v3/queries/credits_calculator.rb | 15 + lib/travis/api/v3/queries/executions.rb | 15 + lib/travis/api/v3/queries/job.rb | 8 +- lib/travis/api/v3/queries/subscriptions.rb | 2 +- lib/travis/api/v3/queries/user_setting.rb | 7 +- lib/travis/api/v3/queries/v2_addon_usages.rb | 10 + lib/travis/api/v3/queries/v2_invoices.rb | 8 + lib/travis/api/v3/queries/v2_plans.rb | 12 + lib/travis/api/v3/queries/v2_subscription.rb | 64 +++ lib/travis/api/v3/queries/v2_subscriptions.rb | 25 ++ lib/travis/api/v3/remote_query.rb | 9 +- lib/travis/api/v3/renderer/allowance.rb | 6 + lib/travis/api/v3/renderer/auto_refill.rb | 6 + lib/travis/api/v3/renderer/build_backup.rb | 12 + lib/travis/api/v3/renderer/build_backups.rb | 6 + .../api/v3/renderer/build_permission.rb | 19 + .../api/v3/renderer/build_permissions.rb | 11 + .../v3/renderer/credits_calculator_config.rb | 5 + lib/travis/api/v3/renderer/credits_result.rb | 5 + lib/travis/api/v3/renderer/credits_results.rb | 6 + lib/travis/api/v3/renderer/execution.rb | 8 + .../api/v3/renderer/execution_per_repo.rb | 6 + .../api/v3/renderer/execution_per_sender.rb | 6 + lib/travis/api/v3/renderer/executions.rb | 6 + .../api/v3/renderer/executions_per_repo.rb | 6 + .../api/v3/renderer/executions_per_sender.rb | 6 + lib/travis/api/v3/renderer/invoice.rb | 2 +- lib/travis/api/v3/renderer/leads.rb | 5 - lib/travis/api/v3/renderer/log.rb | 4 +- lib/travis/api/v3/renderer/owner.rb | 22 +- lib/travis/api/v3/renderer/repository.rb | 18 +- lib/travis/api/v3/renderer/subscription.rb | 2 +- lib/travis/api/v3/renderer/user.rb | 16 +- lib/travis/api/v3/renderer/v2_addon.rb | 10 + lib/travis/api/v3/renderer/v2_addon_config.rb | 6 + lib/travis/api/v3/renderer/v2_addon_usage.rb | 6 + lib/travis/api/v3/renderer/v2_addon_usages.rb | 6 + lib/travis/api/v3/renderer/v2_plan_config.rb | 8 + lib/travis/api/v3/renderer/v2_plans.rb | 6 + lib/travis/api/v3/renderer/v2_subscription.rb | 29 ++ .../api/v3/renderer/v2_subscriptions.rb | 22 + lib/travis/api/v3/routes.rb | 80 +++- lib/travis/api/v3/service.rb | 4 + lib/travis/api/v3/services.rb | 10 +- .../api/v3/services/allowance/for_owner.rb | 15 + lib/travis/api/v3/services/build/cancel.rb | 2 + lib/travis/api/v3/services/build/restart.rb | 10 +- .../api/v3/services/build_backup/find.rb | 10 + .../api/v3/services/build_backups/all.rb | 11 + .../find_for_organization.rb | 9 + .../build_permissions/find_for_repo.rb | 10 + .../update_for_organization.rb | 15 + .../build_permissions/update_for_repo.rb | 15 + .../services/credits_calculator/calculator.rb | 12 + .../credits_calculator/default_config.rb | 11 + .../api/v3/services/executions/for_owner.rb | 34 ++ .../services/executions/for_owner_per_repo.rb | 48 +++ .../executions/for_owner_per_sender.rb | 47 +++ lib/travis/api/v3/services/job/cancel.rb | 2 + lib/travis/api/v3/services/job/restart.rb | 9 +- lib/travis/api/v3/services/log/find.rb | 13 +- .../api/v3/services/repository/activate.rb | 27 +- .../api/v3/services/repository/deactivate.rb | 15 +- lib/travis/api/v3/services/request/preview.rb | 1 + lib/travis/api/v3/services/requests/create.rb | 2 + .../services/subscription/update_address.rb | 2 +- .../api/v3/services/subscriptions/create.rb | 2 +- lib/travis/api/v3/services/user/sync.rb | 2 + .../api/v3/services/user_setting/update.rb | 3 +- lib/travis/api/v3/services/v2_plans/all.rb | 9 + .../services/v2_subscription/auto_refill.rb | 10 + .../v3/services/v2_subscription/buy_addon.rb | 11 + .../api/v3/services/v2_subscription/cancel.rb | 11 + .../v2_subscription/changetofree_plan.rb | 11 + .../v3/services/v2_subscription/invoices.rb | 10 + .../api/v3/services/v2_subscription/pay.rb | 10 + .../v2_subscription/toggle_auto_refill.rb | 10 + .../v2_subscription/update_address.rb | 11 + .../v2_subscription/update_auto_refill.rb | 10 + .../v2_subscription/update_creditcard.rb | 11 + .../services/v2_subscription/update_plan.rb | 11 + .../services/v2_subscription/user_usages.rb | 11 + .../api/v3/services/v2_subscriptions/all.rb | 8 + .../v3/services/v2_subscriptions/create.rb | 13 + lib/travis/config/defaults.rb | 6 +- lib/travis/event/handler/metrics.rb | 6 +- lib/travis/github/services/set_hook.rb | 14 +- lib/travis/github/services/set_key.rb | 52 +-- lib/travis/model.rb | 2 + lib/travis/model/build_backup.rb | 8 + lib/travis/model/owner_group.rb | 6 + lib/travis/model/repository/settings.rb | 4 + lib/travis/model/scope_access.rb | 6 + lib/travis/model/user.rb | 1 + lib/travis/remote_log.rb | 8 +- lib/travis/remote_vcs/client.rb | 14 +- lib/travis/remote_vcs/repository.rb | 9 + lib/travis/remote_vcs/user.rb | 14 + lib/travis/services.rb | 1 + lib/travis/services/find_admin.rb | 18 +- lib/travis/services/find_build_backups.rb | 21 + lib/travis/testing/factories.rb | 28 ++ spec/auth/v1/builds_spec.rb | 14 + spec/auth/v1/logs_spec.rb | 7 +- spec/auth/v2.1/jobs_spec.rb | 20 +- spec/auth/v2.1/logs_spec.rb | 23 +- spec/auth/v2.1/users_spec.rb | 12 +- spec/auth/v2/jobs_spec.rb | 18 +- spec/auth/v2/logs_spec.rb | 21 +- spec/auth/v2/users_spec.rb | 2 + spec/integration/v2/builds_spec.rb | 14 + spec/integration/v2/hooks_spec.rb | 3 +- spec/integration/v2/jobs_spec.rb | 60 +-- spec/integration/v2/requests_spec.rb | 14 + spec/integration/v2/users_spec.rb | 1 + spec/integration/visibility_spec.rb | 5 + spec/lib/github/services/set_key_spec.rb | 89 ++--- spec/lib/services/find_admin_spec.rb | 8 +- spec/lib/services/find_caches_spec.rb | 2 +- .../enqueue/services/restart_model_spec.rb | 139 +++++++ spec/spec_helper.rb | 1 + spec/support/billing_spec_helper.rb | 279 +++++++++++++ spec/travis/remote_vcs/user_spec.rb | 51 +++ .../authorization/user_manager_spec.rb | 8 +- spec/unit/endpoint/authorization_spec.rb | 79 +++- spec/unit/endpoint/users_spec.rb | 15 +- spec/unit/serialize/v2/http/user_spec.rb | 21 +- spec/v3/billing_client_spec.rb | 243 ++++++++++- spec/v3/models/build_backup_spec.rb | 6 + .../models/credits_calculator_config_spec.rb | 21 + spec/v3/models/credits_result_spec.rb | 23 ++ spec/v3/models/v2_subscription_spec.rb | 146 +++++++ spec/v3/queries/build_backup_spec.rb | 23 ++ spec/v3/queries/build_backups_spec.rb | 14 + spec/v3/queries/build_permissions_spec.rb | 70 ++++ spec/v3/renderer/build_backup_spec.rb | 34 ++ spec/v3/services/allowance/for_owner_spec.rb | 46 +++ spec/v3/services/build/cancel_spec.rb | 11 + spec/v3/services/build/find_spec.rb | 4 +- spec/v3/services/build/restart_spec.rb | 23 ++ spec/v3/services/build_backup/find_spec.rb | 61 +++ spec/v3/services/build_backups/all_spec.rb | 57 +++ .../find_for_organization_spec.rb | 41 ++ .../build_permissions/find_for_repo_spec.rb | 41 ++ .../update_for_organization_spec.rb | 36 ++ .../build_permissions/update_for_repo_spec.rb | 41 ++ spec/v3/services/caches/delete_spec.rb | 4 +- spec/v3/services/caches/find_spec.rb | 15 + .../credits_calculator/calculator_spec.rb | 66 +++ .../credits_calculator/default_config_spec.rb | 48 +++ spec/v3/services/installation/find_spec.rb | 11 +- spec/v3/services/job/cancel_spec.rb | 10 + spec/v3/services/job/debug_spec.rb | 8 + spec/v3/services/job/find_spec.rb | 18 +- spec/v3/services/job/restart_spec.rb | 72 ++++ spec/v3/services/jobs/find_spec.rb | 48 ++- spec/v3/services/log/find_spec.rb | 370 ++++++++++++++++- spec/v3/services/organization/find_spec.rb | 12 + .../organizations/for_current_user_spec.rb | 6 + spec/v3/services/owner/find_spec.rb | 66 +++ .../preferences/for_organization_spec.rb | 13 + spec/v3/services/preferences/for_user_spec.rb | 13 + .../repositories/for_current_user_spec.rb | 2 + .../services/repositories/for_owner_spec.rb | 72 +++- spec/v3/services/repository/activate_spec.rb | 205 +--------- .../v3/services/repository/deactivate_spec.rb | 158 +------- spec/v3/services/repository/find_spec.rb | 5 +- spec/v3/services/requests/create_spec.rb | 8 + .../v3/services/subscription/invoices_spec.rb | 8 +- .../subscription/update_address_spec.rb | 6 +- spec/v3/services/subscriptions/all_spec.rb | 5 +- spec/v3/services/subscriptions/create_spec.rb | 8 +- spec/v3/services/trials/all_spec.rb | 4 +- spec/v3/services/trials/create_trial_spec.rb | 16 +- spec/v3/services/user/current_spec.rb | 10 +- spec/v3/services/user/find_spec.rb | 17 +- spec/v3/services/user/sync_spec.rb | 17 +- spec/v3/services/user_setting/update_spec.rb | 5 + .../user_settings/for_repository_spec.rb | 42 +- .../services/v2_subscription/cancel_spec.rb | 39 ++ .../v2_subscription/executions_spec.rb | 191 +++++++++ .../services/v2_subscription/invoices_spec.rb | 58 +++ spec/v3/services/v2_subscription/pay_spec.rb | 38 ++ .../v2_subscription/update_address_spec.rb | 57 +++ .../v2_subscription/update_creditcard_spec.rb | 39 ++ .../v2_subscription/update_plan_spec.rb | 39 ++ spec/v3/services/v2_subscriptions/all_spec.rb | 284 +++++++++++++ .../services/v2_subscriptions/create_spec.rb | 378 ++++++++++++++++++ 233 files changed, 5621 insertions(+), 766 deletions(-) create mode 100644 lib/travis/api/app/endpoint/build_backups.rb create mode 100644 lib/travis/api/v3/models/allowance.rb create mode 100644 lib/travis/api/v3/models/audit.rb create mode 100644 lib/travis/api/v3/models/auto_refill.rb create mode 100644 lib/travis/api/v3/models/build_backup.rb create mode 100644 lib/travis/api/v3/models/build_permission.rb create mode 100644 lib/travis/api/v3/models/credits_calculator_config.rb create mode 100644 lib/travis/api/v3/models/credits_result.rb create mode 100644 lib/travis/api/v3/models/executions.rb delete mode 100644 lib/travis/api/v3/models/leads.rb create mode 100644 lib/travis/api/v3/models/v2_addon.rb create mode 100644 lib/travis/api/v3/models/v2_addon_usage.rb create mode 100644 lib/travis/api/v3/models/v2_plan_config.rb create mode 100644 lib/travis/api/v3/models/v2_subscription.rb create mode 100644 lib/travis/api/v3/queries/allowance.rb create mode 100644 lib/travis/api/v3/queries/build_backup.rb create mode 100644 lib/travis/api/v3/queries/build_backups.rb create mode 100644 lib/travis/api/v3/queries/build_permissions.rb create mode 100644 lib/travis/api/v3/queries/credits_calculator.rb create mode 100644 lib/travis/api/v3/queries/executions.rb create mode 100644 lib/travis/api/v3/queries/v2_addon_usages.rb create mode 100644 lib/travis/api/v3/queries/v2_invoices.rb create mode 100644 lib/travis/api/v3/queries/v2_plans.rb create mode 100644 lib/travis/api/v3/queries/v2_subscription.rb create mode 100644 lib/travis/api/v3/queries/v2_subscriptions.rb create mode 100644 lib/travis/api/v3/renderer/allowance.rb create mode 100644 lib/travis/api/v3/renderer/auto_refill.rb create mode 100644 lib/travis/api/v3/renderer/build_backup.rb create mode 100644 lib/travis/api/v3/renderer/build_backups.rb create mode 100644 lib/travis/api/v3/renderer/build_permission.rb create mode 100644 lib/travis/api/v3/renderer/build_permissions.rb create mode 100644 lib/travis/api/v3/renderer/credits_calculator_config.rb create mode 100644 lib/travis/api/v3/renderer/credits_result.rb create mode 100644 lib/travis/api/v3/renderer/credits_results.rb create mode 100644 lib/travis/api/v3/renderer/execution.rb create mode 100644 lib/travis/api/v3/renderer/execution_per_repo.rb create mode 100644 lib/travis/api/v3/renderer/execution_per_sender.rb create mode 100644 lib/travis/api/v3/renderer/executions.rb create mode 100644 lib/travis/api/v3/renderer/executions_per_repo.rb create mode 100644 lib/travis/api/v3/renderer/executions_per_sender.rb delete mode 100644 lib/travis/api/v3/renderer/leads.rb create mode 100644 lib/travis/api/v3/renderer/v2_addon.rb create mode 100644 lib/travis/api/v3/renderer/v2_addon_config.rb create mode 100644 lib/travis/api/v3/renderer/v2_addon_usage.rb create mode 100644 lib/travis/api/v3/renderer/v2_addon_usages.rb create mode 100644 lib/travis/api/v3/renderer/v2_plan_config.rb create mode 100644 lib/travis/api/v3/renderer/v2_plans.rb create mode 100644 lib/travis/api/v3/renderer/v2_subscription.rb create mode 100644 lib/travis/api/v3/renderer/v2_subscriptions.rb create mode 100644 lib/travis/api/v3/services/allowance/for_owner.rb create mode 100644 lib/travis/api/v3/services/build_backup/find.rb create mode 100644 lib/travis/api/v3/services/build_backups/all.rb create mode 100644 lib/travis/api/v3/services/build_permissions/find_for_organization.rb create mode 100644 lib/travis/api/v3/services/build_permissions/find_for_repo.rb create mode 100644 lib/travis/api/v3/services/build_permissions/update_for_organization.rb create mode 100644 lib/travis/api/v3/services/build_permissions/update_for_repo.rb create mode 100644 lib/travis/api/v3/services/credits_calculator/calculator.rb create mode 100644 lib/travis/api/v3/services/credits_calculator/default_config.rb create mode 100644 lib/travis/api/v3/services/executions/for_owner.rb create mode 100644 lib/travis/api/v3/services/executions/for_owner_per_repo.rb create mode 100644 lib/travis/api/v3/services/executions/for_owner_per_sender.rb create mode 100644 lib/travis/api/v3/services/v2_plans/all.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/auto_refill.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/buy_addon.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/cancel.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/changetofree_plan.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/invoices.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/pay.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/toggle_auto_refill.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/update_address.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/update_auto_refill.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/update_creditcard.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/update_plan.rb create mode 100644 lib/travis/api/v3/services/v2_subscription/user_usages.rb create mode 100644 lib/travis/api/v3/services/v2_subscriptions/all.rb create mode 100644 lib/travis/api/v3/services/v2_subscriptions/create.rb create mode 100644 lib/travis/model/build_backup.rb create mode 100644 lib/travis/model/owner_group.rb create mode 100644 lib/travis/services/find_build_backups.rb create mode 100644 spec/lib/travis/api/enqueue/services/restart_model_spec.rb create mode 100644 spec/travis/remote_vcs/user_spec.rb create mode 100644 spec/v3/models/build_backup_spec.rb create mode 100644 spec/v3/models/credits_calculator_config_spec.rb create mode 100644 spec/v3/models/credits_result_spec.rb create mode 100644 spec/v3/models/v2_subscription_spec.rb create mode 100644 spec/v3/queries/build_backup_spec.rb create mode 100644 spec/v3/queries/build_backups_spec.rb create mode 100644 spec/v3/queries/build_permissions_spec.rb create mode 100644 spec/v3/renderer/build_backup_spec.rb create mode 100644 spec/v3/services/allowance/for_owner_spec.rb create mode 100644 spec/v3/services/build_backup/find_spec.rb create mode 100644 spec/v3/services/build_backups/all_spec.rb create mode 100644 spec/v3/services/build_permissions/find_for_organization_spec.rb create mode 100644 spec/v3/services/build_permissions/find_for_repo_spec.rb create mode 100644 spec/v3/services/build_permissions/update_for_organization_spec.rb create mode 100644 spec/v3/services/build_permissions/update_for_repo_spec.rb create mode 100644 spec/v3/services/credits_calculator/calculator_spec.rb create mode 100644 spec/v3/services/credits_calculator/default_config_spec.rb create mode 100644 spec/v3/services/v2_subscription/cancel_spec.rb create mode 100644 spec/v3/services/v2_subscription/executions_spec.rb create mode 100644 spec/v3/services/v2_subscription/invoices_spec.rb create mode 100644 spec/v3/services/v2_subscription/pay_spec.rb create mode 100644 spec/v3/services/v2_subscription/update_address_spec.rb create mode 100644 spec/v3/services/v2_subscription/update_creditcard_spec.rb create mode 100644 spec/v3/services/v2_subscription/update_plan_spec.rb create mode 100644 spec/v3/services/v2_subscriptions/all_spec.rb create mode 100644 spec/v3/services/v2_subscriptions/create_spec.rb diff --git a/.travis.yml b/.travis.yml index 6ef65f5535..2a9ed5028b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,8 +21,6 @@ env: - CI_NODE_INDEX=1 - CI_NODE_INDEX=2 -cache: bundler - services: - redis-server diff --git a/Dockerfile b/Dockerfile index a6350f3ff9..d53f361410 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,30 +3,40 @@ FROM ruby:2.7.5-slim LABEL maintainer Travis CI GmbH RUN ( \ - bundle config set no-cache 'true'; \ + mkdir -p /app/vendor /app/cache; \ + groupadd -r travis -g 1000 && \ + useradd -u 1000 -r -g travis -s /bin/sh -c "travis user" -d "/app" travis;\ + chown -R travis:travis /app; \ + apt-get update ; \ + apt-get upgrade -y ; \ + apt-get install -y --no-install-recommends git make gcc g++ libpq-dev libjemalloc-dev xz-utils \ + && rm -rf /var/lib/apt/lists/*; \ + gem update --system; \ + bundle config set app_config /app; \ + bundle config set cache_path /app; \ bundle config --global frozen 1; \ bundle config set deployment 'true'; \ - mkdir -p /app; \ + chown -R travis:travis /usr/local/bundle; \ ) + + WORKDIR /app +USER travis COPY Gemfile* /app/ - RUN ( \ - apt-get update ; \ - apt-get upgrade -y ; \ - apt-get install -y --no-install-recommends git make gcc g++ libpq-dev libjemalloc-dev \ - && rm -rf /var/lib/apt/lists/* \ - gem install bundler -v '2.3.6'; \ bundle config set without 'development test'; \ bundler install --verbose --retry=3; \ bundle config set frozen true; \ - apt-get remove -y gcc g++ make git perl && apt-get -y autoremove; \ + ) +USER root +RUN ( apt-get remove -y gcc g++ make git perl xz-utils && apt-get -y autoremove; \ bundle clean && rm -rf /app/vendor/bundle/ruby/2.7.0/cache/*; \ for i in `find /app/vendor/ -name \*.o -o -name \*.c -o -name \*.h`; do rm -f $i; done; \ ) +USER travis ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 COPY . /app diff --git a/Gemfile.lock b/Gemfile.lock index cf64baa08c..169e35c7f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -527,4 +527,4 @@ RUBY VERSION ruby 2.7.5p203 BUNDLED WITH - 2.3.7 + 2.3.24 diff --git a/README.md b/README.md index c3b414d206..7d62a5c0bc 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ https://api.travis-ci.org +## WARNING!!!!! +Master branch is designed for .com only. If you would like to deploy changes for .org please use org-only branch ## Requirements You will need the following packages to get travis-api to work: diff --git a/lib/travis.rb b/lib/travis.rb index d68ebbe680..5146f0326c 100644 --- a/lib/travis.rb +++ b/lib/travis.rb @@ -31,6 +31,8 @@ class GithubApiError < StandardError; end class AdminMissing < StandardError; end class RepositoryMissing < StandardError; end class LogAlreadyRemoved < StandardError; end + class LogExpired < StandardError; end + class LogAccessDenied < StandardError; end class AuthorizationDenied < StandardError; end class JobUnfinished < StandardError; end diff --git a/lib/travis/api/app/endpoint.rb b/lib/travis/api/app/endpoint.rb index e7a61b6c1a..007da24ff8 100644 --- a/lib/travis/api/app/endpoint.rb +++ b/lib/travis/api/app/endpoint.rb @@ -120,6 +120,7 @@ def endpoint(link, query_values = {}) require 'travis/api/app/endpoint/branches' require 'travis/api/app/endpoint/broadcasts' require 'travis/api/app/endpoint/builds' +require 'travis/api/app/endpoint/build_backups' require 'travis/api/app/endpoint/documentation' require 'travis/api/app/endpoint/endpoints' require 'travis/api/app/endpoint/env_vars' diff --git a/lib/travis/api/app/endpoint/authorization.rb b/lib/travis/api/app/endpoint/authorization.rb index f1aea98b8a..da815bfd01 100644 --- a/lib/travis/api/app/endpoint/authorization.rb +++ b/lib/travis/api/app/endpoint/authorization.rb @@ -106,7 +106,6 @@ class Authorization < Endpoint get '/handshake/?:provider?' do method = org? ? :handshake : :vcs_handshake params[:provider] ||= 'github' - send(method) do |user, token, redirect_uri| if target_ok? redirect_uri content_type :html @@ -128,6 +127,21 @@ class Authorization < Endpoint halt 401, 'could not resolve github token' end + get '/confirm_user/:token' do + content_type :json + Travis::RemoteVCS::User.new.confirm_user(token: params[:token]) + { status: 200 }.to_json + rescue Travis::RemoteVCS::ResponseError + halt 404, 'The token is expired or not found.' + end + + get '/request_confirmation/:id' do + content_type :json + Travis::RemoteVCS::User + .new.request_confirmation(id: current_user.id) + { status: 200 }.to_json + end + private # update first login date if not set @@ -166,7 +180,8 @@ def handshake if params[:code] unless state_ok?(params[:state]) log_with_request_id("[handshake] Handshake failed (state mismatch)") - halt 400, 'state mismatch' + handle_invalid_response + return end endpoint.path = config[:access_token_path] @@ -196,7 +211,8 @@ def remote_vcs_user def vcs_handshake if params[:code] unless state_ok?(params[:state], params[:provider]) - halt 400, 'state mismatch' + handle_invalid_response + return end vcs_data = remote_vcs_user.authenticate( @@ -210,7 +226,9 @@ def vcs_handshake return end - yield serialize_user(User.find(vcs_data['user']['id'])), vcs_data['token'], payload(params[:provider]) + user = User.find(vcs_data['user']['id']) + update_first_login(user) + yield serialize_user(user), vcs_data['token'], payload(params[:provider]) else state = vcs_create_state(params[:origin] || params[:redirect_uri]) @@ -259,6 +277,18 @@ def cookie_name(provider = :github) # VCS HANDSHAKE END + def clear_state_cookies + response.delete_cookie cookie_name(:github) + response.delete_cookie cookie_name(:gitlab) + response.delete_cookie cookie_name(:bitbucket) + response.delete_cookie cookie_name(:assembla) + end + + def handle_invalid_response + clear_state_cookies + redirect to("https://#{Travis.config.host}/") + end + def create_state state = SecureRandom.urlsafe_base64(16) redis.sadd('github:states', state) diff --git a/lib/travis/api/app/endpoint/build_backups.rb b/lib/travis/api/app/endpoint/build_backups.rb new file mode 100644 index 0000000000..b2ff881aa3 --- /dev/null +++ b/lib/travis/api/app/endpoint/build_backups.rb @@ -0,0 +1,18 @@ +require 'travis/api/app' +require 'travis/api/app/responders/base' + +class Travis::Api::App + class Endpoint + class BuildBackups < Endpoint + include Helpers::Accept + + before { authenticate_by_mode! } + + get '/' do + prefer_follower do + respond_with service(:find_build_backups, params) + end + end + end + end +end diff --git a/lib/travis/api/app/endpoint/env_vars.rb b/lib/travis/api/app/endpoint/env_vars.rb index dbab2034dd..d779e39f7f 100644 --- a/lib/travis/api/app/endpoint/env_vars.rb +++ b/lib/travis/api/app/endpoint/env_vars.rb @@ -27,6 +27,7 @@ def update respond_with(record, type: :validation_error, version: :v2) end end + end end end diff --git a/lib/travis/api/app/endpoint/jobs.rb b/lib/travis/api/app/endpoint/jobs.rb index a5a4efc925..39a414dd82 100644 --- a/lib/travis/api/app/endpoint/jobs.rb +++ b/lib/travis/api/app/endpoint/jobs.rb @@ -93,16 +93,7 @@ class Jobs < Endpoint # the way we use responders makes it hard to validate proper format # automatically here, so we need to check it explicitly if accepts?('text/plain') - archived_log_path = resource.archived_url - - if params[:cors_hax] - status 204 - headers['Access-Control-Expose-Headers'] = 'Location' - headers['Location'] = archived_log_path - attach_log_token if job.try(:private?) - else - redirect archived_log_path, 307 - end + respond_with resource.archived_log_content elsif accepts?('application/json') attach_log_token if job.try(:private?) respond_with resource.as_json diff --git a/lib/travis/api/app/endpoint/logs.rb b/lib/travis/api/app/endpoint/logs.rb index c6b15a4fd1..f00c45ec77 100644 --- a/lib/travis/api/app/endpoint/logs.rb +++ b/lib/travis/api/app/endpoint/logs.rb @@ -9,6 +9,19 @@ class Logs < Endpoint resource = service(:find_log, id: params[:id]).run job = resource ? Job.find(resource.job_id) : nil + halt 404 unless job + + repo = Travis::API::V3::Models::Repository.find(job.repository.id) + repo_can_write = current_user ? !!repo.users.where(id: current_user.id, permissions: { push: true }).first : false + + if !repo.user_settings.job_log_time_based_limit && job.started_at && job.started_at < Time.now - repo.user_settings.job_log_access_older_than_days.days + halt 403, { error: { message: "We're sorry, but this data is not available anymore. Please check the repository settings in Travis CI." } } + end + + if repo.user_settings.job_log_access_based_limit && !repo_can_write + halt 403, { error: { message: "We're sorry, but this data is not available. Please check the repository settings in Travis CI." } } + end + if !resource || ((job.try(:private?) || !allow_public?) && !has_permission?(job)) halt 404 elsif resource.removed_at && accepts?('application/json') @@ -17,7 +30,7 @@ class Logs < Endpoint # the way we use responders makes it hard to validate proper format # automatically here, so we need to check it explicitly if accepts?('text/plain') - redirect resource.archived_url, 307 + respond_with resource.archived_log_content elsif accepts?('application/json') respond_with resource.as_json else diff --git a/lib/travis/api/enqueue/services/restart_model.rb b/lib/travis/api/enqueue/services/restart_model.rb index b224b84623..a2b050c9d9 100644 --- a/lib/travis/api/enqueue/services/restart_model.rb +++ b/lib/travis/api/enqueue/services/restart_model.rb @@ -4,7 +4,7 @@ module Services class RestartModel attr_reader :current_user, :target - ABUSE_DETECTED = "abuse_detected" + ABUSE_DETECTED = 'abuse_detected' def initialize(current_user, params) @current_user = current_user @@ -15,23 +15,57 @@ def initialize(current_user, params) def push(event, payload) if current_user && target && accept? ::Sidekiq::Client.push( - 'queue' => 'hub', - 'class' => 'Travis::Hub::Sidekiq::Worker', - 'args' => [event, payload] - ) + 'queue' => 'hub', + 'class' => 'Travis::Hub::Sidekiq::Worker', + 'args' => [event, payload] + ) + + Result.new(value: payload) else - @cause_of_denial + Result.new(error: @cause_of_denial || 'restart failed') end end def accept? - current_user && permission? && resetable? + current_user && permission? && resetable? && billing? + end + + def billing? + # there is no billing for .org + return true if Travis.config.org? + + # there is no billing for .enterprise + return true if !!Travis.config.enterprise + + @_billing_ok ||= begin + jobs = target.is_a?(Job) ? [target] : target.matrix + + jobs_attrs = jobs.map do |job| + job.config ? job.config.slice(:os) : {} + end + + client = Travis::API::V3::BillingClient.new(current_user.id) + client.authorize_build(repository, current_user.id, jobs_attrs) + true + rescue Travis::API::V3::InsufficientAccess => e + @cause_of_denial = e.message + false + rescue Travis::API::V3::NotFound + if subscription&.active? || owner_group_subscription? + # Owner is on a legacy plan or belongs to a group + true + else + @cause_of_denial = 'You do not seem to have active subscription.' + false + end + end end def messages messages = [] messages << { notice: "The #{type} was successfully restarted." } if accept? messages << { error: 'You do not seem to have sufficient permissions.' } unless permission? + messages << { error: 'You do not have enough credits.' } unless billing? messages << { error: "This #{type} currently can not be restarted." } unless resetable? messages end @@ -54,23 +88,60 @@ def target private - def permission? - current_user && current_user.permission?(required_role, repository_id: target.repository_id) && !abusive? - end + def subscription + Subscription.where(owner: repository.owner)&.first + end - def abusive? - abusive = Travis.redis.sismember("abuse:offenders", "#{@target.owner.class.name}:#{@target.owner_id}") - @cause_of_denial = ABUSE_DETECTED if abusive - abusive - end + def owner_group + repository&.owner&.owner_group + end + + def owner_group_subscription? + return false if owner_group.blank? + + group_owners = OwnerGroup.where(uuid: owner_group.uuid).map(&:owner) + active_subscriptions = Subscription.where(owner: group_owners).select(&:active?) + active_subscriptions.present? + end + + def permission? + current_user && current_user.permission?(required_role, repository_id: target.repository_id) && !abusive? && build_permission? + end + + def build_permission? + # nil value is considered true + return false if repository.permissions.find_by(user_id: current_user.id).build == false + return false if repository.owner_type == 'Organization' && repository.owner.memberships.find_by(user_id: current_user.id)&.build_permission == false + + true + end + + def abusive? + abusive = Travis.redis.sismember("abuse:offenders", "#{@target.owner.class.name}:#{@target.owner_id}") + @cause_of_denial = ABUSE_DETECTED if abusive + abusive + end + + def resetable? + target.resetable? + end - def resetable? - target.resetable? + def required_role + Travis.config.roles.reset_model + end + + class Result + attr_reader :error, :value + + def initialize(value: nil, error: nil) + @value = value + @error = error end - def required_role - Travis.config.roles.reset_model + def success? + !@error end + end end end end diff --git a/lib/travis/api/serialize/serializer.rb b/lib/travis/api/serialize/serializer.rb index 0257239a5b..933d523c5a 100644 --- a/lib/travis/api/serialize/serializer.rb +++ b/lib/travis/api/serialize/serializer.rb @@ -1,4 +1,5 @@ require 'active_model_serializers' + # This hideousness courtesy of http://stackoverflow.com/a/8339255 module ActiveSupport::JSON::Encoding def self.escape(string) diff --git a/lib/travis/api/v3.rb b/lib/travis/api/v3.rb index a4503c2bfa..16ca8d16b6 100644 --- a/lib/travis/api/v3.rb +++ b/lib/travis/api/v3.rb @@ -39,6 +39,8 @@ def location(env) JobNotCancelable = ClientError .create('job is not running, cannot cancel', status: 409) JobUnfinished = ClientError .create('job still running, cannot remove log yet', status: 409) LogAlreadyRemoved = ClientError .create('log has already been removed', status: 409) + LogExpired = ClientError .create("We're sorry, but this data is not available anymore. Please check the repository settings in Travis CI.", status: 403) + LogAccessDenied = ClientError .create("We're sorry, but this data is not available. Please check the repository settings in Travis CI.", status: 403) LoginRequired = ClientError .create('login required', status: 403) MethodNotAllowed = ClientError .create('method not allowed', status: 405) NotImplemented = ServerError .create('request not (yet) implemented', status: 501) diff --git a/lib/travis/api/v3/access_control/log_token.rb b/lib/travis/api/v3/access_control/log_token.rb index 91effec0ce..3da47dfc42 100644 --- a/lib/travis/api/v3/access_control/log_token.rb +++ b/lib/travis/api/v3/access_control/log_token.rb @@ -5,7 +5,7 @@ module Travis::API::V3 class AccessControl::LogToken < AccessControl::Generic auth_type('log.token') - attr_accessor :token + attr_accessor :token, :repo_can_write def self.for_request(type, token, env) new(token) @@ -13,6 +13,7 @@ def self.for_request(type, token, env) def initialize(token) self.token = token + self.repo_can_write = Travis::API::V3::LogToken.find(token).repo_can_write end def temp_access? diff --git a/lib/travis/api/v3/billing_client.rb b/lib/travis/api/v3/billing_client.rb index 56de2738bd..bc7ef44f0f 100644 --- a/lib/travis/api/v3/billing_client.rb +++ b/lib/travis/api/v3/billing_client.rb @@ -2,10 +2,60 @@ module Travis::API::V3 class BillingClient class ConfigurationError < StandardError; end + ALLOWANCE_TIMEOUT = 1 # second + EXECUTIONS_TIMEOUT = 60 # seconds + def initialize(user_id) @user_id = user_id end + def allowance(owner_type, owner_id) + response = connection(timeout: ALLOWANCE_TIMEOUT).get("/usage/#{owner_type.downcase}s/#{owner_id}/allowance") + return BillingClient.default_allowance_response unless response.status == 200 + + Travis::API::V3::Models::Allowance.new(2, owner_id, response.body) + end + + def authorize_build(repo, sender_id, jobs) + response = connection.post("/#{repo.owner.class.name.downcase.pluralize}/#{repo.owner.id}/authorize_build", { repository: { private: repo.private? }, sender_id: sender_id, jobs: jobs }) + handle_errors_and_respond(response) + end + + def self.default_allowance_response(id = 0) + Travis::API::V3::Models::Allowance.new(1, id, { + "public_repos" => true, + "private_repos" => false, + "concurrency_limit" => 1, + "user_usage" => false, + "pending_user_licenses" => false + }.freeze) + end + + def self.minimal_allowance_response(id = 0) + Travis::API::V3::Models::Allowance.new(2, id, {}) + end + + def executions(owner_type, owner_id, page, per_page, from, to) + response = connection(timeout: EXECUTIONS_TIMEOUT).get("/usage/#{owner_type.downcase}s/#{owner_id}/executions?page=#{page}&per_page=#{per_page}&from=#{from}&to=#{to}") + executions = response.body.map do |execution_data| + Travis::API::V3::Models::Execution.new(execution_data) + end + executions + end + + def calculate_credits(users, executions) + response = connection.post("/usage/credits_calculator", users: users, executions: executions) + response.body.map do |calculator_data| + Travis::API::V3::Models::CreditsResult.new(calculator_data) + end + end + + def credits_calculator_default_config + response = connection.get('/usage/credits_calculator/default_config') + + Travis::API::V3::Models::CreditsCalculatorConfig.new(response.body) + end + def all data = connection.get('/subscriptions').body subscriptions = data.fetch('subscriptions').map do |subscription_data| @@ -16,17 +66,38 @@ def all Travis::API::V3::Models::SubscriptionsCollection.new(subscriptions, permissions) end + def all_v2 + data = connection.get('/v2/subscriptions').body + subscriptions = data.fetch('plans').map do |subscription_data| + Travis::API::V3::Models::V2Subscription.new(subscription_data) + end + permissions = data.fetch('permissions') + + Travis::API::V3::Models::SubscriptionsCollection.new(subscriptions, permissions) + end + def get_subscription(id) response = connection.get("/subscriptions/#{id}") handle_subscription_response(response) end + def get_v2_subscription(id) + response = connection.get("/v2/subscriptions/#{id}") + handle_v2_subscription_response(response) + end + def get_invoices_for_subscription(id) connection.get("/subscriptions/#{id}/invoices").body.map do |invoice_data| Travis::API::V3::Models::Invoice.new(invoice_data) end end + def get_invoices_for_v2_subscription(id) + connection.get("/v2/subscriptions/#{id}/invoices").body.map do |invoice_data| + Travis::API::V3::Models::Invoice.new(invoice_data) + end + end + def trials connection.get('/trials').body.map do | trial_data | Travis::API::V3::Models::Trial.new(trial_data) @@ -43,11 +114,21 @@ def update_address(subscription_id, address_data) handle_subscription_response(response) end + def update_v2_address(subscription_id, address_data) + response = connection.patch("/v2/subscriptions/#{subscription_id}/address", address_data) + handle_v2_subscription_response(response) + end + def update_creditcard(subscription_id, creditcard_token) response = connection.patch("/subscriptions/#{subscription_id}/creditcard", token: creditcard_token) handle_subscription_response(response) end + def update_v2_creditcard(subscription_id, creditcard_token) + response = connection.patch("/v2/subscriptions/#{subscription_id}/creditcard", token: creditcard_token) + handle_v2_subscription_response(response) + end + def update_plan(subscription_id, plan_data) response = connection.patch("/subscriptions/#{subscription_id}/plan", plan_data) handle_subscription_response(response) @@ -58,6 +139,44 @@ def create_subscription(subscription_data) handle_subscription_response(response) end + def create_v2_subscription(subscription_data) + response = connection.post('/v2/subscriptions', subscription_data) + handle_v2_subscription_response(response) + end + + def changetofree_v2_subscription(subscription_id, data) + response = connection.patch("/v2/subscriptions/#{subscription_id}/changetofree", data) + handle_v2_subscription_response(response) + end + + def update_v2_subscription(subscription_id, plan_data) + response = connection.patch("/v2/subscriptions/#{subscription_id}/plan", plan_data) + handle_v2_subscription_response(response) + end + + def purchase_addon(subscription_id, addon_config_id) + response = connection.patch("/v2/subscriptions/#{subscription_id}/addon", { addon: addon_config_id }) + handle_v2_subscription_response(response) + end + + def v2_subscription_user_usages(subscription_id) + connection.get("/v2/subscriptions/#{subscription_id}/user_usage").body.map do |usage_data| + Travis::API::V3::Models::V2AddonUsage.new(usage_data) + end + end + + def v2_plans_for_organization(organization_id) + connection.get("/v2/plans_for/organization/#{organization_id}").body.map do |plan_data| + Travis::API::V3::Models::V2PlanConfig.new(plan_data) + end + end + + def v2_plans_for_user + connection.get('/v2/plans_for/user').body.map do |plan_data| + Travis::API::V3::Models::V2PlanConfig.new(plan_data) + end + end + def cancel_subscription(id, reason_data) response = connection.post("/subscriptions/#{id}/cancel", reason_data) handle_subscription_response(response) @@ -70,7 +189,7 @@ def plans_for_organization(organization_id) end def plans_for_user - connection.get("/plans_for/user").body.map do |plan_data| + connection.get('/plans_for/user').body.map do |plan_data| Travis::API::V3::Models::Plan.new(plan_data) end end @@ -85,6 +204,11 @@ def pay(id) handle_subscription_response(response) end + def pay_v2(id) + response = connection.post("/v2/subscriptions/#{id}/pay") + handle_v2_subscription_response(response) + end + def get_coupon(code) response = connection.get("/coupons/#{code}") handle_coupon_response(response) @@ -95,12 +219,36 @@ def update_organization_billing_permission(organization_id, billing_admin_only) handle_subscription_response(response) end + def create_auto_refill(plan_id, is_enabled) + response = connection.post('/auto_refill', {plan: plan_id, enabled: is_enabled}) + handle_errors_and_respond(response) + end + + def update_auto_refill(addon_id, threshold, amount) + response = connection.patch('/auto_refill', {id: addon_id, threshold: threshold, amount: amount}) + handle_errors_and_respond(response) + end + + def get_auto_refill(plan_id) + response = connection.get("/auto_refill?plan_id=#{plan_id}") + handle_errors_and_respond(response) { |r| Travis::API::V3::Models::AutoRefill.new(r) } + end + + def cancel_v2_subscription(id, reason_data) + response = connection.post("/v2/subscriptions/#{id}/cancel", reason_data) + handle_subscription_response(response) + end + private def handle_subscription_response(response) handle_errors_and_respond(response) { |r| Travis::API::V3::Models::Subscription.new(r) } end + def handle_v2_subscription_response(response) + handle_errors_and_respond(response) { |r| Travis::API::V3::Models::V2Subscription.new(r) } + end + def handle_coupon_response(response) handle_errors_and_respond(response) { |r| Travis::API::V3::Models::Coupon.new(r) } end @@ -113,10 +261,12 @@ def handle_errors_and_respond(response) true when 204 true - when 404 - raise Travis::API::V3::NotFound, response.body['error'] when 400 raise Travis::API::V3::ClientError, response.body['error'] + when 403 + raise Travis::API::V3::InsufficientAccess, response.body['rejection_code'] + when 404 + raise Travis::API::V3::NotFound, response.body['error'] when 422 raise Travis::API::V3::UnprocessableEntity, response.body['error'] else @@ -124,13 +274,15 @@ def handle_errors_and_respond(response) end end - def connection + def connection(timeout: 10) @connection ||= Faraday.new(url: billing_url, ssl: { ca_path: '/usr/lib/ssl/certs' }) do |conn| conn.request(:basic_auth, '_', billing_auth_key) conn.headers['X-Travis-User-Id'] = @user_id.to_s conn.headers['Content-Type'] = 'application/json' conn.request :json conn.response :json + conn.options[:open_timeout] = timeout + conn.options[:timeout] = timeout conn.use OpenCensus::Trace::Integrations::FaradayMiddleware if Travis::Api::App::Middleware::OpenCensus.enabled? conn.adapter :net_http end diff --git a/lib/travis/api/v3/log_token.rb b/lib/travis/api/v3/log_token.rb index cfea1a20af..7ed7201696 100644 --- a/lib/travis/api/v3/log_token.rb +++ b/lib/travis/api/v3/log_token.rb @@ -1,14 +1,18 @@ module Travis::API::V3 class LogToken - attr_accessor :job_id + attr_accessor :job_id, :repo_can_write def self.find(token) - new(redis.get("l:#{token}").to_i) + key = "l:#{token}" + new(redis.hget(key, :job_id).to_i, !!redis.hget(key, :repo_can_write)) end - def self.create(job) + def self.create(job, user_id) + repo_can_write = !!job.repository.users.where(id: user_id, permissions: { push: true }).first + token = SecureRandom.urlsafe_base64(16) - redis.set("l:#{token}", job.id) + redis.hset("l:#{token}", :job_id, job.id) + redis.hset("l:#{token}", :repo_can_write, repo_can_write) redis.expire("l:#{token}", 1.day) token end @@ -17,8 +21,9 @@ def self.redis Travis.redis end - def initialize(job_id) + def initialize(job_id, repo_can_write) self.job_id = job_id + self.repo_can_write = repo_can_write end def matches?(job) diff --git a/lib/travis/api/v3/model.rb b/lib/travis/api/v3/model.rb index 5d3fee8faf..a14650a6f0 100644 --- a/lib/travis/api/v3/model.rb +++ b/lib/travis/api/v3/model.rb @@ -9,5 +9,10 @@ def self.===(other) super or (self == Model and other.class.module_parent == Models) end + def ro_mode? + return false unless Travis.config.org? && Travis.config.read_only? + + !Travis::Features.owner_active?(:read_only_disabled, self) + end end end diff --git a/lib/travis/api/v3/models/allowance.rb b/lib/travis/api/v3/models/allowance.rb new file mode 100644 index 0000000000..984b749950 --- /dev/null +++ b/lib/travis/api/v3/models/allowance.rb @@ -0,0 +1,16 @@ +module Travis::API::V3 + class Models::Allowance + attr_reader :subscription_type, :public_repos, :private_repos, :concurrency_limit, :user_usage, :pending_user_licenses, :id + + def initialize(subscription_type, owner_id, attributes = {}) + @subscription_type = subscription_type + @id = owner_id + @subscription_type = 3 if !!attributes['no_plan'] + @public_repos = attributes.fetch('public_repos', nil) + @private_repos = attributes.fetch('private_repos', nil) + @concurrency_limit = attributes.fetch('concurrency_limit', nil) + @user_usage = attributes.fetch('user_usage', nil) + @pending_user_licenses = attributes.fetch('pending_user_licenses', nil) + end + end +end diff --git a/lib/travis/api/v3/models/audit.rb b/lib/travis/api/v3/models/audit.rb new file mode 100644 index 0000000000..722e661984 --- /dev/null +++ b/lib/travis/api/v3/models/audit.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Models::Audit < Model + belongs_to :owner, polymorphic: true + belongs_to :source, polymorphic: true + end +end diff --git a/lib/travis/api/v3/models/auto_refill.rb b/lib/travis/api/v3/models/auto_refill.rb new file mode 100644 index 0000000000..1685a6ec84 --- /dev/null +++ b/lib/travis/api/v3/models/auto_refill.rb @@ -0,0 +1,13 @@ +module Travis::API::V3 + class Models::AutoRefill + + attr_reader :addon_id, :enabled, :threshold, :amount + def initialize(attributes = {}) + @addon_id = attributes.fetch('addon_id', nil) || attributes.fetch('id', nil) + @enabled = attributes.key?('enabled') ? attributes.fetch('enabled') : true + @threshold = attributes.key?('refill_threshold') ? attributes.fetch('refill_threshold') : 25000 + @amount = attributes.key?('refill_amount') ? attributes.fetch('refill_amount'): 10000 + end + end + +end diff --git a/lib/travis/api/v3/models/build_backup.rb b/lib/travis/api/v3/models/build_backup.rb new file mode 100644 index 0000000000..e5db6aee03 --- /dev/null +++ b/lib/travis/api/v3/models/build_backup.rb @@ -0,0 +1,7 @@ +module Travis::API::V3 + class Models::BuildBackup < Model + attr_accessor :content + + belongs_to :repository + end +end diff --git a/lib/travis/api/v3/models/build_permission.rb b/lib/travis/api/v3/models/build_permission.rb new file mode 100644 index 0000000000..e446e3119f --- /dev/null +++ b/lib/travis/api/v3/models/build_permission.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Models::BuildPermission + attr_accessor :user, :permission, :role + + def initialize(attrs = {}) + @user = attrs.fetch(:user) + @role = attrs.fetch(:role) + @permission = attrs.fetch(:permission) + end + end +end diff --git a/lib/travis/api/v3/models/credits_calculator_config.rb b/lib/travis/api/v3/models/credits_calculator_config.rb new file mode 100644 index 0000000000..0beb3ec654 --- /dev/null +++ b/lib/travis/api/v3/models/credits_calculator_config.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Models::CreditsCalculatorConfig + ATTRS = %w[users minutes os instance_size] + + attr_accessor *ATTRS + + def initialize(attrs) + ATTRS.each { |key| send("#{key}=", attrs[key]) } + end + end +end diff --git a/lib/travis/api/v3/models/credits_result.rb b/lib/travis/api/v3/models/credits_result.rb new file mode 100644 index 0000000000..b26cc31656 --- /dev/null +++ b/lib/travis/api/v3/models/credits_result.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Models::CreditsResult + ATTRS = %w[users minutes os instance_size credits price] + + attr_accessor *ATTRS + + def initialize(attrs) + ATTRS.each { |key| send("#{key}=", attrs[key]) } + end + end +end diff --git a/lib/travis/api/v3/models/env_var.rb b/lib/travis/api/v3/models/env_var.rb index d2e668080f..e05656075d 100644 --- a/lib/travis/api/v3/models/env_var.rb +++ b/lib/travis/api/v3/models/env_var.rb @@ -10,7 +10,7 @@ class Models::EnvVar < Travis::Settings::Model validates :name, presence: true validates_each :id, :name do |record, attr, value| others = record.repository.env_vars.select { |ev| ev.id != record.id } - record.errors.add(:base, :duplicate_resource) if others.find { |ev| ev.send(attr) == record.send(attr) } + record.errors.add(:base, :duplicate_resource) if others.find { |ev| ev.send(attr) == record.send(attr) && ev.send(:branch) == record.send(:branch) } end def repository diff --git a/lib/travis/api/v3/models/executions.rb b/lib/travis/api/v3/models/executions.rb new file mode 100644 index 0000000000..9fec9c75d2 --- /dev/null +++ b/lib/travis/api/v3/models/executions.rb @@ -0,0 +1,43 @@ +module Travis::API::V3 + class Models::Execution + attr_reader :id, :os, :instance_size, :arch, :virtualization_type, :queue, :job_id, :repository_id, :owner_id, + :owner_type, :plan_id, :sender_id, :credits_consumed, :user_license_credits_consumed, :started_at, + :finished_at, :created_at, :updated_at, :sender_login, :repo_slug, :repo_owner_name + + def initialize(attributes = {}) + @id = attributes.fetch('id') + @os = attributes.fetch('os') + @instance_size = attributes.fetch('instance_size') + @arch = attributes.fetch('arch') + @virtualization_type = attributes.fetch('virtualization_type') + @queue = attributes.fetch('queue') + @job_id = attributes.fetch('job_id') + @repository_id = attributes.fetch('repository_id') + @owner_id = attributes.fetch('owner_id') + @owner_type = attributes.fetch('owner_type') + @plan_id = attributes.fetch('plan_id') + @sender_id = attributes.fetch('sender_id') + @credits_consumed = attributes.fetch('credits_consumed') + @user_license_credits_consumed = attributes.fetch('user_license_credits_consumed') + @started_at = attributes.fetch('started_at') + @finished_at = attributes.fetch('finished_at') + @created_at = attributes.fetch('created_at') + @updated_at = attributes.fetch('updated_at') + @sender_login = nil + @repo_slug = nil + @repo_owner_name = nil + end + + def sender_login=(sender_login) + @sender_login = sender_login + end + + def repo_slug=(repo_slug) + @repo_slug = repo_slug + end + + def repo_owner_name=(repo_owner_name) + @repo_owner_name = repo_owner_name + end + end +end diff --git a/lib/travis/api/v3/models/invoice.rb b/lib/travis/api/v3/models/invoice.rb index f98f724cf1..4b8784c40a 100644 --- a/lib/travis/api/v3/models/invoice.rb +++ b/lib/travis/api/v3/models/invoice.rb @@ -1,12 +1,14 @@ module Travis::API::V3 class Models::Invoice - attr_reader :id, :created_at, :url, :amount_due + attr_reader :id, :created_at, :status, :url, :amount_due, :cc_last_digits def initialize(attributes = {}) @id = attributes.fetch('id') @created_at = attributes.fetch('created_at') && DateTime.parse(attributes.fetch('created_at')) + @status = attributes.fetch('status') @url = attributes.fetch('url') @amount_due = attributes.fetch('amount_due') + @cc_last_digits = attributes.fetch('cc_last_digits') end end end diff --git a/lib/travis/api/v3/models/json_slice.rb b/lib/travis/api/v3/models/json_slice.rb index 75ae9e8445..3e112fddb8 100644 --- a/lib/travis/api/v3/models/json_slice.rb +++ b/lib/travis/api/v3/models/json_slice.rb @@ -2,7 +2,9 @@ module Travis::API::V3 class Models::JsonSlice - include Virtus.model, Enumerable, Models::JsonSync, ActiveModel::Validations + include Virtus.model, Enumerable, Models::JsonSync, ActiveModel::Validations, ActiveSupport::Callbacks, ActiveModel::Dirty + extend ActiveSupport::Concern + define_callbacks :after_save class << self attr_accessor :child_klass @@ -30,14 +32,21 @@ def read(name) def update(name, value) raise NotFound unless respond_to?(:"#{name}=") + @changes = { :"#{name}" => { before: send(name), after: value } } unless value == send(name) send(:"#{name}=", value) raise UnprocessableEntity, errors.full_messages.to_sentence unless valid? sync! + run_callbacks :after_save + @changes = {} read(name) end def to_h Hash[map { |x| [x.name, x.value] }] end + + def changes + @changes + end end end diff --git a/lib/travis/api/v3/models/json_sync.rb b/lib/travis/api/v3/models/json_sync.rb index e913f45237..1a160f153f 100644 --- a/lib/travis/api/v3/models/json_sync.rb +++ b/lib/travis/api/v3/models/json_sync.rb @@ -6,7 +6,7 @@ def sync(parent, attr) @parent, @attr = parent, attr @sync = -> do previous = @parent[@attr] || {} - @parent[@attr] = previous.merge(to_h) + @parent[@attr] = previous.merge(to_h).to_json @parent.save! end end diff --git a/lib/travis/api/v3/models/leads.rb b/lib/travis/api/v3/models/leads.rb deleted file mode 100644 index d292784abc..0000000000 --- a/lib/travis/api/v3/models/leads.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Travis::API::V3 - class Models::Leads - attr_reader :id, :name, :status_label, :contacts, :custom - - def initialize(attributes = {}) - @id = attributes.fetch('id') - @name = attributes.fetch('name') - @status_label = attributes.fetch('status_label') - @contacts = attributes.fetch('contacts') - @custom = attributes.fetch('custom') - end - end -end diff --git a/lib/travis/api/v3/models/log.rb b/lib/travis/api/v3/models/log.rb index 5f40f89c4d..2989d63124 100644 --- a/lib/travis/api/v3/models/log.rb +++ b/lib/travis/api/v3/models/log.rb @@ -27,6 +27,10 @@ def repository_private? job.repository.private? end + def repository + @repository ||= Travis::API::V3::Models::Repository.find(job.repository.id) + end + private def archived_log_part diff --git a/lib/travis/api/v3/models/organization_preferences.rb b/lib/travis/api/v3/models/organization_preferences.rb index 2f44ee55a3..4063b5deb9 100644 --- a/lib/travis/api/v3/models/organization_preferences.rb +++ b/lib/travis/api/v3/models/organization_preferences.rb @@ -4,6 +4,8 @@ module Travis::API::V3 class Models::OrganizationPreferences < Models::JsonSlice child Models::Preference + attribute :consume_oss_credits, Boolean, default: true + # whether to show insights about the organization's private repositories to # only admins, all members of the organization, or everybody (public) (note: # insights about public repositories are always public) diff --git a/lib/travis/api/v3/models/subscription.rb b/lib/travis/api/v3/models/subscription.rb index 1d9f0802d1..c2b4422a1e 100644 --- a/lib/travis/api/v3/models/subscription.rb +++ b/lib/travis/api/v3/models/subscription.rb @@ -33,7 +33,7 @@ def initialize(subscriptions, permissions) end class Models::BillingInfo - attr_reader :id, :address, :address2, :billing_email, :city, :company, :country, :first_name, :last_name, :state, :vat_id, :zip_code + attr_reader :id, :address, :address2, :billing_email, :city, :company, :country, :first_name, :last_name, :state, :vat_id, :zip_code, :has_local_registration def initialize(id, attrs) @id = id @@ -48,6 +48,7 @@ def initialize(id, attrs) @state = attrs.fetch('state') @vat_id = attrs.fetch('vat_id') @zip_code = attrs.fetch('zip_code') + @has_local_registration= attrs.fetch('has_local_registration') end end diff --git a/lib/travis/api/v3/models/user_preferences.rb b/lib/travis/api/v3/models/user_preferences.rb index 92b3e307e4..91878210d5 100644 --- a/lib/travis/api/v3/models/user_preferences.rb +++ b/lib/travis/api/v3/models/user_preferences.rb @@ -6,6 +6,8 @@ class Models::UserPreferences < Models::JsonSlice attribute :build_emails, Boolean, default: true + attribute :consume_oss_credits, Boolean, default: true + # whether to show insights about the user's private repositories to # everybody or keep them only for the user (note: insights about public # repositories are always public) diff --git a/lib/travis/api/v3/models/user_settings.rb b/lib/travis/api/v3/models/user_settings.rb index 3f6d77b241..1abddf9a4c 100644 --- a/lib/travis/api/v3/models/user_settings.rb +++ b/lib/travis/api/v3/models/user_settings.rb @@ -14,9 +14,20 @@ class Models::UserSettings < Models::JsonSlice attribute :config_validation, Boolean, default: lambda { |us, _| us.config_validation? } attribute :share_encrypted_env_with_forks, Boolean, default: false attribute :share_ssh_keys_with_forks, Boolean, default: lambda { |us, _| us.share_ssh_keys_with_forks? } + attribute :job_log_time_based_limit, Boolean, default: lambda { |s, _| s.job_log_access_permissions[:time_based_limit] } + attribute :job_log_access_based_limit, Boolean, default: lambda { |s, _| s.job_log_access_permissions[:access_based_limit] } + attribute :job_log_access_older_than_days, Integer, default: lambda { |s, _| s.job_log_access_permissions[:older_than_days] } + + validates :job_log_access_older_than_days, numericality: true + + validate :job_log_access_older_than_days_restriction + + set_callback :after_save, :after, :save_audit attr_reader :repo + attr_accessor :user, :change_source + def initialize(repo, data) @repo = repo super(data) @@ -59,5 +70,24 @@ def cutoff_date def days_since_jan_15 Date.today.mjd - JAN_15.mjd + 1 end + + def job_log_access_permissions + Travis.config.to_h.fetch(:job_log_access_permissions) { {} } + end + + def job_log_access_older_than_days_restriction + if job_log_access_older_than_days.to_i > job_log_access_permissions[:max_days_value] || + job_log_access_older_than_days.to_i < job_log_access_permissions[:min_days_value] + errors.add(:job_log_access_older_than_days, "is outside the bounds") + end + end + + private + + def save_audit + if self.change_source + Travis::API::V3::Models::Audit.create!(owner: self.user, change_source: self.change_source, source: self.repo, source_changes: { settings: self.changes }) + end + end end end diff --git a/lib/travis/api/v3/models/v2_addon.rb b/lib/travis/api/v3/models/v2_addon.rb new file mode 100644 index 0000000000..dfd86c2491 --- /dev/null +++ b/lib/travis/api/v3/models/v2_addon.rb @@ -0,0 +1,13 @@ +module Travis::API::V3 + class Models::V2Addon + attr_reader :id, :name, :type, :current_usage, :recurring + + def initialize(attrs) + @id = attrs.fetch('id') + @name = attrs.fetch('name') + @type = attrs.fetch('type') + @current_usage = attrs['current_usage'] && Models::V2AddonUsage.new(attrs['current_usage']) + @recurring = attrs['recurring'] + end + end +end diff --git a/lib/travis/api/v3/models/v2_addon_usage.rb b/lib/travis/api/v3/models/v2_addon_usage.rb new file mode 100644 index 0000000000..ec68ff9a1a --- /dev/null +++ b/lib/travis/api/v3/models/v2_addon_usage.rb @@ -0,0 +1,17 @@ +module Travis::API::V3 + class Models::V2AddonUsage + attr_reader :id, :addon_id, :addon_quantity, :addon_usage, :remaining, :purchase_date, :valid_to, :active, :status + + def initialize(attrs) + @id = attrs.fetch('id') + @addon_id = attrs.fetch('addon_id') + @addon_quantity = attrs.fetch('addon_quantity') + @addon_usage = attrs.fetch('addon_usage') + @remaining = attrs.fetch('remaining') + @purchase_date = attrs.fetch('purchase_date') + @valid_to = attrs.fetch('valid_to') + @active = attrs.fetch('active') + @status = attrs.fetch('status') + end + end +end diff --git a/lib/travis/api/v3/models/v2_plan_config.rb b/lib/travis/api/v3/models/v2_plan_config.rb new file mode 100644 index 0000000000..e7933ef3c0 --- /dev/null +++ b/lib/travis/api/v3/models/v2_plan_config.rb @@ -0,0 +1,25 @@ +module Travis::API::V3 + class Models::V2PlanConfig + attr_reader :id, :name, :private_repos, :starting_price, :starting_users, :plan_type, + :private_credits, :public_credits, :addon_configs, :concurrency_limit, :available_standalone_addons, :auto_refill_enabled, :trial_plan, + :annual, :auto_refill_thresholds, :auto_refill_amounts + + def initialize(attrs) + @id = attrs.fetch('id') + @name = attrs.fetch('name') + @private_repos = attrs.fetch('private_repos') + @starting_price = attrs.fetch('starting_price') + @starting_users = attrs.fetch('starting_users') + @private_credits = attrs.fetch('private_credits') + @public_credits = attrs.fetch('public_credits') + @addon_configs = attrs.fetch('addon_configs') + @plan_type = attrs.fetch('plan_type') + @concurrency_limit = attrs.fetch('concurrency_limit') + @available_standalone_addons = attrs.fetch('available_standalone_addons') + @annual = attrs.fetch('annual') + @auto_refill_thresholds = attrs.fetch('auto_refill_thresholds') + @auto_refill_amounts = attrs.fetch('auto_refill_amounts') + @trial_plan = attrs.fetch('trial_plan', false) + end + end +end diff --git a/lib/travis/api/v3/models/v2_subscription.rb b/lib/travis/api/v3/models/v2_subscription.rb new file mode 100644 index 0000000000..522a9b3961 --- /dev/null +++ b/lib/travis/api/v3/models/v2_subscription.rb @@ -0,0 +1,67 @@ +module Travis::API::V3 + class Models::V2Subscription + include Models::Owner + + attr_reader :id, :plan, :permissions, :source, :billing_info, :credit_card_info, :owner, :status, :valid_to, :canceled_at, + :client_secret, :payment_intent, :addons, :auto_refill, :available_standalone_addons, :created_at, :scheduled_plan_name + + def initialize(attributes = {}) + @id = attributes.fetch('id') + @plan = attributes['plan_config'] && Models::V2PlanConfig.new(attributes['plan_config']) + @permissions = Models::BillingPermissions.new(attributes.fetch('permissions')) + @source = attributes.fetch('source') + @billing_info = attributes['billing_info'] && Models::V2BillingInfo.new(@id, attributes['billing_info']) + @credit_card_info = attributes['credit_card_info'] && Models::V2CreditCardInfo.new(@id, attributes['credit_card_info']) + @payment_intent = attributes['payment_intent'] && Models::PaymentIntent.new(attributes['payment_intent']) + @owner = fetch_owner(attributes.fetch('owner')) + @client_secret = attributes.fetch('client_secret') + @addons = attributes['addons'].select { |addon| addon['current_usage']['status'] != 'expired' if addon['current_usage'] }.map { |addon| Models::V2Addon.new(addon) } + refill = attributes['addons'].detect { |addon| addon['addon_config_id'] === 'auto_refill' } || {"enabled" => false}; + default_refill = @plan.respond_to?('available_standalone_addons') ? + @plan.available_standalone_addons.detect { |addon| addon['id'] === 'auto_refill' } : nil + + refill['enabled'] = attributes['auto_refill_enabled'] + if default_refill + refill['refill_threshold'] = default_refill['refill_threshold'] unless refill.key?('refill_threshold') + refill['refill_amount'] = default_refill['refill_amount'] unless refill.key?('refill_amount') + end + @auto_refill = Models::AutoRefill.new(refill) + @created_at = attributes.fetch('created_at') + @status = attributes.fetch('status') + @valid_to = attributes.fetch('valid_to') + @canceled_at = attributes.fetch('canceled_at') + @scheduled_plan_name = attributes.fetch('scheduled_plan') + end + end + + class Models::V2BillingInfo + attr_reader :id, :address, :address2, :billing_email, :city, :company, :country, :first_name, :last_name, :state, :vat_id, :zip_code, :has_local_registration + + def initialize(id, attrs) + @id = id + @address = attrs.fetch('address') + @address2 = attrs.fetch('address2') + @billing_email = attrs.fetch('billing_email') + @city = attrs.fetch('city') + @company = attrs.fetch('company') + @country = attrs.fetch('country') + @first_name = attrs.fetch('first_name') + @last_name = attrs.fetch('last_name') + @state = attrs.fetch('state') + @vat_id = attrs.fetch('vat_id') + @zip_code = attrs.fetch('zip_code') + @has_local_registration = attrs.fetch('has_local_registration', false) + end + end + + class Models::V2CreditCardInfo + attr_reader :id, :card_owner, :expiration_date, :last_digits + + def initialize(id, attrs) + @id = id + @card_owner = attrs.fetch('card_owner') + @expiration_date = attrs.fetch('expiration_date') + @last_digits = attrs.fetch('last_digits') + end + end +end diff --git a/lib/travis/api/v3/queries/allowance.rb b/lib/travis/api/v3/queries/allowance.rb new file mode 100644 index 0000000000..3b341787f5 --- /dev/null +++ b/lib/travis/api/v3/queries/allowance.rb @@ -0,0 +1,16 @@ +module Travis::API::V3 + class Queries::Allowance < Query + params :login, :github_id, :provider + + def for_owner(owner, user_id) + client = BillingClient.new(user_id) + client.allowance(owner_type(owner), owner.id) + end + + private + + def owner_type(owner) + owner.vcs_type =~ /User/ ? 'user' : 'organization' + end + end +end diff --git a/lib/travis/api/v3/queries/build.rb b/lib/travis/api/v3/queries/build.rb index 3ae579e044..372a927ac4 100644 --- a/lib/travis/api/v3/queries/build.rb +++ b/lib/travis/api/v3/queries/build.rb @@ -27,13 +27,7 @@ def restart(user) service = Travis::Enqueue::Services::RestartModel.new(user, { build_id: id }) payload = { id: id, user_id: user.id, restarted_by: user.id } - restart_status = service.push("build:restart", payload) - - if restart_status == "abuse_detected" - restart_status - else - payload - end + service.push("build:restart", payload) end def prioritize_and_cancel(user) diff --git a/lib/travis/api/v3/queries/build_backup.rb b/lib/travis/api/v3/queries/build_backup.rb new file mode 100644 index 0000000000..bedf673484 --- /dev/null +++ b/lib/travis/api/v3/queries/build_backup.rb @@ -0,0 +1,21 @@ +module Travis::API::V3 + class Queries::BuildBackup < RemoteQuery + params :id + + def find + raise WrongParams, 'missing build_backup.id'.freeze unless id + build_backup = Models::BuildBackup.find_by_id(id) + content = get(build_backup.file_name) + raise EntityMissing, 'could not retrieve content'.freeze if content.nil? + build_backup.content = content.force_encoding('UTF-8') if content.present? + + build_backup + end + + private + + def main_type + 'build_backup' + end + end +end diff --git a/lib/travis/api/v3/queries/build_backups.rb b/lib/travis/api/v3/queries/build_backups.rb new file mode 100644 index 0000000000..f66f7ea0d0 --- /dev/null +++ b/lib/travis/api/v3/queries/build_backups.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Queries::BuildBackups < Query + params :repository_id + + def all + return Models::BuildBackup.where(repository_id: repository_id) if repository_id + raise WrongParams, 'missing build_backups.repository_id'.freeze + end + end +end diff --git a/lib/travis/api/v3/queries/build_permissions.rb b/lib/travis/api/v3/queries/build_permissions.rb new file mode 100644 index 0000000000..ef8b1f7344 --- /dev/null +++ b/lib/travis/api/v3/queries/build_permissions.rb @@ -0,0 +1,19 @@ +module Travis::API::V3 + class Queries::BuildPermissions < Query + def find_for_repo(repository) + Models::Repository.find(repository.id).permissions.joins(:user).includes(:user) + end + + def find_for_organization(organization) + Models::Membership.where(organization_id: organization.id).joins(:user).includes(:user) + end + + def update_for_organization(organization, user_ids, permission) + Models::Membership.where(organization_id: organization.id, user_id: user_ids).update_all(build_permission: bool(permission)) + end + + def update_for_repo(repository, user_ids, permission) + Models::Permission.where(repository_id: repository.id, user_id: user_ids).update_all(build: bool(permission)) + end + end +end diff --git a/lib/travis/api/v3/queries/credits_calculator.rb b/lib/travis/api/v3/queries/credits_calculator.rb new file mode 100644 index 0000000000..ffef955455 --- /dev/null +++ b/lib/travis/api/v3/queries/credits_calculator.rb @@ -0,0 +1,15 @@ +module Travis::API::V3 + class Queries::CreditsCalculator < Query + params :users, :executions + + def calculate(user_id) + client = BillingClient.new(user_id) + client.calculate_credits(params['users'], params['executions']) + end + + def default_config(user_id) + client = BillingClient.new(user_id) + client.credits_calculator_default_config + end + end +end diff --git a/lib/travis/api/v3/queries/executions.rb b/lib/travis/api/v3/queries/executions.rb new file mode 100644 index 0000000000..e5a36bdf0d --- /dev/null +++ b/lib/travis/api/v3/queries/executions.rb @@ -0,0 +1,15 @@ +module Travis::API::V3 + class Queries::Executions < Query + + def for_owner(owner, user_id, page, per_page, from, to) + client = BillingClient.new(user_id) + client.executions(owner_type(owner), owner.id, page, per_page, from, to) + end + + private + + def owner_type(owner) + owner.vcs_type =~ /User/ ? 'user' : 'organization' + end + end +end diff --git a/lib/travis/api/v3/queries/job.rb b/lib/travis/api/v3/queries/job.rb index 631d96fde6..27b6e98fe8 100644 --- a/lib/travis/api/v3/queries/job.rb +++ b/lib/travis/api/v3/queries/job.rb @@ -25,13 +25,7 @@ def restart(user) service = Travis::Enqueue::Services::RestartModel.new(user, { job_id: id }) payload = { id: id, user_id: user.id, restarted_by: user.id } - restart_status = service.push("job:restart", payload) - - if restart_status == "abuse_detected" - restart_status - else - payload - end + service.push("job:restart", payload) end end end diff --git a/lib/travis/api/v3/queries/subscriptions.rb b/lib/travis/api/v3/queries/subscriptions.rb index 12bd5a32b0..b2e4a382cb 100644 --- a/lib/travis/api/v3/queries/subscriptions.rb +++ b/lib/travis/api/v3/queries/subscriptions.rb @@ -1,7 +1,7 @@ module Travis::API::V3 class Queries::Subscriptions < Query params :plan, :coupon, :organization_id, :client_secret - params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email, prefix: :billing_info + params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email, :has_local_registration, prefix: :billing_info params :token, prefix: :credit_card_info def all(user_id) diff --git a/lib/travis/api/v3/queries/user_setting.rb b/lib/travis/api/v3/queries/user_setting.rb index 2cadb59076..3a1fbe9d1e 100644 --- a/lib/travis/api/v3/queries/user_setting.rb +++ b/lib/travis/api/v3/queries/user_setting.rb @@ -6,8 +6,11 @@ def find(repository) repository.user_settings.read(_name) end - def update(repository) - repository.user_settings.update(_name, _value) + def update(repository, user, from_admin) + user_settings = repository.user_settings + user_settings.user = user + user_settings.change_source = 'travis-api' unless from_admin + user_settings.update(_name, _value) end private diff --git a/lib/travis/api/v3/queries/v2_addon_usages.rb b/lib/travis/api/v3/queries/v2_addon_usages.rb new file mode 100644 index 0000000000..c3dbacb558 --- /dev/null +++ b/lib/travis/api/v3/queries/v2_addon_usages.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Queries::V2AddonUsages < Query + def all(user_id) + return unless params['subscription.id'] + + client = BillingClient.new(user_id) + client.v2_subscription_user_usages(params['subscription.id']) + end + end +end diff --git a/lib/travis/api/v3/queries/v2_invoices.rb b/lib/travis/api/v3/queries/v2_invoices.rb new file mode 100644 index 0000000000..78f5fc4cf9 --- /dev/null +++ b/lib/travis/api/v3/queries/v2_invoices.rb @@ -0,0 +1,8 @@ +module Travis::API::V3 + class Queries::V2Invoices < Query + def all(user_id) + client = BillingClient.new(user_id) + client.get_invoices_for_v2_subscription(params['subscription.id']) + end + end +end diff --git a/lib/travis/api/v3/queries/v2_plans.rb b/lib/travis/api/v3/queries/v2_plans.rb new file mode 100644 index 0000000000..08be4ec776 --- /dev/null +++ b/lib/travis/api/v3/queries/v2_plans.rb @@ -0,0 +1,12 @@ +module Travis::API::V3 + class Queries::V2Plans < Query + def all(user_id) + client = BillingClient.new(user_id) + if params['organization.id'] + client.v2_plans_for_organization(params['organization.id']) + else + client.v2_plans_for_user + end + end + end +end diff --git a/lib/travis/api/v3/queries/v2_subscription.rb b/lib/travis/api/v3/queries/v2_subscription.rb new file mode 100644 index 0000000000..0cf49269f5 --- /dev/null +++ b/lib/travis/api/v3/queries/v2_subscription.rb @@ -0,0 +1,64 @@ +module Travis::API::V3 + class Queries::V2Subscription < Query + params :enabled, :threshold, :amount + + def update_address(user_id) + address_data = params.dup.tap { |h| h.delete('subscription.id') } + client = BillingClient.new(user_id) + client.update_v2_address(params['subscription.id'], address_data) + end + + def update_creditcard(user_id) + client = BillingClient.new(user_id) + client.update_v2_creditcard(params['subscription.id'], params['token']) + end + + def changetofree(user_id) + data = params.dup.tap { |h| h.delete('subscription.id') } + client = BillingClient.new(user_id) + client.changetofree_v2_subscription(params['subscription.id'], data) + end + + def update_plan(user_id) + plan_data = params.dup.tap { |h| h.delete('subscription.id') } + client = BillingClient.new(user_id) + client.update_v2_subscription(params['subscription.id'], plan_data) + end + + def buy_addon(user_id) + client = BillingClient.new(user_id) + client.purchase_addon(params['subscription.id'], params['addon.id']) + end + + def invoices(user_id) + client = BillingClient.new(user_id) + client.get_invoices_for_v2_subscription(params['subscription.id']) + end + + def pay(user_id) + client = BillingClient.new(user_id) + client.pay_v2(params['subscription.id']) + end + + def get_auto_refill(user_id, plan_id) + client = BillingClient.new(user_id) + client.get_auto_refill(plan_id) + end + + def toggle_auto_refill(user_id, plan_id) + client = BillingClient.new(user_id) + client.create_auto_refill(plan_id, enabled) + end + + def cancel(user_id) + reason_data = params.dup.tap { |h| h.delete('subscription.id') } + client = BillingClient.new(user_id) + client.cancel_v2_subscription(params['subscription.id'], reason_data) + end + + def update_auto_refill(user_id, addon_id) + client = BillingClient.new(user_id) + client.update_auto_refill(addon_id, threshold, amount) + end + end +end diff --git a/lib/travis/api/v3/queries/v2_subscriptions.rb b/lib/travis/api/v3/queries/v2_subscriptions.rb new file mode 100644 index 0000000000..6d7bf3ea84 --- /dev/null +++ b/lib/travis/api/v3/queries/v2_subscriptions.rb @@ -0,0 +1,25 @@ +module Travis::API::V3 + class Queries::V2Subscriptions < Query + params :plan, :coupon, :organization_id, :client_secret, :v1_subscription_id + params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email, :has_local_registration, prefix: :billing_info + params :token, prefix: :credit_card_info + + def all(user_id) + client = BillingClient.new(user_id) + client.all_v2 + end + + def create(user_id) + client = BillingClient.new(user_id) + client.create_v2_subscription( + :plan => params['plan'], + :client_secret => params['client_secret'], + :coupon => params['coupon'], + :organization_id => params['organization_id'], + :billing_info => billing_info_params, + :credit_card_info => credit_card_info_params, + :v1_subscription_id => params['v1_subscription_id'] + ) + end + end +end diff --git a/lib/travis/api/v3/remote_query.rb b/lib/travis/api/v3/remote_query.rb index a83f87e613..67b223fa13 100644 --- a/lib/travis/api/v3/remote_query.rb +++ b/lib/travis/api/v3/remote_query.rb @@ -18,6 +18,13 @@ def fetch storage_objects end + def get(key) + io = StringIO.new + gcs_connection.get_object(gcs_config[:bucket_name], key, download_dest: io) + io.rewind + io.read + end + def remove(objects) objects.each do |object| raise SourceUnknown "#{object.source} is an unknown source." unless ['s3', 'gcs'].include? object.source @@ -92,7 +99,7 @@ def s3_objects def gcs_connection gcs = ::Google::Apis::StorageV1::StorageService.new - json_key_io = StringIO.new(gcs_config[:json_key]) + json_key_io = StringIO.new(JSON.dump(gcs_config[:json_key])) gcs.authorization = ::Google::Auth::ServiceAccountCredentials.make_creds( json_key_io: json_key_io, diff --git a/lib/travis/api/v3/renderer/allowance.rb b/lib/travis/api/v3/renderer/allowance.rb new file mode 100644 index 0000000000..c8e6ee4847 --- /dev/null +++ b/lib/travis/api/v3/renderer/allowance.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::Allowance < ModelRenderer + representation(:minimal, :id) + representation(:standard, :subscription_type, :public_repos, :private_repos, :concurrency_limit, :user_usage, :pending_user_licenses, :id) + end +end diff --git a/lib/travis/api/v3/renderer/auto_refill.rb b/lib/travis/api/v3/renderer/auto_refill.rb new file mode 100644 index 0000000000..fb9b41298b --- /dev/null +++ b/lib/travis/api/v3/renderer/auto_refill.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::AutoRefill < ModelRenderer + representation(:standard, :addon_id, :enabled, :threshold, :amount) + representation(:minimal, :addon_id, :enabled, :threshold, :amount) + end +end diff --git a/lib/travis/api/v3/renderer/build_backup.rb b/lib/travis/api/v3/renderer/build_backup.rb new file mode 100644 index 0000000000..cf0b5118ff --- /dev/null +++ b/lib/travis/api/v3/renderer/build_backup.rb @@ -0,0 +1,12 @@ +module Travis::API::V3 + class Renderer::BuildBackup < ModelRenderer + representation(:minimal, :file_name, :created_at) + representation(:standard, *representations[:minimal]) + + def self.render(model, representation = :standard, **options) + return super unless options[:accept] == 'text/plain'.freeze + + model.content + end + end +end diff --git a/lib/travis/api/v3/renderer/build_backups.rb b/lib/travis/api/v3/renderer/build_backups.rb new file mode 100644 index 0000000000..b03bbdf49e --- /dev/null +++ b/lib/travis/api/v3/renderer/build_backups.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::BuildBackups < CollectionRenderer + type :build_backups + collection_key :build_backups + end +end diff --git a/lib/travis/api/v3/renderer/build_permission.rb b/lib/travis/api/v3/renderer/build_permission.rb new file mode 100644 index 0000000000..fe8d03a9bd --- /dev/null +++ b/lib/travis/api/v3/renderer/build_permission.rb @@ -0,0 +1,19 @@ +module Travis::API::V3 + class Renderer::BuildPermission < ModelRenderer + representation(:minimal, :user, :permission, :role) + representation(:standard, :user, :permission, :role) + + def user + Renderer.render_model(model.user, mode: :minimal) + end + + def permission + value = model.respond_to?(:build_permission) ? model.build_permission : model.build + value.nil? ? true : value + end + + def role + model.respond_to?(:role) ? model.role : nil + end + end +end diff --git a/lib/travis/api/v3/renderer/build_permissions.rb b/lib/travis/api/v3/renderer/build_permissions.rb new file mode 100644 index 0000000000..200c601106 --- /dev/null +++ b/lib/travis/api/v3/renderer/build_permissions.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Renderer::BuildPermissions < CollectionRenderer + type :build_permissions + collection_key :build_permissions + + def render_entry(entry, **options) + options[:type] = :build_permission + super + end + end +end diff --git a/lib/travis/api/v3/renderer/credits_calculator_config.rb b/lib/travis/api/v3/renderer/credits_calculator_config.rb new file mode 100644 index 0000000000..b68350d22f --- /dev/null +++ b/lib/travis/api/v3/renderer/credits_calculator_config.rb @@ -0,0 +1,5 @@ +module Travis::API::V3 + class Renderer::CreditsCalculatorConfig < ModelRenderer + representation(:standard, :users, :minutes, :os, :instance_size) + end +end diff --git a/lib/travis/api/v3/renderer/credits_result.rb b/lib/travis/api/v3/renderer/credits_result.rb new file mode 100644 index 0000000000..0ba570a8c7 --- /dev/null +++ b/lib/travis/api/v3/renderer/credits_result.rb @@ -0,0 +1,5 @@ +module Travis::API::V3 + class Renderer::CreditsResult < ModelRenderer + representation(:standard, :users, :minutes, :os, :instance_size, :credits, :price) + end +end diff --git a/lib/travis/api/v3/renderer/credits_results.rb b/lib/travis/api/v3/renderer/credits_results.rb new file mode 100644 index 0000000000..303f581513 --- /dev/null +++ b/lib/travis/api/v3/renderer/credits_results.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::CreditsResults < CollectionRenderer + type :credits_results + collection_key :credits_results + end +end diff --git a/lib/travis/api/v3/renderer/execution.rb b/lib/travis/api/v3/renderer/execution.rb new file mode 100644 index 0000000000..c2795bfdb4 --- /dev/null +++ b/lib/travis/api/v3/renderer/execution.rb @@ -0,0 +1,8 @@ +module Travis::API::V3 + class Renderer::Execution < ModelRenderer + representation :minimal, :id, :os, :instance_size, :arch, :virtualization_type, :queue, :job_id, + :repository_id, :owner_id, :owner_type, :plan_id, :sender_id, :credits_consumed, :started_at, + :user_license_credits_consumed, :finished_at, :created_at, :updated_at, :sender_login, :repo_slug, :repo_owner_name + representation :standard, *representations[:minimal] + end +end diff --git a/lib/travis/api/v3/renderer/execution_per_repo.rb b/lib/travis/api/v3/renderer/execution_per_repo.rb new file mode 100644 index 0000000000..428119a453 --- /dev/null +++ b/lib/travis/api/v3/renderer/execution_per_repo.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::ExecutionPerRepo < ModelRenderer + representation :minimal, :repository_id, :os, :credits_consumed, :minutes_consumed, :repository + representation :standard, *representations[:minimal] + end +end diff --git a/lib/travis/api/v3/renderer/execution_per_sender.rb b/lib/travis/api/v3/renderer/execution_per_sender.rb new file mode 100644 index 0000000000..dc1e08760e --- /dev/null +++ b/lib/travis/api/v3/renderer/execution_per_sender.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::ExecutionPerSender < ModelRenderer + representation :minimal, :credits_consumed, :minutes_consumed, :sender_id, :sender + representation :standard, *representations[:minimal] + end +end diff --git a/lib/travis/api/v3/renderer/executions.rb b/lib/travis/api/v3/renderer/executions.rb new file mode 100644 index 0000000000..4b85ebd807 --- /dev/null +++ b/lib/travis/api/v3/renderer/executions.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::Executions < CollectionRenderer + type :executions + collection_key :executions + end +end diff --git a/lib/travis/api/v3/renderer/executions_per_repo.rb b/lib/travis/api/v3/renderer/executions_per_repo.rb new file mode 100644 index 0000000000..18be82b86f --- /dev/null +++ b/lib/travis/api/v3/renderer/executions_per_repo.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::ExecutionsPerRepo < CollectionRenderer + type :executionsperrepo + collection_key :executionsperrepo + end +end diff --git a/lib/travis/api/v3/renderer/executions_per_sender.rb b/lib/travis/api/v3/renderer/executions_per_sender.rb new file mode 100644 index 0000000000..692383b1bb --- /dev/null +++ b/lib/travis/api/v3/renderer/executions_per_sender.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::ExecutionsPerSender < CollectionRenderer + type :executionspersender + collection_key :executionspersender + end +end diff --git a/lib/travis/api/v3/renderer/invoice.rb b/lib/travis/api/v3/renderer/invoice.rb index 2d7d1899f8..b624d8ee79 100644 --- a/lib/travis/api/v3/renderer/invoice.rb +++ b/lib/travis/api/v3/renderer/invoice.rb @@ -1,5 +1,5 @@ module Travis::API::V3 class Renderer::Invoice < ModelRenderer - representation(:standard, :id, :created_at, :url, :amount_due) + representation(:standard, :id, :created_at, :status, :url, :amount_due, :cc_last_digits) end end diff --git a/lib/travis/api/v3/renderer/leads.rb b/lib/travis/api/v3/renderer/leads.rb deleted file mode 100644 index 559cb61e78..0000000000 --- a/lib/travis/api/v3/renderer/leads.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Travis::API::V3 - class Renderer::Leads < ModelRenderer - representation(:standard, :id, :name, :status_label, :contacts, :custom) - end -end diff --git a/lib/travis/api/v3/renderer/log.rb b/lib/travis/api/v3/renderer/log.rb index 603ad59896..459f3e7f1e 100644 --- a/lib/travis/api/v3/renderer/log.rb +++ b/lib/travis/api/v3/renderer/log.rb @@ -25,8 +25,8 @@ def render(representation) if raw_log_href !~ /^\/v3/ raw_log_href = "/v3#{raw_log_href}" end - if enterprise? || model.repository_private? - token = LogToken.create(model.job) + if enterprise? || model.repository_private? || model.repository.user_settings.job_log_access_based_limit + token = LogToken.create(model.job, access_control&.user&.id) raw_log_href += "?log.token=#{token}" end result['@raw_log_href'] = raw_log_href diff --git a/lib/travis/api/v3/renderer/owner.rb b/lib/travis/api/v3/renderer/owner.rb index bcbabd27dc..ea641cc0fc 100644 --- a/lib/travis/api/v3/renderer/owner.rb +++ b/lib/travis/api/v3/renderer/owner.rb @@ -4,8 +4,9 @@ module Travis::API::V3 class Renderer::Owner < ModelRenderer include Renderer::AvatarURL - representation(:minimal, :id, :login, :vcs_type) - representation(:standard, :id, :login, :name, :github_id, :vcs_id, :vcs_type, :avatar_url, :education, :allow_migration) + representation(:minimal, :id, :login, :name, :vcs_type, :ro_mode) + representation(:standard, :id, :login, :name, :github_id, :vcs_id, :vcs_type, :avatar_url, :education, + :allow_migration, :allowance, :ro_mode) representation(:additional, :repositories, :installation) def initialize(*) @@ -28,5 +29,22 @@ def installation def allow_migration !!Travis::Features.owner_active?(:allow_migration, @model) end + + def allowance + return BillingClient.default_allowance_response(id) if Travis.config.org? + return BillingClient.default_allowance_response(id) unless access_control.user + + BillingClient.minimal_allowance_response(id) + end + + def owner_type + vcs_type.match(/User$/) ? 'User' : 'Organization' + end + + def ro_mode + return false unless Travis.config.org? && Travis.config.read_only? + + !Travis::Features.owner_active?(:read_only_disabled, model) + end end end diff --git a/lib/travis/api/v3/renderer/repository.rb b/lib/travis/api/v3/renderer/repository.rb index a1275b89aa..775fa6ca5d 100644 --- a/lib/travis/api/v3/renderer/repository.rb +++ b/lib/travis/api/v3/renderer/repository.rb @@ -1,9 +1,9 @@ module Travis::API::V3 class Renderer::Repository < ModelRenderer representation(:minimal, :id, :name, :slug) - representation(:standard, :id, :name, :slug, :description, :github_id, :vcs_id, :vcs_type, :github_language, :active, :private, :owner, :owner_name, :vcs_name, :default_branch, :starred, :managed_by_installation, :active_on_org, :migration_status, :history_migration_status, :shared, :config_validation) - representation(:experimental, :id, :name, :slug, :description, :vcs_id, :vcs_type, :github_id, :github_language, :active, :private, :owner, :default_branch, :starred, :current_build, :last_started_build, :next_build_number) - representation(:internal, :id, :name, :slug, :github_id, :vcs_id, :vcs_type, :active, :private, :owner, :default_branch, :private_key, :token, :user_settings) + representation(:standard, :id, :name, :slug, :description, :github_id, :vcs_id, :vcs_type, :github_language, :active, :private, :owner, :owner_name, :vcs_name, :default_branch, :starred, :managed_by_installation, :active_on_org, :migration_status, :history_migration_status, :shared, :config_validation, :server_type) + representation(:experimental, :id, :name, :slug, :description, :vcs_id, :vcs_type, :github_id, :github_language, :active, :private, :owner, :default_branch, :starred, :current_build, :last_started_build, :next_build_number, :server_type) + representation(:internal, :id, :name, :slug, :github_id, :vcs_id, :vcs_type, :active, :private, :owner, :default_branch, :private_key, :token, :user_settings, :server_type) representation(:additional, :allow_migration) hidden_representations(:experimental, :internal) @@ -75,12 +75,18 @@ def owner if included_owner? and owner_href { :@href => owner_href } else - result = { :@type => owner_type, :id => model.owner_id, :login => model.owner_name } + result = { :@type => owner_type, :id => model.owner_id, :login => model.owner_name, :ro_mode => owner_ro_mode } result[:@href] = owner_href if owner_href result end end + def owner_ro_mode + return false unless Travis.config.org? && Travis.config.read_only? + + !Travis::Features.owner_active?(:read_only_disabled, model.owner) + end + def include_owner? return false if model.owner_type.nil? return false if included_owner? @@ -99,5 +105,9 @@ def owner_type def managed_by_installation model.managed_by_installation? end + + def server_type + model.server_type || 'git' + end end end diff --git a/lib/travis/api/v3/renderer/subscription.rb b/lib/travis/api/v3/renderer/subscription.rb index c6f378c7e7..b86a41a5e6 100644 --- a/lib/travis/api/v3/renderer/subscription.rb +++ b/lib/travis/api/v3/renderer/subscription.rb @@ -24,7 +24,7 @@ def discount end class Renderer::BillingInfo < ModelRenderer - representation(:standard, :id, :address, :address2, :billing_email, :city, :company, :country, :first_name, :last_name, :state, :vat_id, :zip_code) + representation(:standard, :id, :address, :address2, :billing_email, :city, :company, :country, :first_name, :last_name, :state, :vat_id, :zip_code, :has_local_registration) end class Renderer::CreditCardInfo < ModelRenderer diff --git a/lib/travis/api/v3/renderer/user.rb b/lib/travis/api/v3/renderer/user.rb index 3488d6005a..567ad3efce 100644 --- a/lib/travis/api/v3/renderer/user.rb +++ b/lib/travis/api/v3/renderer/user.rb @@ -2,15 +2,15 @@ module Travis::API::V3 class Renderer::User < Renderer::Owner - representation(:standard, :email, :is_syncing, :synced_at, :recently_signed_up, :secure_user_hash) + representation(:standard, :email, :is_syncing, :synced_at, :recently_signed_up, :secure_user_hash, :ro_mode, :confirmed_at) representation(:additional, :emails) def email - @model.email if current_user? + @model.email if show_emails? end def emails - current_user? ? @model.emails.map(&:email) : [] + show_emails? ? @model.emails.map(&:email) : [] end def secure_user_hash @@ -18,8 +18,18 @@ def secure_user_hash OpenSSL::HMAC.hexdigest('sha256', hmac_secret_key, @model.id.to_s) if @model.id && hmac_secret_key end + def ro_mode + return false unless Travis.config.org? && Travis.config.read_only? + + current_user? ? !Travis::Features.owner_active?(:read_only_disabled, @model) : false + end + private + def show_emails? + current_user? || options[:show_email] == true + end + def current_user? access_control.class == Travis::API::V3::AccessControl::LegacyToken && access_control.user.id == @model.id end diff --git a/lib/travis/api/v3/renderer/v2_addon.rb b/lib/travis/api/v3/renderer/v2_addon.rb new file mode 100644 index 0000000000..8b3a39c3ca --- /dev/null +++ b/lib/travis/api/v3/renderer/v2_addon.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Renderer::V2Addon < ModelRenderer + representation(:standard, :id, :name, :type, :current_usage, :recurring) + representation(:minimal, :id, :name, :type, :current_usage, :recurring) + + def current_usage + Renderer.render_model(model.current_usage, mode: :standard) unless model.current_usage.nil? + end + end +end diff --git a/lib/travis/api/v3/renderer/v2_addon_config.rb b/lib/travis/api/v3/renderer/v2_addon_config.rb new file mode 100644 index 0000000000..7e0ab2a7ca --- /dev/null +++ b/lib/travis/api/v3/renderer/v2_addon_config.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::V2AddonConfig < ModelRenderer + representation(:standard, :id, :name, :price, :quantity, :type) + representation(:minimal, :id, :name, :price, :quantity, :type) + end +end diff --git a/lib/travis/api/v3/renderer/v2_addon_usage.rb b/lib/travis/api/v3/renderer/v2_addon_usage.rb new file mode 100644 index 0000000000..be1cd7914a --- /dev/null +++ b/lib/travis/api/v3/renderer/v2_addon_usage.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::V2AddonUsage < ModelRenderer + representation(:standard, :id, :addon_id, :addon_quantity, :addon_usage, :remaining, :purchase_date, :valid_to, :active, :status) + representation(:minimal, :id, :addon_id, :addon_quantity, :addon_usage, :remaining, :purchase_date, :valid_to, :active, :status) + end +end diff --git a/lib/travis/api/v3/renderer/v2_addon_usages.rb b/lib/travis/api/v3/renderer/v2_addon_usages.rb new file mode 100644 index 0000000000..6294b37222 --- /dev/null +++ b/lib/travis/api/v3/renderer/v2_addon_usages.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::V2AddonUsages < CollectionRenderer + type :v2_addon_usages + collection_key :v2_addon_usages + end +end diff --git a/lib/travis/api/v3/renderer/v2_plan_config.rb b/lib/travis/api/v3/renderer/v2_plan_config.rb new file mode 100644 index 0000000000..d5d102057e --- /dev/null +++ b/lib/travis/api/v3/renderer/v2_plan_config.rb @@ -0,0 +1,8 @@ +module Travis::API::V3 + class Renderer::V2PlanConfig < ModelRenderer + representation(:standard, :id, :name, :private_repos, :starting_price, :starting_users, :private_credits, + :public_credits, :addon_configs, :plan_type, :concurrency_limit, :available_standalone_addons, :trial_plan, :annual, :auto_refill_thresholds, :auto_refill_amounts) + representation(:minimal, :id, :name, :private_repos, :starting_price, :starting_users, :private_credits, + :public_credits, :addon_configs, :plan_type, :concurrency_limit, :trial_plan, :annual, :auto_refill_thresholds, :auto_refill_amounts) + end +end diff --git a/lib/travis/api/v3/renderer/v2_plans.rb b/lib/travis/api/v3/renderer/v2_plans.rb new file mode 100644 index 0000000000..64486fc67d --- /dev/null +++ b/lib/travis/api/v3/renderer/v2_plans.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::V2Plans < CollectionRenderer + type :v2_plans + collection_key :v2_plans + end +end diff --git a/lib/travis/api/v3/renderer/v2_subscription.rb b/lib/travis/api/v3/renderer/v2_subscription.rb new file mode 100644 index 0000000000..4a6f677331 --- /dev/null +++ b/lib/travis/api/v3/renderer/v2_subscription.rb @@ -0,0 +1,29 @@ +module Travis::API::V3 + class Renderer::V2Subscription < ModelRenderer + representation(:standard, :id, :plan, :addons, :auto_refill, :status, :valid_to, :canceled_at, :source, :owner, :client_secret, :billing_info, :credit_card_info, :payment_intent, :created_at, :scheduled_plan_name) + + def billing_info + Renderer.render_model(model.billing_info, mode: :standard) unless model.billing_info.nil? + end + + def credit_card_info + Renderer.render_model(model.credit_card_info, mode: :standard) unless model.credit_card_info.nil? + end + + def plan + Renderer.render_model(model.plan, mode: :standard) unless model.plan.nil? + end + + def payment_intent + Renderer.render_model(model.payment_intent, mode: :standard) unless model.payment_intent.nil? + end + end + + class Renderer::V2BillingInfo < ModelRenderer + representation(:standard, :id, :address, :address2, :billing_email, :city, :company, :country, :first_name, :last_name, :state, :vat_id, :zip_code, :has_local_registration) + end + + class Renderer::V2CreditCardInfo < ModelRenderer + representation(:standard, :id, :card_owner, :expiration_date, :last_digits) + end +end diff --git a/lib/travis/api/v3/renderer/v2_subscriptions.rb b/lib/travis/api/v3/renderer/v2_subscriptions.rb new file mode 100644 index 0000000000..3f49119da8 --- /dev/null +++ b/lib/travis/api/v3/renderer/v2_subscriptions.rb @@ -0,0 +1,22 @@ +module Travis::API::V3 + class Renderer::V2Subscriptions < CollectionRenderer + type :v2_subscriptions + collection_key :v2_subscriptions + + def fields + super.tap do |fields| + fields[:@permissions] = render_entry(permissions) + end + end + + private + + def list + @list.subscriptions + end + + def permissions + @list.permissions + end + end +end diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb index 16c48cc83b..0093174416 100644 --- a/lib/travis/api/v3/routes.rb +++ b/lib/travis/api/v3/routes.rb @@ -33,6 +33,17 @@ module Routes get :for_current_user end + resource :build_backups do + route '/build_backups' + get :all + end + + resource :build_backup do + route '/build_backup/{build_backup.id}' + get :find + get :find, '.txt' + end + resource :jobs do route '/jobs' get :for_current_user @@ -96,6 +107,12 @@ module Routes get :for_organization patch :update end + + resource :build_permissions do + route '/build_permissions' + get :find_for_organization + patch :update_for_organization + end end resource :organizations do @@ -116,6 +133,32 @@ module Routes route '/active' get :for_owner end + + resource :allowance do + route '/allowance' + get :for_owner + end + + resource :executions do + route '/executions' + get :for_owner + end + + resource :executions do + route '/executions_per_repo' + get :for_owner_per_repo + end + + resource :executions do + route '/executions_per_sender' + get :for_owner_per_sender + end + end + + resource :credits_calculator do + route '/credits_calculator' + post :calculator + get :default_config end resource :repositories do @@ -146,6 +189,12 @@ module Routes end end + resource :build_permissions do + route '/build_permissions' + get :find_for_repo + patch :update_for_repo + end + resource :branches do route '/branches' get :find @@ -153,7 +202,7 @@ module Routes resource :builds do route '/builds' - get :find + get :find end resource :caches do @@ -297,6 +346,12 @@ module Routes post :create end + hidden_resource :v2_subscriptions do + route '/v2_subscriptions' + get :all + post :create + end + hidden_resource :subscription do route '/subscription/{subscription.id}' patch :update_address, '/address' @@ -308,6 +363,22 @@ module Routes get :invoices, '/invoices' end + hidden_resource :v2_subscription do + route '/v2_subscription/{subscription.id}' + patch :update_address, '/address' + patch :update_creditcard, '/creditcard' + patch :changetofree, '/changetofree' + patch :update_plan, '/plan' + post :pay, '/pay' + post :cancel, '/cancel' + post :buy_addon, '/addon/{addon.id}' + get :user_usages, '/user_usages' + get :invoices, '/invoices' + get :auto_refill, '/auto_refill' + patch :toggle_auto_refill, '/auto_refill' + patch :update_auto_refill, '/update_auto_refill' + end + hidden_resource :trials do route '/trials' get :all @@ -323,6 +394,12 @@ module Routes route '/plans_for' get :all, '/user' get :all, '/organization/{organization.id}' + end + + hidden_resource :v2_plans do + route '/v2_plans_for' + get :all, '/user' + get :all, '/organization/{organization.id}' end @@ -344,5 +421,6 @@ module Routes route '/queues/{queue.name}' get :stats, '/stats' end + end end diff --git a/lib/travis/api/v3/service.rb b/lib/travis/api/v3/service.rb index 9cd9057e77..405b7ad854 100644 --- a/lib/travis/api/v3/service.rb +++ b/lib/travis/api/v3/service.rb @@ -192,6 +192,10 @@ def abuse_detected(message = 'Abuse detected. Restart disabled. If you think you rejected(Error.new(message, status: 403)) end + def insufficient_balance(message = 'Builds have been temporarily disabled for private repositories due to a insufficient credit balance') + rejected(Error.new(message, status: 403)) + end + def not_implemented raise NotImplemented end diff --git a/lib/travis/api/v3/services.rb b/lib/travis/api/v3/services.rb index 65c46aec74..90725e9469 100644 --- a/lib/travis/api/v3/services.rb +++ b/lib/travis/api/v3/services.rb @@ -4,6 +4,7 @@ module Services Accounts = Module.new { extend Services } Active = Module.new { extend Services } + Allowance = Module.new { extend Services } BetaFeature = Module.new { extend Services } BetaFeatures = Module.new { extend Services } BetaMigrationRequest = Module.new { extend Services } @@ -14,21 +15,25 @@ module Services Broadcasts = Module.new { extend Services } Build = Module.new { extend Services } Builds = Module.new { extend Services } + BuildBackup = Module.new { extend Services } + BuildBackups = Module.new { extend Services } + BuildPermissions = Module.new { extend Services } Caches = Module.new { extend Services } Coupons = Module.new { extend Services } + CreditsCalculator = Module.new { extend Services } Cron = Module.new { extend Services } Crons = Module.new { extend Services } EmailSubscription = Module.new { extend Services } EnvVar = Module.new { extend Services } EnvVars = Module.new { extend Services } EnterpriseLicense = Module.new { extend Services } + Executions = Module.new { extend Services } Gdpr = Module.new { extend Services } Insights = Module.new { extend Services } Installation = Module.new { extend Services } Job = Module.new { extend Services } Jobs = Module.new { extend Services } KeyPair = Module.new { extend Services } - Leads = Module.new { extend Services } Lint = Module.new { extend Services } Log = Module.new { extend Services } Messages = Module.new { extend Services } @@ -36,6 +41,7 @@ module Services Organizations = Module.new { extend Services } Owner = Module.new { extend Services } Plans = Module.new { extend Services } + V2Plans = Module.new { extend Services } Preferences = Module.new { extend Services } Preference = Module.new { extend Services } Queues = Module.new { extend Services } @@ -47,6 +53,8 @@ module Services Stages = Module.new { extend Services } Subscription = Module.new { extend Services } Subscriptions = Module.new { extend Services } + V2Subscription = Module.new { extend Services } + V2Subscriptions = Module.new { extend Services } Trials = Module.new { extend Services } User = Module.new { extend Services } UserSetting = Module.new { extend Services } diff --git a/lib/travis/api/v3/services/allowance/for_owner.rb b/lib/travis/api/v3/services/allowance/for_owner.rb new file mode 100644 index 0000000000..e70c6ca9dd --- /dev/null +++ b/lib/travis/api/v3/services/allowance/for_owner.rb @@ -0,0 +1,15 @@ +module Travis::API::V3 + class Services::Allowance::ForOwner < Service + def run! + return result BillingClient.default_allowance_response if Travis.config.org? + raise LoginRequired unless access_control.logged_in? + + owner = query(:owner).find + + raise NotFound unless owner + raise InsufficientAccess unless access_control.visible?(owner) + + result query(:allowance).for_owner(owner, access_control.user.id) + end + end +end diff --git a/lib/travis/api/v3/services/build/cancel.rb b/lib/travis/api/v3/services/build/cancel.rb index a7b784cb63..74ddb2dd13 100644 --- a/lib/travis/api/v3/services/build/cancel.rb +++ b/lib/travis/api/v3/services/build/cancel.rb @@ -3,6 +3,8 @@ class Services::Build::Cancel < Service def run build = check_login_and_find(:build) + return not_found if build.owner.ro_mode? + access_control.permissions(build).cancel! query.cancel(access_control.user, build.id) diff --git a/lib/travis/api/v3/services/build/restart.rb b/lib/travis/api/v3/services/build/restart.rb index 359ad2b7e1..18de0d571c 100644 --- a/lib/travis/api/v3/services/build/restart.rb +++ b/lib/travis/api/v3/services/build/restart.rb @@ -3,16 +3,20 @@ class Services::Build::Restart < Service def run build = check_login_and_find(:build) + return not_found if build.owner.ro_mode? return repo_migrated if migrated?(build.repository) access_control.permissions(build).restart! build.clear_debug_options! - restart_status = query.restart(access_control.user) - if restart_status == "abuse_detected" + result = query.restart(access_control.user) + + if result.success? + accepted(build: build, state_change: :restart) + elsif result.error == Travis::Enqueue::Services::RestartModel::ABUSE_DETECTED abuse_detected else - accepted(build: build, state_change: :restart) + insufficient_balance end end end diff --git a/lib/travis/api/v3/services/build_backup/find.rb b/lib/travis/api/v3/services/build_backup/find.rb new file mode 100644 index 0000000000..10e2c4284f --- /dev/null +++ b/lib/travis/api/v3/services/build_backup/find.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Services::BuildBackup::Find < Service + params :repository_id + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + result query(:build_backup).find + end + end +end diff --git a/lib/travis/api/v3/services/build_backups/all.rb b/lib/travis/api/v3/services/build_backups/all.rb new file mode 100644 index 0000000000..3383385857 --- /dev/null +++ b/lib/travis/api/v3/services/build_backups/all.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::BuildBackups::All < Service + params :repository_id + paginate + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + result query(:build_backups).all + end + end +end diff --git a/lib/travis/api/v3/services/build_permissions/find_for_organization.rb b/lib/travis/api/v3/services/build_permissions/find_for_organization.rb new file mode 100644 index 0000000000..57586ccaca --- /dev/null +++ b/lib/travis/api/v3/services/build_permissions/find_for_organization.rb @@ -0,0 +1,9 @@ +module Travis::API::V3 + class Services::BuildPermissions::FindForOrganization < Service + result_type :build_permissions + + def run! + result query.find_for_organization(check_login_and_find(:organization)) + end + end +end diff --git a/lib/travis/api/v3/services/build_permissions/find_for_repo.rb b/lib/travis/api/v3/services/build_permissions/find_for_repo.rb new file mode 100644 index 0000000000..c71912750b --- /dev/null +++ b/lib/travis/api/v3/services/build_permissions/find_for_repo.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Services::BuildPermissions::FindForRepo < Service + paginate + result_type :build_permissions + + def run! + result query.find_for_repo(check_login_and_find(:repository)) + end + end +end diff --git a/lib/travis/api/v3/services/build_permissions/update_for_organization.rb b/lib/travis/api/v3/services/build_permissions/update_for_organization.rb new file mode 100644 index 0000000000..43a94b92c1 --- /dev/null +++ b/lib/travis/api/v3/services/build_permissions/update_for_organization.rb @@ -0,0 +1,15 @@ +module Travis::API::V3 + class Services::BuildPermissions::UpdateForOrganization < Service + params :user_ids, :permission + + def run! + organization = check_login_and_find(:organization) + + raise LoginRequired unless access_control.adminable?(organization) + raise ClientError, 'user_ids must be an array' unless params['user_ids'].is_a?(Array) + query.update_for_organization(organization, params['user_ids'], params['permission']) + + no_content + end + end +end diff --git a/lib/travis/api/v3/services/build_permissions/update_for_repo.rb b/lib/travis/api/v3/services/build_permissions/update_for_repo.rb new file mode 100644 index 0000000000..82287f4f4e --- /dev/null +++ b/lib/travis/api/v3/services/build_permissions/update_for_repo.rb @@ -0,0 +1,15 @@ +module Travis::API::V3 + class Services::BuildPermissions::UpdateForRepo < Service + params :user_ids, :permission + + def run! + repository = check_login_and_find(:repository) + + raise LoginRequired unless access_control.admin_for(repository) + raise ClientError, 'user_ids must be an array' unless params['user_ids'].is_a?(Array) + query.update_for_repo(repository, params['user_ids'], params['permission']) + + no_content + end + end +end diff --git a/lib/travis/api/v3/services/credits_calculator/calculator.rb b/lib/travis/api/v3/services/credits_calculator/calculator.rb new file mode 100644 index 0000000000..a0dee86f39 --- /dev/null +++ b/lib/travis/api/v3/services/credits_calculator/calculator.rb @@ -0,0 +1,12 @@ +module Travis::API::V3 + class Services::CreditsCalculator::Calculator < Service + result_type :credits_results + params :users, :executions + + def run! + raise LoginRequired unless access_control.logged_in? + + result query(:credits_calculator).calculate(access_control.user.id) + end + end +end diff --git a/lib/travis/api/v3/services/credits_calculator/default_config.rb b/lib/travis/api/v3/services/credits_calculator/default_config.rb new file mode 100644 index 0000000000..2455a71862 --- /dev/null +++ b/lib/travis/api/v3/services/credits_calculator/default_config.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::CreditsCalculator::DefaultConfig < Service + result_type :credits_calculator_config + + def run! + raise LoginRequired unless access_control.logged_in? + + result query(:credits_calculator).default_config(access_control.user.id) + end + end +end diff --git a/lib/travis/api/v3/services/executions/for_owner.rb b/lib/travis/api/v3/services/executions/for_owner.rb new file mode 100644 index 0000000000..98af195d49 --- /dev/null +++ b/lib/travis/api/v3/services/executions/for_owner.rb @@ -0,0 +1,34 @@ +module Travis::API::V3 + class Services::Executions::ForOwner < Service + params :page, :per_page, :from, :to + result_type :executions + + def run! + raise MethodNotAllowed if Travis.config.org? + raise LoginRequired unless access_control.logged_in? + + owner = query(:owner).find + + raise NotFound unless owner + raise InsufficientAccess unless access_control.visible?(owner) + + results = query(:executions).for_owner(owner, access_control.user.id, params['page'] || 0, + params['per_page'] || 0, params['from'], params['to']) + result presented_results(results) + end + + def presented_results(results) + senders = Travis::API::V3::Models::User.where(id: results.map(&:sender_id)).index_by(&:id) + repositories = Travis::API::V3::Models::Repository.where(id: results.map(&:repository_id)).index_by(&:id) + + results.map do |execution| + execution.sender_login = senders[execution.sender_id]&.login || 'Unknown Sender' + repo = repositories[execution.repository_id] + execution.repo_slug = repo&.slug || 'Unknown Repository' + execution.repo_owner_name = repo&.owner_name || 'Unknown Repository Owner' + + execution + end + end + end +end diff --git a/lib/travis/api/v3/services/executions/for_owner_per_repo.rb b/lib/travis/api/v3/services/executions/for_owner_per_repo.rb new file mode 100644 index 0000000000..967842da87 --- /dev/null +++ b/lib/travis/api/v3/services/executions/for_owner_per_repo.rb @@ -0,0 +1,48 @@ +module Travis::API::V3 + class Services::Executions::ForOwnerPerRepo < Service + params :from, :to + result_type :executions_per_repo + + def run! + raise MethodNotAllowed if Travis.config.org? + raise LoginRequired unless access_control.logged_in? + + owner = query(:owner).find + + raise NotFound unless owner + raise InsufficientAccess unless access_control.visible?(owner) + + results = query(:executions).for_owner(owner, access_control.user.id, 0, 0, + params['from'], params['to']) + result recuce_by_repo(results) + end + + def recuce_by_repo(results) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + reduced = [] + results.each do |item| + minutes_consumed = calculate_minutes(item.started_at, item.finished_at) + obj = reduced.find { |one| one[:repository_id] == item.repository_id && one[:os] == item.os } + if obj + obj[:credits_consumed] += item.credits_consumed + obj[:minutes_consumed] += minutes_consumed + else + repo = Travis::API::V3::Models::Repository.find(item.repository_id) + reduced << { + repository_id: item.repository_id, + os: item.os, + credits_consumed: item.credits_consumed, + minutes_consumed: minutes_consumed, + repository: Renderer.render_model(repo, mode: :standard) + } + end + end + reduced + end + + def calculate_minutes(start, finish) + return 0 if start.to_s.empty? || finish.to_s.empty? + + ((Time.parse(finish.to_s) - Time.parse(start.to_s)) / 60.to_f).ceil + end + end +end diff --git a/lib/travis/api/v3/services/executions/for_owner_per_sender.rb b/lib/travis/api/v3/services/executions/for_owner_per_sender.rb new file mode 100644 index 0000000000..9276340fc5 --- /dev/null +++ b/lib/travis/api/v3/services/executions/for_owner_per_sender.rb @@ -0,0 +1,47 @@ +module Travis::API::V3 + class Services::Executions::ForOwnerPerSender < Service + params :from, :to + result_type :executions_per_sender + + def run! + raise MethodNotAllowed if Travis.config.org? + raise LoginRequired unless access_control.logged_in? + + owner = query(:owner).find + + raise NotFound unless owner + raise InsufficientAccess unless access_control.visible?(owner) + + results = query(:executions).for_owner(owner, access_control.user.id, 0, 0, + params['from'], params['to']) + result recuce_by_sender(results) + end + + def recuce_by_sender(results) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + reduced = [] + results.each do |item| + minutes_consumed = calculate_minutes(item.started_at, item.finished_at) + obj = reduced.find { |one| one[:sender_id] == item.sender_id } + if obj + obj[:credits_consumed] += item.credits_consumed + obj[:minutes_consumed] += minutes_consumed + else + sender = Travis::API::V3::Models::User.find(item.sender_id) + reduced << { + credits_consumed: item.credits_consumed, + minutes_consumed: minutes_consumed, + sender_id: item.sender_id, + sender: Renderer.render_model(sender, mode: :standard, show_email: true) + } + end + end + reduced + end + + def calculate_minutes(start, finish) + return 0 if start.to_s.empty? || finish.to_s.empty? + + ((Time.parse(finish.to_s) - Time.parse(start.to_s)) / 60.to_f).ceil + end + end +end diff --git a/lib/travis/api/v3/services/job/cancel.rb b/lib/travis/api/v3/services/job/cancel.rb index a6f143ecd5..e0a2ebc716 100644 --- a/lib/travis/api/v3/services/job/cancel.rb +++ b/lib/travis/api/v3/services/job/cancel.rb @@ -3,6 +3,8 @@ class Services::Job::Cancel < Service def run job = check_login_and_find(:job) + return not_found if job.owner.ro_mode? + access_control.permissions(job).cancel! query.cancel(access_control.user) diff --git a/lib/travis/api/v3/services/job/restart.rb b/lib/travis/api/v3/services/job/restart.rb index f8c6fe55d3..183a8a40c4 100644 --- a/lib/travis/api/v3/services/job/restart.rb +++ b/lib/travis/api/v3/services/job/restart.rb @@ -3,17 +3,20 @@ class Services::Job::Restart < Service def run job = check_login_and_find(:job) + return not_found if job.owner.ro_mode? access_control.permissions(job).restart! return repo_migrated if migrated?(job.repository) job.update_attribute(:debug_options, nil) - restart_status = query.restart(access_control.user) + result = query.restart(access_control.user) - if restart_status == "abuse_detected" + if result.success? + accepted(job: job, state_change: :restart) + elsif result.error == Travis::Enqueue::Services::RestartModel::ABUSE_DETECTED abuse_detected else - accepted(job: job, state_change: :restart) + insufficient_balance end end end diff --git a/lib/travis/api/v3/services/log/find.rb b/lib/travis/api/v3/services/log/find.rb index 85a07756a0..0878bf8a26 100644 --- a/lib/travis/api/v3/services/log/find.rb +++ b/lib/travis/api/v3/services/log/find.rb @@ -3,8 +3,19 @@ class Services::Log::Find < Service params 'log.token' def run! - log = query.find_by_job_id(params['job.id']) + job = Models::Job.find(params['job.id']) + log = query.find(job) + repo_can_write = false + if access_control.is_a?(Travis::API::V3::AccessControl::LogToken) + repo_can_write = access_control.repo_can_write + elsif access_control.user + repo_can_write = !!job.repository.users.where(id: access_control.user.id, permissions: { push: true }).first + end + raise(NotFound, :log) unless access_control.visible? log + raise LogExpired if !job.repository.user_settings.job_log_time_based_limit && job.started_at && job.started_at < Time.now - job.repository.user_settings.job_log_access_older_than_days.days + raise LogAccessDenied if job.repository.user_settings.job_log_access_based_limit && !repo_can_write + result log end end diff --git a/lib/travis/api/v3/services/repository/activate.rb b/lib/travis/api/v3/services/repository/activate.rb index 616174920e..4ec90d3c15 100644 --- a/lib/travis/api/v3/services/repository/activate.rb +++ b/lib/travis/api/v3/services/repository/activate.rb @@ -9,26 +9,19 @@ def run! return repo_migrated if migrated?(repository) admin = access_control.admin_for(repository) - if Travis::Features.user_active?(:use_vcs, admin) || !admin.github? - remote_vcs_repository.set_hook( - repository_id: repository.id, - user_id: admin.id - ) - else - github(admin).set_hook(repository, true) - end + remote_vcs_repository.set_hook( + repository_id: repository.id, + user_id: admin.id + ) + repository.update(active: true) if repository.private? || access_control.enterprise? - if Travis::Features.deactivate_owner(:use_vcs, admin) || !admin.github? - remote_vcs_repository.upload_key( - repository_id: repository.id, - user_id: admin.id, - read_only: !Travis::Features.owner_active?(:read_write_github_keys, repository.owner) - ) - else - github(admin).upload_key(repository) - end + remote_vcs_repository.upload_key( + repository_id: repository.id, + user_id: admin.id, + read_only: !Travis::Features.owner_active?(:read_write_github_keys, repository.owner) + ) end query.sync(access_control.user || access_control.admin_for(repository)) diff --git a/lib/travis/api/v3/services/repository/deactivate.rb b/lib/travis/api/v3/services/repository/deactivate.rb index 6a366d67d4..248da1ac3b 100644 --- a/lib/travis/api/v3/services/repository/deactivate.rb +++ b/lib/travis/api/v3/services/repository/deactivate.rb @@ -7,17 +7,12 @@ def run!(activate = false) admin = access_control.admin_for(repository) - if Travis::Features.user_active?(:use_vcs, admin) || !admin.github? - remote_vcs_repository.set_hook( - repository_id: repository.id, - user_id: admin.id, - activate: activate - ) - else - github(admin).set_hook(repository, activate) - end + remote_vcs_repository.set_hook( + repository_id: repository.id, + user_id: admin.id, + activate: activate + ) repository.update(active: activate) - result repository end diff --git a/lib/travis/api/v3/services/request/preview.rb b/lib/travis/api/v3/services/request/preview.rb index 771f94490a..9dc8cd2e2b 100644 --- a/lib/travis/api/v3/services/request/preview.rb +++ b/lib/travis/api/v3/services/request/preview.rb @@ -6,6 +6,7 @@ class Services::Request::Preview < Service def run repository = check_login_and_find(:repository) + access_control.permissions(repository).create_request! user = access_control.user result query(:request_preview).expand(user, repo) diff --git a/lib/travis/api/v3/services/requests/create.rb b/lib/travis/api/v3/services/requests/create.rb index 2d9daaa94b..1ffcc4aba7 100644 --- a/lib/travis/api/v3/services/requests/create.rb +++ b/lib/travis/api/v3/services/requests/create.rb @@ -9,6 +9,8 @@ class Services::Requests::Create < Service def run repository = check_login_and_find(:repository) + return not_found if repository.owner.ro_mode? + access_control.permissions(repository).create_request! return repo_migrated if migrated?(repository) diff --git a/lib/travis/api/v3/services/subscription/update_address.rb b/lib/travis/api/v3/services/subscription/update_address.rb index 943e7ad45c..c07ea7918f 100644 --- a/lib/travis/api/v3/services/subscription/update_address.rb +++ b/lib/travis/api/v3/services/subscription/update_address.rb @@ -1,6 +1,6 @@ module Travis::API::V3 class Services::Subscription::UpdateAddress < Service - params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email + params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email, :has_local_registration def run! raise LoginRequired unless access_control.full_access_or_logged_in? diff --git a/lib/travis/api/v3/services/subscriptions/create.rb b/lib/travis/api/v3/services/subscriptions/create.rb index 4818e6ab7e..8b7a699619 100644 --- a/lib/travis/api/v3/services/subscriptions/create.rb +++ b/lib/travis/api/v3/services/subscriptions/create.rb @@ -2,7 +2,7 @@ module Travis::API::V3 class Services::Subscriptions::Create < Service result_type :subscription params :plan, :coupon, :organization_id, :client_secret - params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email, prefix: :billing_info + params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email, :has_local_registration, prefix: :billing_info params :token, prefix: :credit_card_info def run! diff --git a/lib/travis/api/v3/services/user/sync.rb b/lib/travis/api/v3/services/user/sync.rb index 577136a85d..2970c1a1d2 100644 --- a/lib/travis/api/v3/services/user/sync.rb +++ b/lib/travis/api/v3/services/user/sync.rb @@ -3,6 +3,8 @@ class Services::User::Sync < Service def run! user = check_login_and_find(:user) + return not_found if user.ro_mode? + access_control.permissions(user).sync! result query.sync(user) diff --git a/lib/travis/api/v3/services/user_setting/update.rb b/lib/travis/api/v3/services/user_setting/update.rb index b99aabf51f..483211c8b8 100644 --- a/lib/travis/api/v3/services/user_setting/update.rb +++ b/lib/travis/api/v3/services/user_setting/update.rb @@ -9,8 +9,9 @@ def run! user_setting = query.find(repository) access_control.permissions(user_setting).write! if user_setting + app_id = Travis::Api::App::AccessToken.find_by_token(access_control.token).app_id - user_setting = query.update(repository) + user_setting = query.update(repository, access_control.user, app_id == 2) result user_setting end end diff --git a/lib/travis/api/v3/services/v2_plans/all.rb b/lib/travis/api/v3/services/v2_plans/all.rb new file mode 100644 index 0000000000..3a0e739fb3 --- /dev/null +++ b/lib/travis/api/v3/services/v2_plans/all.rb @@ -0,0 +1,9 @@ +module Travis::API::V3 + class Services::V2Plans::All < Service + params :organization_id + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + result query(:v2_plans).all(access_control.user.id) + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/auto_refill.rb b/lib/travis/api/v3/services/v2_subscription/auto_refill.rb new file mode 100644 index 0000000000..2c290e2341 --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/auto_refill.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Services::V2Subscription::AutoRefill < Service + result_type :auto_refill + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + result query.get_auto_refill(access_control.user.id, params['subscription.id']), status: 200 + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/buy_addon.rb b/lib/travis/api/v3/services/v2_subscription/buy_addon.rb new file mode 100644 index 0000000000..744dde7799 --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/buy_addon.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::V2Subscription::BuyAddon < Service + params :plan + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + query.buy_addon(access_control.user.id) + no_content + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/cancel.rb b/lib/travis/api/v3/services/v2_subscription/cancel.rb new file mode 100644 index 0000000000..9ef5481b79 --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/cancel.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::V2Subscription::Cancel < Service + params :reason, :reason_details + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + query.cancel(access_control.user.id) + no_content + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/changetofree_plan.rb b/lib/travis/api/v3/services/v2_subscription/changetofree_plan.rb new file mode 100644 index 0000000000..1276f41e5b --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/changetofree_plan.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::V2Subscription::Changetofree < Service + params :plan + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + query.changetofree(access_control.user.id) + no_content + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/invoices.rb b/lib/travis/api/v3/services/v2_subscription/invoices.rb new file mode 100644 index 0000000000..0e0b398edf --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/invoices.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Services::V2Subscription::Invoices < Service + result_type :invoices + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + result query(:v2_invoices).all(access_control.user.id) + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/pay.rb b/lib/travis/api/v3/services/v2_subscription/pay.rb new file mode 100644 index 0000000000..3f464409b1 --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/pay.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Services::V2Subscription::Pay < Service + result_type :v2_subscription + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + result query.pay(access_control.user.id), status: 200 + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/toggle_auto_refill.rb b/lib/travis/api/v3/services/v2_subscription/toggle_auto_refill.rb new file mode 100644 index 0000000000..2d9962a0cd --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/toggle_auto_refill.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Services::V2Subscription::ToggleAutoRefill < Service + params :enabled + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + query.toggle_auto_refill(access_control.user.id, params['subscription.id']) + no_content + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/update_address.rb b/lib/travis/api/v3/services/v2_subscription/update_address.rb new file mode 100644 index 0000000000..43c345615d --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/update_address.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::V2Subscription::UpdateAddress < Service + params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email, :has_local_registration + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + query.update_address(access_control.user.id) + no_content + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/update_auto_refill.rb b/lib/travis/api/v3/services/v2_subscription/update_auto_refill.rb new file mode 100644 index 0000000000..377b3ea0b8 --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/update_auto_refill.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Services::V2Subscription::UpdateAutoRefill < Service + params :addon_id, :threshold, :amount + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + query.update_auto_refill(access_control.user.id, params['addon_id']) + no_content + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/update_creditcard.rb b/lib/travis/api/v3/services/v2_subscription/update_creditcard.rb new file mode 100644 index 0000000000..f503f1ea9c --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/update_creditcard.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::V2Subscription::UpdateCreditcard < Service + params :token + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + query.update_creditcard(access_control.user.id) + no_content + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/update_plan.rb b/lib/travis/api/v3/services/v2_subscription/update_plan.rb new file mode 100644 index 0000000000..43a4c34ccf --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/update_plan.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::V2Subscription::UpdatePlan < Service + params :plan, :coupon + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + query.update_plan(access_control.user.id) + no_content + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscription/user_usages.rb b/lib/travis/api/v3/services/v2_subscription/user_usages.rb new file mode 100644 index 0000000000..1c8d14049c --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscription/user_usages.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::V2Subscription::UserUsages < Service + params :subscription_id + result_type :v2_addon_usages + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + result query(:v2_addon_usages).all(access_control.user.id) + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscriptions/all.rb b/lib/travis/api/v3/services/v2_subscriptions/all.rb new file mode 100644 index 0000000000..028fbf6368 --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscriptions/all.rb @@ -0,0 +1,8 @@ +module Travis::API::V3 + class Services::V2Subscriptions::All < Service + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + result query(:v2_subscriptions).all(access_control.user.id) + end + end +end diff --git a/lib/travis/api/v3/services/v2_subscriptions/create.rb b/lib/travis/api/v3/services/v2_subscriptions/create.rb new file mode 100644 index 0000000000..fd0203d5a4 --- /dev/null +++ b/lib/travis/api/v3/services/v2_subscriptions/create.rb @@ -0,0 +1,13 @@ +module Travis::API::V3 + class Services::V2Subscriptions::Create < Service + result_type :v2_subscription + params :plan, :coupon, :organization_id, :client_secret, :v1_subscription_id + params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email, :has_local_registration, prefix: :billing_info + params :token, prefix: :credit_card_info + + def run! + raise LoginRequired unless access_control.full_access_or_logged_in? + result query(:v2_subscriptions).create(access_control.user.id), status: 201 + end + end +end diff --git a/lib/travis/config/defaults.rb b/lib/travis/config/defaults.rb index 381fcb11d0..359365addb 100644 --- a/lib/travis/config/defaults.rb +++ b/lib/travis/config/defaults.rb @@ -42,6 +42,7 @@ def fallback_logs_api_auth_token assets: { host: HOSTS[Travis.env.to_sym] }, amqp: { username: 'guest', password: 'guest', host: 'localhost', prefetch: 1 }, billing: {}, + closeio: { key: 'key' }, gdpr: {}, insights: { endpoint: 'https://insights.travis-ci.dev/', auth_token: 'secret' }, database: { adapter: 'postgresql', database: "travis_#{Travis.env}", encoding: 'unicode', min_messages: 'warning', variables: { statement_timeout: 45_000 } }, @@ -82,10 +83,13 @@ def fallback_logs_api_auth_token oauth2: {}, webhook: { public_key: nil }, cache_options: {}, + build_backup_options: ENV['GCE_BUILD_BACKUP_OPTIONS'] ? JSON.parse(ENV['GCE_BUILD_BACKUP_OPTIONS']) : { gcs: { bucket_name: 'fillme', json_key: JSON.parse("{\n \"type\": \"service_account\",\n \"project_id\": \"fillme\",\n \"private_key_id\": \"b1c57117b4a0b8ae2af2f45b19a1cf9727bc6caf\",\n \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDRaHA5z0vXNVSr\\nlLVd/smJpNkpzk4BoHq+zcuuzvKTf1ZY1LnrAhldUbDTKY67c06eOYwVrQc3tEIp\\nJCNhIDNY1lRfGJag6t2v5C710WY+X7qVnRhSpgthvWFX/Rm9KIv3be8AJvUTMUDQ\\nAL10eYrIWJOI/J59khuKvr7khIlysASwGoZc8UgcufxGuwCziNyEIfH1nxiBKILR\\nM1+LdYi/Avyb4bQth5x03THVEmdRDjV7Yoo2c17XElIXtkl03nUce4w8BCu+T1G2\\nKRkApHcQ8R0BDTjjBzaQuXTtTpLvkmZzJ1i0/kPNdnT70lv6N2nI1AN2DVkXDCkG\\nNlZ283W7AgMBAAECggEAC/W6CyMywqzSFCafISovGoRmvsOAowkmWYVpb6d0JUZt\\niQ9FOw3YowLKZZUHCN+yCslgndBPDDhoWu8schyjshwzn2bJG5GubaBLqlB2VXOk\\nNW1OeVHwbnmheKQE90+8hropn0maT6lNeVPBfkh+y6h7bKR47NUOa6MvRd/n9bvL\\nT7pP5ZAHoPoTcbUftOX0gDq0u+uRULe/rduxB0S2EHDEtZEH+ioUOP9AomnaRDSy\\n0spH1s2FUZxIbKBQzsrqMCai4MSjeUrJMTR3ZlpfXePirettvilSWqEXDLvvwaak\\ngehELuM5lH4T49wf4PmEYZ8Jqkh9ku+oNYJdJvGR2QKBgQD7KjhJx9usl0afrIH3\\nw7saHELluWGqHNa6j+TJDpY7N5lLLIym/br9d+cuLTF5CBEHJ502coDR9cyrLVZX\\na05CGmEfSVrSrLUyAU+mHHdsn8n6CCATmlgtPyzzt2c29J7dHUZL94zW/yG6Btg6\\nm+nY4eBKreLpj0+3KbhI/q0q1wKBgQDVcG8Ek3Kt2buOrpDBqxcwB31QljntT+7+\\nYcTZctYL/y7Lm2VcTjserNa3AjG59Z5iaQjKFPhbAvMHfppklyiVSVBRfn4bLTcx\\nSM9I+lntODtGI/BiHVE7hfoYKzwz/3Aj3npiOO9xnOfAgEubGn9DrOzLXPsvWN7E\\nz+/iSr4zvQKBgHFVB7kjGZizWgbKzIqEI3UQs479K3ibMrlUHKQslNV7rQwiugTQ\\nEQQ2inZnph866JQV5/adjEsxYn0LJB6mKNXjGVgIvZa6n7hEpzAJQEoff//2kqLF\\nzmv8SchfRY+iqdyUTRgSR9broMhUNlWb7NUUdyS7edxx8kJv7NvjLzhZAoGAMre9\\n2bOD26XSeKwof6y9HM+ayox4BVkqLE5lLVqpXD5uCznI0y9PwxFFEEW4NT0VPsNA\\nsGxdO5suzsgZve9hWGAMcuEA7EpJRC/N+cRrm//xrdAabeYTiHZkoFudualoJ03V\\nfQOUekXTmB2kWZ3pQdaUihp1IaIXhWL32Kj0G20CgYAfGInHUZf5mqxRK/id8B5Q\\nYmpnLDXsNu1I4qFKeaBo4dF2SGByNW7fVbK/BdCSg5Ov3Ui6m3QWBbJXh1a8QVYA\\nICvwJWqm53bNpocrFPAeXLy9xL5/5CEeVGQNcxFvUF3QgaPVmjbTsZk8vjbidUZk\\nOU8bArrUjGTxNJOe7GebhA==\\n-----END PRIVATE KEY-----\\n\",\n \"client_email\": \"service@fillme.iam.gserviceaccount.com\",\n \"client_id\": \"100937792194965642651\",\n \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n \"token_uri\": \"https://oauth2.googleapis.com/token\",\n \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/service%40fillme.iam.gserviceaccount.com\"\n}\n") } }, merge: { auth_token: 'merge-auth-token', api_url: 'https://merge.localhost' }, force_authentication: false, yml: { url: 'https://yml.travis-ci.org', token: 'secret', auth_key: 'abc123' }, - vcs: {} + read_only: ENV['READ_ONLY'] || false, + vcs: {}, + job_log_access_permissions: { time_based_limit: false, access_based_limit: false, older_than_days: 365, max_days_value: 730, min_days_value: 30 } default :_access => [:key] diff --git a/lib/travis/event/handler/metrics.rb b/lib/travis/event/handler/metrics.rb index 9a6212aa1b..abdea0805a 100644 --- a/lib/travis/event/handler/metrics.rb +++ b/lib/travis/event/handler/metrics.rb @@ -41,7 +41,11 @@ def queue def meter(events, started_at, finished_at) events.each do |event| - Travis::Metrics.meter(event, started_at: started_at, finished_at: finished_at) + if finished_at + Metriks.timer(event).update(finished_at - started_at) + else + Metriks.timer(event).mark + end end end end diff --git a/lib/travis/github/services/set_hook.rb b/lib/travis/github/services/set_hook.rb index 32bd3b8116..8332928151 100644 --- a/lib/travis/github/services/set_hook.rb +++ b/lib/travis/github/services/set_hook.rb @@ -11,15 +11,11 @@ class SetHook < Travis::Services::Base register :github_set_hook def run - if Travis::Features.user_active?(:use_vcs, current_user) || !current_user.github? - remote_vcs_repository.set_hook( - repository_id: repo.id, - user_id: current_user.id, - activate: active? - ) - else - v3_github.set_hook(repo, active?) - end + remote_vcs_repository.set_hook( + repository_id: repo.id, + user_id: current_user.id, + activate: active? + ) end private diff --git a/lib/travis/github/services/set_key.rb b/lib/travis/github/services/set_key.rb index 04f896d7a5..79c1bacbcc 100644 --- a/lib/travis/github/services/set_key.rb +++ b/lib/travis/github/services/set_key.rb @@ -25,16 +25,10 @@ def has_key? private def keys - if Travis::Features.user_active?(:use_vcs, current_user) || !current_user.github? - @keys ||= remote_vcs_repository.keys( - repository_id: repo.id, - user_id: current_user.id - ) - else - @keys ||= authenticated do - GH[keys_path] - end - end + @keys ||= remote_vcs_repository.keys( + repository_id: repo.id, + user_id: current_user.id + ) end def key @@ -42,37 +36,19 @@ def key end def set_key - read_only = !Travis::Features.owner_active?(:read_write_github_keys, repo.owner) - if Travis::Features.user_active?(:use_vcs, current_user) || !current_user.github? - remote_vcs_repository.upload_key( - repository_id: repo.id, - user_id: current_user.id, - read_only: read_only - ) - else - authenticated do - GH.post keys_path, { - title: Travis.config.host.to_s, - key: repo.key.encoded_public_key, - read_only: read_only - } - end - end + remote_vcs_repository.upload_key( + repository_id: repo.id, + user_id: current_user.id, + read_only: !Travis::Features.owner_active?(:read_write_github_keys, repo.owner) + ) end def delete_key - if Travis::Features.user_active?(:use_vcs, current_user) || !current_user.github? - remote_vcs_repository.delete_key( - repository_id: repo.id, - user_id: current_user.id, - id: key['id'] - ) - else - authenticated do - GH.delete "#{keys_path}/#{key['id']}" #key['_links']['self']['href'] - @keys = [] - end - end + remote_vcs_repository.delete_key( + repository_id: repo.id, + user_id: current_user.id, + id: key['id'] + ) end def keys_path diff --git a/lib/travis/model.rb b/lib/travis/model.rb index 5d4080e8cd..31a05b9b84 100644 --- a/lib/travis/model.rb +++ b/lib/travis/model.rb @@ -12,12 +12,14 @@ class Model < ActiveRecord::Base require 'travis/model/branch' require 'travis/model/broadcast' require 'travis/model/build' + require 'travis/model/build_backup' require 'travis/model/commit' require 'travis/model/email' require 'travis/model/env_helpers' require 'travis/model/job' require 'travis/model/membership' require 'travis/model/organization' + require 'travis/model/owner_group' require 'travis/model/permission' require 'travis/model/pull_request' require 'travis/model/repository' diff --git a/lib/travis/model/build_backup.rb b/lib/travis/model/build_backup.rb new file mode 100644 index 0000000000..bc574e3ae0 --- /dev/null +++ b/lib/travis/model/build_backup.rb @@ -0,0 +1,8 @@ +require 'travis/model' + +class BuildBackup < Travis::Model + include Travis::ScopeAccess + + belongs_to :repository + validates :repository_id, presence: true +end diff --git a/lib/travis/model/owner_group.rb b/lib/travis/model/owner_group.rb new file mode 100644 index 0000000000..89b6f075ff --- /dev/null +++ b/lib/travis/model/owner_group.rb @@ -0,0 +1,6 @@ +require 'gh' +require 'travis/model' + +class OwnerGroup < Travis::Model + belongs_to :owner, polymorphic: true +end \ No newline at end of file diff --git a/lib/travis/model/repository/settings.rb b/lib/travis/model/repository/settings.rb index 03e4726889..01af866ddb 100644 --- a/lib/travis/model/repository/settings.rb +++ b/lib/travis/model/repository/settings.rb @@ -109,6 +109,10 @@ def custom_timeouts?(settings) validates_with TimeoutsValidator + def job_log_access_permissions + Travis.config.to_h.fetch(:job_log_access_permissions) { {} } + end + def auto_cancel_default? ENV.fetch('AUTO_CANCEL_DEFAULT', 'false') == 'true' end diff --git a/lib/travis/model/scope_access.rb b/lib/travis/model/scope_access.rb index 9df03803a2..fc9bcf478f 100644 --- a/lib/travis/model/scope_access.rb +++ b/lib/travis/model/scope_access.rb @@ -34,6 +34,8 @@ def viewable_in_public_mode(user) user.nil? ? where('builds.private <> ?', true) : where('builds.private <> ? OR builds.repository_id IN (?)', true, user.repository_ids) + elsif self == ::BuildBackup + user.nil? ? where('1=0') : where('build_backups.repository_id IN (?)', user.repository_ids) elsif self == ::Job user.nil? ? where('jobs.private <> ?', true) : @@ -60,6 +62,8 @@ def viewable_in_public_mode_with_repo(user, repository_id) return user.repository_ids.include?(repository_id) ? where('true') : where('builds.private <> ?', true) + elsif self == ::BuildBackup + user.repository_ids.include?(repository_id) ? where('true') : where('false') elsif self == ::Job return user.repository_ids.include?(repository_id) ? where('true') : @@ -80,6 +84,8 @@ def viewable_in_private_mode(user) where('requests.repository_id IN (?)', user.repository_ids) elsif self == ::Build where('builds.repository_id IN (?)', user.repository_ids) + elsif self == ::BuildBackup + where('build_backups.repository_id IN (?)', user.repository_ids) elsif self == ::Job where('jobs.repository_id IN (?)', user.repository_ids) else diff --git a/lib/travis/model/user.rb b/lib/travis/model/user.rb index 3ce965d903..f17cee0b0e 100644 --- a/lib/travis/model/user.rb +++ b/lib/travis/model/user.rb @@ -12,6 +12,7 @@ class User < Travis::Model has_many :permissions, dependent: :destroy has_many :repositories, through: :permissions has_many :emails, dependent: :destroy + has_one :owner_group, as: :owner before_create :set_as_recent after_create :create_a_token diff --git a/lib/travis/remote_log.rb b/lib/travis/remote_log.rb index a286e94a0d..8080b048c1 100644 --- a/lib/travis/remote_log.rb +++ b/lib/travis/remote_log.rb @@ -224,14 +224,15 @@ def write_content_for_job_id(job_id, content: '', removed_by: nil) end class ArchiveClient - def initialize(access_key_id: nil, secret_access_key: nil, bucket_name: nil) + def initialize(access_key_id: nil, secret_access_key: nil, bucket_name: nil, region: nil) @bucket_name = bucket_name @s3 = Fog::Storage.new( aws_access_key_id: access_key_id, aws_secret_access_key: secret_access_key, provider: 'AWS', instrumentor: ActiveSupport::Notifications, - connection_options: { instrumentor: ActiveSupport::Notifications } + connection_options: { instrumentor: ActiveSupport::Notifications }, + region: region ) end @@ -318,7 +319,8 @@ def initialize(platform: :default) ArchiveClient.new( access_key_id: archive_s3_config[:access_key_id], secret_access_key: archive_s3_config[:secret_access_key], - bucket_name: archive_s3_bucket + bucket_name: archive_s3_config[:bucket] || archive_s3_bucket, + region: archive_s3_config[:region] || 'us-east-2' ) end diff --git a/lib/travis/remote_vcs/client.rb b/lib/travis/remote_vcs/client.rb index 8dcc3216a1..8a4eebd18f 100644 --- a/lib/travis/remote_vcs/client.rb +++ b/lib/travis/remote_vcs/client.rb @@ -22,14 +22,14 @@ def http_options { ssl: Travis.config.ssl.to_h } end - def request(method, name) + def request(method, name, data_in_body = true) resp = connection.send(method) { |req| yield(req) } - Travis.logger.info "#{self.class.name} #{name} response status: #{resp.status}" - if resp.success? - resp.body.present? ? JSON.parse(resp.body)['data'] : true - else - raise ResponseError, "#{self.class.name} #{name} request unexpected response: #{resp.body} #{resp.status}" - end + + raise ResponseError, "#{self.class.name} #{name} request unexpected response: #{resp.body} #{resp.status}" unless resp.success? + return true unless resp.body.present? + + parsed_response = JSON.parse(resp.body) + data_in_body ? parsed_response['data'] : parsed_response end end end diff --git a/lib/travis/remote_vcs/repository.rb b/lib/travis/remote_vcs/repository.rb index aafbe17ed3..ab805ea0a2 100644 --- a/lib/travis/remote_vcs/repository.rb +++ b/lib/travis/remote_vcs/repository.rb @@ -41,6 +41,15 @@ def delete_key(repository_id:, user_id:, id:) rescue ResponseError false end + + def show(repository_id:, admin_id: nil) + request(:get, __method__, false) do |req| + req.url "repos/#{repository_id}" + req.params['admin_id'] = admin_id + end + rescue ResponseError + nil + end end end end diff --git a/lib/travis/remote_vcs/user.rb b/lib/travis/remote_vcs/user.rb index df48b993f5..5c81e1801d 100644 --- a/lib/travis/remote_vcs/user.rb +++ b/lib/travis/remote_vcs/user.rb @@ -44,6 +44,20 @@ def check_scopes(user_id:) req.url "users/#{user_id}/check_scopes" end && true end + + def confirm_user(token:) + request(:post, __method__) do |req| + req.url 'users/confirm' + req.params['token'] = token + end + end + + def request_confirmation(id:) + request(:post, __method__) do |req| + req.url 'users/request_confirmation' + req.params['id'] = id + end + end end end end diff --git a/lib/travis/services.rb b/lib/travis/services.rb index ddae48158f..2325f71e30 100644 --- a/lib/travis/services.rb +++ b/lib/travis/services.rb @@ -42,6 +42,7 @@ module Travis require 'travis/services/find_branch' require 'travis/services/find_branches' require 'travis/services/find_build' +require 'travis/services/find_build_backups' require 'travis/services/find_builds' require 'travis/services/find_caches' require 'travis/services/find_hooks' diff --git a/lib/travis/services/find_admin.rb b/lib/travis/services/find_admin.rb index f6695d1812..40e7f7adb5 100644 --- a/lib/travis/services/find_admin.rb +++ b/lib/travis/services/find_admin.rb @@ -34,7 +34,7 @@ def candidates def validate(user) Timeout.timeout(2) do - data = Github.authenticated(user) { repository_data } + data = repository_data(user) if data['permissions'] && data['permissions']['admin'] user else @@ -43,10 +43,7 @@ def validate(user) false end end - rescue Timeout::Error => error - handle_error(user, error) - false - rescue GH::Error => error + rescue error handle_error(user, error) false end @@ -56,7 +53,7 @@ def handle_error(user, error) case status when 401 error "[github-admin] token for #{user.login} no longer valid" - user.update!(:github_oauth_token => "") + # user.update!(:github_oauth_token => "") when 404 info "[github-admin] #{user.login} no longer has any access to #{repository.slug}" update(user, {}) @@ -66,10 +63,11 @@ def handle_error(user, error) end # TODO should this not be memoized? - def repository_data - data = GH["repos/#{repository.slug}"] - info "[github-admin] could not retrieve data for #{repository.slug}" unless data - data || { 'permissions' => {} } + def repository_data(user) + Travis::RemoteVCS::Repository.new.show( + repository_id: repository.id, + admin_id: user.id + ) end def update(user, permissions) diff --git a/lib/travis/services/find_build_backups.rb b/lib/travis/services/find_build_backups.rb new file mode 100644 index 0000000000..0dd660e978 --- /dev/null +++ b/lib/travis/services/find_build_backups.rb @@ -0,0 +1,21 @@ +require 'travis/services/base' + +module Travis + module Services + class FindBuildBackups < Base + register :find_build_backups + + scope_access! + + def run + result + end + + private + + def result + @result ||= scope(:build_backup).where(repository_id: params[:repository_id]) + end + end + end +end diff --git a/lib/travis/testing/factories.rb b/lib/travis/testing/factories.rb index 56965f09cd..b3873dbad9 100644 --- a/lib/travis/testing/factories.rb +++ b/lib/travis/testing/factories.rb @@ -13,6 +13,11 @@ private { false } end + factory :build_backup do + repository { Repository.first || FactoryBot.create(:repository_without_last_build) } + sequence(:file_name) { |n| "repository_builds_#{n}-#{n + 100}" } + end + factory :commit do commit { '62aae5f70ceee39123ef' } branch { 'master' } @@ -25,6 +30,29 @@ compare_url { 'https://github.com/svenfuchs/minimal/compare/master...develop' } end + factory :subscription do + association :owner, factory: :user + valid_to { Time.now.utc + 1.week } + customer_id { 'cus_123' } + billing_email { 'shairyar@travis-ci.org' } + cc_last_digits { 111 } + status { 'subscribed'} + source { 'stripe' } + cc_token { 'token_123' } + selected_plan { 'travis-ci-one-build' } + country { 'Germany' } + + factory :valid_stripe_subs do + status { 'subscribed' } + source { 'stripe' } + end + + factory :canceled_stripe_subs do + status { 'canceled' } + source { 'stripe' } + end + end + factory :test, :class => 'Job::Test', aliases: [:job] do owner { User.first || FactoryBot.create(:user) } repository { Repository.first || FactoryBot.create(:repository) } diff --git a/spec/auth/v1/builds_spec.rb b/spec/auth/v1/builds_spec.rb index c0654f1308..8157dd799c 100644 --- a/spec/auth/v1/builds_spec.rb +++ b/spec/auth/v1/builds_spec.rb @@ -3,6 +3,20 @@ let(:repo) { Repository.by_slug('svenfuchs/minimal').first } let(:build) { repo.builds.first } + before do + Travis.config.billing.url = 'http://localhost:9292/' + Travis.config.billing.auth_key = 'secret' + + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: true, rejection_code: nil) + ) + end + + after do + Travis.config.billing.url = nil + Travis.config.billing.auth_key = nil + end + describe 'in public mode, with a private repo', mode: :public, repo: :private do describe 'GET /builds' do it(:with_permission) { should auth status: 200, type: :json, empty: false } diff --git a/spec/auth/v1/logs_spec.rb b/spec/auth/v1/logs_spec.rb index 3a9efddf9d..1e2ea54378 100644 --- a/spec/auth/v1/logs_spec.rb +++ b/spec/auth/v1/logs_spec.rb @@ -6,7 +6,12 @@ let(:log) { double(id: 1) } let(:log_url) { "#{Travis.config[:logs_api][:url]}/logs/1?by=id&source=api" } - before { stub_request(:get, log_url).to_return(status: 200, body: %({"job_id": #{job.id}, "content": "content"})) } + before do + stub_request(:get, log_url).to_return(status: 200, body: %({"job_id": #{job.id}, "content": "content"})) + repository = Travis::API::V3::Models::Repository.find(repo.id) + repository.user_settings.update(:job_log_time_based_limit, true) + repository.save! + end describe 'in public mode, with a private repo', mode: :public, repo: :private do describe 'GET /logs/%{log.id}' do diff --git a/spec/auth/v2.1/jobs_spec.rb b/spec/auth/v2.1/jobs_spec.rb index cbe93a9cc0..72cab2800c 100644 --- a/spec/auth/v2.1/jobs_spec.rb +++ b/spec/auth/v2.1/jobs_spec.rb @@ -30,7 +30,7 @@ allow(Travis::RemoteLog::Remote).to receive(:new).and_return(remote) allow(remote).to receive(:find_by_job_id).and_return(Travis::RemoteLog.new(log_from_api)) allow(remote).to receive(:find_by_id).and_return(Travis::RemoteLog.new(log_from_api)) - allow(remote).to receive(:fetch_archived_url).and_return('https://s3.amazonaws.com/STUFFS') + allow(remote).to receive(:fetch_archived_log_content).and_return(archived_content) end before { Job.update_all(state: :started) } @@ -56,7 +56,7 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 404 } @@ -79,10 +79,10 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } - it(:without_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } + it(:without_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:invalid_token) { should auth status: 403 } - it(:unauthenticated) { should auth status: [200, 307], type: :json, empty: false } + it(:unauthenticated) { should auth status: 200, type: [:json, :text], empty: false } end end @@ -102,7 +102,7 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -131,7 +131,7 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -154,10 +154,10 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } - it(:without_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } + it(:without_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:invalid_token) { should auth status: 403 } - it(:unauthenticated) { should auth status: [200, 307], type: :json, empty: false } + it(:unauthenticated) { should auth status: 200, type: [:json, :text], empty: false } end end end diff --git a/spec/auth/v2.1/logs_spec.rb b/spec/auth/v2.1/logs_spec.rb index 825a206679..588676c093 100644 --- a/spec/auth/v2.1/logs_spec.rb +++ b/spec/auth/v2.1/logs_spec.rb @@ -31,12 +31,15 @@ allow(Travis::RemoteLog::Remote).to receive(:new).and_return(remote) allow(remote).to receive(:find_by_job_id).and_return(Travis::RemoteLog.new(log_from_api)) allow(remote).to receive(:find_by_id).and_return(Travis::RemoteLog.new(log_from_api)) - allow(remote).to receive(:fetch_archived_url).and_return('https://s3.amazonaws.com/STUFFS') + allow(remote).to receive(:fetch_archived_log_content).and_return(archived_content) + repository = Travis::API::V3::Models::Repository.find(repo.id) + repository.user_settings.update(:job_log_time_based_limit, true) + repository.save! end describe 'in public mode, with a private repo', mode: :public, repo: :private do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 404 } @@ -45,16 +48,16 @@ describe 'in public mode, with a public repo', mode: :public, repo: :public do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } - it(:without_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } + it(:without_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:invalid_token) { should auth status: 403 } - it(:unauthenticated) { should auth status: [200, 307], type: :json, empty: false } + it(:unauthenticated) { should auth status: 200, type: [:json, :text], empty: false } end end describe 'in private mode, with a public repo', mode: :private, repo: :public do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -69,7 +72,7 @@ describe 'in private mode, with a private repo', mode: :private, repo: :private do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -78,10 +81,10 @@ describe 'in org mode, with a public repo', mode: :org, repo: :public do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } - it(:without_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } + it(:without_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:invalid_token) { should auth status: 403 } - it(:unauthenticated) { should auth status: [200, 307], type: :json, empty: false } + it(:unauthenticated) { should auth status: 200, type: [:json, :text], empty: false } end end end diff --git a/spec/auth/v2.1/users_spec.rb b/spec/auth/v2.1/users_spec.rb index 4544fcaa1c..7e77e6480f 100644 --- a/spec/auth/v2.1/users_spec.rb +++ b/spec/auth/v2.1/users_spec.rb @@ -1,7 +1,17 @@ describe 'v2.1 users', auth_helpers: true, api_version: :'v2.1', set_app: true do let(:user) { User.first } let(:repo) { Repository.by_slug('svenfuchs/minimal').first } - + let!(:request) do + WebMock.stub_request(:post, 'http://vcsfake.travis-ci.com/users/1/check_scopes') + .to_return( + status: 200, + body: nil, + ) + end + before do + Travis.config.vcs.url = 'http://vcsfake.travis-ci.com' + Travis.config.vcs.token = 'vcs-token' + end # TODO put /users/ # TODO put /users/:id ? # TODO post /users/sync diff --git a/spec/auth/v2/jobs_spec.rb b/spec/auth/v2/jobs_spec.rb index 6ab2ce71ec..397a68e570 100644 --- a/spec/auth/v2/jobs_spec.rb +++ b/spec/auth/v2/jobs_spec.rb @@ -32,7 +32,7 @@ allow(Travis::RemoteLog::Remote).to receive(:new).and_return(remote) allow(remote).to receive(:find_by_job_id).and_return(Travis::RemoteLog.new(log_from_api)) allow(remote).to receive(:find_by_id).and_return(Travis::RemoteLog.new(log_from_api)) - allow(remote).to receive(:fetch_archived_url).and_return('https://s3.amazonaws.com/STUFFS') + allow(remote).to receive(:fetch_archived_log_content).and_return(archived_content) end before { Job.update_all(state: :started) } @@ -58,7 +58,7 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -81,8 +81,8 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } - it(:without_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } + it(:without_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } end @@ -104,7 +104,7 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: [:json, :text], empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -133,7 +133,7 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -156,10 +156,10 @@ end describe 'GET /jobs/%{job.id}/log' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } - it(:without_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } + it(:without_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:invalid_token) { should auth status: 403 } - it(:unauthenticated) { should auth status: [200, 307], type: :json, empty: false } + it(:unauthenticated) { should auth status: 200, type: [:json, :text], empty: false } end end end diff --git a/spec/auth/v2/logs_spec.rb b/spec/auth/v2/logs_spec.rb index 845070a186..cae31da587 100644 --- a/spec/auth/v2/logs_spec.rb +++ b/spec/auth/v2/logs_spec.rb @@ -31,12 +31,15 @@ allow(Travis::RemoteLog::Remote).to receive(:new).and_return(remote) allow(remote).to receive(:find_by_job_id).and_return(Travis::RemoteLog.new(log_from_api)) allow(remote).to receive(:find_by_id).and_return(Travis::RemoteLog.new(log_from_api)) - allow(remote).to receive(:fetch_archived_url).and_return('https://s3.amazonaws.com/STUFFS') + allow(remote).to receive(:fetch_archived_log_content).and_return(archived_content) + repository = Travis::API::V3::Models::Repository.find(repo.id) + repository.user_settings.update(:job_log_time_based_limit, true) + repository.save! end describe 'in public mode, with a private repo', mode: :public, repo: :private do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -45,8 +48,8 @@ describe 'in public mode, with a public repo', mode: :public, repo: :public do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } - it(:without_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } + it(:without_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } end @@ -54,7 +57,7 @@ describe 'in private mode, with a public repo', mode: :private, repo: :public do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: [:json, :text], empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -69,7 +72,7 @@ describe 'in private mode, with a private repo', mode: :private, repo: :private do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:without_permission) { should auth status: 404 } it(:invalid_token) { should auth status: 403 } it(:unauthenticated) { should auth status: 401 } @@ -78,10 +81,10 @@ describe 'in org mode, with a public repo', mode: :org, repo: :public do describe 'GET /logs/%{log.id}' do - it(:with_permission) { should auth status: [200, 307], type: :json, empty: false } - it(:without_permission) { should auth status: [200, 307], type: :json, empty: false } + it(:with_permission) { should auth status: 200, type: [:json, :text], empty: false } + it(:without_permission) { should auth status: 200, type: [:json, :text], empty: false } it(:invalid_token) { should auth status: 403 } - it(:unauthenticated) { should auth status: [200, 307], type: :json, empty: false } + it(:unauthenticated) { should auth status: 200, type: [:json, :text], empty: false } end end end diff --git a/spec/auth/v2/users_spec.rb b/spec/auth/v2/users_spec.rb index 0db97498a1..387698d66f 100644 --- a/spec/auth/v2/users_spec.rb +++ b/spec/auth/v2/users_spec.rb @@ -2,6 +2,8 @@ let(:user) { User.first } let(:repo) { Repository.by_slug('svenfuchs/minimal').first } + before { allow_any_instance_of(Travis::RemoteVCS::User).to receive(:check_scopes) } + # TODO put /users/ # TODO put /users/:id ? # TODO post /users/sync diff --git a/spec/integration/v2/builds_spec.rb b/spec/integration/v2/builds_spec.rb index 4670e29286..1204106fc9 100644 --- a/spec/integration/v2/builds_spec.rb +++ b/spec/integration/v2/builds_spec.rb @@ -3,6 +3,20 @@ let(:build) { repo.builds.first } let(:headers) { { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json' } } + before do + Travis.config.billing.url = 'http://localhost:9292/' + Travis.config.billing.auth_key = 'secret' + + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: true, rejection_code: nil) + ) + end + + after do + Travis.config.billing.url = nil + Travis.config.billing.auth_key = nil + end + it 'GET /builds?repository_id=1' do response = get '/builds', { repository_id: repo.id }, headers expect(response).to deliver_json_for(repo.builds.order('id DESC'), version: 'v2') diff --git a/spec/integration/v2/hooks_spec.rb b/spec/integration/v2/hooks_spec.rb index a0c0f72125..bc4e33a68c 100644 --- a/spec/integration/v2/hooks_spec.rb +++ b/spec/integration/v2/hooks_spec.rb @@ -30,8 +30,7 @@ before(:each) do Travis.config.service_hook_url = 'notify.travis-ci.org' - stub_request(:get, "https://api.github.com/repositories/#{repo.github_id}/hooks?per_page=100").to_return(status: 200, body: '[]') - stub_request(:post, "https://api.github.com/repositories/#{repo.github_id}/hooks") + allow_any_instance_of(Travis::RemoteVCS::Repository).to receive(:set_hook) end it 'sets the hook' do diff --git a/spec/integration/v2/jobs_spec.rb b/spec/integration/v2/jobs_spec.rb index 355265a289..2c24978fdb 100644 --- a/spec/integration/v2/jobs_spec.rb +++ b/spec/integration/v2/jobs_spec.rb @@ -39,6 +39,20 @@ allow(remote).to receive(:send).and_return(remote) # ignore attribute updates end + before do + Travis.config.billing.url = 'http://localhost:9292/' + Travis.config.billing.auth_key = 'secret' + + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: true, rejection_code: nil) + ) + end + + after do + Travis.config.billing.url = nil + Travis.config.billing.auth_key = nil + end + it '/jobs?queue=builds.common' do skip('querying with a queue does not appear to be used anymore') response = get '/jobs', { queue: 'builds.common' }, headers @@ -71,10 +85,9 @@ end context 'GET /jobs/:job_id/log.txt' do - it 'returns redirects to archived log url' do + it 'returns the log' do response = get("/jobs/#{job.id}/log.txt") - expect(response.status).to eq(307) - expect(response.location).to eq(archived_log_url) + expect(response.status).to eq(200) end it 'returns 406 (Unprocessable) if Accept header requests JSON' do @@ -83,13 +96,14 @@ end context 'when log is archived' do - it 'redirects to archive' do + it 'returns the log' do remote = double('remote') remote_log = double('remote log') expect(remote_log).to receive(:archived?).and_return(true) allow(remote_log).to receive(:removed_at).and_return(nil) + allow(remote_log).to receive(:archived_log_content).and_return(archived_content) allow(remote).to receive(:find_by_job_id).and_return(remote_log) - expect(remote_log).to receive(:archived_url).and_return("https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt") + allow(remote).to receive(:fetch_archived_log_content).and_return(archived_content) expect(Travis::RemoteLog::Remote).to receive(:new).and_return(remote) stub_request(:get, "#{Travis.config.logs_api.url}/logs/#{job.id}?by=job_id&source=api") .to_return( @@ -105,14 +119,12 @@ {}, { 'HTTP_ACCEPT' => 'text/plain; version=2' } ) - expect(response).to redirect_to( - "https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt" - ) + expect(response.status).to eq(200) end end context 'when log is missing' do - it 'redirects to archived log url' do + it 'returns the log retrieved from s3' do stub_request(:get, "#{Travis.config.logs_api.url}/logs/#{job.id}?by=job_id&source=api") .to_return(status: 404, body: '') response = get( @@ -120,35 +132,7 @@ {}, { 'HTTP_ACCEPT' => 'text/plain; version=2' } ) - expect(response.status).to eq(307) - expect(response.location).to eq(archived_log_url) - end - end - - context 'with cors_hax param' do - it 'renders No Content response with location of the archived log' do - stub_request(:get, "#{Travis.config.logs_api.url}/logs/#{job.id}?by=job_id&source=api") - .to_return( - status: 200, - body: JSON.dump( - content: nil, - aggregated_at: Time.now, - archived_at: Time.now, - archive_verified: true - ) - ) - allow_any_instance_of(Travis::RemoteLog).to receive(:archived_url).and_return( - "https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt" - ) - response = get( - "/jobs/#{job.id}/log.txt?cors_hax=true", - {}, - { 'HTTP_ACCEPT' => 'text/plain; version=2' } - ) - expect(response.status).to eq 204 - expect(response.headers['Location']).to eq( - "https://s3.amazonaws.com/archive.travis-ci.org/jobs/#{job.id}/log.txt" - ) + expect(response.status).to eq(200) end end diff --git a/spec/integration/v2/requests_spec.rb b/spec/integration/v2/requests_spec.rb index fd3132d030..807e5cf284 100644 --- a/spec/integration/v2/requests_spec.rb +++ b/spec/integration/v2/requests_spec.rb @@ -8,6 +8,20 @@ let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: -1) } let(:headers) { { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json', 'HTTP_AUTHORIZATION' => "token #{token}" } } + before do + Travis.config.billing.url = 'http://localhost:9292/' + Travis.config.billing.auth_key = 'secret' + + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: true, rejection_code: nil) + ) + end + + after do + Travis.config.billing.url = nil + Travis.config.billing.auth_key = nil + end + describe 'GET /requests' do it 'fetches requests' do response = get '/requests', { repository_id: repo.id }, headers diff --git a/spec/integration/v2/users_spec.rb b/spec/integration/v2/users_spec.rb index 1d27ad538e..5ff778d550 100644 --- a/spec/integration/v2/users_spec.rb +++ b/spec/integration/v2/users_spec.rb @@ -11,6 +11,7 @@ before do user.permissions.create!(repository: repo1) user.permissions.create!(repository: repo2) + allow_any_instance_of(Travis::RemoteVCS::User).to receive(:check_scopes) end it 'fetches a list of channels for a user' do diff --git a/spec/integration/visibility_spec.rb b/spec/integration/visibility_spec.rb index 3c9fd50e56..4242c1bf1d 100644 --- a/spec/integration/visibility_spec.rb +++ b/spec/integration/visibility_spec.rb @@ -16,6 +16,11 @@ before { requests[0].update(private: false) } before { builds[0].update(private: false) } before { jobs[0].update(private: false) } + before do + repository = Travis::API::V3::Models::Repository.find(repo.id) + repository.user_settings.update(:job_log_time_based_limit, true) + repository.save! + end before :each do Fog.mock! storage = Fog::Storage.new({ diff --git a/spec/lib/github/services/set_key_spec.rb b/spec/lib/github/services/set_key_spec.rb index 292ebda0b5..08806d2338 100644 --- a/spec/lib/github/services/set_key_spec.rb +++ b/spec/lib/github/services/set_key_spec.rb @@ -1,80 +1,77 @@ describe Travis::Github::Services::SetKey do include Travis::Testing::Stubs - let(:keys_path) { 'repos/travis-ci/travis-core/keys' } let(:key_path) { "#{keys_path}/1" } let(:keys) { [{ 'id' => 1, 'key' => SSL_KEYS[:public_base64], '_links' => { 'self' => { 'href' => key_path } } }] } let(:key) { SslKey.new(SSL_KEYS.slice(:private_key, :public_key)) } - let(:owner) { User.new(login: 'travis-ci') } - let(:repo) { Repository.new(owner_name: 'travis-ci', name: 'travis-core', key: key, owner: owner) } - + let(:owner) { User.new(id: 1, login: 'travis-ci') } + let(:repo) { Repository.new(id: 1, owner_name: 'travis-ci', name: 'travis-core', key: key, owner: owner) } let(:params) { { id: repo.id } } let(:service) { described_class.new(user, params) } - let(:publisher) { Travis::Notification::Publisher::Memory.new } let(:event) { publisher.events.last } - - before :each do - allow(GH).to receive(:[]).and_return([]) - allow(GH).to receive(:post) - allow(GH).to receive(:delete) + let!(:keys_request) do + WebMock.stub_request(:get, "http://vcsfake.travis-ci.com/repos/#{repo.id}/keys?user_id=#{owner.id}") + .to_return( + status: 200, + body: JSON.dump( + data: keys, + ) + ) + end + let!(:delete_request) do + WebMock.stub_request(:delete, "http://vcsfake.travis-ci.com/repos/#{repo.id}/keys/1?user_id=#{owner.id}") + .to_return( + status: 200, + body: nil, + ) + end + let!(:create_request) do + WebMock.stub_request(:post, "http://vcsfake.travis-ci.com/repos/#{repo.id}/keys?user_id=#{owner.id}&read_only=true") + .to_return( + status: 201, + body: nil, + ) + end + before do + Travis.config.vcs.url = 'http://vcsfake.travis-ci.com' + Travis.config.vcs.token = 'vcs-token' Travis::Notification.publishers.replace([publisher]) allow_any_instance_of(Travis::Services::FindRepo).to receive(:run).and_return(repo) end - - it 'authenticates with the current user' do - expect(Travis::Github).to receive(:authenticated).with(user).at_least(:once).and_return([]) - service.run - end - describe 'given force: false' do before :each do params.update force: false end - it 'does not try to delete an existing key on github' do - allow(GH).to receive(:[]).with('repos/travis-ci/travis-core/keys').and_return(keys) - expect(GH).not_to receive(:delete) service.run + expect(delete_request).not_to have_been_made + expect(create_request).not_to have_been_made end - - it 'sets the encoded public repository key to github if github does not have it' do - allow(GH).to receive(:[]).with(keys_path).and_return([]) - expect(GH).to receive(:post).with(keys_path, title: 'travis-ci.org', key: SSL_KEYS[:public_base64], read_only: true) - service.run - end - - it 'does not set anything to github if github already has the encoded public repository key' do - allow(GH).to receive(:[]).with('repos/travis-ci/travis-core/keys').and_return(keys) - expect(GH).not_to receive(:post) - service.run + context 'when there are no keys' do + let(:keys) { [] } + it 'sets the encoded public repository key to github' do + service.run + expect(create_request).to have_been_made + end end end - describe 'given force: true' do before :each do params.update force: true end - - it 'does not try to delete a key on github when no one exists' do - allow(GH).to receive(:[]).with('repos/travis-ci/travis-core/keys').and_return([]) - expect(GH).not_to receive(:delete) - service.run + context 'when no keys exist' do + let(:keys) { [] } + it 'does not try to delete a key on github' do + service.run + expect(delete_request).not_to have_been_made + end end - it 'deletes an existing key on github' do - allow(GH).to receive(:[]).with('repos/travis-ci/travis-core/keys').and_return(keys) - expect(GH).to receive(:delete).with(key_path) - service.run - end - - it 'sets the encoded public repository key to github' do - allow(GH).to receive(:[]).with('repos/travis-ci/travis-core/keys').and_return(keys) - expect(GH).to receive(:post).with(keys_path, title: 'travis-ci.org', key: SSL_KEYS[:public_base64], read_only: true) service.run + expect(delete_request).to have_been_made end end - it 'publishes an event' do service.run expect(event).to publish_instrumentation_event( diff --git a/spec/lib/services/find_admin_spec.rb b/spec/lib/services/find_admin_spec.rb index 0b5527f0ca..2a6acab02d 100644 --- a/spec/lib/services/find_admin_spec.rb +++ b/spec/lib/services/find_admin_spec.rb @@ -9,10 +9,6 @@ end describe 'given a user has admin access to a repository (as seen by github)' do - before :each do - allow(GH).to receive(:[]).with("repos/#{repository.slug}").and_return('permissions' => { 'admin' => true }) - end - it 'returns that user' do expect(result).to eq(user) end @@ -20,7 +16,6 @@ describe 'given a user does not have access to a repository' do before :each do - allow(GH).to receive(:[]).with("repos/#{repository.slug}").and_return('permissions' => { 'admin' => false }) allow(user).to receive(:update!) end @@ -74,7 +69,6 @@ def ignore_exception(&block) before :each do Travis::Notification.publishers.replace([publisher]) allow(User).to receive(:with_permissions).with(repository_id: repository.id, admin: true).and_return [user] - allow(GH).to receive(:[]).with("repos/#{repository.slug}").and_return('permissions' => { 'admin' => true }) service.run end @@ -82,7 +76,7 @@ def ignore_exception(&block) expect(event).to publish_instrumentation_event( event: 'travis.services.find_admin.run:completed', message: 'Travis::Services::FindAdmin#run:completed for svenfuchs/minimal: svenfuchs', - result: user, + result: user ) end end diff --git a/spec/lib/services/find_caches_spec.rb b/spec/lib/services/find_caches_spec.rb index 436168d81e..dfa19021b5 100644 --- a/spec/lib/services/find_caches_spec.rb +++ b/spec/lib/services/find_caches_spec.rb @@ -71,7 +71,7 @@ end context 'with GCS configuration' do - let(:cache_options) { { gcs: { bucket_name: '', json_key: '' } } } + let(:cache_options) { { gcs: { bucket_name: '', json_key: { type: 'service_account', project_id: 'test-project-id' } } } } its(:size) { is_expected.to eq 0 } end end diff --git a/spec/lib/travis/api/enqueue/services/restart_model_spec.rb b/spec/lib/travis/api/enqueue/services/restart_model_spec.rb new file mode 100644 index 0000000000..ae39b56e10 --- /dev/null +++ b/spec/lib/travis/api/enqueue/services/restart_model_spec.rb @@ -0,0 +1,139 @@ +describe Travis::Enqueue::Services::RestartModel do + let(:owner) { FactoryBot.create(:user) } + let(:repository) { FactoryBot.create(:repository, owner: owner) } + let(:job) { FactoryBot.create(:job, repository: repository, state: 'canceled') } + let(:user) { FactoryBot.create(:user) } + let(:subscription) { nil } + + let(:service) { Travis::Enqueue::Services::RestartModel.new(user, { job_id: job.id }) } + + before do + Travis.config.billing.url = 'http://localhost:9292/' + Travis.config.billing.auth_key = 'secret' + end + + after do + Travis.config.billing.url = nil + Travis.config.billing.auth_key = nil + end + + describe 'push' do + let(:payload) { { id: job.id, user_id: user.id } } + + subject { service.push('job:restart', payload) } + + shared_examples 'restarts the job' do + it do + expect(subject.value).to eq({ id: job.id, user_id: user.id }) + expect(subject.error).to eq(nil) + end + end + + shared_examples 'does not restart the job' do + it do + expect(subject.value).to eq(nil) + expect(subject.error).to eq('restart failed') + end + end + + context 'when owner active plan' do + before do + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: true, rejection_code: nil) + ) + end + context 'build permissions' do + context 'when owner is a user' do + context 'on repo level' do + context 'when value is nil' do + before { repository.permissions.create(user: user, build: nil) } + + include_examples 'restarts the job' + end + + context 'when value is true' do + before { repository.permissions.create(user: user, build: true) } + + include_examples 'restarts the job' + end + + context 'when value is false' do + before { repository.permissions.create(user: user, build: false) } + + include_examples 'does not restart the job' + end + end + end + + context 'when owner is an organization' do + let(:owner) { FactoryBot.create(:org) } + + before { repository.permissions.create(user: user, build: true) } + + context 'on organization level' do + context 'when value is nil' do + before { owner.memberships.create(user: user, build_permission: nil) } + + include_examples 'restarts the job' + end + + context 'when value is true' do + before { owner.memberships.create(user: user, build_permission: true) } + + include_examples 'restarts the job' + end + + context 'when value is false' do + before { owner.memberships.create(user: user, build_permission: false) } + + include_examples 'does not restart the job' + end + end + end + end + end + + context 'when customer does not have active plan' do + before do + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/) + .to_return(status: 404, body: JSON.dump(error: 'Not Found')) + end + + context 'when customer has no old subscription' do + include_examples 'does not restart the job' + end + + context 'when customer has an old active subscription' do + before do + repository.permissions.create(user: user, build: true) + FactoryBot.create(:valid_stripe_subs, owner: owner) + end + + include_examples 'restarts the job' + end + + context 'when customer has an old canceled subscription' do + let(:subscription) { FactoryBot.create(:canceled_stripe_subs, owner: owner) } + + include_examples 'does not restart the job' + end + + context 'when customer belongs to a group' do + let(:uuid) { SecureRandom.uuid } + let!(:travis) { FactoryBot.create(:org, login: 'travis') } + let!(:john) { FactoryBot.create(:user, login: 'john') } + let!(:doe) { FactoryBot.create(:user, login: 'doe') } + before do + repository.permissions.create(user: user, build: true) + FactoryBot.create(:valid_stripe_subs, owner: john) + OwnerGroup.create(uuid: uuid, owner: owner) + OwnerGroup.create(uuid: uuid, owner: john) + OwnerGroup.create(uuid: uuid, owner: doe) + end + + include_examples 'restarts the job' + end + + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6969736af0..d3e7dbd492 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -107,6 +107,7 @@ def parsed_body DatabaseCleaner.start Redis.new(Travis.config.redis.to_h).flushall Travis.config.public_mode = true + Travis.config.read_only = true Travis.config.host = 'travis-ci.org' Travis.config.oauth2.scope = "user:email,public_repo" end diff --git a/spec/support/billing_spec_helper.rb b/spec/support/billing_spec_helper.rb index 707f3edc30..751ccb69dc 100644 --- a/spec/support/billing_spec_helper.rb +++ b/spec/support/billing_spec_helper.rb @@ -22,6 +22,7 @@ def billing_subscription_response_body(attributes={}) "last_name" => "rosas", "company" => "", "billing_email" => "a.rosas10@gmail.com", + 'has_local_registration' => nil, "zip_code" => "28450", "address" => "Luis Spota", "address2" => "", @@ -43,6 +44,173 @@ def billing_subscription_response_body(attributes={}) }.deep_merge(attributes) end + def billing_v2_subscription_response_body(attributes={}) + { + "permissions" => { "read" => true, "write" => true }, + "id" => 81, + 'status' => nil, + 'valid_to' => nil, + 'canceled_at' => nil, + "scheduled_plan" => nil, + "plan_config" => { + 'id' => 'pro_tier_plan', + 'name' => 'Pro Tier Plan', + 'plan_type' => 'metered', + 'concurrency_limit' => 20, + 'private_repos' => true, + 'starting_price' => 30000, + 'starting_users' => 10000, + 'private_credits' => 500000, + 'public_credits' => 40000, + 'annual' => false, + 'auto_refill_thresholds' => [10000, 50000, 100000], + 'auto_refill_amounts' => [ + { + 'amount' => 25000, + 'price' => 1500 + }, + { + 'amount' => 100000, + 'price' => 6000 + }, + { + 'amount' => 200000, + 'price' => 6000 + }, + { + 'amount' => 400000, + 'price' => 12000 + } + ], + 'available_standalone_addons' => [ + { + 'id' => 'credits_25k', + 'name' => '25 000 credits (2,5k Linux build minutes)', + 'price' => 1500, + 'quantity' => 25000, + 'type' => 'credit_private' + }, + { + 'id' => 'credits_500k', + 'name' => '500 000 credits (50k Linux build minutes)', + 'price' => 30000, + 'quantity' => 500000, + 'type' => 'credit_private' + } + ], + 'addon_configs' => { + 'free_tier_credits' => { + 'name' => 'Free 10 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_1234567890', + 'price_type' => 'fixed', + 'quantity' => 10_000, + 'standalone' => false, + 'type' => 'credit_private', + 'available_for_plans' => '%w[free_tier_plan]' + }, + 'oss_tier_credits' => { + 'name' => 'Free 40 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_0987654321', + 'price_type' => 'fixed', + 'quantity' => 40_000, + 'standalone' => false, + 'type' => 'credit_public', + 'private_repos' => false, + 'available_for_plans' => '%w[free_tier_plan standard_tier_plan pro_tier_plan]' + } + } + }, + "addons" => billing_addons_response_body, + "source" => "stripe", + "created_at" => "2017-11-28T00:09:59.502Z", + "billing_info" => { + "first_name" => "ana", + "last_name" => "rosas", + "company" => "", + "billing_email" => "a.rosas10@gmail.com", + "zip_code" => "28450", + "address" => "Luis Spota", + "address2" => "", + "city" => "Comala", + "state" => nil, + "country" => "Mexico", + "vat_id" => "123456" + }, + "credit_card_info" => { + "card_owner" => "ana", + "last_digits" => "4242", + "expiration_date" => "9/2021" + }, + "owner" => { + "type" => "Organization", + "id" => 43 + } + }.deep_merge(attributes) + end + + def billing_addons_response_body + [ + { + "id" => "1", + "name" => "OSS Build Credits", + "type" => "credit_public", + "recurring" => false, + "current_usage" => { + "id" => 1, + "addon_id" => 1, + "addon_quantity" => 40000, + "addon_usage" => 0, + "remaining" => 40000, + "purchase_date" => "2017-11-28T00:09:59.502Z", + "valid_to" => "2017-12-28T00:09:59.502Z", + "status" => "subscribed", + "active" => true + } + }, + { + "id" => 2, + "name" => "Build Credits", + "type" => "credit_private", + "recurring" => false, + "current_usage" => { + "id" => 2, + "addon_id" => 2, + "addon_quantity" => 10000, + "addon_usage" => 0, + "remaining" => 10000, + "purchase_date" => "2017-11-28T00:09:59.502Z", + "valid_to" => "", + "status" => "subscribed", + "active" => true + } + } + ] + end + + def billing_addon_usage_response_body(attributes = {}) + { + 'id' => 1, + 'addon_id' => 1, + 'addon_quantity' => 100, + 'addon_usage' => 0, + 'remaining' => 100, + 'purchase_date' => '2020-09-14T11:25:02.612Z', + 'valid_to' => '2020-10-14T11:25:02.612Z', + 'status' => 'subscribed', + 'active' => true, + 'created_at' => '2020-09-14T11:25:02.614Z', + 'updated_at' => '2020-09-14T11:25:02.614Z' + }.deep_merge(attributes) + end + def billing_plan_response_body(attributes={}) { "id" => "travis-ci-ten-builds", @@ -54,6 +222,94 @@ def billing_plan_response_body(attributes={}) }.deep_merge(attributes) end + def billing_v2_plan_response_body(attributes = {}) + { + 'id' => 'free_tier_plan', + 'name' => 'Free Tier Plan', + 'private_repos' => true, + 'plan_type' => 'metered', + 'concurrency_limit' => 20, + 'addon_configs' => [ + { + 'id' => 'oss_tier_credits', + 'name' => 'Free 40 000 credits (renewed monthly)', + 'price' => 0, + 'quantity' => 40_000, + 'type' => 'credit_public' + }, + { + 'id' => 'free_tier_credits', + 'name' => 'Free 10 000 credits (renewed monthly)', + 'price' => 0, + 'quantity' => 10_000, + 'type' => 'credit_private' + }, + { + 'id' => 'users_free', + 'name' => 'Unlimited users', + 'price' => 0, + 'quantity' => 999_999, + 'type' => 'user_license' + } + ], + 'starting_price' => 0, + 'starting_users' => 999_999, + 'private_credits' => 10_000, + 'public_credits' => 40_000, + 'annual' => false, + 'auto_refill_thresholds' => [10000, 50000, 100000], + 'auto_refill_amounts' => [ + { + 'amount' => 25000, + 'price' => 1500 + }, + { + 'amount' => 100000, + 'price' => 6000 + }, + { + 'amount' => 200000, + 'price' => 6000 + }, + { + 'amount' => 400000, + 'price' => 12000 + } + ], + 'available_standalone_addons' => [] + }.deep_merge(attributes) + end + + def billing_v2_credits_calculator_body + [ + { + 'users' => 3, + 'minutes' => nil, + 'os' => nil, + 'instance_size' => nil, + 'credits' => 25_000, + 'price' => 1_500 + }, + { + 'users' => nil, + 'minutes' => 1000, + 'os' => 'linux', + 'instance_size' => '2x-large', + 'credits' => 250_000, + 'price' => 15_000 + } + ] + end + + def billing_v2_credits_calculator_config_body + { + 'users' => 10, + 'minutes' => 1000, + 'os' => 'linux', + 'instance_size' => '2x-large' + } + end + def billing_coupon_response_body(attributes = {}) { "id" => "10_BUCKS_OFF", @@ -79,5 +335,28 @@ def billing_trial_response_body(attributes = {}) 'builds_remaining' => 5 }.deep_merge(attributes) end + + def billing_executions_response_body(attributes = {}) + { + 'id' => 1, + 'os' => 'linux', + 'instance_size' => 'standard-2', + 'arch' => 'amd64', + 'virtualization_type' => 'vm', + 'queue' => 'builds.gce-oss', + 'job_id' => 123, + 'repository_id' => 1, + 'owner_id' => 1, + 'owner_type' => 'User', + 'plan_id' => 2, + 'sender_id' => 1, + 'credits_consumed' => 5, + 'user_license_credits_consumed' => 4, + 'started_at' => Time.now, + 'finished_at' => Time.now + 10.minutes, + 'created_at' => Time.now, + 'updated_at' => Time.now + }.deep_merge(attributes) + end end end diff --git a/spec/travis/remote_vcs/user_spec.rb b/spec/travis/remote_vcs/user_spec.rb new file mode 100644 index 0000000000..ab0eea9972 --- /dev/null +++ b/spec/travis/remote_vcs/user_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'rspec' + +describe Travis::RemoteVCS::User do + describe '#confirm_user' do + let(:token) { double(:token) } + let(:instance) { described_class.new } + let(:req) { double(:request) } + let(:params) { double(:params) } + + subject { instance.confirm_user(token: token) } + + before do + allow(req).to receive(:url) + allow(req).to receive(:params).and_return(params) + allow(params).to receive(:[]=) + end + + it 'performs POST to VCS with proper params' do + expect(instance).to receive(:request).with(:post, :confirm_user).and_yield(req) + expect(req).to receive(:url).with('users/confirm') + expect(params).to receive(:[]=).with('token', token) + + subject + end + end + + describe '#request_confirmation' do + let(:id) { double(:id) } + let(:instance) { described_class.new } + let(:req) { double(:request) } + let(:params) { double(:params) } + + subject { instance.request_confirmation(id: id) } + + before do + allow(req).to receive(:url) + allow(req).to receive(:params).and_return(params) + allow(params).to receive(:[]=) + end + + it 'performs POST to VCS with proper params' do + expect(instance).to receive(:request).with(:post, :request_confirmation).and_yield(req) + expect(req).to receive(:url).with('users/request_confirmation') + expect(params).to receive(:[]=).with('id', id) + + subject + end + end +end diff --git a/spec/unit/endpoint/authorization/user_manager_spec.rb b/spec/unit/endpoint/authorization/user_manager_spec.rb index 9cfc5dec72..4c9543da54 100644 --- a/spec/unit/endpoint/authorization/user_manager_spec.rb +++ b/spec/unit/endpoint/authorization/user_manager_spec.rb @@ -1,4 +1,4 @@ -describe Travis::Api::App::Endpoint::Authorization::UserManager do +describe Travis::Api::App::Endpoint::Authorization::UserManager, billing_spec_helper: true do let(:manager) { described_class.new(data, 'abc123') } before do @@ -51,9 +51,15 @@ context 'with existing user' do let!(:user) { FactoryBot.create(:user, login: 'drogus', github_id: 456, github_oauth_token: token) } let(:token) { nil } + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } before do allow(manager).to receive(:education).and_return(false) + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + stubbed_request = stub_billing_request(:post, "/v2/initial_subscription", auth_key: billing_auth_key, user_id: user.id) + .to_return(status: 201, body: JSON.dump(billing_v2_subscription_response_body('id' => 456, 'owner' => { 'type' => 'User', 'id' => user.id }))) end context 'without any User#tokens record' do diff --git a/spec/unit/endpoint/authorization_spec.rb b/spec/unit/endpoint/authorization_spec.rb index b1f25a14ab..6b77e40ec4 100644 --- a/spec/unit/endpoint/authorization_spec.rb +++ b/spec/unit/endpoint/authorization_spec.rb @@ -1,6 +1,10 @@ -describe Travis::Api::App::Endpoint::Authorization do +describe Travis::Api::App::Endpoint::Authorization, billing_spec_helper: true do include Travis::Testing::Stubs + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + before { allow_any_instance_of(Travis::RemoteVCS::User).to receive(:check_scopes) } + before do add_endpoint '/info' do get '/login', scope: :private do @@ -21,6 +25,10 @@ scope: 'public_repo,user:email,new_scope', insufficient_access_redirect_url: 'https://travis-ci.org/insufficient_access' } + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + WebMock.stub_request(:post, 'http://billingfake.travis-ci.com/v2/initial_subscription') + .to_return(status: 200, body: JSON.dump(billing_v2_subscription_response_body('id' => 456, 'owner' => { 'type' => 'User', 'id' => user.id }))) end after do @@ -48,11 +56,25 @@ end describe 'evil hackers messing with the state' do - it 'does not succeed if state cookie mismatches' do + before do + WebMock.stub_request(:post, "https://foobar.com/access_token_path"). + with( + body: "{\"client_id\":\"client-id\",\"scope\":\"public_repo,user:email,new_scope\",\"redirect_uri\":\"http://example.org/auth/handshake\",\"state\":\"github-state\",\"code\":\"oauth-code\",\"client_secret\":\"client-secret\"}", + headers: { + 'Accept' => '*/*', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Connection' => 'keep-alive', + 'Content-Type' => 'application/json', + 'Keep-Alive' => '30', + 'User-Agent' => 'Faraday v0.17.3' + }). + to_return(status: 200, body: "", headers: {}) + end + + it 'does not succeed if state cookie mismatches (redirects)' do Travis.redis.sadd('github:states', 'github-state') response = get '/auth/handshake?state=github-state&code=oauth-code' - expect(response.status).to eq(400) - expect(response.body).to eq("state mismatch") + expect(response.status).to eq(302) Travis.redis.srem('github:states', 'github-state') end end @@ -282,4 +304,53 @@ def user_for(github_token) expect(post('/auth/github', github_token: 'public repos')).to be_ok end end + + describe 'GET /confirm_user/:token' do + context 'when response is ok' do + before { allow_any_instance_of(Travis::RemoteVCS::User).to receive(:confirm_user) } + + it 'returns ok' do + expect(get('/auth/confirm_user/mytokentopass')).to be_ok + end + + it 'calls VCS service with proper params' do + expect_any_instance_of(Travis::RemoteVCS::User) + .to receive(:confirm_user).with(token: 'mytokentopass') + + get('/auth/confirm_user/mytokentopass') + end + end + + context 'when response is not ok' do + before do + allow_any_instance_of(Travis::RemoteVCS::User) + .to receive(:confirm_user).and_raise(Travis::RemoteVCS::ResponseError) + end + + it 'returns 404 with a message' do + expect(get('/auth/confirm_user/mytokentopass')).not_to be_ok + expect(last_response.status).to eq(404) + expect(body).to include('The token is expired or not found.') + end + end + end + + describe 'GET /request_confirmation/:session_token/:id' do + let(:current_user) { double(:user, id: 123) } + before do + allow_any_instance_of(described_class).to receive(:current_user).and_return(current_user) + allow_any_instance_of(Travis::RemoteVCS::User).to receive(:request_confirmation) + end + + it 'returns ok' do + expect(get('/auth/request_confirmation/123')).to be_ok + end + + it 'calls VCS service with proper params' do + expect_any_instance_of(Travis::RemoteVCS::User) + .to receive(:request_confirmation).with(id: 123) + + get('/auth/request_confirmation/123') + end + end end diff --git a/spec/unit/endpoint/users_spec.rb b/spec/unit/endpoint/users_spec.rb index b865c1179a..0809bba4da 100644 --- a/spec/unit/endpoint/users_spec.rb +++ b/spec/unit/endpoint/users_spec.rb @@ -1,17 +1,21 @@ describe Travis::Api::App::Endpoint::Users, set_app: true do include Travis::Testing::Stubs let(:access_token) { Travis::Api::App::AccessToken.create(user: user, app_id: -1) } - before do - allow(User).to receive(:find_by_github_id).and_return(user) + allow(User).to receive(:find_by_vcs_id).and_return(user) allow(User).to receive(:find).and_return(user) allow(user).to receive(:github_scopes).and_return(['public_repo', 'user:email']) + Travis.config.vcs.url = 'http://vcsfake.travis-ci.com' + Travis.config.vcs.token = 'vcs-token' + WebMock.stub_request(:post, 'http://vcsfake.travis-ci.com/users/1/check_scopes') + .to_return( + status: 200, + body: nil, + ) end - it 'needs to be authenticated' do expect(get('/users', {}, 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json, */*; q=0.01')).not_to be_ok end - it 'replies with the current user' do expect(get('/users', { access_token: access_token.to_s }, 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json, */*; q=0.01')).to be_ok expect(parsed_body['user']).to eq({ @@ -32,16 +36,13 @@ "vcs_type" => "GithubUser", }) end - context 'when responding to POST for /users/sync' do context 'when sync is in progress' do before :each do allow(user).to receive(:syncing?).and_return(true) end - it 'returns 409' do response = post('/users/sync', { access_token: access_token.to_s }, 'HTTP_ACCEPT' => 'application/vnd.travis-ci.2+json, */*; q=0.01') - expect(response.status).to eq(409) expect(JSON.parse(response.body)).to eq({ 'message' => 'Sync already in progress. Try again later.' }) end diff --git a/spec/unit/serialize/v2/http/user_spec.rb b/spec/unit/serialize/v2/http/user_spec.rb index d938ba728d..a58537fb17 100644 --- a/spec/unit/serialize/v2/http/user_spec.rb +++ b/spec/unit/serialize/v2/http/user_spec.rb @@ -1,6 +1,5 @@ describe Travis::Api::Serialize::V2::Http::User do include Travis::Testing::Stubs, Support::Formats - let(:user) { stub_user(repository_ids: [1, 4, 8]) } let(:data) { described_class.new(user).data } let(:expected_data) { @@ -22,48 +21,46 @@ 'vcs_type' => 'GithubUser' } } - + let!(:request) do + WebMock.stub_request(:post, 'http://vcsfake.travis-ci.com/users/1/check_scopes') + .to_return( + status: 200, + body: nil, + ) + end before do + Travis.config.vcs.url = 'http://vcsfake.travis-ci.com' + Travis.config.vcs.token = 'vcs-token' allow(user).to receive(:github_scopes).and_return(['public_repo', 'user:email']) end - it 'user' do expect(data['user']).to eq(expected_data) end - context 'allow_migration' do subject { data['user']['allow_migration'] } - context 'when feature is not enabled for the user' do it { is_expected.to be_falsey } end - context 'when feature is enabled for the user' do before { expect(Travis::Features).to receive(:user_active?).with(:allow_migration, user).and_return(true) } - it { is_expected.to be_truthy } end end - context 'when there is an Intercom HMAC secret key' do before do Travis.config.intercom = { hmac_secret_key: 'USER_HASH_SECRET_KEY' } end - it 'user' do secure_user_hash = OpenSSL::HMAC.hexdigest( 'sha256', 'USER_HASH_SECRET_KEY', '1' ) - expected_data["secure_user_hash"] = secure_user_hash - expect(data['user']).to eq(expected_data) end - after do Travis.config.intercom = nil end diff --git a/spec/v3/billing_client_spec.rb b/spec/v3/billing_client_spec.rb index 45a9e021b6..9e45f15bf3 100644 --- a/spec/v3/billing_client_spec.rb +++ b/spec/v3/billing_client_spec.rb @@ -12,6 +12,12 @@ let(:subscription_id) { rand(999) } let(:invoice_id) { "TP#{rand(999)}" } + let(:page) { 1 } + let(:per_page) { 25 } + let(:from) { DateTime.now - 2.months } + let(:to) { DateTime.now } + let(:owner_id) { rand(999) } + let(:owner_type) { 'user' } describe '#get_subscription' do subject { billing.get_subscription(subscription_id) } @@ -46,10 +52,11 @@ it 'returns a list of invoices' do stub_billing_request(:get, "/subscriptions/#{subscription_id}/invoices", auth_key: auth_key, user_id: user_id) - .to_return(body: JSON.dump([{'id' => invoice_id, 'created_at' => Time.now, 'url' => 'https://billing-test.travis-ci.com/invoices/111.pdf', amount_due: 999 }])) + .to_return(body: JSON.dump([{'id' => invoice_id, 'created_at' => Time.now, 'url' => 'https://billing-test.travis-ci.com/invoices/111.pdf', amount_due: 999, status: 'paid', cc_last_digits: '4242' }])) expect(subject.first).to be_a(Travis::API::V3::Models::Invoice) expect(subject.first.id).to eq(invoice_id) expect(subject.first.amount_due).to eq(999) + expect(subject.first.cc_last_digits).to eq('4242') end it 'returns an empty list if there are no invoices' do @@ -60,6 +67,26 @@ end end + describe '#get_invoices_for_v2_subscription' do + subject { billing.get_invoices_for_v2_subscription(subscription_id) } + + it 'returns a list of invoices' do + stub_billing_request(:get, "/v2/subscriptions/#{subscription_id}/invoices", auth_key: auth_key, user_id: user_id) + .to_return(body: JSON.dump([{'id' => invoice_id, 'created_at' => Time.now, 'url' => 'https://billing-test.travis-ci.com/invoices/111.pdf', amount_due: 999, status: 'paid', cc_last_digits: '4242' }])) + expect(subject.first).to be_a(Travis::API::V3::Models::Invoice) + expect(subject.first.id).to eq(invoice_id) + expect(subject.first.amount_due).to eq(999) + expect(subject.first.cc_last_digits).to eq('4242') + end + + it 'returns an empty list if there are no invoices' do + stub_billing_request(:get, "/v2/subscriptions/#{subscription_id}/invoices", auth_key: auth_key, user_id: user_id) + .to_return(body: JSON.dump([])) + + expect(subject.size).to eq 0 + end + end + describe '#all' do subject { billing.all } @@ -75,6 +102,21 @@ end end + describe '#all_v2' do + subject { billing.all_v2 } + + let(:permissions) { [{'owner' => {'type' => 'Organization', 'id' => 1}, 'create' => true}] } + + it 'returns the list of subscriptions' do + stub_billing_request(:get, '/v2/subscriptions', auth_key: auth_key, user_id: user_id) + .to_return(body: JSON.dump(plans: [billing_v2_subscription_response_body('id' => subscription_id, 'client_secret' => 'client_secret', 'owner' => { 'type' => 'Organization', 'id' => organization.id })], permissions: permissions)) + + expect(subject.subscriptions.size).to eq 1 + expect(subject.subscriptions.first.id).to eq(subscription_id) + expect(subject.permissions).to eq(permissions) + end + end + describe '#update_address' do let(:address_data) { { 'address' => 'Rigaer Strasse' } } subject { billing.update_address(subscription_id, address_data) } @@ -89,6 +131,20 @@ end end + describe '#update_v2_address' do + let(:address_data) { { 'address' => 'Rigaer Strasse' } } + subject { billing.update_v2_address(subscription_id, address_data) } + + it 'requests the update' do + stubbed_request = stub_billing_request(:patch, "/v2/subscriptions/#{subscription_id}/address", auth_key: auth_key, user_id: user_id) + .with(body: JSON.dump(address_data)) + .to_return(status: 204) + + expect { subject }.to_not raise_error + expect(stubbed_request).to have_been_made + end + end + describe '#update_plan' do let(:plan_data) { { 'plan' => 'travis-ci-ten-builds' } } subject { billing.update_plan(subscription_id, plan_data) } @@ -117,6 +173,20 @@ end end + describe '#update_v2_creditcard' do + let(:creditcard_token) { 'token' } + subject { billing.update_v2_creditcard(subscription_id, creditcard_token) } + + it 'requests the update' do + stubbed_request = stub_billing_request(:patch, "/v2/subscriptions/#{subscription_id}/creditcard", auth_key: auth_key, user_id: user_id) + .with(body: JSON.dump(token: creditcard_token)) + .to_return(status: 204) + + expect { subject }.to_not raise_error + expect(stubbed_request).to have_been_made + end + end + describe '#resubscribe' do subject { billing.resubscribe(subscription_id) } @@ -156,6 +226,61 @@ end end + describe '#create_v2_subscription' do + let(:subscription_data) {{ 'address' => 'Rigaer' }} + subject { billing.create_v2_subscription(subscription_data) } + + it 'requests the creation and returns the representation' do + stubbed_request = stub_billing_request(:post, "/v2/subscriptions", auth_key: auth_key, user_id: user_id) + .with(body: JSON.dump(subscription_data)) + .to_return(status: 201, body: JSON.dump(billing_v2_subscription_response_body('id' => 456, 'client_secret' => 'client_secret', 'owner' => { 'type' => 'Organization', 'id' => organization.id }))) + + expect(subject.id).to eq(456) + expect(stubbed_request).to have_been_made + end + end + + describe '#changetofree_v2_subscription' do + let(:plan_data) { { 'plan' => 'enterprise_tier_plan' } } + subject { billing.changetofree_v2_subscription(subscription_id, plan_data) } + + it 'requests the update' do + stubbed_request = stub_billing_request(:patch, "/v2/subscriptions/#{subscription_id}/changetofree", auth_key: auth_key, user_id: user_id) + .with(body: JSON.dump(plan_data)) + .to_return(status: 204) + + expect { subject }.to_not raise_error + expect(stubbed_request).to have_been_made + end + end + + describe '#update_v2_subscription' do + let(:plan_data) { { 'plan' => 'enterprise_tier_plan' } } + subject { billing.update_v2_subscription(subscription_id, plan_data) } + + it 'requests the update' do + stubbed_request = stub_billing_request(:patch, "/v2/subscriptions/#{subscription_id}/plan", auth_key: auth_key, user_id: user_id) + .with(body: JSON.dump(plan_data)) + .to_return(status: 204) + + expect { subject }.to_not raise_error + expect(stubbed_request).to have_been_made + end + end + + describe '#purchase_addon' do + let(:addon_config_id) { 'credits_500k' } + subject { billing.purchase_addon(subscription_id, addon_config_id) } + + it 'requests the update' do + stubbed_request = stub_billing_request(:patch, "/v2/subscriptions/#{subscription_id}/addon", auth_key: auth_key, user_id: user_id) + .with(body: JSON.dump(addon: addon_config_id)) + .to_return(status: 204) + + expect { subject }.to_not raise_error + end + end + describe '#pay' do subject { billing.pay(subscription_id) } @@ -168,6 +293,18 @@ end end + describe '#pay_v2' do + subject { billing.pay_v2(subscription_id) } + + it 'requests to retry payment' do + stubbed_request = stub_billing_request(:post, "/v2/subscriptions/#{subscription_id}/pay", auth_key: auth_key, user_id: user_id) + .to_return(status: 200, body: JSON.dump(billing_v2_subscription_response_body('id' => subscription_id, 'client_secret' => 'client_secret', 'owner' => { 'type' => 'Organization', 'id' => organization.id }))) + + expect { subject }.to_not raise_error + expect(stubbed_request).to have_been_made + end + end + describe '#trials' do subject { billing.trials } let(:trial_id) { rand(999) } @@ -231,6 +368,47 @@ end end + describe '#v2_plans_for' do + describe '#organization' do + subject { billing.v2_plans_for_organization(organization.id) } + + it 'returns the list of v2 plans for an organization' do + stub_request(:get, "#{billing_url}v2/plans_for/organization/#{organization.id}").with(basic_auth: ['_', auth_key], headers: { 'X-Travis-User-Id' => user_id }) + .to_return(body: JSON.dump([billing_v2_plan_response_body('id' => 'plan-id')])) + + expect(subject.size).to eq 1 + expect(subject.first.id).to eq('plan-id') + expect(subject.first.addon_configs.first['id']).to eq('oss_tier_credits') + end + end + + describe '#user' do + subject { billing.v2_plans_for_user } + + it 'returns the list of v2 plans for an user' do + stub_request(:get, "#{billing_url}v2/plans_for/user").with(basic_auth: ['_', auth_key], headers: { 'X-Travis-User-Id' => user_id }) + .to_return(body: JSON.dump([billing_v2_plan_response_body('id' => 'plan-id')])) + + expect(subject.size).to eq 1 + expect(subject.first.id).to eq('plan-id') + expect(subject.first.addon_configs.first['id']).to eq('oss_tier_credits') + end + end + end + + describe '#v2_subscription_user_usages' do + subject { billing.v2_subscription_user_usages(subscription_id)} + + it 'returns the list of user license usages for the subscription' do + stub_request(:get, "#{billing_url}v2/subscriptions/#{subscription_id}/user_usage").with(basic_auth: ['_', auth_key], headers: { 'X-Travis-User-Id' => user_id }) + .to_return(body: JSON.dump([billing_addon_usage_response_body])) + + expect(subject.size).to eq 1 + expect(subject.first.addon_quantity).to eq 100 + expect(subject.first.addon_usage).to eq 0 + end + end + describe '#update_organization_billing_permission' do let(:billing_admin_only) { { billing_admin_only: true } } subject { billing.update_organization_billing_permission(organization.id, billing_admin_only) } @@ -244,4 +422,67 @@ expect(stubbed_request).to have_been_made end end + + describe '#update_organization_billing_permission' do + subject { billing.executions(owner_type, owner_id, page, per_page, from, to) } + + it 'returns the list of executions for the subscription' do + stub_request(:get, "#{billing_url}usage/#{owner_type.downcase}s/#{owner_id}/executions?page=#{page}&per_page=#{per_page}&from=#{from}&to=#{to}").with(basic_auth: ['_', auth_key], headers: { 'X-Travis-User-Id' => user_id }) + .to_return(body: JSON.dump([billing_executions_response_body])) + + expect(subject.first).to be_a(Travis::API::V3::Models::Execution) + expect(subject.first.credits_consumed).to eq 5 + expect(subject.first.os).to eq 'linux' + end + end + + describe '#cancel_v2_subscription' do + let(:reason_data) { { 'reason' => 'Other', 'reason_details' => 'Cancellation details go here' } } + subject { billing.cancel_v2_subscription(subscription_id, reason_data) } + + it 'requests the cancelation of a subscription' do + stubbed_request = stub_billing_request(:post, "/v2/subscriptions/#{subscription_id}/cancel", auth_key: auth_key, user_id: user_id) + .to_return(status: 204) + + expect { subject }.to_not raise_error + expect(stubbed_request).to have_been_made + end + end + + describe '#calculate_credits' do + let(:users) { 3 } + let(:executions) do + [ + { + minutes: '1000', + os: 'linux', + instance_size: '2x-large' + } + ] + end + + subject { billing.calculate_credits(users, executions) } + + it 'returns the results of the calculation' do + stub_request(:post, "#{billing_url}usage/credits_calculator").with(basic_auth: ['_', auth_key], headers: { 'X-Travis-User-Id' => user_id }) + .to_return(body: JSON.dump(billing_v2_credits_calculator_body)) + + expect(subject.first).to be_a(Travis::API::V3::Models::CreditsResult) + expect(subject.first.users).to eq(3) + expect(subject.last.os).to eq('linux') + end + end + + describe '#calculate_credits' do + subject { billing.credits_calculator_default_config } + + it 'returns the results of the calculation' do + stub_request(:get, "#{billing_url}usage/credits_calculator/default_config").with(basic_auth: ['_', auth_key], headers: { 'X-Travis-User-Id' => user_id }) + .to_return(body: JSON.dump(billing_v2_credits_calculator_config_body)) + + expect(subject).to be_a(Travis::API::V3::Models::CreditsCalculatorConfig) + expect(subject.users).to eq(10) + expect(subject.os).to eq('linux') + end + end end diff --git a/spec/v3/models/build_backup_spec.rb b/spec/v3/models/build_backup_spec.rb new file mode 100644 index 0000000000..1fbe9b770d --- /dev/null +++ b/spec/v3/models/build_backup_spec.rb @@ -0,0 +1,6 @@ +describe Travis::API::V3::Models::BuildBackup do + let(:build_backup) { FactoryBot.create(:build_backup) } + subject { Travis::API::V3::Models::BuildBackup.find_by_id(build_backup.id) } + + example { expect(subject.file_name).to be_present } +end diff --git a/spec/v3/models/credits_calculator_config_spec.rb b/spec/v3/models/credits_calculator_config_spec.rb new file mode 100644 index 0000000000..f8e50df4b5 --- /dev/null +++ b/spec/v3/models/credits_calculator_config_spec.rb @@ -0,0 +1,21 @@ +describe Travis::API::V3::Models::CreditsResult do + let(:user) { FactoryBot.create(:user) } + let(:attributes) do + { + 'users' => 5, + 'minutes' => 1200, + 'os' => 'linux', + 'instance_size' => '2x-large' + } + end + + subject { Travis::API::V3::Models::CreditsCalculatorConfig.new(attributes) } + + context 'basic fields' do + it 'returns basic fields' do + attributes.each do |key, value| + expect(subject.send(key)).to eq(value) + end + end + end +end diff --git a/spec/v3/models/credits_result_spec.rb b/spec/v3/models/credits_result_spec.rb new file mode 100644 index 0000000000..a4299a85cc --- /dev/null +++ b/spec/v3/models/credits_result_spec.rb @@ -0,0 +1,23 @@ +describe Travis::API::V3::Models::CreditsResult do + let(:user) { FactoryBot.create(:user) } + let(:attributes) do + { + 'users' => 5, + 'minutes' => 1200, + 'os' => 'linux', + 'instance_size' => '2x-large', + 'credits' => 25_000, + 'price' => 1_500 + } + end + + subject { Travis::API::V3::Models::CreditsResult.new(attributes) } + + context 'basic fields' do + it 'returns basic fields' do + attributes.each do |key, value| + expect(subject.send(key)).to eq(value) + end + end + end +end diff --git a/spec/v3/models/v2_subscription_spec.rb b/spec/v3/models/v2_subscription_spec.rb new file mode 100644 index 0000000000..5933c7393d --- /dev/null +++ b/spec/v3/models/v2_subscription_spec.rb @@ -0,0 +1,146 @@ +describe Travis::API::V3::Models::V2Subscription do + let(:user) { FactoryBot.create(:user) } + let(:attributes) do + { + 'id' => 'id', + 'permissions' => { 'read' => true, 'write' => true }, + 'created_at' => Date.today.to_s, + 'status' => nil, + 'valid_to' => nil, + 'canceled_at' => nil, + 'scheduled_plan' => nil, + 'billing_info' => { + 'address' => 'Washington str.', + 'address2' => '', + 'billing_email' => 'john.doe@example.com', + 'city' => 'Washington', + 'company' => 'Travis CI', + 'country' => 'United States of America', + 'first_name' => 'John', + 'last_name' => 'Doe', + 'has_local_registration' => true, + 'state' => 'Alabama', + 'vat_id' => '', + 'zip_code' => '2001', + }, + 'plan_config' => { + 'id' => 'pro_tier_plan', + 'name' => 'Pro Tier Plan', + 'plan_type' => 'metered', + 'concurrency_limit' => 20, + 'private_repos' => true, + 'starting_price' => 30000, + 'starting_users' => 10000, + 'private_credits' => 500000, + 'public_credits' => 40000, + 'annual' => false, + 'auto_refill_thresholds' => [10000, 50000, 100000], + 'auto_refill_amounts' => [ + { + 'amount' => 25000, + 'price' => 1500 + }, + { + 'amount' => 100000, + 'price' => 6000 + }, + { + 'amount' => 200000, + 'price' => 6000 + }, + { + 'amount' => 400000, + 'price' => 12000 + } + ], + 'available_standalone_addons' => [ + { + 'id' => 'credits_25k', + 'name' => '25 000 credits (2,5k Linux build minutes)', + 'price' => 1500, + 'quantity' => 25000, + 'type' => 'credit_private' + }, + { + 'id' => 'credits_500k', + 'name' => '500 000 credits (50k Linux build minutes)', + 'price' => 30000, + 'quantity' => 500000, + 'type' => 'credit_private' + } + ], + 'addon_configs' => { + 'free_tier_credits' => { + 'name' => 'Free 10 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_1234567890', + 'price_type' => 'fixed', + 'quantity' => 10_000, + 'standalone' => false, + 'type' => 'credit_private', + 'available_for_plans' => '%w[free_tier_plan]' + }, + 'oss_tier_credits' => { + 'name' => 'Free 40 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_0987654321', + 'price_type' => 'fixed', + 'quantity' => 40_000, + 'standalone' => false, + 'type' => 'credit_public', + 'private_repos' => false, + 'available_for_plans' => '%w[free_tier_plan standard_tier_plan pro_tier_plan]' + } + } + }, + 'addons' => [{ + 'id' => 7, + 'name' => 'OSS Build Credits', + 'plan_id' => 3, + 'addon_config_id' => 'oss_tier_credits', + 'type' => 'credit_public', + 'created_at' => Date.today.to_s, + 'updated_at' => Date.today.to_s, + 'recurring' => false, + 'current_usage_id' => 7, + 'current_usage' => { + 'id' => 7, + 'addon_id' => 7, + 'addon_quantity' => 40_000, + 'addon_usage' => 0, + 'remaining' => 40_000, + 'purchase_date' => Date.today.to_s, + 'valid_to' => Date.today.to_s, + 'status' => 'pending', + 'active' => false, + 'created_at' => Date.today.to_s, + 'updated_at' => Date.today.to_s + } + }], + 'source' => 'stripe', + 'owner' => { 'id' => user.id, 'type' => 'User'}, + 'client_secret' => 'secret', + 'payment_intent' => { 'status' => 'requires_action', 'client_secret' => 'abc', 'last_payment_error' => {} } + } + end + + subject { Travis::API::V3::Models::V2Subscription.new(attributes) } + + context 'basic fields' do + it 'returns basic fields' do + expect(subject.id).to eq(attributes['id']) + expect(subject.plan).to be_a(Travis::API::V3::Models::V2PlanConfig) + expect(subject.permissions).to be_a(Travis::API::V3::Models::BillingPermissions) + expect(subject.owner).to be_a(Travis::API::V3::Models::User) + expect(subject.payment_intent).to be_a(Travis::API::V3::Models::PaymentIntent) + expect(subject.billing_info).to be_a(Travis::API::V3::Models::V2BillingInfo) + expect(subject.billing_info.has_local_registration).to be true + end + end +end diff --git a/spec/v3/queries/build_backup_spec.rb b/spec/v3/queries/build_backup_spec.rb new file mode 100644 index 0000000000..7f12397bdf --- /dev/null +++ b/spec/v3/queries/build_backup_spec.rb @@ -0,0 +1,23 @@ +describe Travis::API::V3::Queries::BuildBackup do + subject { described_class.new({ 'build_backup.id' => build_backup.id }, 'BuildBackup') } + + describe '#find' do + let(:repo) { FactoryBot.create(:repository) } + let!(:build_backup) { FactoryBot.create(:build_backup, repository: repo) } + let(:content) { '123' } + + before do + stub_request(:post, 'https://www.googleapis.com/oauth2/v4/token'). + to_return(status: 200, body: '{}', headers: { 'Content-Type' => 'application/json' }) + stub_request(:get, /o\/#{build_backup.file_name}\?alt=media/). + to_return(status: 200, body: content, headers: { 'Content-Type' => 'application/json' }) + end + + it 'returns backups for repo' do + backup = subject.find + + expect(backup.file_name).to eq(build_backup.file_name) + expect(backup.content).to eq(content) + end + end +end diff --git a/spec/v3/queries/build_backups_spec.rb b/spec/v3/queries/build_backups_spec.rb new file mode 100644 index 0000000000..feda8f140a --- /dev/null +++ b/spec/v3/queries/build_backups_spec.rb @@ -0,0 +1,14 @@ +describe Travis::API::V3::Queries::BuildBackups do + subject { described_class.new({ 'build_backups.repository_id' => repo.id }, 'BuildBackups') } + + describe '#all' do + let(:repo) { FactoryBot.create(:repository) } + let!(:build_backup) { FactoryBot.create(:build_backup, repository: repo) } + + it 'returns backups for repo' do + backups = subject.all + + expect(backups.first.file_name).to eq(build_backup.file_name) + end + end +end diff --git a/spec/v3/queries/build_permissions_spec.rb b/spec/v3/queries/build_permissions_spec.rb new file mode 100644 index 0000000000..f2db0da809 --- /dev/null +++ b/spec/v3/queries/build_permissions_spec.rb @@ -0,0 +1,70 @@ +describe Travis::API::V3::Queries::BuildPermissions do + let(:user) { FactoryBot.create(:user) } + + subject { described_class.new({}, 'BuildPermissions') } + + describe '#find_for_repo' do + let(:repo) { FactoryBot.create(:repository) } + let!(:permission) { repo.permissions.create(build: true, user: user) } + + it 'returns permissions for repo' do + perms = subject.find_for_repo(repo) + + expect(perms.first.build).to eq(true) + expect(perms.first.user.id).to eq(user.id) + end + + context 'when permission has user_id: nil' do + let!(:permission) { repo.permissions.create(build: true, user_id: nil) } + + it 'filters it out' do + perms = subject.find_for_repo(repo) + expect(perms.length).to eq(0) + end + end + end + + describe '#find_for_organization' do + let(:organization) { FactoryBot.create(:org) } + + let!(:membership) { organization.memberships.create(user: user, role: 'admin', build_permission: true) } + + it 'returns build memberships for organization' do + perms = subject.find_for_organization(organization) + + expect(perms.first.build_permission).to eq(true) + expect(perms.first.user.id).to eq(user.id) + end + + context 'when membership has user_id: nil' do + let!(:membership) { organization.memberships.create(user_id: nil, role: 'admin', build_permission: true) } + + it 'filters it out' do + perms = subject.find_for_organization(organization) + expect(perms.length).to eq(0) + end + end + end + + describe '#update_for_repo' do + let(:repo) { FactoryBot.create(:repository) } + + before { repo.permissions.create(build: true, user: user) } + + it 'updates build permissions' do + expect(subject.update_for_repo(repo, [user.id], false)).to eq(1) + expect(repo.permissions.first.build).to eq(false) + end + end + + describe '#update_for_organization' do + let(:organization) { FactoryBot.create(:org) } + + before { organization.memberships.create(user: user, role: 'admin', build_permission: true) } + + it 'updates build permissions' do + expect(subject.update_for_organization(organization, [user.id], false)).to eq(1) + expect(organization.memberships.first.build_permission).to eq(false) + end + end +end diff --git a/spec/v3/renderer/build_backup_spec.rb b/spec/v3/renderer/build_backup_spec.rb new file mode 100644 index 0000000000..ae0038fa78 --- /dev/null +++ b/spec/v3/renderer/build_backup_spec.rb @@ -0,0 +1,34 @@ +describe Travis::API::V3::Renderer::BuildBackup do + let!(:build_backup) { FactoryBot.create(:build_backup) } + let(:backup_model) { Travis::API::V3::Models::BuildBackup.find_by_id(build_backup.id) } + let(:renderer) { Travis::API::V3::Renderer::BuildBackup.new(repo) } + let(:content) { '123' } + + describe '.render' do + subject { described_class.render(backup_model, :standard, accept: accept) } + + before { allow(backup_model).to receive(:content) { content } } + + context 'when accept is none' do + let(:accept) { nil } + + it 'returns an object' do + expect(subject).to eq( + :@href => "/build_backup/#{build_backup.id}", + :@representation => :standard, + :@type => :build_backup, + created_at: build_backup.created_at.iso8601, + file_name: build_backup.file_name + ) + end + end + + context 'when accept is text/plain' do + let(:accept) { 'text/plain' } + + it 'returns a string' do + expect(subject).to eq(content) + end + end + end +end diff --git a/spec/v3/services/allowance/for_owner_spec.rb b/spec/v3/services/allowance/for_owner_spec.rb new file mode 100644 index 0000000000..25e4e3adef --- /dev/null +++ b/spec/v3/services/allowance/for_owner_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +RSpec.describe Travis::API::V3::Services::Allowance::ForOwner, set_app: true, billing_spec_helper: true do + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + let(:json_headers) { { 'HTTP_ACCEPT' => 'application/json' } } + let(:user_token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + + before do + Travis.config.host = 'travis-ci.com' + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user, name: 'Joe', login: 'joe') } + let(:v2_response_body) { JSON.dump(allowance_data) } + + before do + stub_billing_request(:get, "/usage/users/#{user.id}/allowance", auth_key: billing_auth_key, user_id: user.id) + .to_return(status: 200, body: v2_response_body) + end + + context 'when user has no plan' do + let(:allowance_data) { {'no_plan' => true} } + + describe 'returns subscription_type=3' do + before { get("/v3/owner/#{user.login}/allowance", {}, json_headers.merge('HTTP_AUTHORIZATION' => "token #{user_token}")) } + + example { expect(last_response).to be_ok } + example { expect(JSON.parse(last_response.body)['subscription_type']).to eq(3) } + end + end + + context 'when user has a plan' do + let(:allowance_data) { {'no_plan' => false} } + + describe 'returns subscription_type=3' do + before { get("/v3/owner/#{user.login}/allowance", {}, json_headers.merge('HTTP_AUTHORIZATION' => "token #{user_token}")) } + + example { expect(last_response).to be_ok } + example { expect(JSON.parse(last_response.body)['subscription_type']).to eq(2) } + end + end + end +end diff --git a/spec/v3/services/build/cancel_spec.rb b/spec/v3/services/build/cancel_spec.rb index ec0d38afc7..aa9449a5cc 100644 --- a/spec/v3/services/build/cancel_spec.rb +++ b/spec/v3/services/build/cancel_spec.rb @@ -6,6 +6,7 @@ before do allow(Travis::Features).to receive(:owner_active?).and_return(true) allow(Travis::Features).to receive(:owner_active?).with(:enqueue_to_hub, repo.owner).and_return(false) + allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, repo.owner).and_return(true) @original_sidekiq = Sidekiq::Client Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = [] @@ -40,6 +41,16 @@ }} end + describe "existing repository, repo owner ro_mode" do + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true) } + before { allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, repo.owner).and_return(false) } + before { post("/v3/build/#{build.id}/cancel", {}, headers) } + + example { expect(last_response.status).to be == 404 } + end + describe "existing repository, pull access" do let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} diff --git a/spec/v3/services/build/find_spec.rb b/spec/v3/services/build/find_spec.rb index 6000c02d0d..ad77645681 100644 --- a/spec/v3/services/build/find_spec.rb +++ b/spec/v3/services/build/find_spec.rb @@ -382,7 +382,7 @@ describe 'including log_complete on hosted' do before do jobs.each do |j| - stub_request(:get, "http://travis-logs-notset.example.com:1234/logs/#{j.id}?by=job_id&source=api"). + stub_request(:get, "#{Travis.config.logs_api.url}/logs/#{j.id}?by=job_id&source=api"). with( headers: { 'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', @@ -406,7 +406,7 @@ describe 'including log_complete on enterprise' do before do jobs.each do |j| - stub_request(:get, "http://travis-logs-notset.example.com:1234/logs/#{j.id}?by=job_id&source=api"). + stub_request(:get, "#{Travis.config.logs_api.url}/logs/#{j.id}?by=job_id&source=api"). with( headers: { 'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', diff --git a/spec/v3/services/build/restart_spec.rb b/spec/v3/services/build/restart_spec.rb index da50ad9323..de4831e9fc 100644 --- a/spec/v3/services/build/restart_spec.rb +++ b/spec/v3/services/build/restart_spec.rb @@ -5,14 +5,25 @@ let(:payload) { { 'id'=> "#{build.id}", 'user_id' => 1 } } before do + build.update(state: :passed) + Travis.config.billing.url = 'http://localhost:9292/' + Travis.config.billing.auth_key = 'secret' + + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: true, rejection_code: nil) + ) + allow(Travis::Features).to receive(:owner_active?).and_return(true) allow(Travis::Features).to receive(:owner_active?).with(:enqueue_to_hub, repo.owner).and_return(false) + allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, repo.owner).and_return(true) @original_sidekiq = Sidekiq::Client Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = [] end after do + Travis.config.billing.url = nil + Travis.config.billing.auth_key = nil Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = @original_sidekiq end @@ -79,6 +90,18 @@ end end + describe "existing repository, repo owner ro_mode" do + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before do + Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true) + allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, repo.owner).and_return(false) + post("/v3/build/#{build.id}/restart", {}, headers) + end + + example { expect(last_response.status).to be == 404 } + end + describe "existing repository, pull access" do let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} diff --git a/spec/v3/services/build_backup/find_spec.rb b/spec/v3/services/build_backup/find_spec.rb new file mode 100644 index 0000000000..d99fdcb82f --- /dev/null +++ b/spec/v3/services/build_backup/find_spec.rb @@ -0,0 +1,61 @@ +describe Travis::API::V3::Services::BuildBackup::Find, set_app: true do + let(:parsed_body) { JSON.parse(last_response.body) } + + context 'unauthenticated' do + it 'responds 403' do + get('/v3/build_backup/1') + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:repository) { FactoryBot.create(:repository, owner: user) } + let!(:build_backup) { FactoryBot.create(:build_backup, repository: repository) } + let(:organization) { FactoryBot.create(:org, login: 'travis') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } + let(:content) { '123' } + + before do + stub_request(:post, 'https://www.googleapis.com/oauth2/v4/token'). + to_return(status: 200, body: '{}', headers: { 'Content-Type' => 'application/json' }) + stub_request(:get, /o\/#{build_backup.file_name}\?alt=media/). + to_return(status: 200, body: content, headers: { 'Content-Type' => 'application/json' }) + end + + it 'responds with build_backup' do + get("/v3/build_backup/#{build_backup.id}", {}, headers) + + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json({ + '@type' => 'build_backup', + '@representation' => 'standard', + '@href' => "/v3/build_backup/#{build_backup.id}", + 'file_name' => build_backup.file_name, + 'created_at' => build_backup.created_at.iso8601 + }) + end + + context 'when text/plain Accept header is present' do + before { headers['HTTP_ACCEPT'] = 'text/plain' } + + it 'responds with content' do + get("/v3/build_backup/#{build_backup.id}", {}, headers) + + expect(last_response.status).to eq(200) + expect(last_response.body).to eq(content) + end + end + + context 'when txt extension is present' do + it 'responds with content' do + get("/v3/build_backup/#{build_backup.id}.txt", {}, headers) + + expect(last_response.status).to eq(200) + expect(last_response.body).to eq(content) + end + end + end +end diff --git a/spec/v3/services/build_backups/all_spec.rb b/spec/v3/services/build_backups/all_spec.rb new file mode 100644 index 0000000000..1236fb0e9f --- /dev/null +++ b/spec/v3/services/build_backups/all_spec.rb @@ -0,0 +1,57 @@ +describe Travis::API::V3::Services::BuildBackups::All, set_app: true do + let(:parsed_body) { JSON.parse(last_response.body) } + + context 'unauthenticated' do + it 'responds 403' do + get('/v3/build_backups') + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:repository) { FactoryBot.create(:repository, owner: user) } + let!(:build_backup) { FactoryBot.create(:build_backup, repository: repository) } + let(:organization) { FactoryBot.create(:org, login: 'travis') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } + + it 'responds with list of build_backups' do + get('/v3/build_backups', { repository_id: repository.id }, headers) + + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json({ + '@type' => 'build_backups', + '@pagination' => { + 'limit' => 25, + 'offset' => 0, + 'count' => 1, + 'is_first' => true, + 'is_last' => true, + 'next' => nil, + 'prev' => nil, + 'first' => { + '@href' => "/v3/build_backups?repository_id=#{repository.id}", + 'offset' => 0, + 'limit' => 25 + }, + 'last' => { + '@href' => "/v3/build_backups?repository_id=#{repository.id}", + 'offset' => 0, + 'limit' => 25 + } + }, + '@representation' => 'standard', + '@href' => "/v3/build_backups?repository_id=#{repository.id}", + 'build_backups' => [{ + '@type' => 'build_backup', + '@representation' => 'standard', + '@href' => "/v3/build_backup/#{build_backup.id}", + 'file_name' => build_backup.file_name, + 'created_at' => build_backup.created_at.iso8601 + }] + }) + end + end +end diff --git a/spec/v3/services/build_permissions/find_for_organization_spec.rb b/spec/v3/services/build_permissions/find_for_organization_spec.rb new file mode 100644 index 0000000000..03e62c6487 --- /dev/null +++ b/spec/v3/services/build_permissions/find_for_organization_spec.rb @@ -0,0 +1,41 @@ +describe Travis::API::V3::Services::BuildPermissions::FindForOrganization, set_app: true do + let(:organization) { FactoryBot.create(:org_v3) } + let(:user) { FactoryBot.create(:user, login: 'pavel-d', vcs_type: 'GithubUser') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } + + before { organization.memberships.create(user: user, role: 'admin', build_permission: true) } + + context 'not authenticated' do + it 'returns access error' do + get("/v3/org/#{organization.id}/build_permissions") + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + it 'returns build permissions' do + get("/v3/org/#{organization.id}/build_permissions", {}, headers) + + expect(last_response.status).to eq(200) + expect(JSON.parse(last_response.body)['build_permissions'].first).to eq( + { + '@type' => 'build_permission', + '@representation' => 'standard', + 'user' => { + '@type' => 'user', + '@href' => "/user/#{user.id}", + '@representation' => 'minimal', + 'id' => user.id, + 'login' => user.login, + 'name' => user.name, + 'vcs_type' => 'GithubUser', + 'ro_mode' => false + }, + 'permission' => true, + 'role' => 'admin' + } + ) + end + end +end diff --git a/spec/v3/services/build_permissions/find_for_repo_spec.rb b/spec/v3/services/build_permissions/find_for_repo_spec.rb new file mode 100644 index 0000000000..39d2b855f4 --- /dev/null +++ b/spec/v3/services/build_permissions/find_for_repo_spec.rb @@ -0,0 +1,41 @@ +describe Travis::API::V3::Services::BuildPermissions::FindForRepo, set_app: true do + let(:repository) { FactoryBot.create(:repository) } + let(:user) { FactoryBot.create(:user, login: 'pavel-d', vcs_type: 'GithubUser') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } + + before { FactoryBot.create(:permission, user: user, repository: repository, build: true) } + + context 'not authenticated' do + it 'returns access error' do + get("/v3/repo/#{repository.id}/build_permissions") + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + it 'returns build permissions' do + get("/v3/repo/#{repository.id}/build_permissions", {}, headers) + + expect(last_response.status).to eq(200) + expect(JSON.parse(last_response.body)['build_permissions'].first).to eq( + { + "@type" => "build_permission", + "@representation" => "standard", + "user" => { + "@type" => "user", + "@href" => "/user/#{user.id}", + "@representation" => "minimal", + "id" => user.id, + "login" => user.login, + "name" => user.name, + "vcs_type" => 'GithubUser', + "ro_mode" => false + }, + "permission" => true, + "role" => nil + } + ) + end + end +end diff --git a/spec/v3/services/build_permissions/update_for_organization_spec.rb b/spec/v3/services/build_permissions/update_for_organization_spec.rb new file mode 100644 index 0000000000..e55de28fd5 --- /dev/null +++ b/spec/v3/services/build_permissions/update_for_organization_spec.rb @@ -0,0 +1,36 @@ +describe Travis::API::V3::Services::BuildPermissions::UpdateForOrganization, set_app: true do + let(:organization) { FactoryBot.create(:org_v3) } + let(:user) { FactoryBot.create(:user, login: 'pavel-d') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } + + context 'not authenticated' do + it 'returns access error' do + patch("/v3/org/#{organization.id}/build_permissions", { user_ids: [user.id], permission: false }) + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + context 'user is an admin' do + before { organization.memberships.create(user: user, role: 'admin', build_permission: true) } + + it 'updates build permissions' do + patch("/v3/org/#{organization.id}/build_permissions", { user_ids: [user.id], permission: false }, headers) + + expect(last_response.status).to eq(204) + expect(organization.memberships.first.build_permission).to eq(false) + end + end + + context 'user is a member' do + before { organization.memberships.create(user: user, role: 'member', build_permission: true) } + + it 'returns access error' do + patch("/v3/org/#{organization.id}/build_permissions", { user_ids: [user.id], permission: false }, headers) + + expect(last_response.status).to eq(403) + end + end + end +end diff --git a/spec/v3/services/build_permissions/update_for_repo_spec.rb b/spec/v3/services/build_permissions/update_for_repo_spec.rb new file mode 100644 index 0000000000..d4b796bb2c --- /dev/null +++ b/spec/v3/services/build_permissions/update_for_repo_spec.rb @@ -0,0 +1,41 @@ +describe Travis::API::V3::Services::BuildPermissions::UpdateForRepo, set_app: true do + let(:organization) { FactoryBot.create(:org) } + let(:repository) { FactoryBot.create(:repository, owner: organization) } + let(:user) { FactoryBot.create(:user, login: 'pavel-d') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } + + context 'not authenticated' do + it 'returns access error' do + patch("/v3/repo/#{repository.id}/build_permissions", { user_ids: [user.id], permission: false }) + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + context 'user is admin' do + before do + organization.memberships.create(user: user, role: 'admin') + FactoryBot.create(:permission, user: user, repository: repository, admin: true, build: true) + end + + it 'updates build permissions' do + patch("/v3/repo/#{repository.id}/build_permissions", { user_ids: [user.id], permission: false }, headers) + expect(last_response.status).to eq(204) + expect(repository.permissions.first.build).to eq(false) + end + end + + context 'user is a member' do + before do + organization.memberships.create(user: user, role: 'member') + FactoryBot.create(:permission, user: user, repository: repository, build: true) + end + + it 'returns access error' do + patch("/v3/repo/#{repository.id}/build_permissions", { user_ids: [user.id], permission: false }, headers) + expect(last_response.status).to eq(403) + end + end + end +end diff --git a/spec/v3/services/caches/delete_spec.rb b/spec/v3/services/caches/delete_spec.rb index 96970b7eac..53d9db8431 100644 --- a/spec/v3/services/caches/delete_spec.rb +++ b/spec/v3/services/caches/delete_spec.rb @@ -144,7 +144,7 @@ Travis.config.cache_options.s3 = { access_key_id: 'key', secret_access_key: 'secret', bucket_name: s3_bucket_name } Travis.config.cache_options.gcs = { bucket_name: 'travis-cache-production-org-gce', json_key: - JSON.generate({ + { "type" => "service_account", "project_id" => "123", "private_key_id" => "123456", @@ -155,7 +155,7 @@ "token_uri" => "https://accounts.google.com/oauth2/v3/token", "auth_provider_x509_cert_url" => "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url" => "travis-cache-org-api-production" - }), + }, project_id: 'foo-bar-99515' } example.run Travis.config.cache_options = {} diff --git a/spec/v3/services/caches/find_spec.rb b/spec/v3/services/caches/find_spec.rb index 5071dcf2d0..068c57b346 100644 --- a/spec/v3/services/caches/find_spec.rb +++ b/spec/v3/services/caches/find_spec.rb @@ -211,6 +211,21 @@ "client_x509_cert_url" => "travis-cache-org-api-production" }), project_id: 'foo-bar-99515' } + Travis.config.cache_options.gcs = { bucket_name: 'travis-cache-production-org-gce', + json_key: + { + "type" => "service_account", + "project_id" => "123", + "private_key_id" => "123456", + "private_key" => TEST_PRIVATE_KEY, + "client_email" => "travis-cache-org-api-production", + "client_id" => "1234", + "auth_uri" => "https://accounts.google.com/o/oauth2/auth", + "token_uri" => "https://accounts.google.com/oauth2/v4/token", + "auth_provider_x509_cert_url" => "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url" => "travis-cache-org-api-production" + }, + project_id: 'foo-bar-99515' } example.run Travis.config.cache_options = {} end diff --git a/spec/v3/services/credits_calculator/calculator_spec.rb b/spec/v3/services/credits_calculator/calculator_spec.rb new file mode 100644 index 0000000000..983d0794f5 --- /dev/null +++ b/spec/v3/services/credits_calculator/calculator_spec.rb @@ -0,0 +1,66 @@ +describe Travis::API::V3::Services::CreditsCalculator::Calculator, set_app: true, billing_spec_helper: true do + let(:parsed_body) { JSON.load(last_response.body) } + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + post('/v3/credits_calculator', { users: 6, executions: [] }, {}) + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + + let(:v2_response_body) { JSON.dump(billing_v2_credits_calculator_body) } + + let(:expected_json) do + { + '@type' => 'credits_results', + '@representation' => 'standard', + 'credits_results' => [ + { + '@type' => 'credits_result', + '@representation' => 'standard', + 'users' => 3, + 'minutes' => nil, + 'os' => nil, + 'instance_size' => nil, + 'credits' => 25_000, + 'price' => 1_500 + }, + { + '@type' => 'credits_result', + '@representation' => 'standard', + 'users' => nil, + 'minutes' => 1000, + 'os' => 'linux', + 'instance_size' => '2x-large', + 'credits' => 250_000, + 'price' => 15_000 + } + ] + } + end + + before do + stub_billing_request(:post, '/usage/credits_calculator', auth_key: billing_auth_key, user_id: user.id) + .to_return(status: 200, body: v2_response_body) + end + + it 'responds with list of credits results' do + post('/v3/credits_calculator', { users: 6, executions: [] }, headers) + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json(expected_json) + end + end +end diff --git a/spec/v3/services/credits_calculator/default_config_spec.rb b/spec/v3/services/credits_calculator/default_config_spec.rb new file mode 100644 index 0000000000..dc15efd176 --- /dev/null +++ b/spec/v3/services/credits_calculator/default_config_spec.rb @@ -0,0 +1,48 @@ +describe Travis::API::V3::Services::CreditsCalculator::DefaultConfig, set_app: true, billing_spec_helper: true do + let(:parsed_body) { JSON.load(last_response.body) } + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + get('/v3/credits_calculator', { users: 6, executions: [] }, {}) + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + + let(:v2_response_body) { JSON.dump(billing_v2_credits_calculator_config_body) } + + let(:expected_json) do + { + '@type' => 'credits_calculator_config', + '@representation' => 'standard', + 'users' => 10, + 'minutes' => 1000, + 'os' => 'linux', + 'instance_size' => '2x-large' + } + end + + before do + stub_billing_request(:get, '/usage/credits_calculator/default_config', auth_key: billing_auth_key, user_id: user.id) + .to_return(status: 200, body: v2_response_body) + end + + it 'responds with list of credits results' do + get('/v3/credits_calculator', {}, headers) + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json(expected_json) + end + end +end diff --git a/spec/v3/services/installation/find_spec.rb b/spec/v3/services/installation/find_spec.rb index 033be7d15f..9462d0ba16 100644 --- a/spec/v3/services/installation/find_spec.rb +++ b/spec/v3/services/installation/find_spec.rb @@ -22,7 +22,9 @@ "@representation"=>"minimal", "id"=>user.id, "login"=>user.login, - "vcs_type" => user.vcs_type + "vcs_type" => user.vcs_type, + "ro_mode" => true, + "name" => user.name } }} end @@ -55,9 +57,16 @@ "is_syncing" => nil, "synced_at" => nil, "education" => nil, + "allowance" => { + "@representation" => "minimal", + "@type" => "allowance", + "id" => 1 + }, "allow_migration" => false, "recently_signed_up" => false, "secure_user_hash" => nil, + "ro_mode" => true, + "confirmed_at" => nil, } }} end diff --git a/spec/v3/services/job/cancel_spec.rb b/spec/v3/services/job/cancel_spec.rb index f69cd0d29b..8f30c17037 100644 --- a/spec/v3/services/job/cancel_spec.rb +++ b/spec/v3/services/job/cancel_spec.rb @@ -7,6 +7,7 @@ before do allow(Travis::Features).to receive(:owner_active?).and_return(true) allow(Travis::Features).to receive(:owner_active?).with(:enqueue_to_hub, repo.owner).and_return(false) + allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, repo.owner).and_return(true) @original_sidekiq = Sidekiq::Client Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = [] @@ -60,6 +61,15 @@ } end + describe "existing repository, repo owner ro_mode" do + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before { allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, repo.owner).and_return(false) } + before { post("/v3/job/#{job.id}/cancel", {}, headers) } + + example { expect(last_response.status).to be == 404 } + end + describe "existing repository, pull access" do let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} diff --git a/spec/v3/services/job/debug_spec.rb b/spec/v3/services/job/debug_spec.rb index be72468fdc..b4f1ff987f 100644 --- a/spec/v3/services/job/debug_spec.rb +++ b/spec/v3/services/job/debug_spec.rb @@ -9,14 +9,22 @@ before { ActiveRecord::Base.connection.execute("truncate requests cascade") } before do + Travis.config.billing.url = 'http://localhost:9292/' + Travis.config.billing.auth_key = 'secret' allow(Travis::Features).to receive(:owner_active?).and_return(true) @original_sidekiq = Sidekiq::Client Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = [] Travis::Features.activate_repository(:debug_tools, job.repository) + + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: true, rejection_code: nil) + ) end after do + Travis.config.billing.url = nil + Travis.config.billing.auth_key = nil Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = @original_sidekiq end diff --git a/spec/v3/services/job/find_spec.rb b/spec/v3/services/job/find_spec.rb index bb793207a0..78195338d1 100644 --- a/spec/v3/services/job/find_spec.rb +++ b/spec/v3/services/job/find_spec.rb @@ -110,7 +110,9 @@ "@representation" => "minimal", "id" => owner.id, "login" => owner.login, - "vcs_type" => owner.vcs_type + "name" => owner.name, + "vcs_type" => owner.vcs_type, + "ro_mode" => false } })} end @@ -139,7 +141,7 @@ end describe "fetching job on private repository, private API, with a log.token" do - let(:log_token) { Travis::API::V3::LogToken.create(job).to_s } + let(:log_token) { Travis::API::V3::LogToken.create(job, owner.id).to_s } before { repo.update_attribute(:private, true) } before { get("/v3/job/#{job.id}?log.token=#{log_token}", {}, {}) } after { repo.update_attribute(:private, false) } @@ -227,7 +229,9 @@ "@representation" => "minimal", "id" => owner.id, "login" => owner.login, - "vcs_type" => owner.vcs_type + "name" => owner.name, + "vcs_type" => owner.vcs_type, + "ro_mode" => true } })} end @@ -306,7 +310,9 @@ "@representation" => "minimal", "id" => owner.id, "login" => owner.login, - "vcs_type" => owner.vcs_type + "name" => owner.name, + "vcs_type" => owner.vcs_type, + "ro_mode" => false }, "config" => { "language" => "shell", @@ -323,7 +329,7 @@ describe 'including log_complete on hosted' do before do - stub_request(:get, "http://travis-logs-notset.example.com:1234/logs/#{job.id}?by=job_id&source=api"). + stub_request(:get, "#{Travis.config.logs_api.url}/logs/#{job.id}?by=job_id&source=api"). with( headers: { 'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', @@ -345,7 +351,7 @@ describe 'including log_complete on enterprise' do before do - stub_request(:get, "http://travis-logs-notset.example.com:1234/logs/#{job2.id}?by=job_id&source=api"). + stub_request(:get, "#{Travis.config.logs_api.url}/logs/#{job2.id}?by=job_id&source=api"). with( headers: { 'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', diff --git a/spec/v3/services/job/restart_spec.rb b/spec/v3/services/job/restart_spec.rb index e1c0b9188a..38a808b7c3 100644 --- a/spec/v3/services/job/restart_spec.rb +++ b/spec/v3/services/job/restart_spec.rb @@ -6,14 +6,25 @@ let(:payload) { { 'id'=> "#{job.id}", 'user_id' => 1 } } before do + job.update(state: :passed) + Travis.config.billing.url = 'http://localhost:9292/' + Travis.config.billing.auth_key = 'secret' + + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: true, rejection_code: nil) + ) + allow(Travis::Features).to receive(:owner_active?).and_return(true) allow(Travis::Features).to receive(:owner_active?).with(:enqueue_to_hub, repo.owner).and_return(false) + allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, repo.owner).and_return(true) @original_sidekiq = Sidekiq::Client Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = [] end after do + Travis.config.billing.url = nil + Travis.config.billing.auth_key = nil Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = @original_sidekiq end @@ -61,6 +72,15 @@ } end + describe "existing repository, repo owner ro_mode" do + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before { allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, repo.owner).and_return(false) } + before { post("/v3/job/#{job.id}/cancel", {}, headers) } + + example { expect(last_response.status).to be == 404 } + end + describe "existing repo, repo owner is flagged abusive" do let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} @@ -209,6 +229,58 @@ example { expect(Sidekiq::Client.last['class']).to be == 'Travis::Hub::Sidekiq::Worker' } end + context 'billing authorization' do + before do + @old_host = Travis.config.host + Travis.config.host = 'travis-ci.com' + end + + after do + Travis.config.host = @old_host + end + + context 'billing service authorizes the job' do + before do + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: true, rejection_code: :nil), status: 200 + ) + end + + it 'restarts the job' do + post("/v3/job/#{job.id}/restart", params, headers) + expect(last_response.status).to eq(202) + end + end + + context 'billing service returns 404 (user is not on a new plan)' do + before do + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(error: 'Plan not found'), status: 404 + ) + Travis.config.host = 'travis-ci.com' + end + + it 'restarts the job' do + post("/v3/job/#{job.id}/restart", params, headers) + expect(last_response.status).to eq(403) + end + end + + context 'billing service rejects the job' do + before do + stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return( + body: MultiJson.dump(allowed: false, rejection_code: :no_build_credits), status: 403 + ) + Travis.config.host = 'travis-ci.com' + end + + it 'does not restart the job' do + post("/v3/job/#{job.id}/restart", params, headers) + expect(last_response.status).to eq(403) + end + end + end + describe "passed state" do include_examples 'clears debug_options' diff --git a/spec/v3/services/jobs/find_spec.rb b/spec/v3/services/jobs/find_spec.rb index 6cc364b6d1..a0b816081a 100644 --- a/spec/v3/services/jobs/find_spec.rb +++ b/spec/v3/services/jobs/find_spec.rb @@ -100,7 +100,9 @@ "@representation" => "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}}, + "ro_mode" => false, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}}, {"@type" => "job", "@href" => "/v3/job/#{jobs[1].id}", "@representation" => "standard", @@ -177,7 +179,9 @@ "@representation" => "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}}, + "ro_mode" => false, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}}, {"@type" => "job", "@href" => "/v3/job/#{jobs[2].id}", "@representation" => "standard", @@ -254,7 +258,9 @@ "@representation" => "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}}, + "ro_mode" => false, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}}, {"@type" => "job", "@href" => "/v3/job/#{jobs[3].id}", "@representation" => "standard", @@ -331,7 +337,9 @@ "@representation" => "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}} + "ro_mode" => false, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}} ] }) } @@ -426,7 +434,9 @@ "@representation" => "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}}, + "ro_mode" => true, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}}, {"@type" => "job", "@href" => "/v3/job/#{jobs[1].id}", "@representation" => "standard", @@ -503,7 +513,9 @@ "@representation" => "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}}, + "ro_mode" => true, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}}, {"@type" => "job", "@href" => "/v3/job/#{jobs[2].id}", "@representation" => "standard", @@ -580,7 +592,9 @@ "@representation" => "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}}, + "ro_mode" => true, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}}, {"@type" => "job", "@href" => "/v3/job/#{jobs[3].id}", "@representation" => "standard", @@ -655,9 +669,11 @@ "@type" => "user", "@href" => "/v3/user/1", "@representation" => "minimal", + "ro_mode" => true, "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}} + "login" => "svenfuchs", + "name" => "Sven Fuchs"}} ] }) } @@ -755,7 +771,9 @@ "@representation"=> "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}}, + "ro_mode" => true, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}}, {"@type" => "job", "@href" => "/v3/job/#{jobs[1].id}", "@representation" => "standard", @@ -832,7 +850,9 @@ "@representation"=> "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}}, + "ro_mode" => true, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}}, {"@type" => "job", "@href" => "/v3/job/#{jobs[2].id}", "@representation" => "standard", @@ -909,7 +929,9 @@ "@representation"=> "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}}, + "ro_mode" => true, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}}, {"@type" => "job", "@href" => "/v3/job/#{jobs[3].id}", "@representation" => "standard", @@ -986,7 +1008,9 @@ "@representation"=> "minimal", "id" => 1, "vcs_type" => 'GithubUser', - "login" => "svenfuchs"}} + "ro_mode" => true, + "login" => "svenfuchs", + "name" => "Sven Fuchs"}} ] }) } diff --git a/spec/v3/services/log/find_spec.rb b/spec/v3/services/log/find_spec.rb index 1558bb4bf6..72657c33d4 100644 --- a/spec/v3/services/log/find_spec.rb +++ b/spec/v3/services/log/find_spec.rb @@ -4,11 +4,12 @@ let(:user) { FactoryBot.create(:user) } let(:repo) { FactoryBot.create(:repository, owner_name: user.login, name: 'minimal', owner: user)} let(:build) { FactoryBot.create(:build, repository: repo) } - let(:job) { Travis::API::V3::Models::Job.create(build: build) } - let(:job2) { Travis::API::V3::Models::Job.create(build: build)} - let(:job3) { Travis::API::V3::Models::Job.create(build: build)} - let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo) } - let(:s3job2) { Travis::API::V3::Models::Job.create(build: build) } + let(:perm) { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, pull: true, push: true)} + let(:job) { Travis::API::V3::Models::Job.create(build: build, started_at: Time.now - 10.days, repository: repo) } + let(:job2) { Travis::API::V3::Models::Job.create(build: build, started_at: Time.now - 10.days, repository: repo)} + let(:job3) { Travis::API::V3::Models::Job.create(build: build, started_at: Time.now - 10.days, repository: repo)} + let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo, started_at: Time.now - 10.days) } + let(:s3job2) { Travis::API::V3::Models::Job.create(build: build, started_at: Time.now - 10.days, repository: repo) } let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } let(:parsed_body) { JSON.load(body) } @@ -213,5 +214,364 @@ expect(last_response.headers).to include('Content-Type' => 'application/json') end end + + context 'with authentication and new settings' do + context 'when public repo' do + before { repo.update(private: false) } + + context 'when access to old logs is not allowed and write/push setting is off' do + before do + user_settings = Travis::API::V3::Models::Repository.find(repo.id).user_settings + user_settings.user = user + user_settings.change_source = 'travis-api' + user_settings.update(:job_log_time_based_limit, false) + user_settings.update(:job_log_access_based_limit, false) + end + + context 'unauthenticated user' do + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + + context 'old log' do + let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo, started_at: Time.now - 1000.days) } + + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'log_expired', + 'error_message'=>"We're sorry, but this data is not available anymore. Please check the repository settings in Travis CI." + }) + end + end + end + end + + context 'when access to old logs is not allowed and write/push setting is on' do + before do + user_settings = Travis::API::V3::Models::Repository.find(repo.id).user_settings + user_settings.user = user + user_settings.change_source = 'travis-api' + user_settings.update(:job_log_time_based_limit, false) + user_settings.update(:job_log_access_based_limit, true) + end + + context 'unauthenticated user' do + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'log_access_denied', + 'error_message'=>"We're sorry, but this data is not available. Please check the repository settings in Travis CI." + }) + end + end + + context 'authenticated user read' do + before { perm.update!(push: false) } + + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'log_access_denied', + 'error_message'=>"We're sorry, but this data is not available. Please check the repository settings in Travis CI." + }) + end + end + + context 'authenticated user write' do + before { perm.update!(push: true) } + + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + + context 'old log' do + let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo, started_at: Time.now - 1000.days) } + + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'not_found', + 'error_type'=>'log_expired', + 'error_message'=>"We're sorry, but this data is not available anymore. Please check the repository settings in Travis CI." + }) + end + end + end + end + + context 'when access to old logs is allowed and write/push setting is on' do + before do + user_settings = Travis::API::V3::Models::Repository.find(repo.id).user_settings + user_settings.user = user + user_settings.change_source = 'travis-api' + user_settings.update(:job_log_time_based_limit, true) + user_settings.update(:job_log_access_based_limit, true) + end + + context 'unauthenticated user' do + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'log_access_denied', + 'error_message'=>"We're sorry, but this data is not available. Please check the repository settings in Travis CI." + }) + end + end + + context 'authenticated user read' do + before { perm.update!(push: false) } + + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'log_access_denied', + 'error_message'=>"We're sorry, but this data is not available. Please check the repository settings in Travis CI." + }) + end + end + + context 'authenticated user write' do + before { perm.update!(push: true) } + + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + + context 'old log' do + let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo, started_at: Time.now - 1000.days) } + + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + end + end + end + + context 'when access to old logs is allowed and write/push setting is off' do + before do + user_settings = Travis::API::V3::Models::Repository.find(repo.id).user_settings + user_settings.user = user + user_settings.change_source = 'travis-api' + user_settings.update(:job_log_time_based_limit, true) + user_settings.update(:job_log_access_based_limit, false) + end + + context 'unauthenticated user' do + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + + context 'old log' do + let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo, started_at: Time.now - 1000.days) } + + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + end + end + end + end + + context 'when private repo' do + before { repo.update(private: true) } + + context 'when access to old logs is not allowed and write/push setting is off' do + before do + user_settings = Travis::API::V3::Models::Repository.find(repo.id).user_settings + user_settings.user = user + user_settings.change_source = 'travis-api' + user_settings.update(:job_log_time_based_limit, false) + user_settings.update(:job_log_access_based_limit, false) + end + + context 'unauthenticated user' do + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'not_found', + 'error_message'=>'log not found (or insufficient access)', + 'resource_type'=>'log' + }) + end + + context 'old log' do + let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo, started_at: Time.now - 1000.days) } + + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'not_found', + 'error_message'=>'log not found (or insufficient access)', + 'resource_type'=>'log' + }) + end + end + end + end + + context 'when access to old logs is not allowed and write/push setting is on' do + before do + user_settings = Travis::API::V3::Models::Repository.find(repo.id).user_settings + user_settings.user = user + user_settings.change_source = 'travis-api' + user_settings.update(:job_log_time_based_limit, false) + user_settings.update(:job_log_access_based_limit, true) + end + + context 'unauthenticated user' do + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'not_found', + 'error_message'=>'log not found (or insufficient access)', + 'resource_type'=>'log' + }) + end + end + + context 'authenticated user read' do + before { perm.update!(push: false) } + + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'log_access_denied', + 'error_message'=>"We're sorry, but this data is not available. Please check the repository settings in Travis CI." + }) + end + end + + context 'authenticated user write' do + before { perm.update!(push: true) } + + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + + context 'old log' do + let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo, started_at: Time.now - 1000.days) } + + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'not_found', + 'error_type'=>'log_expired', + 'error_message'=>"We're sorry, but this data is not available anymore. Please check the repository settings in Travis CI." + }) + end + end + end + end + + context 'when access to old logs is allowed and write/push setting is on' do + before do + user_settings = Travis::API::V3::Models::Repository.find(repo.id).user_settings + user_settings.user = user + user_settings.change_source = 'travis-api' + user_settings.update(:job_log_time_based_limit, true) + user_settings.update(:job_log_access_based_limit, true) + end + + context 'unauthenticated user' do + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, { 'HTTP_ACCEPT' => 'text/plain' }) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'not_found', + 'error_message'=>'log not found (or insufficient access)', + 'resource_type'=>'log' + }) + end + end + + context 'authenticated user read' do + before { perm.update!(push: false) } + + it 'does not return log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(parsed_body).to eq({ + '@type'=>'error', + 'error_type'=>'log_access_denied', + 'error_message'=>"We're sorry, but this data is not available. Please check the repository settings in Travis CI." + }) + end + end + + context 'authenticated user write' do + before { perm.update!(push: true) } + + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + + context 'old log' do + let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo, started_at: Time.now - 1000.days) } + + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + end + end + end + + context 'when access to old logs is allowed and write/push setting is off' do + before do + user_settings = Travis::API::V3::Models::Repository.find(repo.id).user_settings + user_settings.user = user + user_settings.change_source = 'travis-api' + user_settings.update(:job_log_time_based_limit, true) + user_settings.update(:job_log_access_based_limit, false) + end + + context 'authenticated user' do + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + + context 'old log' do + let(:s3job) { Travis::API::V3::Models::Job.create(build: build, repository: repo, started_at: Time.now - 1000.days) } + + it 'returns the log' do + get("/v3/job/#{s3job.id}/log", {}, headers.merge('HTTP_ACCEPT' => 'text/plain')) + expect(last_response.headers).to include('Content-Type' => 'text/plain') + expect(body).to eq(archived_content) + end + end + end + end + end + end end end diff --git a/spec/v3/services/organization/find_spec.rb b/spec/v3/services/organization/find_spec.rb index 99854d4238..f93bb1a5b3 100644 --- a/spec/v3/services/organization/find_spec.rb +++ b/spec/v3/services/organization/find_spec.rb @@ -23,6 +23,12 @@ "avatar_url" => nil, "education" => false, "allow_migration" => false, + "ro_mode" => true, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => org.id + } }} end @@ -52,6 +58,12 @@ "avatar_url" => nil, "education" => true, "allow_migration" => true, + "ro_mode" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => org.id + } }} end diff --git a/spec/v3/services/organizations/for_current_user_spec.rb b/spec/v3/services/organizations/for_current_user_spec.rb index 64aebff6ee..b60480f37d 100644 --- a/spec/v3/services/organizations/for_current_user_spec.rb +++ b/spec/v3/services/organizations/for_current_user_spec.rb @@ -59,6 +59,12 @@ "avatar_url" => nil, "education" => false, "allow_migration" => false, + "ro_mode" => true, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => org.id + } }] }} end diff --git a/spec/v3/services/owner/find_spec.rb b/spec/v3/services/owner/find_spec.rb index 7f8f4c1b22..ffc531639d 100644 --- a/spec/v3/services/owner/find_spec.rb +++ b/spec/v3/services/owner/find_spec.rb @@ -20,9 +20,15 @@ "github_id" => 1234, "vcs_id" => org.vcs_id, "vcs_type" => org.vcs_type, + "ro_mode" => true, "avatar_url" => nil, "education" => false, "allow_migration" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => org.id + } }} end @@ -40,9 +46,15 @@ "github_id" => 1234, "vcs_id" => org.vcs_id, "vcs_type" => org.vcs_type, + "ro_mode" => true, "avatar_url" => nil, "education" => false, "allow_migration" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => org.id + } }} end @@ -65,9 +77,15 @@ "github_id" => 1234, "vcs_id" => org.vcs_id, "vcs_type" => org.vcs_type, + "ro_mode" => true, "avatar_url" => nil, "education" => false, "allow_migration" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => org.id + }, "repositories" => [{ "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", @@ -98,6 +116,7 @@ "github_language" => nil, "active" => false, "private" => false, + "server_type" => 'git', "shared" => false, "owner" => { "@href"=> "/v3/org/#{org.id}" }, "default_branch" => { @@ -134,9 +153,15 @@ "github_id" => 1234, "vcs_id" => org.vcs_id, "vcs_type" => org.vcs_type, + "ro_mode" => true, "avatar_url" => nil, "education" => false, "allow_migration" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => org.id + }, "repositories" => [{ "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", @@ -167,6 +192,7 @@ "github_language" => nil, "active" => false, "private" => false, + "server_type" => 'git', "shared" => false, "owner" => { "@href"=> "/v3/org/#{org.id}" }, "default_branch" => { @@ -198,9 +224,15 @@ "github_id" => 1234, "vcs_id" => org.vcs_id, "vcs_type" => org.vcs_type, + "ro_mode" => true, "avatar_url" => nil, "education" => false, "allow_migration" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => org.id + } }} end @@ -222,9 +254,15 @@ "github_id" => 1234, "vcs_id" => org.vcs_id, "vcs_type" => org.vcs_type, + "ro_mode" => true, "avatar_url" => nil, "education" => false, "allow_migration"=> false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => org.id + }, "@warnings" => [{ "@type" => "warning", "message" => "query parameter organization.id not safelisted, ignored", @@ -259,8 +297,15 @@ "synced_at" => nil, "education" => nil, "allow_migration"=> false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => user.id + }, "recently_signed_up"=>false, "secure_user_hash" => nil, + "ro_mode" => false, + "confirmed_at" => nil, }} end @@ -284,8 +329,15 @@ "is_syncing" => nil, "synced_at" => nil, "allow_migration"=> false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => user.id + }, "recently_signed_up"=>false, "secure_user_hash" => nil, + "ro_mode" => false, + "confirmed_at" => nil, }} end @@ -309,8 +361,15 @@ "is_syncing" => nil, "synced_at" => nil, "allow_migration" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => user.id + }, "recently_signed_up"=>false, "secure_user_hash" => nil, + "ro_mode" => false, + "confirmed_at" => nil, }} end @@ -338,8 +397,15 @@ "is_syncing" => nil, "synced_at" => nil, "allow_migration" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => user.id + }, "recently_signed_up"=>false, "secure_user_hash" => nil, + "ro_mode" => false, + "confirmed_at" => nil, "@warnings" => [{ "@type" => "warning", "message" => "query parameter user.id not safelisted, ignored", diff --git a/spec/v3/services/preferences/for_organization_spec.rb b/spec/v3/services/preferences/for_organization_spec.rb index 4c2f92c30f..ca81f49cb1 100644 --- a/spec/v3/services/preferences/for_organization_spec.rb +++ b/spec/v3/services/preferences/for_organization_spec.rb @@ -46,6 +46,12 @@ "@representation" => "standard", "preferences" => [ { + "@type" => "preference", + "@href" => "/v3/org/#{organization.id}/preference/consume_oss_credits", + "@representation" => "standard", + "name" => "consume_oss_credits", + "value" => true + }, { "@type" => "preference", "@href" => "/v3/org/#{organization.id}/preference/private_insights_visibility", "@representation" => "standard", @@ -60,6 +66,7 @@ describe 'some preference has been set' do before do organization.preferences.update(:private_insights_visibility, 'members') + organization.preferences.update(:consume_oss_credits, false) end it 'returns the set value merged with the defaults' do @@ -69,6 +76,12 @@ "@representation" => "standard", "preferences" => [ { + "@type" => "preference", + "@href" => "/v3/org/#{organization.id}/preference/consume_oss_credits", + "@representation" => "standard", + "name" => "consume_oss_credits", + "value" => false + }, { "@type" => "preference", "@href" => "/v3/org/#{organization.id}/preference/private_insights_visibility", "@representation" => "standard", diff --git a/spec/v3/services/preferences/for_user_spec.rb b/spec/v3/services/preferences/for_user_spec.rb index 10807ef7c2..c0b57f55e4 100644 --- a/spec/v3/services/preferences/for_user_spec.rb +++ b/spec/v3/services/preferences/for_user_spec.rb @@ -26,6 +26,12 @@ "@representation" => "standard", "name" => "build_emails", "value" => true + }, { + "@type" => "preference", + "@href" => "/v3/preference/consume_oss_credits", + "@representation" => "standard", + "name" => "consume_oss_credits", + "value" => true }, { "@type" => "preference", "@href" => "/v3/preference/private_insights_visibility", @@ -41,6 +47,7 @@ describe 'authenticated, user has prefs' do before do user.preferences.update(:build_emails, false) + user.preferences.update(:consume_oss_credits, false) user.preferences.update(:private_insights_visibility, 'public') get("/v3/preferences", {}, auth_headers) end @@ -59,6 +66,12 @@ "@representation" => "standard", "name" => "build_emails", "value" => false + }, { + "@type" => "preference", + "@href" => "/v3/preference/consume_oss_credits", + "@representation" => "standard", + "name" => "consume_oss_credits", + "value" => false }, { "@type" => "preference", "@href" => "/v3/preference/private_insights_visibility", diff --git a/spec/v3/services/repositories/for_current_user_spec.rb b/spec/v3/services/repositories/for_current_user_spec.rb index a9d3817920..fbf9b9c504 100644 --- a/spec/v3/services/repositories/for_current_user_spec.rb +++ b/spec/v3/services/repositories/for_current_user_spec.rb @@ -63,11 +63,13 @@ "github_language" => nil, "active" => true, "private" => true, + "server_type" => 'git', "shared" => false, "owner" => { "@type" => "user", "@href" => "/v3/user/#{repo.owner_id}", "id" => repo.owner_id, + "ro_mode" => true, "login" => "svenfuchs" }, "default_branch" => { "@type" => "branch", diff --git a/spec/v3/services/repositories/for_owner_spec.rb b/spec/v3/services/repositories/for_owner_spec.rb index 14e223b362..600e63a7e5 100644 --- a/spec/v3/services/repositories/for_owner_spec.rb +++ b/spec/v3/services/repositories/for_owner_spec.rb @@ -1,9 +1,11 @@ -describe Travis::API::V3::Services::Repositories::ForOwner, set_app: true do +describe Travis::API::V3::Services::Repositories::ForOwner, set_app: true, billing_spec_helper: true do include Support::Formats let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } let(:sharedrepo) { Travis::API::V3::Models::Repository.where(owner_name: 'sharedrepoowner', name: 'sharedrepo').first } let(:build) { repo.builds.first } let(:jobs) { Travis::API::V3::Models::Build.find(build.id).jobs } + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} @@ -88,11 +90,13 @@ "github_language" => nil, "active" => true, "private" => true, + "server_type" => 'git', "shared" => false, "owner" => { "@type" => "user", "id" => repo.owner_id, "login" => "svenfuchs", + "ro_mode" => true, "@href" => "/v3/user/#{repo.owner_id}" }, "default_branch" => { "@type" => "branch", @@ -141,11 +145,13 @@ "github_language" =>nil, "active" =>true, "private" =>true, + "server_type" => 'git', "shared" =>false, "owner" =>{ "@type" =>"user", "id" =>1, "login" =>"svenfuchs", + "ro_mode" => true, "@href" =>"/v3/user/1"}, "default_branch" =>{ "@type" =>"branch", @@ -256,11 +262,13 @@ "github_language" => nil, "active" => true, "private" => true, + "server_type" => 'git', "shared" => false, "owner" => { "@type" => "user", "id" => 1, "login" => "svenfuchs", + "ro_mode" => true, "@href" => "/v3/user/1"}, "default_branch" => { "@type" => "branch", @@ -417,10 +425,12 @@ "github_language" => nil, "active" => true, "private" => true, + "server_type" => 'git', "owner" => { "@type" => "user", "id" => 1, "login" => "svenfuchs", + "ro_mode" => true, "@href" => "/v3/user/1" }, "default_branch" => { "@type" => "branch", @@ -463,11 +473,13 @@ "github_language" => nil, "active" => true, "private" => false, + "server_type" => 'git', "shared" => false, "owner" => { "@type" => "user", "id" => 1, "login" => "svenfuchs", + "ro_mode" => true, "@href" => "/v3/user/1" }, "default_branch" => { "@type" => "branch", @@ -535,10 +547,12 @@ "github_language" => nil, "active" => true, "private" => false, + "server_type" => 'git', "shared" => true, "owner" => { "@type" => "user", "id" => sharedrepo.owner_id, + "ro_mode" => true, "login" => "sharedrepoowner", "@href" => "/v3/user/#{sharedrepo.owner_id}" }, "default_branch" => { @@ -554,4 +568,60 @@ "config_validation" => false }]}} end + + describe "allowance, org" do + before { get("/v3/owner/svenfuchs/allowance", {}, headers) } + example { expect(last_response).to be_ok } + example { expect(JSON.load(body)).to be == { + "@representation" => "standard", + "@type" => "allowance", + "concurrency_limit" => 1, + "private_repos" => false, + "public_repos" => true, + "subscription_type" => 1, + "user_usage" => false, + "pending_user_licenses" => false, + "id" => 0 + }} + end + + describe "allowance, com" do + before do + Travis.config.host = 'travis-ci.com' + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + stub_billing_request(:get, "/usage/users/1/allowance", auth_key: billing_auth_key, user_id: 1) + .to_return(body: JSON.dump({ 'public_repos': true, 'private_repos': true, 'user_usage': true, 'pending_user_licenses': false, 'concurrency_limit': 666 })) + get("/v3/owner/svenfuchs/allowance", {}, headers) + end + example { expect(last_response).to be_ok } + example { expect(JSON.load(body)).to be == { + "@representation" => "standard", + "@type" => "allowance", + "concurrency_limit" => 666, + "private_repos" => true, + "public_repos" => true, + "subscription_type" => 2, + "user_usage" => true, + "pending_user_licenses" => false, + "id" => 1 + }} + end + + describe "allowance with bad owner, com" do + before do + Travis.config.host = 'travis-ci.com' + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + get("/v3/owner/another/allowance", {}, headers) + end + example { expect(last_response.status).to eq(404) } + example do + expect(JSON.load(body)).to eq( + '@type' => 'error', + 'error_type' => 'not_found', + 'error_message' => 'resource not found (or insufficient access)' + ) + end + end end diff --git a/spec/v3/services/repository/activate_spec.rb b/spec/v3/services/repository/activate_spec.rb index 4a04e64b14..24e6cce273 100644 --- a/spec/v3/services/repository/activate_spec.rb +++ b/spec/v3/services/repository/activate_spec.rb @@ -1,19 +1,10 @@ describe Travis::API::V3::Services::Repository::Activate, set_app: true do - let(:sidekiq_job) { Sidekiq::Client.last.deep_symbolize_keys } let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } - before do + Travis.config.vcs.url = 'http://vcsfake.travis-ci.com' + Travis.config.vcs.token = 'vcs-token' repo.update!(active: false) - @original_sidekiq = Sidekiq::Client - Sidekiq.send(:remove_const, :Client) # to avoid a warning - Sidekiq::Client = [] end - - after do - Sidekiq.send(:remove_const, :Client) # to avoid a warning - Sidekiq::Client = @original_sidekiq - end - describe "not authenticated" do before { post("/v3/repo/#{repo.id}/activate") } example { expect(last_response.status).to be == 403 } @@ -23,11 +14,9 @@ "error_message" => "login required" }} end - shared_examples 'repository activation' do describe "missing repo, authenticated" do before { post("/v3/repo/9999999999/activate", {}, headers) } - example { expect(last_response.status).to be == 404 } example { expect(JSON.load(body)).to be == { "@type" => "error", @@ -36,187 +25,34 @@ "resource_type" => "repository" }} end - describe "existing repository, push access" do - let(:webhook_payload) { JSON.dump(name: 'web', events: Travis::API::V3::GitHub::EVENTS, active: true, config: { url: Travis.config.service_hook_url || '', insecure_ssl: false }) } - let(:service_hook_payload) { JSON.dump(events: Travis::API::V3::GitHub::EVENTS, active: false) } - before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, admin: true, pull: true, push: true) } - before { allow_any_instance_of(Travis::API::V3::GitHub).to receive(:upload_key) } - before { stub_request(:any, %r(https://api.github.com/repositories/#{repo.github_id}/hooks(/\d+)?)) } - around do |ex| Travis.config.service_hook_url = 'https://url.of.listener.something' ex.run Travis.config.service_hook_url = nil end - - context 'queues sidekiq job' do - before do - stub_request(:get, "https://api.github.com/repositories/#{repo.github_id}/hooks?per_page=100").to_return(status: 200, body: '[]') - post("/v3/repo/#{repo.id}/activate", {}, headers) - end - - example do - expect(sidekiq_job).to eq( - queue: :sync, - class: 'Travis::GithubSync::Worker', - args: [:sync_repo, repo_id: 1, user_id: 1] - ) - end - end - - context 'when both service hook and webhook exist' do - before do - stub_request(:get, "https://api.github.com/repositories/#{repo.github_id}/hooks?per_page=100").to_return( - status: 200, body: JSON.dump( - [ - { name: 'travis', url: "https://api.github.com/repositories/#{repo.github_id}/hooks/123", config: { domain: 'https://url.of.listener.something' } }, - { name: 'web', url: "https://api.github.com/repositories/#{repo.github_id}/hooks/456", config: { url: Travis.config.service_hook_url } } - ] - ) - ) - post("/v3/repo/#{repo.id}/activate", {}, headers) - end - - context 'enterprise' do - around do |ex| - Travis.config.enterprise = true - ex.run - Travis.config.enterprise = false - end - - example 'deactivates service hook' do - expect(WebMock).to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/123").with(body: service_hook_payload).once - end - end - - example 'no longer deactivates service hook' do - expect(WebMock).not_to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/123").with(body: service_hook_payload) - end - - example 'updates webhook' do - expect(WebMock).to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/456").with(body: webhook_payload).once - end - - example 'is success' do - expect(last_response.status).to eq 200 - expect(JSON.load(body)).to include( - '@type' => 'repository', - 'active' => true - ) - end - end - - context 'when webhook exists' do - before do - stub_request(:get, "https://api.github.com/repositories/#{repo.github_id}/hooks?per_page=100").to_return( - status: 200, body: JSON.dump( - [ - { name: 'web', url: "https://api.github.com/repositories/#{repo.github_id}/hooks/456", config: { url: Travis.config.service_hook_url } } - ] - ) - ) - post("/v3/repo/#{repo.id}/activate", {}, headers) - end - - example 'updates webhook' do - expect(WebMock).to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/456").with(body: webhook_payload).once - end - - example 'is success' do - expect(last_response.status).to eq 200 - expect(JSON.load(body)).to include( - '@type' => 'repository', - 'active' => true - ) - end - - context 'when ssl verification has been disabled' do - let(:webhook_payload) { JSON.dump(name: 'web', events: Travis::API::V3::GitHub::EVENTS, active: true, config: { url: Travis.config.service_hook_url || '', insecure_ssl: true }) } - - around do |ex| - Travis.config.ssl = { verify: false } - ex.run - Travis.config.ssl = {} - end - - example 'updates webhook with ssl disabled' do - expect(WebMock).to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/456").with(body: webhook_payload).once - end - - example 'is success' do - expect(last_response.status).to eq 200 - expect(JSON.load(body)).to include( - '@type' => 'repository', - 'active' => true + context 'request' do + let!(:request) do + stub_request(:post, "http://vcsfake.travis-ci.com/repos/#{repo.id}/hook?user_id=#{repo.owner_id}") + .to_return( + status: 200, + body: nil, ) - end - end - end - - context 'when webhook does not exist' do - let(:webhook_payload) { JSON.dump(name: 'web', events: Travis::API::V3::GitHub::EVENTS, active: true, config: { url: Travis.config.service_hook_url || '', insecure_ssl: false }) } - - before do - stub_request(:get, "https://api.github.com/repositories/#{repo.github_id}/hooks?per_page=100").to_return(status: 200, body: '[]') - post("/v3/repo/#{repo.id}/activate", {}, headers) - end - - example 'creates webhook' do - expect(WebMock).to have_requested(:post, "https://api.github.com/repositories/#{repo.github_id}/hooks").with(body: webhook_payload).once - end - - example 'is success' do - expect(last_response.status).to eq 200 - expect(JSON.load(body)).to include( - '@type' => 'repository', - 'active' => true - ) end - - context 'when ssl verification has been disabled' do - let(:webhook_payload) { JSON.dump(name: 'web', events: Travis::API::V3::GitHub::EVENTS, active: true, config: { url: Travis.config.service_hook_url || '', insecure_ssl: true}) } - - around do |ex| - Travis.config.ssl = { verify: false } - ex.run - Travis.config.ssl = {} - end - - example 'requests webhooks without ssl verification' do - expect(WebMock).to have_requested(:post, "https://api.github.com/repositories/#{repo.github_id}/hooks").with(body: webhook_payload).once - end - end - end - - context 'when the repo ssh key does not exist' do - before do - repo.key.destroy - post("/v3/repo/#{repo.id}/activate", {}, headers) - end - - example { expect(last_response.status).to eq 409 } - example do - expect(JSON.load(body)).to eq( - '@type' => 'error', - 'error_type' => 'repo_ssh_key_missing', - 'error_message' => 'request cannot be completed because the repo ssh key is still pending to be created. please retry in a bit, or try syncing the repository if this condition does not resolve' - ) + post("/v3/repo/#{repo.id}/activate", {}, headers) + expect(request).to have_been_made end end end end - context 'with user auth' do let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} it_behaves_like 'repository activation' - describe "existing repository, no push access" do before { post("/v3/repo/#{repo.id}/activate", {}, headers) } - example { expect(last_response.status).to be == 403 } example { expect(JSON.load(body).to_s).to include( "@type", @@ -230,12 +66,10 @@ "activate" )} end - describe "private repository, no access" do before { repo.update_attribute(:private, true) } before { post("/v3/repo/#{repo.id}/activate", {}, headers) } after { repo.update_attribute(:private, false) } - example { expect(last_response.status).to be == 404 } example { expect(JSON.load(body)).to be == { "@type" => "error", @@ -244,32 +78,31 @@ "resource_type" => "repository" }} end - end - context 'with internal auth' do let(:internal_token) { 'FOO' } let(:headers) { { 'HTTP_AUTHORIZATION' => "internal admin:#{internal_token}" } } - around do |ex| apps = Travis.config.applications Travis.config.applications = { 'admin' => { token: internal_token, full_access: true }} ex.run Travis.config.applications = apps end - it_behaves_like 'repository activation' end - context do let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } - before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, admin: true, push: true, pull: true) } - + before do + Travis.config.host = 'http://travis-ci.org' + Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, admin: true, push: true, pull: true) + end + after do + Travis.config.host = 'http://travis-ci.com' + end describe "repo migrating" do before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/activate", {}, headers) } - example { expect(last_response.status).to be == 403 } example { expect(JSON.load(body)).to be == { "@type" => "error", @@ -277,11 +110,9 @@ "error_message" => "This repository has been migrated to travis-ci.com. Modifications to repositories, builds, and jobs are disabled on travis-ci.org. If you have any questions please contact us at support@travis-ci.com" }} end - - describe "repo migrating" do + describe "repo migrated" do before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/activate", {}, headers) } - example { expect(last_response.status).to be == 403 } example { expect(JSON.load(body)).to be == { "@type" => "error", diff --git a/spec/v3/services/repository/deactivate_spec.rb b/spec/v3/services/repository/deactivate_spec.rb index 5cfa365290..0c4f0b4104 100644 --- a/spec/v3/services/repository/deactivate_spec.rb +++ b/spec/v3/services/repository/deactivate_spec.rb @@ -1,10 +1,10 @@ describe Travis::API::V3::Services::Repository::Deactivate, set_app: true do let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } - before do + Travis.config.vcs.url = 'http://vcsfake.travis-ci.com' + Travis.config.vcs.token = 'vcs-token' repo.update!(active: true) end - describe "not authenticated" do before { post("/v3/repo/#{repo.id}/deactivate") } example { expect(last_response.status).to be == 403 } @@ -14,12 +14,10 @@ "error_message" => "login required" }} end - describe "missing repo, authenticated" do let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} before { post("/v3/repo/9999999999/deactivate", {}, headers) } - example { expect(last_response.status).to be == 404 } example { expect(JSON.load(body)).to be == { "@type" => "error", @@ -28,13 +26,10 @@ "resource_type" => "repository" }} end - shared_examples 'repository deactivation' do describe 'existing repository, wrong access' do before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } - before { stub_request(:any, %r(api.github.com/repositories/#{repo.github_id}/hooks(/\d+)?)) } before { post("/v3/repo/#{repo.id}/deactivate", {}, headers) } - example 'is success' do expect(last_response.status).to eq 403 expect(JSON.load(body)).to include( @@ -43,143 +38,37 @@ ) end end - describe "existing repository, admin and push access" do - let(:webhook_payload) { JSON.dump(name: 'web', events: Travis::API::V3::GitHub::EVENTS, active: false, config: { url: Travis.config.service_hook_url || '', insecure_ssl: false }) } - let(:service_hook_payload) { JSON.dump(events: Travis::API::V3::GitHub::EVENTS, active: false) } - + let!(:request) do + stub_request(:delete, "http://vcsfake.travis-ci.com/repos/#{repo.id}/hook?user_id=#{repo.owner_id}") + .to_return( + status: 200, + body: nil, + ) + end before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, admin: true, push: true) } - before { stub_request(:any, %r(api.github.com/repositories/#{repo.github_id}/hooks(/\d+)?)) } - around do |ex| Travis.config.service_hook_url = 'https://url.of.listener.something' ex.run Travis.config.service_hook_url = nil end - - context 'when repo has service hook and webhook' do - before do - stub_request(:get, "https://api.github.com/repositories/#{repo.github_id}/hooks?per_page=100").to_return( - status: 200, body: JSON.dump( - [ - { name: 'travis', url: "https://api.github.com/repositories/#{repo.github_id}/hooks/123", config: { domain: 'https://url.of.listener.something' } }, - { name: 'web', url: "https://api.github.com/repositories/#{repo.github_id}/hooks/456", config: { url: Travis.config.service_hook_url } } - ] - ) - ) - post("/v3/repo/#{repo.id}/deactivate", {}, headers) - end - - context 'enterprise' do - around do |ex| - Travis.config.enterprise = true - ex.run - Travis.config.enterprise = false - end - - example 'deactivates service hook' do - expect(WebMock).to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/123").with(body: service_hook_payload).once - end - end - - example 'no longer deactivates service hook' do - expect(WebMock).not_to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/123").with(body: service_hook_payload) - end - - example 'updates webhook' do - expect(WebMock).to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/456").with(body: webhook_payload).once - end - - example 'is success' do - expect(last_response.status).to eq 200 - expect(JSON.load(body)).to include( - '@type' => 'repository', - 'active' => false - ) - end - end - - context 'when repo has only service hook' do - before do - stub_request(:get, "https://api.github.com/repositories/#{repo.github_id}/hooks?per_page=100").to_return( - status: 200, body: JSON.dump( - [ - { name: 'travis', url: "https://api.github.com/repositories/#{repo.github_id}/hooks/123", config: { domain: 'https://url.of.listener.something' } } - ] - ) - ) - post("/v3/repo/#{repo.id}/deactivate", {}, headers) - end - - context 'enterprise' do - around do |ex| - Travis.config.enterprise = true - ex.run - Travis.config.enterprise = false - end - - example 'deactivates service hook' do - expect(WebMock).to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/123").with(body: service_hook_payload).once - end - end - - example 'no longer deactivates service hook' do - expect(WebMock).not_to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/123").with(body: service_hook_payload) - end - - example 'creates webhook' do - expect(WebMock).to have_requested(:post, "https://api.github.com/repositories/#{repo.github_id}/hooks").once - end - - example 'is success' do - expect(last_response.status).to eq 200 - expect(JSON.load(body)).to include( - '@type' => 'repository', - 'active' => false - ) - end - end - - context 'when repo has only webhook' do - before do - stub_request(:get, "https://api.github.com/repositories/#{repo.github_id}/hooks?per_page=100").to_return( - status: 200, body: JSON.dump( - [ - { name: 'web', url: "https://api.github.com/repositories/#{repo.github_id}/hooks/456", config: { url: Travis.config.service_hook_url } } - ] - ) - ) - post("/v3/repo/#{repo.id}/deactivate", {}, headers) - end - - example 'does nothing with service hook' do - expect(WebMock).not_to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/123") - end - - example 'updates webhook' do - expect(WebMock).to have_requested(:patch, "https://api.github.com/repositories/#{repo.github_id}/hooks/456").once - end - - example 'is success' do - expect(last_response.status).to eq 200 - expect(JSON.load(body)).to include( - '@type' => 'repository', - 'active' => false - ) - end + example 'creates webhook' do + post("/v3/repo/#{repo.id}/deactivate", {}, headers) + expect(request).to have_been_made + expect(last_response.status).to eq 200 + expect(JSON.load(body)).to include( + '@type' => 'repository', + 'active' => false + ) end end end - context 'user auth' do let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} - it_behaves_like 'repository deactivation' - describe "existing repository, no push access" do before { post("/v3/repo/#{repo.id}/deactivate", {}, headers) } - example { expect(last_response.status).to be == 403 } example { expect(JSON.load(body).to_s).to include( "@type", @@ -193,12 +82,10 @@ "deactivate") } end - describe "private repository, no access" do before { repo.update_attribute(:private, true) } before { post("/v3/repo/#{repo.id}/deactivate", {}, headers) } after { repo.update_attribute(:private, false) } - example { expect(last_response.status).to be == 404 } example { expect(JSON.load(body)).to be == { "@type" => "error", @@ -208,34 +95,27 @@ }} end end - context 'internal auth' do let(:internal_token) { 'FOO' } let(:headers) { { 'HTTP_AUTHORIZATION' => "internal admin:#{internal_token}" } } - around do |ex| apps = Travis.config.applications Travis.config.applications = { 'admin' => { token: internal_token, full_access: true }} ex.run Travis.config.applications = apps end - it_behaves_like 'repository deactivation' end - describe "existing repository, push access" # as this requires a call to github, and stubbing this request has proven difficult, # this test has been omitted for now - context do let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, admin: true, push: true, pull: true) } - describe "repo migrating" do before { repo.update(migration_status: "migrating") } before { post("/v3/repo/#{repo.id}/deactivate", {}, headers) } - example { expect(last_response.status).to be == 403 } example { expect(JSON.load(body)).to be == { "@type" => "error", @@ -243,11 +123,9 @@ "error_message" => "This repository has been migrated to travis-ci.com. Modifications to repositories, builds, and jobs are disabled on travis-ci.org. If you have any questions please contact us at support@travis-ci.com" }} end - - describe "repo migrating" do + describe "repo migrated" do before { repo.update(migration_status: "migrated") } before { post("/v3/repo/#{repo.id}/deactivate", {}, headers) } - example { expect(last_response.status).to be == 403 } example { expect(JSON.load(body)).to be == { "@type" => "error", diff --git a/spec/v3/services/repository/find_spec.rb b/spec/v3/services/repository/find_spec.rb index 1ffb9c4c26..5af584539f 100644 --- a/spec/v3/services/repository/find_spec.rb +++ b/spec/v3/services/repository/find_spec.rb @@ -85,11 +85,13 @@ "github_language" => nil, "active" => true, "private" => opts[:private], + "server_type" => 'git', "shared" => false, "owner" => { "id" => repo.owner_id, "login" => "svenfuchs", "@type" => "user", + "ro_mode" => true, "@href" => "/v3/user/#{repo.owner_id}"}, "default_branch" => { "@type" => "branch", @@ -143,7 +145,8 @@ owner_id: 1, owner_type: "User", last_build_state: "passed", - github_id: 12345 + github_id: 12345, + server_type: 'git' ) get("/v3/repo/svenfuchs%2FMinimal") } diff --git a/spec/v3/services/requests/create_spec.rb b/spec/v3/services/requests/create_spec.rb index 35c277eeec..ea6832ae7e 100644 --- a/spec/v3/services/requests/create_spec.rb +++ b/spec/v3/services/requests/create_spec.rb @@ -168,6 +168,14 @@ def compact(hash) it { expect(body).to eq insufficient_access } end + describe 'existing repository, owner in read-only mode' do + let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } + before { allow(Travis::Features).to receive(:owner_active?).and_return(false) } + before { post("/v3/repo/#{repo.id}/requests", {}, headers) } + + it { expect(last_response.status).to be == 404 } + end + describe 'private repository, no access' do let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } before { repo.update_attribute(:private, true) } diff --git a/spec/v3/services/subscription/invoices_spec.rb b/spec/v3/services/subscription/invoices_spec.rb index 041dd6d62b..ae47c30126 100644 --- a/spec/v3/services/subscription/invoices_spec.rb +++ b/spec/v3/services/subscription/invoices_spec.rb @@ -25,10 +25,12 @@ let(:created_at) { '2018-04-17T18:30:32Z' } let(:url) { 'https://billing-test.travis-ci.com/invoices/111.pdf' } let(:amount_due) { 100 } + let(:status) { 'paid' } let(:subscription_id) { rand(999) } + let(:cc_last_digits) { '4242' } before do stub_billing_request(:get, "/subscriptions/#{subscription_id}/invoices", auth_key: billing_auth_key, user_id: user.id) - .to_return(status: 200, body: JSON.dump([{'id' => invoice_id, 'created_at' => created_at, 'url' => url, 'amount_due' => amount_due }])) + .to_return(status: 200, body: JSON.dump([{'id' => invoice_id, 'created_at' => created_at, 'url' => url, 'amount_due' => amount_due, 'status' => status, 'cc_last_digits' => cc_last_digits }])) end it 'responds with list of subscriptions' do @@ -45,7 +47,9 @@ 'id' => invoice_id, 'created_at' => created_at, 'url' => url, - 'amount_due' => amount_due + 'amount_due' => amount_due, + 'status' => status, + 'cc_last_digits' => cc_last_digits }] }) end diff --git a/spec/v3/services/subscription/update_address_spec.rb b/spec/v3/services/subscription/update_address_spec.rb index e150377a75..0b719a56ed 100644 --- a/spec/v3/services/subscription/update_address_spec.rb +++ b/spec/v3/services/subscription/update_address_spec.rb @@ -28,7 +28,8 @@ 'city' => 'Berlin', 'country' => 'Germany', 'zip_code' => '10001', - 'billing_email' => 'travis@example.org' + 'billing_email' => 'travis@example.org', + 'has_local_registration' => true } } let(:subscription_id) { rand(999) } @@ -42,7 +43,8 @@ 'city' => 'Berlin', 'country' => 'Germany', 'zip_code' => '10001', - 'billing_email' => 'travis@example.org' + 'billing_email' => 'travis@example.org', + 'has_local_registration' => true }) .to_return(status: 204) end diff --git a/spec/v3/services/subscriptions/all_spec.rb b/spec/v3/services/subscriptions/all_spec.rb index c665cb4e62..d6358e5f5f 100644 --- a/spec/v3/services/subscriptions/all_spec.rb +++ b/spec/v3/services/subscriptions/all_spec.rb @@ -65,6 +65,7 @@ 'last_name' => 'rosas', 'company' => '', 'billing_email' => 'a.rosas10@gmail.com', + 'has_local_registration' => nil, 'zip_code' => '28450', 'address' => 'Luis Spota', 'address2' => '', @@ -98,7 +99,9 @@ '@href' => "/v3/org/#{organization.id}", 'id' => organization.id, 'vcs_type' => organization.vcs_type, - 'login' => 'travis' + 'login' => 'travis', + 'name' => organization.name, + 'ro_mode' => true }, 'payment_intent' => nil }] diff --git a/spec/v3/services/subscriptions/create_spec.rb b/spec/v3/services/subscriptions/create_spec.rb index a370ace889..f14b2a76c5 100644 --- a/spec/v3/services/subscriptions/create_spec.rb +++ b/spec/v3/services/subscriptions/create_spec.rb @@ -35,6 +35,7 @@ 'billing_info.country' => 'Germany', 'billing_info.zip_code' => '10001', 'billing_info.billing_email' => 'travis@example.org', + 'billing_info.has_local_registration' => nil, 'credit_card_info.token' => 'token_from_stripe' } end @@ -56,6 +57,7 @@ 'country' => 'Germany', 'zip_code' => '10001', 'billing_email' => 'travis@example.org', + 'has_local_registration' => nil, }, 'credit_card_info' => { 'token' => 'token_from_stripe' @@ -85,6 +87,7 @@ 'vat_id' => nil, 'zip_code' => '10001', 'billing_email' => 'travis@example.org', + 'has_local_registration' => nil }, 'credit_card_info' => { 'card_owner' => 'Travis Schmidt', @@ -126,6 +129,7 @@ 'last_name' => 'Schmidt', 'company' => 'Travis', 'billing_email' => 'travis@example.org', + 'has_local_registration' => nil, 'zip_code' => '10001', 'address' => 'Rigaer Strasse', 'address2' => nil, @@ -148,7 +152,9 @@ '@href' => "/v3/org/#{organization.id}", 'id' => organization.id, 'vcs_type' => organization.vcs_type, - 'login' => 'travis' + 'login' => 'travis', + 'name' => organization.name, + 'ro_mode' => true }, 'payment_intent' => nil, 'discount' => nil diff --git a/spec/v3/services/trials/all_spec.rb b/spec/v3/services/trials/all_spec.rb index 1256c34b25..b9799c8b68 100644 --- a/spec/v3/services/trials/all_spec.rb +++ b/spec/v3/services/trials/all_spec.rb @@ -49,7 +49,9 @@ '@representation' => 'minimal', 'id' => user.id, 'login' => 'svenfuchs', - 'vcs_type' => 'GithubUser' + 'vcs_type' => 'GithubUser', + 'name' => user.name, + 'ro_mode' => true }, 'created_at' => created_at, 'status' => 'started', diff --git a/spec/v3/services/trials/create_trial_spec.rb b/spec/v3/services/trials/create_trial_spec.rb index 0587856e88..fa43e5f1dd 100644 --- a/spec/v3/services/trials/create_trial_spec.rb +++ b/spec/v3/services/trials/create_trial_spec.rb @@ -50,7 +50,9 @@ '@representation' => 'minimal', 'id' => user.id, 'vcs_type' => user.vcs_type, - 'login' => user.login + 'login' => user.login, + 'name' => user.name, + 'ro_mode' => true }, 'created_at' => created_at, 'status' => 'started', @@ -70,7 +72,9 @@ '@representation' => 'minimal', 'id' => organization.id, 'vcs_type' => organization.vcs_type, - 'login' => organization.login + 'login' => organization.login, + 'name' => organization.name, + 'ro_mode' => true }, 'created_at' => created_at, 'status' => 'started', @@ -99,7 +103,9 @@ '@representation' => 'minimal', 'id' => user.id, 'vcs_type' => user.vcs_type, - 'login' => user.login + 'login' => user.login, + 'name' => user.name, + 'ro_mode' => true }, 'created_at' => created_at, 'status' => 'started', @@ -119,7 +125,9 @@ '@representation' => 'minimal', 'id' => organization.id, 'vcs_type' => organization.vcs_type, - 'login' => organization.login + 'login' => organization.login, + 'name' => organization.name, + 'ro_mode' => true }, 'created_at' => created_at, 'status' => 'started', diff --git a/spec/v3/services/user/current_spec.rb b/spec/v3/services/user/current_spec.rb index 965238f121..9ba1a367d6 100644 --- a/spec/v3/services/user/current_spec.rb +++ b/spec/v3/services/user/current_spec.rb @@ -4,6 +4,7 @@ let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + describe "authenticated as user with access" do before { get("/v3/user", {}, headers) } example { expect(last_response).to be_ok } @@ -24,8 +25,15 @@ "synced_at" => user.synced_at, "education" => nil, "allow_migration" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => user.id + }, "recently_signed_up"=>false, - "secure_user_hash" => nil + "secure_user_hash" => nil, + "ro_mode" => true, + "confirmed_at" => nil, }} end end diff --git a/spec/v3/services/user/find_spec.rb b/spec/v3/services/user/find_spec.rb index a4abc12bdd..5639d24680 100644 --- a/spec/v3/services/user/find_spec.rb +++ b/spec/v3/services/user/find_spec.rb @@ -1,12 +1,20 @@ -describe Travis::API::V3::Services::User::Find, set_app: true do +describe Travis::API::V3::Services::User::Find, set_app: true, billing_spec_helper: true do let(:user) { Travis::API::V3::Models::User.find_by_login('svenfuchs') } let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } before do user.education = true user.save! + Travis.config.host = 'travis-ci.com' + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + stub_billing_request(:get, "/usage/users/#{user.id}/allowance", auth_key: billing_auth_key, user_id: user.id) + .to_return(body: JSON.dump({ 'public_repos': true, 'private_repos': true, 'user_usage': true, 'pending_user_licenses': false, 'concurrency_limit': 666 })) end describe "authenticated as user with access" do @@ -29,8 +37,15 @@ "synced_at" => user.synced_at, "education" => true, "allow_migration" => false, + "allowance" => { + "@type" => "allowance", + "@representation" => "minimal", + "id" => user.id + }, "recently_signed_up"=>false, "secure_user_hash" => nil, + "ro_mode" => false, + "confirmed_at" => nil, }} end end diff --git a/spec/v3/services/user/sync_spec.rb b/spec/v3/services/user/sync_spec.rb index 895f1bb579..aae9be8626 100644 --- a/spec/v3/services/user/sync_spec.rb +++ b/spec/v3/services/user/sync_spec.rb @@ -7,6 +7,8 @@ before do user.update_attribute(:is_syncing, false) allow(Travis::Features).to receive(:owner_active?).and_return(true) + allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, user).and_return(true) + allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, user2).and_return(true) @original_sidekiq = Sidekiq::Client Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = [] @@ -86,11 +88,24 @@ "@representation"=> "minimal", "id" => user2.id, 'vcs_type' => user2.vcs_type, - "login" => "carlad" + "login" => "carlad", + "name" => user2.name, + "ro_mode" => false } }} end + describe "existing user, current user in read-only mode " do + let(:params) {{}} + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before { Travis::API::V3::Models::Permission.create(user: user) } + before { allow(Travis::Features).to receive(:owner_active?).with(:read_only_disabled, user).and_return(false) } + before { post("/v3/user/#{user.id}/sync", params, headers) } + + example { expect(last_response.status).to be == 404 } + end + describe "existing user, authorized, user already syncing " do let(:params) {{}} let(:token) { Travis::Api::App::AccessToken.create(user: user2, app_id: 1) } diff --git a/spec/v3/services/user_setting/update_spec.rb b/spec/v3/services/user_setting/update_spec.rb index d4e2c127a2..1968b29b94 100644 --- a/spec/v3/services/user_setting/update_spec.rb +++ b/spec/v3/services/user_setting/update_spec.rb @@ -58,6 +58,11 @@ example 'does not clobber other things in the settings hash' do expect(repo.reload.settings['env_vars']).to eq(['something']) end + example 'audit is created' do + expect(Travis::API::V3::Models::Audit.last.source_id).to eq(repo.id) + expect(Travis::API::V3::Models::Audit.last.source_type).to eq('Repository') + expect(Travis::API::V3::Models::Audit.last.source_changes).to eq({"settings"=>{"build_pushes"=>{"after"=>false, "before"=>true}}}) + end end describe 'authenticated, existing repo, old params' do diff --git a/spec/v3/services/user_settings/for_repository_spec.rb b/spec/v3/services/user_settings/for_repository_spec.rb index ae34bd0d79..11e4bcd746 100644 --- a/spec/v3/services/user_settings/for_repository_spec.rb +++ b/spec/v3/services/user_settings/for_repository_spec.rb @@ -42,15 +42,18 @@ '@href' => "/v3/repo/#{repo.id}/settings", '@representation' => 'standard', 'settings' => [ - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/builds_only_with_travis_yml", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'builds_only_with_travis_yml', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/build_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'build_pushes', 'value' => true }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/build_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'build_pull_requests', 'value' => true }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/maximum_number_of_builds", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'maximum_number_of_builds', 'value' => 0 }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pushes', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pull_requests', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/config_validation", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'config_validation', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_encrypted_env_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_encrypted_env_with_forks', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_ssh_keys_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_ssh_keys_with_forks', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/builds_only_with_travis_yml", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'builds_only_with_travis_yml', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/build_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'build_pushes', 'value' => true }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/build_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'build_pull_requests', 'value' => true }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/maximum_number_of_builds", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'maximum_number_of_builds', 'value' => 0 }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pushes', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pull_requests', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/config_validation", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'config_validation', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_encrypted_env_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_encrypted_env_with_forks', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_ssh_keys_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_ssh_keys_with_forks', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/job_log_time_based_limit", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'job_log_time_based_limit', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/job_log_access_based_limit", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'job_log_access_based_limit', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/job_log_access_older_than_days", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'job_log_access_older_than_days', 'value' => 365 }, ] ) end @@ -81,15 +84,18 @@ '@href' => "/v3/repo/#{repo.id}/settings", '@representation' => 'standard', 'settings' => [ - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/builds_only_with_travis_yml", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'builds_only_with_travis_yml', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/build_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'build_pushes', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/build_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'build_pull_requests', 'value' => true }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/maximum_number_of_builds", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'maximum_number_of_builds', 'value' => 0 }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pushes', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pull_requests', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/config_validation", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'config_validation', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_encrypted_env_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_encrypted_env_with_forks', 'value' => false }, - { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_ssh_keys_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_ssh_keys_with_forks', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/builds_only_with_travis_yml", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'builds_only_with_travis_yml', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/build_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'build_pushes', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/build_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'build_pull_requests', 'value' => true }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/maximum_number_of_builds", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'maximum_number_of_builds', 'value' => 0 }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pushes", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pushes', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/auto_cancel_pull_requests", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'auto_cancel_pull_requests', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/config_validation", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'config_validation', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_encrypted_env_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_encrypted_env_with_forks', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/share_ssh_keys_with_forks", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'share_ssh_keys_with_forks', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/job_log_time_based_limit", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'job_log_time_based_limit', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/job_log_access_based_limit", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'job_log_access_based_limit', 'value' => false }, + { '@type' => 'setting', '@href' => "/v3/repo/#{repo.id}/setting/job_log_access_older_than_days", '@representation' => 'standard', '@permissions' => { 'read' => true, 'write' => true }, 'name' => 'job_log_access_older_than_days', 'value' => 365 }, ] ) end diff --git a/spec/v3/services/v2_subscription/cancel_spec.rb b/spec/v3/services/v2_subscription/cancel_spec.rb new file mode 100644 index 0000000000..9f8f839551 --- /dev/null +++ b/spec/v3/services/v2_subscription/cancel_spec.rb @@ -0,0 +1,39 @@ +describe Travis::API::V3::Services::V2Subscription::Cancel, set_app: true, billing_spec_helper: true do + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + let(:reason_data) { { 'reason' => 'Other', 'reason_details' => 'Cancellation details go here' } } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + post('/v3/v2_subscription/123/cancel', {}) + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}", + 'CONTENT_TYPE' => 'application/json' }} + let(:subscription_id) { rand(999) } + + let!(:stubbed_request) do + stub_billing_request(:post, "/v2/subscriptions/#{subscription_id}/cancel", auth_key: billing_auth_key, user_id: user.id) + .with(body: reason_data) + .to_return(status: 204) + end + + it 'cancels the subscription' do + post("/v3/v2_subscription/#{subscription_id}/cancel", JSON.generate(reason_data), headers) + + expect(last_response.status).to eq(204) + expect(stubbed_request).to have_been_made.once + end + end +end diff --git a/spec/v3/services/v2_subscription/executions_spec.rb b/spec/v3/services/v2_subscription/executions_spec.rb new file mode 100644 index 0000000000..df5c5647ca --- /dev/null +++ b/spec/v3/services/v2_subscription/executions_spec.rb @@ -0,0 +1,191 @@ +describe Travis::API::V3::Services::Executions, set_app: true, billing_spec_helper: true do + let(:parsed_body) { JSON.load(last_response.body) } + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } + + before do + Travis.config.host = 'travis-ci.com' + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + get('/v3/owner/123/executions') + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user, login: 'travis-ci') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) { { 'HTTP_AUTHORIZATION' => "token #{token}" } } + let(:invoice_id) { "TP#{rand(999)}" } + let(:created_at) { '2018-04-17T18:30:32Z' } + let(:url) { 'https://billing-test.travis-ci.com/invoices/111.pdf' } + let(:amount_due) { 100 } + let(:status) { 'paid' } + let(:subscription_id) { rand(999) } + let(:page) { 1 } + let(:per_page) { 25 } + let(:from) { Date.today - 2.months } + let(:to) { Date.today } + before do + stub_request(:get, "#{billing_url}/usage/users/#{user.id}/executions?page=#{page}&per_page=#{per_page}&from=#{from.to_s}&to=#{to.to_s}") + .with(basic_auth: ['_', billing_auth_key], headers: { 'X-Travis-User-Id' => user.id }) + .to_return(body: JSON.dump([billing_executions_response_body])) + stub_request(:get, "#{billing_url}/usage/users/#{user.id}/executions?page=0&per_page=0&from=#{from.to_s}&to=#{to.to_s}") + .with(basic_auth: ['_', billing_auth_key], headers: { 'X-Travis-User-Id' => user.id }) + .to_return(body: JSON.dump([billing_executions_response_body])) + end + + it 'responds with list of executions' do + get("/v3/owner/#{user.login}/executions?page=#{page}&per_page=#{per_page}&from=#{from.to_s}&to=#{to.to_s}", {}, headers) + + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json({ + '@type' => 'executions', + '@href' => "/v3/owner/travis-ci/executions?page=1&per_page=25&from=#{from.to_s}&to=#{to.to_s}", + '@representation' => 'standard', + 'executions' => [{ + '@type' => 'execution', + '@representation' => 'standard', + 'id' => 1, + 'os' => 'linux', + 'instance_size' => 'standard-2', + 'arch' => 'amd64', + 'virtualization_type' => 'vm', + 'queue' => 'builds.gce-oss', + 'job_id' => 123, + 'repository_id' => repo.id, + 'owner_id' => 1, + 'owner_type' => 'User', + 'plan_id' => 2, + 'sender_id' => 1, + 'credits_consumed' => 5, + 'user_license_credits_consumed' => 4, + 'started_at' => Time.now.to_s, + 'finished_at' => (Time.now + 10.minutes).to_s, + 'created_at' => Time.now.to_s, + 'updated_at' => Time.now.to_s, + 'repo_owner_name' => "svenfuchs", + 'repo_slug' => "svenfuchs/minimal", + 'sender_login' => "svenfuchs" + }] + }) + end + + it 'responds with list of executions per repo' do + get("/v3/owner/#{user.login}/executions_per_repo?from=#{from.to_s}&to=#{to.to_s}", {}, headers) + + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json({ + '@type' => 'executionsperrepo', + '@href' => "/v3/owner/travis-ci/executions_per_repo?from=#{from.to_s}&to=#{to.to_s}", + '@representation' => 'standard', + 'executionsperrepo' => + [ + { + "repository_id"=>1, + "os"=>"linux", + "credits_consumed"=>5, + "minutes_consumed"=>10, + "repository"=> + { + "@type"=>"repository", + "@href"=>"/repo/1", + "@representation"=>"standard", + "@permissions"=> + { + "read"=>true, + "activate"=>false, + "deactivate"=>false, + "migrate"=>false, + "star"=>false, + "unstar"=>false, + "create_cron"=>false, + "create_env_var"=>false, + "create_key_pair"=>false, + "delete_key_pair"=>false, + "create_request"=>false, + "admin"=>false + }, + "id"=>1, + "name"=>"minimal", + "slug"=>"svenfuchs/minimal", + "description"=>nil, + "github_id"=>1, + "vcs_id"=>nil, + "vcs_type"=>"GithubRepository", + "github_language"=>nil, + "active"=>true, + "private"=>false, + "server_type" => 'git', + "owner"=>{"@type"=>"user", "id"=>1, "login"=>"svenfuchs", "@href"=>"/user/1", "ro_mode"=>false}, + "owner_name"=>"svenfuchs", + "vcs_name"=>"minimal", + "default_branch"=>{"@type"=>"branch", "@href"=>"/repo/1/branch/master", "@representation"=>"minimal", "name"=>"master"}, + "starred"=>false, + "managed_by_installation"=>false, + "active_on_org"=>nil, + "migration_status"=>nil, + "history_migration_status"=>nil, + "shared"=>false, + "config_validation"=>false + } + } + ] + }) + end + + it 'responds with list of executions per sender' do + get("/v3/owner/#{user.login}/executions_per_sender?from=#{from.to_s}&to=#{to.to_s}", {}, headers) + + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json({ + '@type' => 'executionspersender', + '@href' => "/v3/owner/travis-ci/executions_per_sender?from=#{from.to_s}&to=#{to.to_s}", + '@representation' => 'standard', + 'executionspersender' => + [ + { + "credits_consumed"=>5, + "minutes_consumed"=>10, + "sender_id"=>1, + "sender"=> + { + "@type"=>"user", + "@href"=>"/user/1", + "@representation"=>"standard", + "@permissions"=>{"read"=>true, "sync"=>false}, + "id"=>1, + "login"=>"svenfuchs", + "name"=>"Sven Fuchs", + "github_id"=>nil, + "vcs_id"=>nil, + "vcs_type"=>"GithubUser", + "avatar_url"=>"https://0.gravatar.com/avatar/07fb84848e68b96b69022d333ca8a3e2", + "education"=>nil, + "allow_migration"=>false, + "allowance"=> + { + "@type"=>"allowance", + "@representation"=>"minimal", + "id"=>1 + }, + "email"=>"sven@fuchs.com", + "is_syncing"=>nil, + "synced_at"=>nil, + "recently_signed_up"=>false, + "secure_user_hash"=>nil, + "ro_mode" => false, + "confirmed_at" => nil, + } + } + ]} + ) + end + end +end diff --git a/spec/v3/services/v2_subscription/invoices_spec.rb b/spec/v3/services/v2_subscription/invoices_spec.rb new file mode 100644 index 0000000000..ee931b634a --- /dev/null +++ b/spec/v3/services/v2_subscription/invoices_spec.rb @@ -0,0 +1,58 @@ +describe Travis::API::V3::Services::V2Subscription::Invoices, set_app: true, billing_spec_helper: true do + let(:parsed_body) { JSON.load(last_response.body) } + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + get('/v3/v2_subscriptions') + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:organization) { FactoryBot.create(:org, login: 'travis') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + let(:invoice_id) { "TP#{rand(999)}" } + let(:created_at) { '2018-04-17T18:30:32Z' } + let(:url) { 'https://billing-test.travis-ci.com/invoices/111.pdf' } + let(:amount_due) { 100 } + let(:status) { 'paid' } + let(:subscription_id) { rand(999) } + let(:cc_last_digits) { '4242' } + + before do + stub_billing_request(:get, "/v2/subscriptions/#{subscription_id}/invoices", auth_key: billing_auth_key, user_id: user.id) + .to_return(status: 200, body: JSON.dump([{'id' => invoice_id, 'created_at' => created_at, 'url' => url, 'amount_due' => amount_due, 'status' => status, 'cc_last_digits' => cc_last_digits }])) + end + + it 'responds with list of subscriptions' do + get("/v3/v2_subscription/#{subscription_id}/invoices", {}, headers) + + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json({ + '@type' => 'invoices', + '@representation' => 'standard', + '@href' => "/v3/v2_subscription/#{subscription_id}/invoices", + 'invoices' => [{ + '@type' => 'invoice', + '@representation' => 'standard', + 'id' => invoice_id, + 'created_at' => created_at, + 'url' => url, + 'amount_due' => amount_due, + 'status' => status, + 'cc_last_digits' => cc_last_digits + }] + }) + end + end +end diff --git a/spec/v3/services/v2_subscription/pay_spec.rb b/spec/v3/services/v2_subscription/pay_spec.rb new file mode 100644 index 0000000000..84c660e45d --- /dev/null +++ b/spec/v3/services/v2_subscription/pay_spec.rb @@ -0,0 +1,38 @@ +describe Travis::API::V3::Services::V2Subscription::Pay, set_app: true, billing_spec_helper: true do + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + let(:organization) { FactoryBot.create(:org, login: 'travis') } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + post('/v3/v2_subscription/123/pay', nil) + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}", + 'CONTENT_TYPE' => 'application/json' }} + let(:subscription_id) { rand(999) } + + let!(:stubbed_request) do + stub_billing_request(:post, "/v2/subscriptions/#{subscription_id}/pay", auth_key: billing_auth_key, user_id: user.id) + .to_return(status: 200, body: JSON.dump(billing_v2_subscription_response_body('id' => subscription_id, 'client_secret' => 'client_secret', 'owner' => { 'type' => 'Organization', 'id' => organization.id }))) + end + + it 'pays the subscription' do + post("/v3/v2_subscription/#{subscription_id}/pay", nil, headers) + + expect(last_response.status).to eq(200) + expect(stubbed_request).to have_been_made.once + end + end +end diff --git a/spec/v3/services/v2_subscription/update_address_spec.rb b/spec/v3/services/v2_subscription/update_address_spec.rb new file mode 100644 index 0000000000..2fa90e3b72 --- /dev/null +++ b/spec/v3/services/v2_subscription/update_address_spec.rb @@ -0,0 +1,57 @@ +describe Travis::API::V3::Services::V2Subscription::UpdateAddress, set_app: true, billing_spec_helper: true do + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + patch('/v3/v2_subscription/123/address', { }) + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}", + 'CONTENT_TYPE' => 'application/json' }} + let(:address_data) { { + 'address' => 'Rigaer Strasse', + 'first_name' => 'Travis', + 'last_name' => 'Schmidt', + 'company' => 'Travis', + 'city' => 'Berlin', + 'country' => 'Germany', + 'zip_code' => '10001', + 'billing_email' => 'travis@example.org' + } } + let(:subscription_id) { rand(999) } + + let!(:stubbed_request) do + stub_billing_request(:patch, "/v2/subscriptions/#{subscription_id}/address", auth_key: billing_auth_key, user_id: user.id) + .with(body: { + 'first_name' => 'Travis', + 'last_name' => 'Schmidt', + 'company' => 'Travis', + 'address' => 'Rigaer Strasse', + 'city' => 'Berlin', + 'country' => 'Germany', + 'zip_code' => '10001', + 'billing_email' => 'travis@example.org' + }) + .to_return(status: 204) + end + + it 'updates the address' do + patch("/v3/v2_subscription/#{subscription_id}/address", JSON.generate(address_data), headers) + + expect(last_response.status).to eq(204) + expect(stubbed_request).to have_been_made.once + end + end +end diff --git a/spec/v3/services/v2_subscription/update_creditcard_spec.rb b/spec/v3/services/v2_subscription/update_creditcard_spec.rb new file mode 100644 index 0000000000..9d67463795 --- /dev/null +++ b/spec/v3/services/v2_subscription/update_creditcard_spec.rb @@ -0,0 +1,39 @@ +describe Travis::API::V3::Services::V2Subscription::UpdateCreditcard, set_app: true, billing_spec_helper: true do + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + patch('/v3/v2_subscription/123/creditcard', { }) + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}", + 'CONTENT_TYPE' => 'application/json' }} + let(:creditcard_token) { { 'token' => 'token_from_stripe' } } + let(:subscription_id) { rand(999) } + + let!(:stubbed_request) do + stub_billing_request(:patch, "/v2/subscriptions/#{subscription_id}/creditcard", auth_key: billing_auth_key, user_id: user.id) + .with(body: { 'token' => 'token_from_stripe' }) + .to_return(status: 204) + end + + it 'updates the creditcard' do + patch("/v3/v2_subscription/#{subscription_id}/creditcard", JSON.generate(creditcard_token), headers) + + expect(last_response.status).to eq(204) + expect(stubbed_request).to have_been_made.once + end + end +end diff --git a/spec/v3/services/v2_subscription/update_plan_spec.rb b/spec/v3/services/v2_subscription/update_plan_spec.rb new file mode 100644 index 0000000000..f55519e8a6 --- /dev/null +++ b/spec/v3/services/v2_subscription/update_plan_spec.rb @@ -0,0 +1,39 @@ +describe Travis::API::V3::Services::V2Subscription::UpdatePlan, set_app: true, billing_spec_helper: true do + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + patch('/v3/v2_subscription/123/plan', { }) + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}", + 'CONTENT_TYPE' => 'application/json' }} + let(:plan_data) { { 'plan' => 'pro_tier_plan' } } + let(:subscription_id) { rand(999) } + + let!(:stubbed_request) do + stub_billing_request(:patch, "/v2/subscriptions/#{subscription_id}/plan", auth_key: billing_auth_key, user_id: user.id) + .with(body: { 'plan' => 'pro_tier_plan' }) + .to_return(status: 204) + end + + it 'updates the plan' do + patch("/v3/v2_subscription/#{subscription_id}/plan", JSON.generate(plan_data), headers) + + expect(last_response.status).to eq(204) + expect(stubbed_request).to have_been_made.once + end + end +end diff --git a/spec/v3/services/v2_subscriptions/all_spec.rb b/spec/v3/services/v2_subscriptions/all_spec.rb new file mode 100644 index 0000000000..c1796b6d94 --- /dev/null +++ b/spec/v3/services/v2_subscriptions/all_spec.rb @@ -0,0 +1,284 @@ +describe Travis::API::V3::Services::V2Subscriptions::All, set_app: true, billing_spec_helper: true do + let(:parsed_body) { JSON.load(last_response.body) } + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + get('/v3/v2_subscriptions') + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:organization) { FactoryBot.create(:org, login: 'travis') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + let(:plan) do + { + '@type': 'v2_plan_config', + '@representation': 'standard', + 'id': 'pro_tier_plan', + 'name': 'Pro Tier Plan', + 'private_repos': true, + 'starting_price': 30_000, + 'starting_users': 10_000, + 'private_credits': 500_000, + 'public_credits': 40_000, + 'trial_plan': false, + 'addon_configs' => { + 'free_tier_credits' => { + 'name' => 'Free 10 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_1234567890', + 'price_type' => 'fixed', + 'quantity' => 10_000, + 'standalone' => false, + 'type' => 'credit_private', + 'available_for_plans' => '%w[free_tier_plan]' + }, + 'oss_tier_credits' => { + 'name' => 'Free 40 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_0987654321', + 'price_type' => 'fixed', + 'quantity' => 40_000, + 'standalone' => false, + 'type' => 'credit_public', + 'private_repos' => false, + 'available_for_plans' => '%w[free_tier_plan standard_tier_plan pro_tier_plan]' + } + } + } + end + + let(:subscriptions_data) { [billing_v2_subscription_response_body('id' => 1234, 'client_secret' => 'client_secret', 'plan_config' => plan, 'permissions' => { 'read' => true, 'write' => false }, 'owner' => { 'type' => 'Organization', 'id' => organization.id })] } + let(:permissions_data) { [{'owner' => {'type' => 'Organization', 'id' => 1}, 'create' => true}] } + + let(:v2_response_body) { JSON.dump(plans: subscriptions_data, permissions: permissions_data) } + + let(:expected_json) do + { + '@type' => 'v2_subscriptions', + '@representation' => 'standard', + '@href' => '/v3/v2_subscriptions', + '@permissions' => permissions_data, + 'v2_subscriptions' => [{ + '@type' => 'v2_subscription', + '@representation' => 'standard', + 'id' => 1234, + 'canceled_at' => nil, + 'status' => nil, + 'valid_to' => nil, + 'scheduled_plan_name' => nil, + 'plan' => { + '@type' => 'v2_plan_config', + '@representation' => 'standard', + 'id' => 'pro_tier_plan', + 'name' => 'Pro Tier Plan', + 'concurrency_limit' => 20, + 'plan_type' => 'metered', + 'private_repos' => true, + 'starting_price' => 30_000, + 'starting_users' => 10_000, + 'private_credits' => 500_000, + 'public_credits' => 40_000, + 'annual' => false, + 'auto_refill_thresholds' => [10000, 50000, 100000], + 'auto_refill_amounts' => [ + { + 'amount' => 25000, + 'price' => 1500 + }, + { + 'amount' => 100000, + 'price' => 6000 + }, + { + 'amount' => 200000, + 'price' => 6000 + }, + { + 'amount' => 400000, + 'price' => 12000 + } + ], + 'trial_plan' => false, + 'available_standalone_addons' => [ + { + 'id' => 'credits_25k', + 'name' => '25 000 credits (2,5k Linux build minutes)', + 'price' => 1500, + 'quantity' => 25000, + 'type' => 'credit_private' + }, + { + 'id' => 'credits_500k', + 'name' => '500 000 credits (50k Linux build minutes)', + 'price' => 30000, + 'quantity' => 500000, + 'type' => 'credit_private' + } + ], + 'addon_configs' => { + 'free_tier_credits' => { + 'name' => 'Free 10 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_1234567890', + 'price_type' => 'fixed', + 'quantity' => 10_000, + 'standalone' => false, + 'type' => 'credit_private', + 'available_for_plans' => '%w[free_tier_plan]' + }, + 'oss_tier_credits' => { + 'name' => 'Free 40 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_0987654321', + 'price_type' => 'fixed', + 'quantity' => 40_000, + 'standalone' => false, + 'type' => 'credit_public', + 'private_repos' => false, + 'available_for_plans' => '%w[free_tier_plan standard_tier_plan pro_tier_plan]' + } + } + }, + 'auto_refill' => { + '@type' => 'auto_refill', + '@representation' => 'minimal', + 'addon_id' => nil, + 'enabled' => nil, + 'threshold' => 25000, + 'amount' => 10000 + }, + 'addons' => [ + { + '@type' => 'v2_addon', + '@representation' => 'minimal', + 'id' => '1', + 'name' => 'OSS Build Credits', + 'type' => 'credit_public', + 'recurring' => false, + 'current_usage' => { + '@type' => 'v2_addon_usage', + '@representation' => 'standard', + 'id' => 1, + 'addon_id' => 1, + 'addon_quantity' => 40_000, + 'addon_usage' => 0, + 'remaining' => 40_000, + 'purchase_date' => '2017-11-28T00:09:59.502Z', + 'valid_to' => '2017-12-28T00:09:59.502Z', + 'status' => 'subscribed', + 'active' => true + } + }, + { + '@type' => 'v2_addon', + '@representation' => 'minimal', + 'id' => 2, + 'name' => 'Build Credits', + 'type' => 'credit_private', + 'recurring' => false, + 'current_usage' => + { + '@type' => 'v2_addon_usage', + '@representation' => 'standard', + 'id' => 2, + 'addon_id' => 2, + 'addon_quantity' => 10_000, + 'addon_usage' => 0, + 'remaining' => 10_000, + 'purchase_date' => '2017-11-28T00:09:59.502Z', + 'valid_to' => '', + 'status' => 'subscribed', + 'active' => true + } + } + ], + 'source' => 'stripe', + 'owner' => { + '@type' => 'organization', + '@href' => "/v3/org/#{organization.id}", + '@representation' => 'minimal', + 'id' => organization.id, + 'vcs_type' => organization.vcs_type, + 'login' => 'travis', + 'name' => organization.name, + 'ro_mode' => true + }, + 'billing_info' => { + '@type' => 'v2_billing_info', + '@representation' => 'standard', + 'id' => 1234, + 'address' => 'Luis Spota', + 'address2' => '', + 'billing_email' => 'a.rosas10@gmail.com', + 'city' => 'Comala', + 'company' => '', + 'country' => 'Mexico', + 'first_name' => 'ana', + 'last_name' => 'rosas', + 'state' => nil, + 'vat_id' => '123456', + 'zip_code' => '28450', + 'has_local_registration' => false, + }, + 'credit_card_info' => { + '@type' => 'v2_credit_card_info', + '@representation' => 'standard', + 'id' => 1234, + 'card_owner' => 'ana', + 'expiration_date' => '9/2021', + 'last_digits' => '4242' + }, + 'client_secret' => 'client_secret', + 'payment_intent' => nil, + 'created_at' => '2017-11-28T00:09:59.502Z' + }] + } + end + + before do + stub_billing_request(:get, '/v2/subscriptions', auth_key: billing_auth_key, user_id: user.id) + .to_return(status: 200, body: v2_response_body) + end + + it 'responds with list of subscriptions' do + get('/v3/v2_subscriptions', {}, headers) + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json(expected_json) + end + + context 'with a null plan' do + let(:plan) { nil } + + it 'responds with a null plan' do + get('/v3/v2_subscriptions', {}, headers) + + expect(last_response.status).to eq(200) + expect(parsed_body['v2_subscriptions'][0].fetch('plan')).to eq(nil) + end + end + end +end diff --git a/spec/v3/services/v2_subscriptions/create_spec.rb b/spec/v3/services/v2_subscriptions/create_spec.rb new file mode 100644 index 0000000000..3f0434458e --- /dev/null +++ b/spec/v3/services/v2_subscriptions/create_spec.rb @@ -0,0 +1,378 @@ +describe Travis::API::V3::Services::V2Subscriptions::Create, set_app: true, billing_spec_helper: true do + let(:parsed_body) { JSON.load(last_response.body) } + let(:billing_url) { 'http://billingfake.travis-ci.com' } + let(:billing_auth_key) { 'secret' } + + before do + Travis.config.billing.url = billing_url + Travis.config.billing.auth_key = billing_auth_key + end + + context 'unauthenticated' do + it 'responds 403' do + get('/v3/v2_subscriptions') + + expect(last_response.status).to eq(403) + end + end + + context 'authenticated' do + let(:user) { FactoryBot.create(:user) } + let(:organization) { FactoryBot.create(:org, login: 'travis') } + let(:token) { Travis::Api::App::AccessToken.create(user: user, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}", + 'CONTENT_TYPE' => 'application/json' }} + let(:subscription_data) do + { + 'plan' => 'pro_tier_plan', + 'client_secret' => 'client_secret', + 'organization_id' => organization.id, + 'billing_info.first_name' => 'Travis', + 'billing_info.last_name' => 'Schmidt', + 'billing_info.company' => 'Travis', + 'billing_info.address' => 'Rigaer Strasse', + 'billing_info.city' => 'Berlin', + 'billing_info.country' => 'Germany', + 'billing_info.zip_code' => '10001', + 'billing_info.billing_email' => 'travis@example.org', + 'billing_info.state' => 'Alabama', + 'billing_info.has_local_registration' => true, + 'credit_card_info.token' => 'token_from_stripe' + } + end + + context 'billing app returns a successful response' do + let!(:stubbed_request) do + stub_billing_request(:post, '/v2/subscriptions', auth_key: billing_auth_key, user_id: user.id) + .with(body: { + 'plan' => 'pro_tier_plan', + 'client_secret' => 'client_secret', + 'coupon' => nil, + 'organization_id' => organization.id, + 'billing_info' => { + 'first_name' => 'Travis', + 'last_name' => 'Schmidt', + 'company' => 'Travis', + 'address' => 'Rigaer Strasse', + 'city' => 'Berlin', + 'country' => 'Germany', + 'zip_code' => '10001', + 'billing_email' => 'travis@example.org', + 'state' => 'Alabama', + 'has_local_registration' => true + }, + 'credit_card_info' => { + 'token' => 'token_from_stripe' + }, + 'v1_subscription_id': nil + }) + .to_return(status: 201, body: JSON.dump(billing_subscription_response_body( + 'id' => 1234, + 'owner' => { 'type' => 'Organization', 'id' => organization.id }, + 'canceled_at': nil, + 'valid_to': nil, + 'status': nil, + 'scheduled_plan': nil, + 'plan_config' => { + 'id' => 'pro_tier_plan', + 'name' => 'Pro Tier Plan', + 'plan_type' => 'metered', + 'concurrency_limit' => 20, + 'private_repos' => true, + 'starting_price' => 30_000, + 'starting_users' => 10_000, + 'private_credits' => 500_000, + 'public_credits' => 40_000, + 'annual' => false, + 'auto_refill_thresholds' => [10000, 50000, 100000], + 'auto_refill_amounts' => [ + { + 'amount' => 25000, + 'price' => 1500 + }, + { + 'amount' => 100000, + 'price' => 6000 + }, + { + 'amount' => 200000, + 'price' => 6000 + }, + { + 'amount' => 400000, + 'price' => 12000 + } + ], + 'trial_plan': false, + 'available_standalone_addons' => [ + { + 'id' => 'credits_25k', + 'name' => '25 000 credits (2,5k Linux build minutes)', + 'price' => 1500, + 'quantity' => 25000, + 'type' => 'credit_private' + }, + { + 'id' => 'credits_500k', + 'name' => '500 000 credits (50k Linux build minutes)', + 'price' => 30000, + 'quantity' => 500000, + 'type' => 'credit_private' + } + ], + 'addon_configs' => { + 'free_tier_credits' => { + 'name' => 'Free 10 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_1234567890', + 'price_type' => 'fixed', + 'quantity' => 10_000, + 'standalone' => false, + 'type' => 'credit_private', + 'available_for_plans' => '%w[free_tier_plan]' + }, + 'oss_tier_credits' => { + 'name' => 'Free 40 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_0987654321', + 'price_type' => 'fixed', + 'quantity' => 40_000, + 'standalone' => false, + 'type' => 'credit_public', + 'private_repos' => false, + 'available_for_plans' => '%w[free_tier_plan standard_tier_plan pro_tier_plan]' + } + } + }, + 'addons' => [{ + 'id': 7, + 'plan_id': 3, + "name": "OSS Build Credits", + 'addon_config_id': 'oss_tier_credits', + 'type': 'credit_public', + 'created_at': '2017-11-28T00:09:59.502Z', + 'updated_at': '2017-11-28T00:09:59.502Z', + 'current_usage_id': 7, + 'current_usage': { + 'id': 7, + 'addon_id': 7, + 'addon_quantity': 40_000, + 'addon_usage': 0, + 'remaining': 40_000, + 'purchase_date': '2017-11-28T00:09:59.502Z', + 'valid_to': '2017-11-28T00:09:59.502Z', + 'status': 'pending', + 'active': false, + 'created_at': '2017-11-28T00:09:59.502Z', + 'updated_at': '2017-11-28T00:09:59.502Z' + } + }], + 'discount' => nil, + 'client_secret' => 'client_secret', + 'billing_info' => { + 'first_name' => 'Travis', + 'last_name' => 'Schmidt', + 'company' => 'Travis', + 'address' => 'Rigaer Strasse', + 'address2' => nil, + 'city' => 'Berlin', + 'state' => nil, + 'country' => 'Germany', + 'vat_id' => nil, + 'zip_code' => '10001', + 'billing_email' => 'travis@example.org', + 'has_local_registration' => true, + }, + 'credit_card_info' => { + 'card_owner' => 'Travis Schmidt', + 'expiration_date' => '11/21', + 'last_digits' => '1111' + }))) + end + + it 'creates the subscription and responds with its representation' do + post('/v3/v2_subscriptions', JSON.dump(subscription_data), headers) + + expect(last_response.status).to eq(201) + expect(parsed_body).to eql_json({ + '@type' => 'v2_subscription', + '@representation' => 'standard', + 'id' => 1234, + 'created_at' => '2017-11-28T00:09:59.502Z', + 'canceled_at' => nil, + 'status' => nil, + 'valid_to' => nil, + 'scheduled_plan_name' => nil, + 'plan' => { + '@type' => 'v2_plan_config', + '@representation' => 'standard', + 'id' => 'pro_tier_plan', + 'name' => 'Pro Tier Plan', + 'private_repos' => true, + 'starting_users' => 10_000, + 'starting_price' => 30_000, + 'private_credits' => 500_000, + 'public_credits' => 40_000, + 'concurrency_limit' => 20, + 'plan_type' => 'metered', + 'annual' => false, + 'auto_refill_thresholds' => [10000, 50000, 100000], + 'auto_refill_amounts' => [ + { + 'amount' => 25000, + 'price' => 1500 + }, + { + 'amount' => 100000, + 'price' => 6000 + }, + { + 'amount' => 200000, + 'price' => 6000 + }, + { + 'amount' => 400000, + 'price' => 12000 + } + ], + 'trial_plan' => false, + 'available_standalone_addons' => [ + { + 'id' => 'credits_25k', + 'name' => '25 000 credits (2,5k Linux build minutes)', + 'price' => 1500, + 'quantity' => 25000, + 'type' => 'credit_private' + }, + { + 'id' => 'credits_500k', + 'name' => '500 000 credits (50k Linux build minutes)', + 'price' => 30000, + 'quantity' => 500000, + 'type' => 'credit_private' + } + ], + 'addon_configs' => { + 'free_tier_credits' => { + 'name' => 'Free 10 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_1234567890', + 'price_type' => 'fixed', + 'quantity' => 10_000, + 'standalone' => false, + 'type' => 'credit_private', + 'available_for_plans' => '%w[free_tier_plan]' + }, + 'oss_tier_credits' => { + 'name' => 'Free 40 000 credits (renewed monthly)', + 'expires' => true, + 'expires_in' => 1, + 'renew_after_expiration' => true, + 'price' => 0, + 'price_id' => 'price_0987654321', + 'price_type' => 'fixed', + 'quantity' => 40_000, + 'standalone' => false, + 'type' => 'credit_public', + 'private_repos' => false, + 'available_for_plans' => '%w[free_tier_plan standard_tier_plan pro_tier_plan]' + } + } + }, + 'auto_refill' => { + '@type' => 'auto_refill', + '@representation' => 'minimal', + 'addon_id' => nil, + 'enabled' => nil, + 'threshold' => 25000, + 'amount' => 10000 + }, + 'addons' => [{ + '@type' => 'v2_addon', + '@representation' => 'minimal', + 'id' => 7, + 'name' => 'OSS Build Credits', + 'type' => 'credit_public', + 'recurring' => nil, + 'current_usage' => { + '@type' => 'v2_addon_usage', + '@representation' => 'standard', + 'id' => 7, + 'addon_id' => 7, + 'addon_quantity' => 40_000, + 'addon_usage' => 0, + 'purchase_date' => '2017-11-28T00:09:59.502Z', + 'valid_to' => '2017-11-28T00:09:59.502Z', + 'remaining' => 40_000, + 'status' => 'pending', + 'active' => false + } + }], + 'client_secret' => 'client_secret', + 'source' => 'stripe', + 'billing_info' => { + '@type' => 'v2_billing_info', + '@representation' => 'standard', + 'id' => 1234, + 'first_name' => 'Travis', + 'last_name' => 'Schmidt', + 'company' => 'Travis', + 'billing_email' => 'travis@example.org', + 'zip_code' => '10001', + 'address' => 'Rigaer Strasse', + 'address2' => nil, + 'city' => 'Berlin', + 'state' => nil, + 'country' => 'Germany', + 'vat_id' => nil, + 'has_local_registration' => true, + }, + 'credit_card_info' => { + 'id' => 1234, + '@type' => 'v2_credit_card_info', + '@representation' => 'standard', + 'card_owner' => 'Travis Schmidt', + 'last_digits' => '1111', + 'expiration_date' => '11/21' + }, + 'owner' => { + '@type' => 'organization', + '@representation' => 'minimal', + '@href' => "/v3/org/#{organization.id}", + 'id' => organization.id, + 'vcs_type' => organization.vcs_type, + 'name' => organization.name, + 'login' => 'travis', + 'ro_mode' => true + }, + 'payment_intent' => nil, + }) + expect(stubbed_request).to have_been_made.once + end + end + + context 'billing app returns an error' do + let!(:stubbed_request) do + stub_billing_request(:post, '/v2/subscriptions', auth_key: billing_auth_key, user_id: user.id) + .to_return(status: 422, body: JSON.dump(error: 'This is the error message from the billing app')) + end + + it 'responds with the same error' do + post('/v3/v2_subscriptions', JSON.dump(subscription_data), headers) + + expect(last_response.status).to eq(422) + expect(parsed_body).to eql_json('@type' => 'error', + 'error_type' => 'unprocessable_entity', 'error_message' => 'This is the error message from the billing app') + end + end + end +end From cd697da6f759f0cc272543ba48a35c6952a5045e Mon Sep 17 00:00:00 2001 From: gabriel-arc <57348209+GbArc@users.noreply.github.com> Date: Wed, 28 Dec 2022 10:21:08 +0100 Subject: [PATCH 25/46] sinatra up to 2.2.3 (#1264) --- Gemfile | 2 +- Gemfile.lock | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index 9620afa0a5..3cca1571e6 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'travis-lock', git: 'https://github.com/travis-ci/travis-lock/', branch: gem 'travis-github_apps', git: 'https://github.com/travis-ci/travis-github_apps', branch: 'ga-ext_access' gem 'travis-rollout', '~> 0.0.2' -gem 'sinatra' +gem 'sinatra', '~> 2' gem 'sinatra-contrib', require: nil #git: 'https://github.com/sinatra/sinatra-contrib', require: nil gem 'simple_states', git: 'https://github.com/travis-ci/simple_states', branch: '6.1' diff --git a/Gemfile.lock b/Gemfile.lock index 169e35c7f6..28daee6561 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -299,7 +299,7 @@ GEM msgpack (1.4.5) multi_json (1.15.0) multipart-post (2.2.3) - mustermann (1.1.1) + mustermann (2.0.2) ruby2_keywords (~> 0.0.1) nakayoshi_fork (0.0.4) net-http-persistent (2.9.4) @@ -330,12 +330,12 @@ GEM pusher-signature (~> 0.1.8) pusher-signature (0.1.8) racc (1.6.0) - rack (2.2.3.1) + rack (2.2.4) rack-attack (5.4.2) rack (>= 1.0, < 3) rack-contrib (2.3.0) rack (~> 2.0) - rack-protection (2.2.0) + rack-protection (2.2.3) rack rack-ssl (1.4.1) rack @@ -398,20 +398,20 @@ GEM simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) - sinatra (2.2.0) - mustermann (~> 1.0) + sinatra (2.2.3) + mustermann (~> 2.0) rack (~> 2.2) - rack-protection (= 2.2.0) + rack-protection (= 2.2.3) tilt (~> 2.0) - sinatra-contrib (2.2.0) + sinatra-contrib (2.2.3) multi_json - mustermann (~> 1.0) - rack-protection (= 2.2.0) - sinatra (= 2.2.0) + mustermann (~> 2.0) + rack-protection (= 2.2.3) + sinatra (= 2.2.3) tilt (~> 2.0) stackprof (0.2.17) thread_safe (0.3.6) - tilt (2.0.10) + tilt (2.0.11) timecop (0.9.4) tool (0.2.3) travis-rollout (0.0.2) @@ -505,7 +505,7 @@ DEPENDENCIES sidekiq (~> 6.4.0) simple_states! simplecov - sinatra + sinatra (~> 2) sinatra-contrib stackprof timecop From 415f12cf953050a7d31a76261c795d70a9780163 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Wed, 11 Jan 2023 15:39:35 +0100 Subject: [PATCH 26/46] bump travis-lock, travis-settings --- Gemfile | 2 +- Gemfile.lock | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Gemfile b/Gemfile index 3cca1571e6..060f46b7f0 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem 'mime-types' gem 'travis-support', git: 'https://github.com/travis-ci/travis-support', ref: '4dda53ffa96b804db22c261551256caa18c4a2cc' gem 'travis-amqp', git: 'https://github.com/travis-ci/travis-amqp' gem 'travis-config', git: 'https://github.com/travis-ci/travis-config', branch: 'fix-docker-redis-url' -gem 'travis-settings', git: 'https://github.com/travis-ci/travis-settings' +gem 'travis-settings', git: 'https://github.com/travis-ci/travis-settings', branch: '6.1' gem 'travis-lock', git: 'https://github.com/travis-ci/travis-lock/', branch: '6.1' gem 'travis-github_apps', git: 'https://github.com/travis-ci/travis-github_apps', branch: 'ga-ext_access' gem 'travis-rollout', '~> 0.0.2' diff --git a/Gemfile.lock b/Gemfile.lock index 28daee6561..9c28bee3b7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -77,17 +77,18 @@ GIT GIT remote: https://github.com/travis-ci/travis-lock/ - revision: 1dbed2874330d5d24c1dcdb9143ecf9a5eb041a9 + revision: e5d38061f92a133488aeca9078c8ba2b11659377 branch: 6.1 specs: travis-lock (0.1.1) GIT remote: https://github.com/travis-ci/travis-settings - revision: debef595a6a54b082176edba630fdb5ee9d705af + revision: 9d6f936fd5eb3431162d82783e7ca3f64d22db95 + branch: 6.1 specs: - travis-settings (0.0.1) - activemodel + travis-settings (0.0.2) + activemodel (~> 6.1.6.1) virtus GIT @@ -294,7 +295,7 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2022.0105) mini_portile2 (2.8.0) - minitest (5.16.3) + minitest (5.17.0) mocha (1.13.0) msgpack (1.4.5) multi_json (1.15.0) @@ -437,7 +438,7 @@ GEM webrick (1.7.0) yard (0.9.27) webrick (~> 1.7.0) - zeitwerk (2.6.0) + zeitwerk (2.6.6) PLATFORMS ruby From fe488474c93f0c9f58ad40d60834c350eb4456d7 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Wed, 11 Jan 2023 16:46:59 +0100 Subject: [PATCH 27/46] simplecov moved to test group --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 060f46b7f0..f9e2c736c5 100644 --- a/Gemfile +++ b/Gemfile @@ -31,7 +31,6 @@ gem 'http', '~> 4' gem 'metriks', '0.9.9.6' gem 'metriks-librato_metrics', git: 'https://github.com/eric/metriks-librato_metrics' gem 'librato-metrics' -gem 'simplecov' gem 'stackprof' gem "ipaddress", "~> 0.8.3" gem 'nakayoshi_fork' @@ -89,6 +88,7 @@ group :test do gem 'hashdiff' gem 'pry-byebug' gem 'rack-test' + gem 'simplecov' end group :development do From edfd3a7225cecb0a63f3e87581c38222e2f17de8 Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Mon, 30 Jan 2023 11:51:06 +0100 Subject: [PATCH 28/46] sinatra bump to 2.2.4, hostname added for cache queries --- Gemfile.lock | 14 +++++++------- lib/travis/api/v3/remote_query.rb | 1 + lib/travis/services/find_caches.rb | 2 ++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9c28bee3b7..58454f6f83 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -331,12 +331,12 @@ GEM pusher-signature (~> 0.1.8) pusher-signature (0.1.8) racc (1.6.0) - rack (2.2.4) + rack (2.2.6.2) rack-attack (5.4.2) rack (>= 1.0, < 3) rack-contrib (2.3.0) rack (~> 2.0) - rack-protection (2.2.3) + rack-protection (2.2.4) rack rack-ssl (1.4.1) rack @@ -399,16 +399,16 @@ GEM simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) - sinatra (2.2.3) + sinatra (2.2.4) mustermann (~> 2.0) rack (~> 2.2) - rack-protection (= 2.2.3) + rack-protection (= 2.2.4) tilt (~> 2.0) - sinatra-contrib (2.2.3) + sinatra-contrib (2.2.4) multi_json mustermann (~> 2.0) - rack-protection (= 2.2.3) - sinatra (= 2.2.3) + rack-protection (= 2.2.4) + sinatra (= 2.2.4) tilt (~> 2.0) stackprof (0.2.17) thread_safe (0.3.6) diff --git a/lib/travis/api/v3/remote_query.rb b/lib/travis/api/v3/remote_query.rb index 67b223fa13..3c8bdab2c5 100644 --- a/lib/travis/api/v3/remote_query.rb +++ b/lib/travis/api/v3/remote_query.rb @@ -83,6 +83,7 @@ def s3_connection aws_secret_access_key: s3_config[:secret_access_key], provider: 'AWS', region: s3_config[:region], + host: s3_config[:hostname], instrumentor: ActiveSupport::Notifications, connection_options: { instrumentor: ActiveSupport::Notifications } ) diff --git a/lib/travis/services/find_caches.rb b/lib/travis/services/find_caches.rb index e38adcf921..b1b601465a 100644 --- a/lib/travis/services/find_caches.rb +++ b/lib/travis/services/find_caches.rb @@ -147,6 +147,8 @@ def fetch_s3(cache_objects, options) aws_access_key_id: config[:access_key_id], aws_secret_access_key: config[:secret_access_key], provider: 'AWS', + host: config[:hostname], + region: config[:region], instrumentor: ActiveSupport::Notifications, connection_options: { instrumentor: ActiveSupport::Notifications }) bucket = svc.directories.get(config[:bucket_name], options) From 22f789321b3e7f51d2ac557f812ebcdf8b7ce60b Mon Sep 17 00:00:00 2001 From: gabriel-arc Date: Thu, 2 Feb 2023 13:15:05 +0100 Subject: [PATCH 29/46] activesupport up to 6.1.7.2 --- Gemfile | 2 +- Gemfile.lock | 26 +++++++++---------- .../active_record/predicate_builder.rb | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Gemfile b/Gemfile index f9e2c736c5..2381ca8ccf 100644 --- a/Gemfile +++ b/Gemfile @@ -65,7 +65,7 @@ gem 'google-api-client', '~> 0.9.4' gem 'google-protobuf', '~> 3.19.6' gem 'fog-aws', '~> 0.12.0' gem 'fog-google', '~> 0.4.2' -gem 'activerecord', '~> 6.1.6.1' +gem 'activerecord', '~> 6.1.7.2' gem 'rollout', '~> 1.1.0' gem 'coder', '~> 0.4.0' gem 'virtus', '~> 1.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 58454f6f83..c1b2f888ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -43,11 +43,11 @@ GIT GIT remote: https://github.com/travis-ci/simple_states - revision: b7dffc715181e54313784b315f6b7df795d01db4 + revision: 458685f90e64639a6dc5e49081b3275777ed9edb branch: 6.1 specs: simple_states (1.0.2) - activesupport (~> 6.1.6.1) + activesupport (~> 6.1.7.2) GIT remote: https://github.com/travis-ci/travis-amqp @@ -84,11 +84,11 @@ GIT GIT remote: https://github.com/travis-ci/travis-settings - revision: 9d6f936fd5eb3431162d82783e7ca3f64d22db95 + revision: dd614292ede63952f75d5f78594a23e5e05a862a branch: 6.1 specs: travis-settings (0.0.2) - activemodel (~> 6.1.6.1) + activemodel (~> 6.1.7.1) virtus GIT @@ -104,12 +104,12 @@ GEM active_model_serializers (0.9.8) activemodel (>= 3.2) concurrent-ruby (~> 1.0) - activemodel (6.1.6.1) - activesupport (= 6.1.6.1) - activerecord (6.1.6.1) - activemodel (= 6.1.6.1) - activesupport (= 6.1.6.1) - activesupport (6.1.6.1) + activemodel (6.1.7.2) + activesupport (= 6.1.7.2) + activerecord (6.1.7.2) + activemodel (= 6.1.7.2) + activesupport (= 6.1.7.2) + activesupport (6.1.7.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -136,7 +136,7 @@ GEM descendants_tracker (~> 0.0.1) composite_primary_keys (13.0.3) activerecord (~> 6.1.0) - concurrent-ruby (1.1.10) + concurrent-ruby (1.2.0) connection_pool (2.2.5) crack (0.4.5) rexml @@ -416,7 +416,7 @@ GEM timecop (0.9.4) tool (0.2.3) travis-rollout (0.0.2) - tzinfo (2.0.5) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.0.15) unf (0.1.4) @@ -445,7 +445,7 @@ PLATFORMS DEPENDENCIES active_model_serializers (~> 0.9.8) - activerecord (~> 6.1.6.1) + activerecord (~> 6.1.7.2) addressable (~> 2.8.0) allocation_tracer bunny (~> 2.9.2) diff --git a/lib/patches/active_record/predicate_builder.rb b/lib/patches/active_record/predicate_builder.rb index 134a213a6b..c9ec1dc90b 100644 --- a/lib/patches/active_record/predicate_builder.rb +++ b/lib/patches/active_record/predicate_builder.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -EXPECTED_AR_VERSION = '6.1.6.1'.freeze +EXPECTED_AR_VERSION = '6.1.7.2'.freeze ACTUAL_AR_VERSION = "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}.#{ActiveRecord::VERSION::TINY}.#{ActiveRecord::VERSION::PRE}" if EXPECTED_AR_VERSION != ACTUAL_AR_VERSION From fedd96cf59399df556febad7eb3eca9e9364b778 Mon Sep 17 00:00:00 2001 From: GbArc Date: Fri, 26 May 2023 09:50:51 +0200 Subject: [PATCH 30/46] managing email subscriptions for whole org --- lib/travis/api/v3/queries/email_subscription.rb | 12 ++++++++++++ lib/travis/api/v3/routes.rb | 6 ++++++ .../v3/services/email_subscription/resubscribe.rb | 9 +++++++++ .../v3/services/email_subscription/unsubscribe.rb | 9 +++++++++ 4 files changed, 36 insertions(+) diff --git a/lib/travis/api/v3/queries/email_subscription.rb b/lib/travis/api/v3/queries/email_subscription.rb index f034217752..917d2cc9b9 100644 --- a/lib/travis/api/v3/queries/email_subscription.rb +++ b/lib/travis/api/v3/queries/email_subscription.rb @@ -7,5 +7,17 @@ def unsubscribe(user, repository) def resubscribe(user, repository) repository.email_unsubscribes.where(user: user).destroy_all end + + def unsubscribe_organization(user, organization) + organization.repositories.each do |repo| + repo.email_unsubscribes.find_or_create_by!(user: user) #if repo.permissions.find_by(user_id: user.id) + end + end + + def resubscribe_organization(user, organization) + organization.repositories.each do |repo| + repo.email_unsubscribes.where(user: user).destroy_all + end + end end end diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb index 0093174416..41f478acde 100644 --- a/lib/travis/api/v3/routes.rb +++ b/lib/travis/api/v3/routes.rb @@ -113,6 +113,12 @@ module Routes get :find_for_organization patch :update_for_organization end + + resource :email_subscription do + route '/email_subscription' + delete :unsubscribe + post :resubscribe + end end resource :organizations do diff --git a/lib/travis/api/v3/services/email_subscription/resubscribe.rb b/lib/travis/api/v3/services/email_subscription/resubscribe.rb index e984ca8841..207a03a09e 100644 --- a/lib/travis/api/v3/services/email_subscription/resubscribe.rb +++ b/lib/travis/api/v3/services/email_subscription/resubscribe.rb @@ -1,11 +1,20 @@ module Travis::API::V3 class Services::EmailSubscription::Resubscribe < Service def run! + return run_for_org if params.include?('organization.id') + repository = check_login_and_find(:repository) return repo_migrated if migrated?(repository) query.resubscribe(access_control.user, repository) no_content end + + def run_for_org + organization = check_login_and_find(:organization) + + query.resubscribe_organization(access_control.user, organization) + no_content + end end end diff --git a/lib/travis/api/v3/services/email_subscription/unsubscribe.rb b/lib/travis/api/v3/services/email_subscription/unsubscribe.rb index 306d0b6b44..e08ddbad45 100644 --- a/lib/travis/api/v3/services/email_subscription/unsubscribe.rb +++ b/lib/travis/api/v3/services/email_subscription/unsubscribe.rb @@ -1,11 +1,20 @@ module Travis::API::V3 class Services::EmailSubscription::Unsubscribe < Service def run! + return run_for_org if params.include?('organization.id') + repository = check_login_and_find(:repository) return repo_migrated if migrated?(repository) query.unsubscribe(access_control.user, repository) no_content end + + def run_for_org + organization = check_login_and_find(:organization) + + query.unsubscribe_organization(access_control.user, organization) + no_content + end end end From 9deeb7122c7d8632098765dde545437211effac0 Mon Sep 17 00:00:00 2001 From: vitalie Date: Mon, 26 Jun 2023 18:55:53 +0100 Subject: [PATCH 31/46] Update gem database_cleaner --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c1b2f888ad..e570bdc134 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -141,9 +141,9 @@ GEM crack (0.4.5) rexml dalli (3.2.1) - database_cleaner (2.0.1) - database_cleaner-active_record (~> 2.0.0) - database_cleaner-active_record (2.0.1) + database_cleaner (2.0.2) + database_cleaner-active_record (>= 2, < 3) + database_cleaner-active_record (2.1.0) activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) From 09ac6dd96e8ef4757b6f460ac9faef779f0fdfdc Mon Sep 17 00:00:00 2001 From: piccadilly-circus <134370605+piccadilly-circus@users.noreply.github.com> Date: Mon, 28 Aug 2023 15:08:53 +0500 Subject: [PATCH 32/46] Fix for SUPP-725 ship:docker (#1295) --- lib/travis/remote_log.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/travis/remote_log.rb b/lib/travis/remote_log.rb index 8080b048c1..b012c6c02e 100644 --- a/lib/travis/remote_log.rb +++ b/lib/travis/remote_log.rb @@ -105,7 +105,7 @@ def as_json(chunked: false, after: nil, part_numbers: []) part_numbers: part_numbers ).map(&:as_json) else - ret['body'] = archived_log_content || content + ret['body'] = archived? ? archived_log_content : content end { 'log' => ret } From ab08a8cb692649ff845f5969d2ec76da8f9ab62e Mon Sep 17 00:00:00 2001 From: Andrii Mysko Date: Wed, 21 Feb 2024 08:40:03 +0200 Subject: [PATCH 33/46] [BSFY-277] Add tag_name to build request (#1305) * Add tag_name to build request * Restrict ruby gem-update version --------- Co-authored-by: piccadilly-circus <134370605+piccadilly-circus@users.noreply.github.com> --- .travis.yml | 1 + lib/travis/api/v3/queries/request.rb | 3 ++- spec/v3/services/requests/create_spec.rb | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2a9ed5028b..2b9106bc0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,7 @@ services: - redis-server before_install: + - 'gem install rubygems-update -v 3.4.22' - 'gem update --system' jobs: diff --git a/lib/travis/api/v3/queries/request.rb b/lib/travis/api/v3/queries/request.rb index 5b80b00d76..d70265d51b 100644 --- a/lib/travis/api/v3/queries/request.rb +++ b/lib/travis/api/v3/queries/request.rb @@ -1,6 +1,6 @@ module Travis::API::V3 class Queries::Request < Query - params :id, :message, :branch, :sha, :merge_mode, :config, :configs, :token, prefix: :request + params :id, :message, :branch, :sha, :tag_name, :merge_mode, :config, :configs, :token, prefix: :request def find raise WrongParams, 'missing request.id'.freeze unless id @@ -36,6 +36,7 @@ def schedule(repository, user) id: request.id, message: message, branch: branch || repository.default_branch.name, + tag_name: tag_name, sha: sha, configs: request_configs, # BC, remove once everyone is on yml/configs, coordinate with Gatekeeper diff --git a/spec/v3/services/requests/create_spec.rb b/spec/v3/services/requests/create_spec.rb index ea6832ae7e..ddaf00eff6 100644 --- a/spec/v3/services/requests/create_spec.rb +++ b/spec/v3/services/requests/create_spec.rb @@ -135,6 +135,7 @@ message: nil, branch: 'master', sha: nil, + tag_name: nil, merge_mode: nil, config: nil, configs: nil @@ -272,6 +273,11 @@ def compact(hash) it { expect(sidekiq_payload).to eq payload.merge(sha: params[:sha]) } end + describe 'overriding tag_name (in request)' do + let(:params) { { request: { tag_name: 'v1.0' } } } + it { expect(sidekiq_payload).to eq payload.merge(tag_name: params[:request][:tag_name]) } + end + describe 'when the repository is inactive' do before { repo.update!(active: false) } before { post("/v3/repo/#{repo.id}/requests", {}, headers) } From b3b45c174863678260aea7fed0fed609ee9a677b Mon Sep 17 00:00:00 2001 From: Sebastian Karpeta Date: Wed, 20 Mar 2024 14:25:19 +0100 Subject: [PATCH 34/46] API merge. Enterprise to master. --- Gemfile | 25 +- Gemfile.lock | 686 ------------------ .../api/enqueue/services/restart_model.rb | 2 - lib/travis/api/v3/billing_client.rb | 24 - lib/travis/api/v3/proxy_service.rb | 2 +- lib/travis/api/v3/renderer/allowance.rb | 3 +- .../v3/services/v2_subscriptions/create.rb | 2 +- lib/travis/config/defaults.rb | 4 +- lib/travis/model/organization.rb | 4 - spec/lib/github/services/set_key_spec.rb | 4 +- spec/support/billing_spec_helper.rb | 112 --- spec/support/s3.rb | 12 +- spec/v3/billing_client_spec.rb | 12 - 13 files changed, 26 insertions(+), 866 deletions(-) delete mode 100644 Gemfile.lock diff --git a/Gemfile b/Gemfile index 9ea0db707f..82254ad2c7 100644 --- a/Gemfile +++ b/Gemfile @@ -9,13 +9,16 @@ gem 'travis-support', git: 'https://github.com/travis-ci/travis-support', ref: gem 'travis-amqp', git: 'https://github.com/travis-ci/travis-amqp' gem 'travis-config', git: 'https://github.com/travis-ci/travis-config' gem 'travis-settings', git: 'https://github.com/travis-ci/travis-settings', branch: 'master' -gem 'travis-lock', git: 'https://github.com/travis-ci/travis-lock/', branch: '6.1' -gem 'travis-github_apps', git: 'https://github.com/travis-ci/travis-github_apps', branch: 'ga-ext_access' +gem 'travis-lock', git: 'https://github.com/travis-ci/travis-lock/', branch: 'master' +gem 'travis-github_apps', git: 'https://github.com/travis-ci/travis-github_apps', branch: 'master' gem 'travis-rollout', git: 'https://github.com/travis-ci/travis-rollout' gem 'simple_states', git: 'https://github.com/travis-ci/simple_states', branch: 'prd-ruby-upgrade-dev' +gem 'metriks', git: 'https://github.com/travis-ci/metriks' +gem 'metriks-librato_metrics', git: 'https://github.com/travis-ci/metriks-librato_metrics' gem 'marginalia', git: 'https://github.com/travis-ci/marginalia' -gem 'gh', git: 'https://github.com/travis-ci/gh' +gem 'gh', git: 'https://github.com/travis-ci/gh', branch: 'master' gem 'rollout', git: 'https://github.com/travis-ci/rollout' +gem 'mustermann' gem 'sinatra', '~> 2' gem 'sinatra-contrib', require: nil #git: 'https://github.com/sinatra/sinatra-contrib', require: nil @@ -31,28 +34,26 @@ gem 'bunny', '~> 2.22' gem 'dalli' gem 'pry' gem 'http', '~> 4' -gem 'metriks', '0.9.9.6' -gem 'metriks-librato_metrics', git: 'https://github.com/eric/metriks-librato_metrics' gem 'librato-metrics' gem 'stackprof' gem "ipaddress", "~> 0.8.3" gem 'nakayoshi_fork' -gem 'sidekiq', '~> 6.4.0' +gem 'sidekiq', '~> 7' gem 'redis-namespace' gem 'rbtrace' gem 'memory_profiler' -gem 'allocation_tracer' +#gem 'allocation_tracer' gem 'redlock' -gem 'rake', '~> 13.0.6' +gem 'rake', '~> 13.0' gem 'libhoney' gem 'opencensus' gem 'opencensus-stackdriver' -gem 'faraday' -gem 'faraday-net_http_persistent' +gem 'faraday', '~>2' +gem 'faraday-net_http_persistent', '~>2' gem 'knapsack' @@ -64,10 +65,8 @@ gem 'useragent' gem 'tool' gem 'google-cloud-storage' gem 'aws-sdk-s3' -gem 'activerecord', '~> 7.0.8' # it was fixed in predicate_builder file to 7.0.6 but gh gem requires 7.0.8 +gem 'activerecord', '~> 7.0.6' # it was fixed in predicate_builder file to 7.0.6 but gh gem requires 7.0.8 gem 'google-protobuf', '~> 3.19.6' -gem 'fog-aws', '~> 0.12.0' -gem 'fog-google' gem 'coder', '~> 0.4.0' gem 'dry-types' gem 'dry-struct' diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 0a6bf92129..0000000000 --- a/Gemfile.lock +++ /dev/null @@ -1,686 +0,0 @@ -GIT - remote: https://github.com/eric/metriks-librato_metrics - revision: 3acb88b36c014a8b93bdd91a867c1b3db781ad4e - specs: - metriks-librato_metrics (1.0.6) - metriks (>= 0.9.9.6) - -GIT - remote: https://github.com/rkh/yard-sinatra - revision: 5705d6e2bd8e4546a17a5d25eb97df5ed0f63500 - specs: - yard-sinatra (1.0.0) - yard (~> 0.7) - -GIT - remote: https://github.com/rtomayko/rack-cache - revision: 07ff2f8d61379e0f54464928baf5f1cc3d94039c - specs: - rack-cache (1.13.0) - rack (>= 0.4) - -GIT - remote: https://github.com/travis-ci/gh - revision: 3319c500df8b8bdde82ee7c330cc7f971fee2c20 - specs: - gh (0.15.1) - addressable (~> 2.8.0) - backports - faraday (~> 1.0) - multi_json (~> 1.0) - net-http-persistent (~> 2.9) - net-http-pipeline - -GIT - remote: https://github.com/travis-ci/marginalia - revision: 07f19a9ee5869a4557437a9f24608c7b1c4275bf - specs: - marginalia (1.6.0) - pg (~> 1.3) - -GIT - remote: https://github.com/travis-ci/rollout - revision: ec4db3ae6bbf8cf56ce4adce0814247c46195a0e - specs: - rollout (3.0.0) - redis (~> 5.0) - -GIT - remote: https://github.com/travis-ci/simple_states - revision: 1112afaf7bbbe51a6fdf8abae769ef827ab3bfd8 - branch: prd-ruby-upgrade-dev - specs: - simple_states (1.0.2) - activesupport (~> 7.0) - -GIT - remote: https://github.com/travis-ci/travis-amqp - revision: 69e72f432436eca5d39991255d5cc3b45c1035e6 - specs: - travis-amqp (0.0.3) - -GIT - remote: https://github.com/travis-ci/travis-config - revision: 601e9a6dcb799dc14944c40153c60aaf935629ee - specs: - travis-config (2.0.0) - hashr (~> 2.0) - -GIT - remote: https://github.com/travis-ci/travis-github_apps - revision: 929dadf0b4f60ca4240d52a11fc032917ff3f83a - branch: ga-ext_access - specs: - travis-github_apps (0.2.1) - activesupport (>= 3.2) - faraday - faraday_middleware - jwt - redis - -GIT - remote: https://github.com/travis-ci/travis-lock - revision: e5d38061f92a133488aeca9078c8ba2b11659377 - branch: 6.1 - specs: - travis-lock (0.1.1) - -GIT - remote: https://github.com/travis-ci/travis-rollout - revision: 4e89a17a4b5ca1f6269fb8bc1d067faabc49ac92 - specs: - travis-rollout (0.1.0) - -GIT - remote: https://github.com/travis-ci/travis-settings - revision: 7e48e09c1df1c95abaf13a0dcec78bdfab9f86ee - branch: master - specs: - travis-settings (0.1.0) - activemodel - virtus - -GIT - remote: https://github.com/travis-ci/travis-support - revision: 4dda53ffa96b804db22c261551256caa18c4a2cc - ref: 4dda53ffa96b804db22c261551256caa18c4a2cc - specs: - travis-support (0.0.1) - -GEM - remote: https://rubygems.org/ - specs: - active_model_serializers (0.9.9) - activemodel (>= 3.2) - concurrent-ruby (~> 1.0) - activemodel (7.0.8.1) - activesupport (= 7.0.8.1) - activerecord (7.0.8.1) - activemodel (= 7.0.8.1) - activesupport (= 7.0.8.1) - activesupport (7.0.8.1) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) - aggregate (0.2.4) - allocation_tracer (0.6.3) - amq-protocol (2.3.2) - ansi (1.5.0) - ast (2.4.2) - atomic (1.1.101) - avl_tree (1.1.3) - aws-eventstream (1.3.0) - aws-partitions (1.899.0) - aws-sdk-core (3.191.4) - aws-eventstream (~> 1, >= 1.3.0) - aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.8) - jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.78.0) - aws-sdk-core (~> 3, >= 3.191.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.146.0) - aws-sdk-core (~> 3, >= 3.191.0) - aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) - aws-eventstream (~> 1, >= 1.0.2) - axiom-types (0.1.1) - descendants_tracker (~> 0.0.4) - ice_nine (~> 0.11.0) - thread_safe (~> 0.3, >= 0.3.1) - backports (3.25.0) - base64 (0.2.0) - bigdecimal (3.1.7) - builder (3.2.4) - bunny (2.22.0) - amq-protocol (~> 2.3, >= 2.3.1) - sorted_set (~> 1, >= 1.0.2) - byebug (11.1.3) - closeio (3.12.0) - faraday - faraday_middleware - json - coder (0.4.0) - coderay (1.1.3) - coercible (1.0.0) - descendants_tracker (~> 0.0.1) - composite_primary_keys (14.0.9) - activerecord (~> 7.0.2) - concurrent-ruby (1.2.3) - connection_pool (2.4.1) - crack (1.0.0) - bigdecimal - rexml - dalli (3.2.8) - database_cleaner (2.0.2) - database_cleaner-active_record (>= 2, < 3) - database_cleaner-active_record (2.1.0) - activerecord (>= 5.a) - database_cleaner-core (~> 2.0.0) - database_cleaner-core (2.0.1) - declarative (0.0.20) - descendants_tracker (0.0.4) - thread_safe (~> 0.3, >= 0.3.1) - diff-lcs (1.5.1) - digest-crc (0.6.5) - rake (>= 12.0.0, < 14.0.0) - docile (1.4.0) - domain_name (0.6.20240107) - dry-configurable (1.1.0) - dry-core (~> 1.0, < 2) - zeitwerk (~> 2.6) - dry-core (1.0.1) - concurrent-ruby (~> 1.0) - zeitwerk (~> 2.6) - dry-inflector (1.0.0) - dry-initializer (3.1.1) - dry-logic (1.5.0) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0, < 2) - zeitwerk (~> 2.6) - dry-schema (1.13.3) - concurrent-ruby (~> 1.0) - dry-configurable (~> 1.0, >= 1.0.1) - dry-core (~> 1.0, < 2) - dry-initializer (~> 3.0) - dry-logic (>= 1.4, < 2) - dry-types (>= 1.7, < 2) - zeitwerk (~> 2.6) - dry-struct (1.6.0) - dry-core (~> 1.0, < 2) - dry-types (>= 1.7, < 2) - ice_nine (~> 0.11) - zeitwerk (~> 2.6) - dry-types (1.7.2) - bigdecimal (~> 3.0) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - equalizer (0.0.11) - excon (0.110.0) - factory_bot (6.4.6) - activesupport (>= 5.0.0) - faraday (1.10.3) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0) - faraday-multipart (~> 1.0) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.0) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - faraday-retry (~> 1.0) - ruby2_keywords (>= 0.0.4) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) - faraday-net_http (1.0.1) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - faraday-retry (1.0.3) - faraday_middleware (1.2.0) - faraday (~> 1.0) - ffi (1.16.3) - ffi-compiler (1.3.2) - ffi (>= 1.15.5) - rake - fog-aws (0.12.0) - fog-core (~> 1.38) - fog-json (~> 1.0) - fog-xml (~> 0.1) - ipaddress (~> 0.8) - fog-core (1.45.0) - builder - excon (~> 0.58) - formatador (~> 0.2) - fog-google (1.23.0) - addressable (>= 2.7.0) - fog-core (< 2.3) - fog-json (~> 1.2) - fog-xml (~> 0.1.0) - google-apis-compute_v1 (~> 0.53) - google-apis-dns_v1 (~> 0.28) - google-apis-iamcredentials_v1 (~> 0.15) - google-apis-monitoring_v3 (~> 0.37) - google-apis-pubsub_v1 (~> 0.30) - google-apis-sqladmin_v1beta4 (~> 0.38) - google-apis-storage_v1 (>= 0.19, < 1) - google-cloud-env (~> 1.2) - fog-json (1.2.0) - fog-core - multi_json (~> 1.10) - fog-xml (0.1.4) - fog-core - nokogiri (>= 1.5.11, < 2.0.0) - foreman (0.87.2) - formatador (0.3.0) - gapic-common (0.20.0) - faraday (>= 1.9, < 3.a) - faraday-retry (>= 1.0, < 3.a) - google-protobuf (~> 3.14) - googleapis-common-protos (>= 1.3.12, < 2.a) - googleapis-common-protos-types (>= 1.3.1, < 2.a) - googleauth (~> 1.0) - grpc (~> 1.36) - google-apis-compute_v1 (0.86.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.3) - addressable (~> 2.5, >= 2.5.1) - googleauth (>= 0.16.2, < 2.a) - httpclient (>= 2.8.1, < 3.a) - mini_mime (~> 1.0) - representable (~> 3.0) - retriable (>= 2.0, < 4.a) - rexml - google-apis-dns_v1 (0.36.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-iamcredentials_v1 (0.17.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-monitoring_v3 (0.54.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-pubsub_v1 (0.45.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-sqladmin_v1beta4 (0.61.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.31.0) - google-apis-core (>= 0.11.0, < 2.a) - google-cloud-core (1.7.0) - google-cloud-env (>= 1.0, < 3.a) - google-cloud-errors (~> 1.0) - google-cloud-env (1.6.0) - faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.4.0) - google-cloud-monitoring-v3 (0.14.0) - gapic-common (>= 0.20.0, < 2.a) - google-cloud-errors (~> 1.0) - google-cloud-storage (1.47.0) - addressable (~> 2.8) - digest-crc (~> 0.4) - google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.31.0) - google-cloud-core (~> 1.6) - googleauth (>= 0.16.2, < 2.a) - mini_mime (~> 1.0) - google-cloud-trace-v2 (0.7.0) - gapic-common (>= 0.20.0, < 2.a) - google-cloud-errors (~> 1.0) - google-protobuf (3.19.6) - googleapis-common-protos (1.5.0) - google-protobuf (~> 3.18) - googleapis-common-protos-types (~> 1.7) - grpc (~> 1.41) - googleapis-common-protos-types (1.14.0) - google-protobuf (~> 3.18) - googleauth (1.8.1) - faraday (>= 0.17.3, < 3.a) - jwt (>= 1.4, < 3.0) - multi_json (~> 1.11) - os (>= 0.9, < 2.0) - signet (>= 0.16, < 2.a) - grpc (1.48.0) - google-protobuf (~> 3.19) - googleapis-common-protos-types (~> 1.0) - hashdiff (1.1.0) - hashr (2.0.1) - hitimes (1.3.1) - http (4.4.1) - addressable (~> 2.3) - http-cookie (~> 1.0) - http-form_data (~> 2.2) - http-parser (~> 1.2.0) - http-cookie (1.0.5) - domain_name (~> 0.5) - http-form_data (2.3.0) - http-parser (1.2.3) - ffi-compiler (>= 1.0, < 2.0) - httpclient (2.8.3) - i18n (1.14.4) - concurrent-ruby (~> 1.0) - ice_nine (0.11.2) - ipaddress (0.8.3) - jmespath (1.6.2) - json (2.7.1) - jwt (2.8.1) - base64 - kgio (2.11.4) - knapsack (4.0.0) - rake - language_server-protocol (3.17.0.3) - libhoney (2.3.0) - addressable (~> 2.0) - excon - http (>= 2.0, < 6.0) - librato-metrics (2.1.2) - aggregate (~> 0.2.2) - faraday - listen (3.9.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - memory_profiler (1.0.1) - method_source (1.0.0) - metriks (0.9.9.6) - atomic (~> 1.0) - avl_tree (~> 1.1.2) - hitimes (~> 1.1) - mime-types (3.5.2) - mime-types-data (~> 3.2015) - mime-types-data (3.2024.0305) - mini_mime (1.1.5) - minitest (5.22.3) - mocha (2.1.0) - ruby2_keywords (>= 0.0.5) - msgpack (1.7.2) - multi_json (1.15.0) - multipart-post (2.4.0) - mustermann (2.0.2) - ruby2_keywords (~> 0.0.1) - nakayoshi_fork (0.0.4) - net-http-persistent (2.9.4) - net-http-pipeline (1.0.1) - nokogiri (1.16.3-arm64-darwin) - racc (~> 1.4) - nokogiri (1.16.3-x86_64-linux) - racc (~> 1.4) - opencensus (0.5.0) - opencensus-stackdriver (0.4.1) - concurrent-ruby (~> 1.0) - google-cloud-env (~> 1.3) - google-cloud-monitoring-v3 (~> 0.1) - google-cloud-trace-v2 (~> 0.1) - opencensus (~> 0.5) - optimist (3.1.0) - os (1.1.4) - parallel (1.24.0) - parser (3.3.0.5) - ast (~> 2.4.1) - racc - pg (1.5.6) - pry (0.14.2) - coderay (~> 1.1) - method_source (~> 1.0) - pry-byebug (3.10.1) - byebug (~> 11.0) - pry (>= 0.13, < 0.15) - public_suffix (5.0.4) - pusher (2.0.3) - httpclient (~> 2.8) - multi_json (~> 1.15) - pusher-signature (~> 0.1.8) - pusher-signature (0.1.8) - racc (1.7.3) - rack (2.2.8.1) - rack-attack (6.7.0) - rack (>= 1.0, < 4) - rack-contrib (2.3.0) - rack (~> 2.0) - rack-protection (2.2.4) - rack - rack-ssl (1.4.1) - rack - rack-test (2.1.0) - rack (>= 1.3) - rainbow (3.1.1) - raindrops (0.20.1) - rake (13.0.6) - rb-fsevent (0.11.2) - rb-inotify (0.10.1) - ffi (~> 1.0) - rbtrace (0.5.1) - ffi (>= 1.0.6) - msgpack (>= 0.4.3) - optimist (>= 3.0.0) - rbtree (0.4.6) - redcarpet (3.6.0) - redis (5.1.0) - redis-client (>= 0.17.0) - redis-client (0.21.0) - connection_pool - redis-namespace (1.11.0) - redis (>= 4) - redlock (2.0.6) - redis-client (>= 0.14.1, < 1.0.0) - regexp_parser (2.9.0) - representable (3.2.0) - declarative (< 0.1.0) - trailblazer-option (>= 0.1.1, < 0.2.0) - uber (< 0.2.0) - rerun (0.14.0) - listen (~> 3.0) - retriable (3.1.2) - rexml (3.2.6) - rspec (3.13.0) - rspec-core (~> 3.13.0) - rspec-expectations (~> 3.13.0) - rspec-mocks (~> 3.13.0) - rspec-core (3.13.0) - rspec-support (~> 3.13.0) - rspec-expectations (3.13.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.13.0) - rspec-its (1.3.0) - rspec-core (>= 3.0.0) - rspec-expectations (>= 3.0.0) - rspec-mocks (3.13.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.13.0) - rspec-support (3.13.1) - rubocop (1.62.1) - json (~> 2.3) - language_server-protocol (>= 3.17.0) - parallel (~> 1.10) - parser (>= 3.3.0.2) - rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.31.1, < 2.0) - ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.2) - parser (>= 3.3.0.4) - rubocop-capybara (2.20.0) - rubocop (~> 1.41) - rubocop-factory_bot (2.25.1) - rubocop (~> 1.41) - rubocop-performance (1.20.2) - rubocop (>= 1.48.1, < 2.0) - rubocop-ast (>= 1.30.0, < 2.0) - rubocop-rspec (2.27.1) - rubocop (~> 1.40) - rubocop-capybara (~> 2.17) - rubocop-factory_bot (~> 2.22) - ruby-progressbar (1.13.0) - ruby2_keywords (0.0.5) - sentry-ruby (5.17.1) - bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) - set (1.1.0) - sidekiq (6.4.2) - connection_pool (>= 2.2.2) - rack (~> 2.0) - redis (>= 4.2.0) - signet (0.19.0) - addressable (~> 2.8) - faraday (>= 0.17.5, < 3.a) - jwt (>= 1.5, < 3.0) - multi_json (~> 1.10) - simplecov (0.22.0) - docile (~> 1.1) - simplecov-html (~> 0.11) - simplecov_json_formatter (~> 0.1) - simplecov-console (0.9.1) - ansi - simplecov - terminal-table - simplecov-html (0.12.3) - simplecov_json_formatter (0.1.4) - sinatra (2.2.4) - mustermann (~> 2.0) - rack (~> 2.2) - rack-protection (= 2.2.4) - tilt (~> 2.0) - sinatra-contrib (2.2.4) - multi_json - mustermann (~> 2.0) - rack-protection (= 2.2.4) - sinatra (= 2.2.4) - tilt (~> 2.0) - sorted_set (1.0.3) - rbtree - set (~> 1.0) - stackprof (0.2.26) - terminal-table (3.0.2) - unicode-display_width (>= 1.1.1, < 3) - thread_safe (0.3.6) - tilt (2.3.0) - timecop (0.9.8) - tool (0.2.3) - trailblazer-option (0.1.2) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - uber (0.1.0) - unicode-display_width (2.5.0) - unicorn (6.1.0) - kgio (~> 2.6) - raindrops (~> 0.7) - useragent (0.16.10) - virtus (1.0.5) - axiom-types (~> 0.1) - coercible (~> 1.0) - descendants_tracker (~> 0.0, >= 0.0.3) - equalizer (~> 0.0, >= 0.0.9) - webmock (3.23.0) - addressable (>= 2.8.0) - crack (>= 0.3.2) - hashdiff (>= 0.4.0, < 2.0.0) - yard (0.9.36) - zeitwerk (2.6.13) - -PLATFORMS - arm64-darwin-23 - x86_64-linux - -DEPENDENCIES - active_model_serializers (~> 0.9.9) - activerecord (~> 7.0.8) - addressable (~> 2.8.0) - allocation_tracer - aws-sdk-s3 - bunny (~> 2.22) - closeio - coder (~> 0.4.0) - composite_primary_keys (~> 14.0) - dalli - database_cleaner - dry-schema - dry-struct - dry-types - factory_bot - faraday - faraday-net_http_persistent - fog-aws (~> 0.12.0) - fog-google - foreman - gh! - google-cloud-storage - google-protobuf (~> 3.19.6) - hashdiff - hashr - http (~> 4) - ipaddress (~> 0.8.3) - knapsack - libhoney - librato-metrics - marginalia! - memory_profiler - metriks (= 0.9.9.6) - metriks-librato_metrics! - mime-types - mocha - multi_json - nakayoshi_fork - opencensus - opencensus-stackdriver - os (~> 1.1.4) - pg (~> 1.5) - pry - pry-byebug - pusher (~> 2.0.3) - rack (~> 2.2.3) - rack-attack (~> 6) - rack-cache! - rack-contrib (= 2.3.0) - rack-ssl (~> 1.4) - rack-test - rake (~> 13.0.6) - rb-fsevent (~> 0.11) - rbtrace - redcarpet (>= 3.6) - redis (~> 5.0) - redis-namespace - redlock - rerun - rollout! - rspec - rspec-its - rubocop - rubocop-performance - rubocop-rspec - sentry-ruby - sidekiq (~> 6.4.0) - simple_states! - simplecov - simplecov-console - sinatra (~> 2) - sinatra-contrib - stackprof - timecop - tool - travis-amqp! - travis-config! - travis-github_apps! - travis-lock! - travis-rollout! - travis-settings! - travis-support! - unicorn - useragent - virtus (~> 1.0.0) - webmock - yard-sinatra! - -RUBY VERSION - ruby 3.2.2p53 - -BUNDLED WITH - 2.4.19 diff --git a/lib/travis/api/enqueue/services/restart_model.rb b/lib/travis/api/enqueue/services/restart_model.rb index 599b10ae0c..b7bdf2c92e 100644 --- a/lib/travis/api/enqueue/services/restart_model.rb +++ b/lib/travis/api/enqueue/services/restart_model.rb @@ -21,8 +21,6 @@ def push(event, payload) ) Result.new(value: payload) - - Result.new(value: payload) else Result.new(error: @cause_of_denial || 'restart failed') end diff --git a/lib/travis/api/v3/billing_client.rb b/lib/travis/api/v3/billing_client.rb index 527d7c8311..4c42ca7cba 100644 --- a/lib/travis/api/v3/billing_client.rb +++ b/lib/travis/api/v3/billing_client.rb @@ -70,16 +70,6 @@ def all Travis::API::V3::Models::SubscriptionsCollection.new(subscriptions, permissions) end - def all_v2 - data = connection.get('/v2/subscriptions').body - subscriptions = data.fetch('plans').map do |subscription_data| - Travis::API::V3::Models::V2Subscription.new(subscription_data) - end - permissions = data.fetch('permissions') - - Travis::API::V3::Models::SubscriptionsCollection.new(subscriptions, permissions) - end - def all_v2 data = body(connection.get('/v2/subscriptions')) subscriptions = data.fetch('plans').map do |subscription_data| @@ -106,18 +96,6 @@ def get_invoices_for_subscription(id) end end - def get_invoices_for_v2_subscription(id) - body(connection.get("/v2/subscriptions/#{id}/invoices")).map do |invoice_data| - Travis::API::V3::Models::Invoice.new(invoice_data) - end - end - - def get_invoices_for_v2_subscription(id) - connection.get("/v2/subscriptions/#{id}/invoices").body.map do |invoice_data| - Travis::API::V3::Models::Invoice.new(invoice_data) - end - end - def trials body(connection.get('/trials')).map do | trial_data | Travis::API::V3::Models::Trial.new(trial_data) @@ -322,8 +300,6 @@ def connection(timeout: 10) conn.response :json conn.options[:open_timeout] = timeout conn.options[:timeout] = timeout - conn.options[:open_timeout] = timeout - conn.options[:timeout] = timeout conn.adapter :net_http end end diff --git a/lib/travis/api/v3/proxy_service.rb b/lib/travis/api/v3/proxy_service.rb index 866c0d2d37..f3df464558 100644 --- a/lib/travis/api/v3/proxy_service.rb +++ b/lib/travis/api/v3/proxy_service.rb @@ -30,7 +30,7 @@ def proxy! class ProxyClient def initialize(endpoint, auth_token) @connection = Faraday::Connection.new(URI(endpoint)) do |conn| - conn.token_auth auth_token + conn.headers[:Authorization] = "Token token=\"#{auth_token}\"" conn.response :json, content_type: 'application/json' conn.adapter Faraday.default_adapter end diff --git a/lib/travis/api/v3/renderer/allowance.rb b/lib/travis/api/v3/renderer/allowance.rb index c8e6ee4847..f83616fcbf 100644 --- a/lib/travis/api/v3/renderer/allowance.rb +++ b/lib/travis/api/v3/renderer/allowance.rb @@ -1,6 +1,7 @@ module Travis::API::V3 class Renderer::Allowance < ModelRenderer representation(:minimal, :id) - representation(:standard, :subscription_type, :public_repos, :private_repos, :concurrency_limit, :user_usage, :pending_user_licenses, :id) + representation(:standard, :subscription_type, :public_repos, :private_repos, :concurrency_limit, :user_usage, :pending_user_licenses, + :payment_changes_block_credit, :payment_changes_block_captcha, :credit_card_block_duration, :captcha_block_duration, :id) end end diff --git a/lib/travis/api/v3/services/v2_subscriptions/create.rb b/lib/travis/api/v3/services/v2_subscriptions/create.rb index 18037e184a..8460024223 100644 --- a/lib/travis/api/v3/services/v2_subscriptions/create.rb +++ b/lib/travis/api/v3/services/v2_subscriptions/create.rb @@ -3,7 +3,7 @@ class Services::V2Subscriptions::Create < Service result_type :v2_subscription params :plan, :coupon, :organization_id, :client_secret, :v1_subscription_id params :first_name, :last_name, :company, :address, :address2, :city, :country, :state, :vat_id, :zip_code, :billing_email, :has_local_registration, prefix: :billing_info - params :token, prefix: :credit_card_info + params :token, :fingerprint, prefix: :credit_card_info def run! raise LoginRequired unless access_control.full_access_or_logged_in? diff --git a/lib/travis/config/defaults.rb b/lib/travis/config/defaults.rb index be75a58203..e3f89f4751 100644 --- a/lib/travis/config/defaults.rb +++ b/lib/travis/config/defaults.rb @@ -43,8 +43,8 @@ def fallback_logs_api_auth_token amqp: { username: 'guest', password: 'guest', host: 'localhost', prefetch: 1 }, closeio: { key: 'key' }, gdpr: {}, - database: { adapter: 'postgresql', database: "travis_#{Travis.env}", encoding: 'unicode', min_messages: 'warning', variables: { statement_timeout: 45_000 } }, - db: { max_statement_timeout_in_seconds: 45, slow_host_max_statement_timeout_in_seconds: 60}, + database: { adapter: 'postgresql', database: "travis_#{Travis.env}", encoding: 'unicode', min_messages: 'warning', variables: { statement_timeout: ENV['TRAVIS_DB_STATEMENT_TIMEOUT'] || 10000 } }, + db: { max_statement_timeout_in_seconds: 15, slow_host_max_statement_timeout_in_seconds: ENV['TRAVIS_MAX_DB_STATEMENT_TIMEOUT'] || 15}, log_options: { s3: { access_key_id: '', secret_access_key: ''}}, s3: { access_key_id: '', secret_access_key: ''}, pusher: { app_id: 'app-id', key: 'key', secret: 'secret' }, diff --git a/lib/travis/model/organization.rb b/lib/travis/model/organization.rb index 388dc375f5..421beb4cb5 100644 --- a/lib/travis/model/organization.rb +++ b/lib/travis/model/organization.rb @@ -18,10 +18,6 @@ class Organization < Travis::Model ensure_preferences end - after_initialize do - ensure_preferences - end - before_save do ensure_preferences end diff --git a/spec/lib/github/services/set_key_spec.rb b/spec/lib/github/services/set_key_spec.rb index 5662fa0ac0..b219296a2f 100644 --- a/spec/lib/github/services/set_key_spec.rb +++ b/spec/lib/github/services/set_key_spec.rb @@ -14,9 +14,7 @@ WebMock.stub_request(:get, "http://vcsfake.travis-ci.com/repos/#{repo.id}/keys?user_id=#{owner.id}") .to_return( status: 200, - body: JSON.dump( - data: keys, - ) + body: JSON.dump(keys) ) end let!(:delete_request) do diff --git a/spec/support/billing_spec_helper.rb b/spec/support/billing_spec_helper.rb index 7b6bb0b4c8..572937ca03 100644 --- a/spec/support/billing_spec_helper.rb +++ b/spec/support/billing_spec_helper.rb @@ -211,118 +211,6 @@ def billing_addon_usage_response_body(attributes = {}) }.deep_merge(attributes) end - def billing_v2_subscription_response_body(attributes={}) - { - "permissions" => { "read" => true, "write" => true }, - "id" => 81, - 'status' => nil, - 'valid_to' => nil, - 'canceled_at' => nil, - "scheduled_plan" => nil, - "plan_config" => { - 'id' => 'pro_tier_plan', - 'name' => 'Pro Tier Plan', - 'plan_type' => 'metered', - 'concurrency_limit' => 20, - 'private_repos' => true, - 'starting_price' => 30000, - 'starting_users' => 10000, - 'private_credits' => 500000, - 'public_credits' => 40000, - 'annual' => false, - 'auto_refill_thresholds' => [10000, 50000, 100000], - 'auto_refill_amounts' => [ - { - 'amount' => 25000, - 'price' => 1500 - }, - { - 'amount' => 100000, - 'price' => 6000 - }, - { - 'amount' => 200000, - 'price' => 6000 - }, - { - 'amount' => 400000, - 'price' => 12000 - } - ], - 'available_standalone_addons' => [ - { - 'id' => 'credits_25k', - 'name' => '25 000 credits (2,5k Linux build minutes)', - 'price' => 1500, - 'quantity' => 25000, - 'type' => 'credit_private' - }, - { - 'id' => 'credits_500k', - 'name' => '500 000 credits (50k Linux build minutes)', - 'price' => 30000, - 'quantity' => 500000, - 'type' => 'credit_private' - } - ], - 'addon_configs' => { - 'free_tier_credits' => { - 'name' => 'Free 10 000 credits (renewed monthly)', - 'expires' => true, - 'expires_in' => 1, - 'renew_after_expiration' => true, - 'price' => 0, - 'price_id' => 'price_1234567890', - 'price_type' => 'fixed', - 'quantity' => 10_000, - 'standalone' => false, - 'type' => 'credit_private', - 'available_for_plans' => '%w[free_tier_plan]' - }, - 'oss_tier_credits' => { - 'name' => 'Free 40 000 credits (renewed monthly)', - 'expires' => true, - 'expires_in' => 1, - 'renew_after_expiration' => true, - 'price' => 0, - 'price_id' => 'price_0987654321', - 'price_type' => 'fixed', - 'quantity' => 40_000, - 'standalone' => false, - 'type' => 'credit_public', - 'private_repos' => false, - 'available_for_plans' => '%w[free_tier_plan standard_tier_plan pro_tier_plan]' - } - } - }, - "addons" => billing_addons_response_body, - "source" => "stripe", - "created_at" => "2017-11-28T00:09:59.502Z", - "billing_info" => { - "first_name" => "ana", - "last_name" => "rosas", - "company" => "", - "billing_email" => "a.rosas10@gmail.com", - "zip_code" => "28450", - "address" => "Luis Spota", - "address2" => "", - "city" => "Comala", - "state" => nil, - "country" => "Mexico", - "vat_id" => "123456" - }, - "credit_card_info" => { - "card_owner" => "ana", - "last_digits" => "4242", - "expiration_date" => "9/2021" - }, - "owner" => { - "type" => "Organization", - "id" => 43 - } - }.deep_merge(attributes) - end - def billing_addons_response_body [ { diff --git a/spec/support/s3.rb b/spec/support/s3.rb index 4301056ddd..ebd611e36b 100644 --- a/spec/support/s3.rb +++ b/spec/support/s3.rb @@ -3,9 +3,9 @@ module Support module S3 class FakeObject attr_accessor :key, :size, :last_modified - def initialize(key) + def initialize(key, options = {}) @key = key - @size = "0" + @size = options[:size] || "0" end end @@ -34,11 +34,12 @@ def list_objects(params = {}) FakeBucket.new(@contents.select { |o| o.key.start_with? prefix }) end - def create(key) - contents << FakeObject.new(key) + + def add(key, options = {}) + contents << FakeObject.new(key, options) end - alias_method :<<, :create + alias_method :<<, :add end extend ActiveSupport::Concern @@ -47,6 +48,7 @@ def create(key) before(:each) { allow(Aws::S3::Client).to receive(:new).and_return(s3_service) } let(:s3_service) { service = FakeService.new(s3_bucket, s3_objects) + allow(service.buckets).to receive(:find).and_return(s3_bucket) service } let(:s3_bucket) { FakeBucket.new(s3_objects) } diff --git a/spec/v3/billing_client_spec.rb b/spec/v3/billing_client_spec.rb index 1fd65acd77..37b1ec8b11 100644 --- a/spec/v3/billing_client_spec.rb +++ b/spec/v3/billing_client_spec.rb @@ -306,18 +306,6 @@ end end - describe '#pay_v2' do - subject { billing.pay_v2(subscription_id) } - - it 'requests to retry payment' do - stubbed_request = stub_billing_request(:post, "/v2/subscriptions/#{subscription_id}/pay", auth_key: auth_key, user_id: user_id) - .to_return(status: 200, body: JSON.dump(billing_v2_subscription_response_body('id' => subscription_id, 'client_secret' => 'client_secret', 'owner' => { 'type' => 'Organization', 'id' => organization.id }))) - - expect { subject }.to_not raise_error - expect(stubbed_request).to have_been_made - end - end - describe '#trials' do subject { billing.trials } let(:trial_id) { rand(999) } From 83d69447c3641f56f35a931ef0e8d2c5d57ee3a2 Mon Sep 17 00:00:00 2001 From: Sebastian Karpeta Date: Thu, 21 Mar 2024 12:50:15 +0100 Subject: [PATCH 35/46] TravisCI API merge. Enterprise to master. --- Gemfile | 38 ++- Gemfile.lock | 638 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 655 insertions(+), 21 deletions(-) create mode 100644 Gemfile.lock diff --git a/Gemfile b/Gemfile index 82254ad2c7..776befb82a 100644 --- a/Gemfile +++ b/Gemfile @@ -5,45 +5,46 @@ ruby '3.2.2' gem 'mime-types' # travis maintained gems -gem 'travis-support', git: 'https://github.com/travis-ci/travis-support', ref: '4dda53ffa96b804db22c261551256caa18c4a2cc' +gem 'travis-support', git: 'https://github.com/travis-ci/travis-support' gem 'travis-amqp', git: 'https://github.com/travis-ci/travis-amqp' gem 'travis-config', git: 'https://github.com/travis-ci/travis-config' -gem 'travis-settings', git: 'https://github.com/travis-ci/travis-settings', branch: 'master' -gem 'travis-lock', git: 'https://github.com/travis-ci/travis-lock/', branch: 'master' -gem 'travis-github_apps', git: 'https://github.com/travis-ci/travis-github_apps', branch: 'master' +gem 'travis-settings', git: 'https://github.com/travis-ci/travis-settings' +gem 'travis-lock', git: 'https://github.com/travis-ci/travis-lock' +gem 'travis-github_apps', git: 'https://github.com/travis-ci/travis-github_apps' gem 'travis-rollout', git: 'https://github.com/travis-ci/travis-rollout' gem 'simple_states', git: 'https://github.com/travis-ci/simple_states', branch: 'prd-ruby-upgrade-dev' gem 'metriks', git: 'https://github.com/travis-ci/metriks' gem 'metriks-librato_metrics', git: 'https://github.com/travis-ci/metriks-librato_metrics' gem 'marginalia', git: 'https://github.com/travis-ci/marginalia' -gem 'gh', git: 'https://github.com/travis-ci/gh', branch: 'master' +gem 'gh', git: 'https://github.com/travis-ci/gh' gem 'rollout', git: 'https://github.com/travis-ci/rollout' -gem 'mustermann' -gem 'sinatra', '~> 2' +gem 'mustermann' +gem 'sinatra' gem 'sinatra-contrib', require: nil #git: 'https://github.com/sinatra/sinatra-contrib', require: nil gem 'active_model_serializers' , '~> 0.9.9' gem 'unicorn' gem 'sentry-ruby' gem 'yard-sinatra', git: 'https://github.com/rkh/yard-sinatra' -gem 'rack-contrib', '= 2.3.0' +gem 'rack', '~> 2.2' +gem 'rack-contrib' gem 'rack-cache', git: 'https://github.com/rtomayko/rack-cache' gem 'rack-attack', '~> 6' gem 'bunny', '~> 2.22' gem 'dalli' gem 'pry' -gem 'http', '~> 4' gem 'librato-metrics' +gem 'simplecov' gem 'stackprof' gem "ipaddress", "~> 0.8.3" gem 'nakayoshi_fork' -gem 'sidekiq', '~> 7' +gem 'sidekiq' gem 'redis-namespace' gem 'rbtrace' gem 'memory_profiler' -#gem 'allocation_tracer' +gem 'allocation_tracer' gem 'redlock' gem 'rake', '~> 13.0' @@ -52,8 +53,8 @@ gem 'libhoney' gem 'opencensus' gem 'opencensus-stackdriver' -gem 'faraday', '~>2' -gem 'faraday-net_http_persistent', '~>2' +gem 'faraday', '~> 2' +gem 'faraday-net_http_persistent', '~> 2' gem 'knapsack' @@ -65,21 +66,16 @@ gem 'useragent' gem 'tool' gem 'google-cloud-storage' gem 'aws-sdk-s3' -gem 'activerecord', '~> 7.0.6' # it was fixed in predicate_builder file to 7.0.6 but gh gem requires 7.0.8 -gem 'google-protobuf', '~> 3.19.6' +gem 'activerecord', '~> 7.0.8' # it was fixed in predicate_builder file to 7.0.6 but gh gem requires 7.0.8 gem 'coder', '~> 0.4.0' gem 'dry-types' gem 'dry-struct' gem 'dry-schema' gem 'redis', '~> 5.0' -gem 'virtus', '~> 1.0.0' gem 'hashr' gem 'pusher', '~> 2.0.3' gem 'multi_json' -gem 'closeio' -gem 'addressable', '~> 2.8.0' -gem 'rack', '~> 2.2.3' -gem 'os', '~> 1.1.4' +gem 'closeio', '~> 3.15' group :test do gem 'rspec' @@ -92,7 +88,6 @@ group :test do gem 'hashdiff' gem 'pry-byebug' gem 'rack-test' - gem 'simplecov' end group :development do @@ -105,5 +100,6 @@ group :development, :test do gem 'rubocop', require: false gem 'rubocop-performance', require: false gem 'rubocop-rspec', require: false + gem 'simplecov', require: false gem 'simplecov-console', require: false end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..afb553b26b --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,638 @@ +GIT + remote: https://github.com/rkh/yard-sinatra + revision: b0d84033056dabdba08e7eee9438a3796d0d087d + specs: + yard-sinatra (1.0.0) + yard (~> 0.7) + +GIT + remote: https://github.com/rtomayko/rack-cache + revision: 07ff2f8d61379e0f54464928baf5f1cc3d94039c + specs: + rack-cache (1.13.0) + rack (>= 0.4) + +GIT + remote: https://github.com/travis-ci/gh + revision: e1fcd75786ffa75667e47d3d824b54d1bd0017fe + specs: + gh (0.21.0) + activesupport (~> 7.0.8) + addressable (~> 2.8) + faraday (~> 2) + faraday-retry + faraday-typhoeus + multi_json (~> 1) + net-http-persistent (~> 4) + net-http-pipeline + +GIT + remote: https://github.com/travis-ci/marginalia + revision: d7c711abd60517b435e50b499fc8997ab67ababe + specs: + marginalia (1.6.0) + pg + +GIT + remote: https://github.com/travis-ci/metriks + revision: ca03449b2928962e41c8389283bd092053e91670 + specs: + metriks (0.9.9.8) + HDRHistogram (~> 0.1) + atomic (~> 1.0) + avl_tree (~> 1.2) + hitimes (~> 1.3) + +GIT + remote: https://github.com/travis-ci/metriks-librato_metrics + revision: e876ca2f0e1abcc745260c3772118e63fb946c8a + specs: + metriks-librato_metrics (1.0.6) + +GIT + remote: https://github.com/travis-ci/rollout + revision: ec4db3ae6bbf8cf56ce4adce0814247c46195a0e + specs: + rollout (3.0.0) + redis (~> 5.0) + +GIT + remote: https://github.com/travis-ci/simple_states + revision: 1112afaf7bbbe51a6fdf8abae769ef827ab3bfd8 + branch: prd-ruby-upgrade-dev + specs: + simple_states (1.0.2) + activesupport (~> 7.0) + +GIT + remote: https://github.com/travis-ci/travis-amqp + revision: 69e72f432436eca5d39991255d5cc3b45c1035e6 + specs: + travis-amqp (0.0.3) + +GIT + remote: https://github.com/travis-ci/travis-config + revision: 601e9a6dcb799dc14944c40153c60aaf935629ee + specs: + travis-config (2.0.0) + hashr (~> 2.0) + +GIT + remote: https://github.com/travis-ci/travis-github_apps + revision: 146c5c4583a80ecab41017749eb97aade600e365 + specs: + travis-github_apps (0.3.0) + activesupport (>= 3.2) + faraday (~> 2) + faraday-follow_redirects + jwt + redis + +GIT + remote: https://github.com/travis-ci/travis-lock + revision: aeee7b5d11e3d44f19d0a113c2e54ec54756f20f + specs: + travis-lock (0.2.0) + +GIT + remote: https://github.com/travis-ci/travis-rollout + revision: 4e89a17a4b5ca1f6269fb8bc1d067faabc49ac92 + specs: + travis-rollout (0.1.0) + +GIT + remote: https://github.com/travis-ci/travis-settings + revision: 7e48e09c1df1c95abaf13a0dcec78bdfab9f86ee + specs: + travis-settings (0.1.0) + activemodel + virtus + +GIT + remote: https://github.com/travis-ci/travis-support + revision: 8b566a94502267b3115c901f8409dc2165b6539b + specs: + travis-support (0.1.0) + +GEM + remote: https://rubygems.org/ + specs: + HDRHistogram (0.1.11) + active_model_serializers (0.9.9) + activemodel (>= 3.2) + concurrent-ruby (~> 1.0) + activemodel (7.0.8.1) + activesupport (= 7.0.8.1) + activerecord (7.0.8.1) + activemodel (= 7.0.8.1) + activesupport (= 7.0.8.1) + activesupport (7.0.8.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.4) + public_suffix (>= 2.0.2, < 6.0) + aggregate (0.2.3) + allocation_tracer (0.6.3) + amq-protocol (2.3.2) + ansi (1.5.0) + ast (2.4.2) + atomic (1.1.101) + avl_tree (1.2.1) + atomic (~> 1.1) + aws-eventstream (1.2.0) + aws-partitions (1.791.0) + aws-sdk-core (3.178.0) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.71.0) + aws-sdk-core (~> 3, >= 3.177.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.131.0) + aws-sdk-core (~> 3, >= 3.177.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.6) + aws-sigv4 (1.6.0) + aws-eventstream (~> 1, >= 1.0.2) + axiom-types (0.1.1) + descendants_tracker (~> 0.0.4) + ice_nine (~> 0.11.0) + thread_safe (~> 0.3, >= 0.3.1) + bunny (2.22.0) + amq-protocol (~> 2.3, >= 2.3.1) + sorted_set (~> 1, >= 1.0.2) + byebug (11.1.3) + closeio (3.15.0) + faraday (> 2.0) + json + coder (0.4.0) + coderay (1.1.3) + coercible (1.0.0) + descendants_tracker (~> 0.0.1) + composite_primary_keys (14.0.6) + activerecord (~> 7.0.2) + concurrent-ruby (1.2.2) + connection_pool (2.4.1) + crack (0.4.5) + rexml + dalli (3.2.5) + database_cleaner (2.0.2) + database_cleaner-active_record (>= 2, < 3) + database_cleaner-active_record (2.1.0) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) + declarative (0.0.20) + descendants_tracker (0.0.4) + thread_safe (~> 0.3, >= 0.3.1) + diff-lcs (1.5.0) + digest-crc (0.6.5) + rake (>= 12.0.0, < 14.0.0) + docile (1.4.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dry-configurable (1.1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-core (1.0.0) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-inflector (1.0.0) + dry-initializer (3.1.1) + dry-logic (1.5.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-schema (1.13.2) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.0, < 2) + dry-initializer (~> 3.0) + dry-logic (>= 1.4, < 2) + dry-types (>= 1.7, < 2) + zeitwerk (~> 2.6) + dry-struct (1.6.0) + dry-core (~> 1.0, < 2) + dry-types (>= 1.7, < 2) + ice_nine (~> 0.11) + zeitwerk (~> 2.6) + dry-types (1.7.1) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) + ethon (0.16.0) + ffi (>= 1.15.0) + excon (0.100.0) + factory_bot (6.2.1) + activesupport (>= 5.0.0) + faraday (2.7.10) + faraday-net_http (>= 2.0, < 3.1) + ruby2_keywords (>= 0.0.4) + faraday-follow_redirects (0.3.0) + faraday (>= 1, < 3) + faraday-net_http (3.0.2) + faraday-net_http_persistent (2.1.0) + faraday (~> 2.5) + net-http-persistent (~> 4.0) + faraday-retry (2.2.0) + faraday (~> 2.0) + faraday-typhoeus (1.1.0) + faraday (~> 2.0) + typhoeus (~> 1.4) + ffi (1.15.5) + ffi-compiler (1.0.1) + ffi (>= 1.0.0) + rake + foreman (0.87.2) + gapic-common (0.19.1) + faraday (>= 1.9, < 3.a) + faraday-retry (>= 1.0, < 3.a) + google-protobuf (~> 3.14) + googleapis-common-protos (>= 1.3.12, < 2.a) + googleapis-common-protos-types (>= 1.3.1, < 2.a) + googleauth (~> 1.0) + grpc (~> 1.36) + google-apis-core (0.11.1) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) + google-cloud-core (1.6.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.3.1) + google-cloud-monitoring-v3 (0.12.1) + gapic-common (>= 0.19.1, < 2.a) + google-cloud-errors (~> 1.0) + google-cloud-storage (1.44.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.19.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + google-cloud-trace-v2 (0.6.1) + gapic-common (>= 0.19.1, < 2.a) + google-cloud-errors (~> 1.0) + google-protobuf (3.23.4-arm64-darwin) + google-protobuf (3.23.4-x86_64-linux) + googleapis-common-protos (1.4.0) + google-protobuf (~> 3.14) + googleapis-common-protos-types (~> 1.2) + grpc (~> 1.27) + googleapis-common-protos-types (1.7.0) + google-protobuf (~> 3.14) + googleauth (1.7.0) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + grpc (1.56.2) + google-protobuf (~> 3.23) + googleapis-common-protos-types (~> 1.0) + grpc (1.56.2-x86_64-linux) + google-protobuf (~> 3.23) + googleapis-common-protos-types (~> 1.0) + hashdiff (1.0.1) + hashr (2.0.1) + hitimes (1.3.1) + http (5.1.1) + addressable (~> 2.8) + http-cookie (~> 1.0) + http-form_data (~> 2.2) + llhttp-ffi (~> 0.4.0) + http-cookie (1.0.5) + domain_name (~> 0.5) + http-form_data (2.3.0) + httpclient (2.8.3) + i18n (1.14.1) + concurrent-ruby (~> 1.0) + ice_nine (0.11.2) + ipaddress (0.8.3) + jmespath (1.6.2) + json (2.6.3) + jwt (2.7.1) + kgio (2.11.4) + knapsack (4.0.0) + rake + language_server-protocol (3.17.0.3) + libhoney (2.2.0) + addressable (~> 2.0) + excon + http (>= 2.0, < 6.0) + librato-metrics (2.1.2) + aggregate (~> 0.2.2) + faraday + listen (3.8.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + llhttp-ffi (0.4.0) + ffi-compiler (~> 1.0) + rake (~> 13.0) + memoist (0.16.2) + memory_profiler (1.0.1) + method_source (1.0.0) + mime-types (3.4.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2023.0218.1) + mini_mime (1.1.2) + minitest (5.18.1) + mocha (2.0.4) + ruby2_keywords (>= 0.0.5) + msgpack (1.7.2) + multi_json (1.15.0) + mustermann (3.0.0) + ruby2_keywords (~> 0.0.1) + nakayoshi_fork (0.0.4) + net-http-persistent (4.0.2) + connection_pool (~> 2.2) + net-http-pipeline (1.0.1) + opencensus (0.5.0) + opencensus-stackdriver (0.4.1) + concurrent-ruby (~> 1.0) + google-cloud-env (~> 1.3) + google-cloud-monitoring-v3 (~> 0.1) + google-cloud-trace-v2 (~> 0.1) + opencensus (~> 0.5) + optimist (3.0.1) + os (1.1.4) + parallel (1.23.0) + parser (3.2.2.3) + ast (~> 2.4.1) + racc + pg (1.5.3) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.10.1) + byebug (~> 11.0) + pry (>= 0.13, < 0.15) + public_suffix (5.0.3) + pusher (2.0.3) + httpclient (~> 2.8) + multi_json (~> 1.15) + pusher-signature (~> 0.1.8) + pusher-signature (0.1.8) + racc (1.7.1) + rack (2.2.7) + rack-attack (6.6.1) + rack (>= 1.0, < 3) + rack-contrib (2.3.0) + rack (~> 2.0) + rack-protection (3.0.6) + rack + rack-ssl (1.4.1) + rack + rack-test (2.1.0) + rack (>= 1.3) + rainbow (3.1.1) + raindrops (0.20.1) + rake (13.0.6) + rb-fsevent (0.11.2) + rb-inotify (0.10.1) + ffi (~> 1.0) + rbtrace (0.4.14) + ffi (>= 1.0.6) + msgpack (>= 0.4.3) + optimist (>= 3.0.0) + rbtree (0.4.6) + redcarpet (3.6.0) + redis (5.0.6) + redis-client (>= 0.9.0) + redis-client (0.14.1) + connection_pool + redis-namespace (1.11.0) + redis (>= 4) + redlock (2.0.2) + redis-client (~> 0.14.1) + regexp_parser (2.8.1) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + rerun (0.14.0) + listen (~> 3.0) + retriable (3.1.2) + rexml (3.2.5) + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-its (1.3.0) + rspec-core (>= 3.0.0) + rspec-expectations (>= 3.0.0) + rspec-mocks (3.12.6) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-support (3.12.1) + rubocop (1.54.2) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.2.2.3) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.28.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.29.0) + parser (>= 3.2.1.0) + rubocop-capybara (2.18.0) + rubocop (~> 1.41) + rubocop-factory_bot (2.23.1) + rubocop (~> 1.33) + rubocop-performance (1.18.0) + rubocop (>= 1.7.0, < 2.0) + rubocop-ast (>= 0.4.0) + rubocop-rspec (2.22.0) + rubocop (~> 1.33) + rubocop-capybara (~> 2.17) + rubocop-factory_bot (~> 2.22) + ruby-progressbar (1.13.0) + ruby2_keywords (0.0.5) + sentry-ruby (5.10.0) + concurrent-ruby (~> 1.0, >= 1.0.2) + set (1.0.3) + sidekiq (7.1.2) + concurrent-ruby (< 2) + connection_pool (>= 2.3.0) + rack (>= 2.2.4) + redis-client (>= 0.14.0) + signet (0.17.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-console (0.9.1) + ansi + simplecov + terminal-table + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.4) + sinatra (3.0.6) + mustermann (~> 3.0) + rack (~> 2.2, >= 2.2.4) + rack-protection (= 3.0.6) + tilt (~> 2.0) + sinatra-contrib (3.0.6) + multi_json + mustermann (~> 3.0) + rack-protection (= 3.0.6) + sinatra (= 3.0.6) + tilt (~> 2.0) + sorted_set (1.0.3) + rbtree + set (~> 1.0) + stackprof (0.2.25) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + thread_safe (0.3.6) + tilt (2.2.0) + timecop (0.9.6) + tool (0.2.3) + trailblazer-option (0.1.2) + typhoeus (1.4.1) + ethon (>= 0.9.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8.2) + unicode-display_width (2.4.2) + unicorn (6.1.0) + kgio (~> 2.6) + raindrops (~> 0.7) + useragent (0.16.10) + virtus (2.0.0) + axiom-types (~> 0.1) + coercible (~> 1.0) + descendants_tracker (~> 0.0, >= 0.0.3) + webmock (3.18.1) + addressable (>= 2.8.0) + crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) + webrick (1.8.1) + yard (0.9.34) + zeitwerk (2.6.8) + +PLATFORMS + arm64-darwin-22 + x86_64-linux + +DEPENDENCIES + active_model_serializers (~> 0.9.9) + activerecord (~> 7.0.8) + allocation_tracer + aws-sdk-s3 + bunny (~> 2.22) + closeio (~> 3.15) + coder (~> 0.4.0) + composite_primary_keys (~> 14.0) + dalli + database_cleaner + dry-schema + dry-struct + dry-types + factory_bot + faraday (~> 2) + faraday-net_http_persistent (~> 2) + foreman + gh! + google-cloud-storage + hashdiff + hashr + ipaddress (~> 0.8.3) + knapsack + libhoney + librato-metrics + marginalia! + memory_profiler + metriks! + metriks-librato_metrics! + mime-types + mocha + multi_json + mustermann + nakayoshi_fork + opencensus + opencensus-stackdriver + pg (~> 1.5) + pry + pry-byebug + pusher (~> 2.0.3) + rack (~> 2.2) + rack-attack (~> 6) + rack-cache! + rack-contrib + rack-ssl (~> 1.4) + rack-test + rake (~> 13.0) + rb-fsevent (~> 0.11) + rbtrace + redcarpet (>= 3.6) + redis (~> 5.0) + redis-namespace + redlock + rerun + rollout! + rspec + rspec-its + rubocop + rubocop-performance + rubocop-rspec + sentry-ruby + sidekiq + simple_states! + simplecov + simplecov-console + sinatra + sinatra-contrib + stackprof + timecop + tool + travis-amqp! + travis-config! + travis-github_apps! + travis-lock! + travis-rollout! + travis-settings! + travis-support! + unicorn + useragent + webmock + yard-sinatra! + +RUBY VERSION + ruby 3.2.2p53 + +BUNDLED WITH + 2.4.14 From 27fec3b67baa36fa4e11753f53bcecdf1ea8b77b Mon Sep 17 00:00:00 2001 From: Sebastian Karpeta Date: Tue, 2 Apr 2024 10:44:49 +0200 Subject: [PATCH 36/46] TravisCI API. Review fixes. --- lib/travis/api/v3/billing_client.rb | 6 ++++ lib/travis/api/v3/queries/jobs.rb | 3 -- lib/travis/config/defaults.rb | 2 +- lib/travis/model/repository.rb | 7 ++-- spec/support/billing_spec_helper.rb | 55 ----------------------------- 5 files changed, 12 insertions(+), 61 deletions(-) diff --git a/lib/travis/api/v3/billing_client.rb b/lib/travis/api/v3/billing_client.rb index 4c42ca7cba..4d864ad062 100644 --- a/lib/travis/api/v3/billing_client.rb +++ b/lib/travis/api/v3/billing_client.rb @@ -96,6 +96,12 @@ def get_invoices_for_subscription(id) end end + def get_invoices_for_v2_subscription(id) + body(connection.get("/v2/subscriptions/#{id}/invoices")).map do |invoice_data| + Travis::API::V3::Models::Invoice.new(invoice_data) + end + end + def trials body(connection.get('/trials')).map do | trial_data | Travis::API::V3::Models::Trial.new(trial_data) diff --git a/lib/travis/api/v3/queries/jobs.rb b/lib/travis/api/v3/queries/jobs.rb index b00f8b2951..93f39735d1 100644 --- a/lib/travis/api/v3/queries/jobs.rb +++ b/lib/travis/api/v3/queries/jobs.rb @@ -35,13 +35,10 @@ def for_owner(relation) def for_user(user) set_custom_timeout(host_timeout) if ENV['TCIE_BETA_MOST_RECENT_JOBS_LW'] == 'true' - puts "USING LW JOBS!!\n\n" jobs = V3::Models::Job.where("jobs.id in (select id from most_recent_job_ids_for_user_repositories_by_states_lw(#{user.id}, ?))", states) else - puts "USING REGULAR JOBS!!!\n\n" jobs = V3::Models::Job.where("jobs.id in (select id from most_recent_job_ids_for_user_repositories_by_states(#{user.id}, ?))", states) end - puts jobs.inspect sort filter(jobs) end diff --git a/lib/travis/config/defaults.rb b/lib/travis/config/defaults.rb index e3f89f4751..b9a5d8ac0c 100644 --- a/lib/travis/config/defaults.rb +++ b/lib/travis/config/defaults.rb @@ -44,7 +44,7 @@ def fallback_logs_api_auth_token closeio: { key: 'key' }, gdpr: {}, database: { adapter: 'postgresql', database: "travis_#{Travis.env}", encoding: 'unicode', min_messages: 'warning', variables: { statement_timeout: ENV['TRAVIS_DB_STATEMENT_TIMEOUT'] || 10000 } }, - db: { max_statement_timeout_in_seconds: 15, slow_host_max_statement_timeout_in_seconds: ENV['TRAVIS_MAX_DB_STATEMENT_TIMEOUT'] || 15}, + db: { max_statement_timeout_in_seconds: 15, slow_host_max_statement_timeout_in_seconds: ENV['TRAVIS_MAX_DB_STATEMENT_TIMEOUT'] || 60}, log_options: { s3: { access_key_id: '', secret_access_key: ''}}, s3: { access_key_id: '', secret_access_key: ''}, pusher: { app_id: 'app-id', key: 'key', secret: 'secret' }, diff --git a/lib/travis/model/repository.rb b/lib/travis/model/repository.rb index 88845cd492..e77b20cbd5 100644 --- a/lib/travis/model/repository.rb +++ b/lib/travis/model/repository.rb @@ -204,8 +204,11 @@ def settings end def settings=(value) - value = value.is_a?(String) ? JSON.parse(value) : value - super(value) + if value.is_a?(String) || value.nil? + super(value) + else + super(value.to_json) + end end def users_with_permission(permission) diff --git a/spec/support/billing_spec_helper.rb b/spec/support/billing_spec_helper.rb index 572937ca03..4e2daf055b 100644 --- a/spec/support/billing_spec_helper.rb +++ b/spec/support/billing_spec_helper.rb @@ -211,61 +211,6 @@ def billing_addon_usage_response_body(attributes = {}) }.deep_merge(attributes) end - def billing_addons_response_body - [ - { - "id" => "1", - "name" => "OSS Build Credits", - "type" => "credit_public", - "recurring" => false, - "current_usage" => { - "id" => 1, - "addon_id" => 1, - "addon_quantity" => 40000, - "addon_usage" => 0, - "remaining" => 40000, - "purchase_date" => "2017-11-28T00:09:59.502Z", - "valid_to" => "2017-12-28T00:09:59.502Z", - "status" => "subscribed", - "active" => true - } - }, - { - "id" => 2, - "name" => "Build Credits", - "type" => "credit_private", - "recurring" => false, - "current_usage" => { - "id" => 2, - "addon_id" => 2, - "addon_quantity" => 10000, - "addon_usage" => 0, - "remaining" => 10000, - "purchase_date" => "2017-11-28T00:09:59.502Z", - "valid_to" => "", - "status" => "subscribed", - "active" => true - } - } - ] - end - - def billing_addon_usage_response_body(attributes = {}) - { - 'id' => 1, - 'addon_id' => 1, - 'addon_quantity' => 100, - 'addon_usage' => 0, - 'remaining' => 100, - 'purchase_date' => '2020-09-14T11:25:02.612Z', - 'valid_to' => '2020-10-14T11:25:02.612Z', - 'status' => 'subscribed', - 'active' => true, - 'created_at' => '2020-09-14T11:25:02.614Z', - 'updated_at' => '2020-09-14T11:25:02.614Z' - }.deep_merge(attributes) - end - def billing_plan_response_body(attributes={}) { "id" => "travis-ci-ten-builds", From 063ffb30d3938256b3a4197ddf0a09f88c538c75 Mon Sep 17 00:00:00 2001 From: GbArc Date: Tue, 2 Apr 2024 11:35:28 +0200 Subject: [PATCH 37/46] repo spec --- spec/lib/model/repository_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/lib/model/repository_spec.rb b/spec/lib/model/repository_spec.rb index 2e8c629fbf..732b8aad57 100644 --- a/spec/lib/model/repository_spec.rb +++ b/spec/lib/model/repository_spec.rb @@ -428,12 +428,12 @@ repo.settings = {'build_pushes' => false}.to_json repo.save - expect(repo.reload.attributes['settings']).to be_a(Hash) + expect(JSON.parse(repo.reload.attributes['settings'])).to be_a(Hash) repo.settings = {'build_pushes' => false} repo.save - expect(repo.reload.attributes['settings']).to be_a(Hash) + expect(JSON.parse(repo.reload.attributes['settings'])).to be_a(Hash) end end end From e830a8006cb96643dd85dee16ce81df1cba2df31 Mon Sep 17 00:00:00 2001 From: GbArc Date: Tue, 2 Apr 2024 12:20:32 +0200 Subject: [PATCH 38/46] specs, ship:docker --- spec/lib/model/build_spec.rb | 6 +++--- spec/lib/model/job/test_spec.rb | 2 +- spec/lib/services/update_job_spec.rb | 14 +++++++------- spec/lib/travis/config_spec.rb | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/spec/lib/model/build_spec.rb b/spec/lib/model/build_spec.rb index b96022a4ec..670895b308 100644 --- a/spec/lib/model/build_spec.rb +++ b/spec/lib/model/build_spec.rb @@ -61,7 +61,7 @@ FactoryBot.create(:build, state: 'failed') FactoryBot.create(:build, state: 'created') - expect(Build.recent.all.map(&:state)).to eq(['failed', 'passed']) + expect(Build.recent.all.map(&:state)).to eq([:failed, :passed]) end end @@ -71,7 +71,7 @@ FactoryBot.create(:build, state: 'started') FactoryBot.create(:build, state: 'created') - expect(Build.was_started.map(&:state).sort).to eq(['passed', 'started']) + expect(Build.was_started.map(&:state).sort).to eq([:passed, :started]) end end @@ -301,7 +301,7 @@ it 'sets the state to :created' do build.reset - expect(build.state).to eq('created') + expect(build.state).to eq(:created) end it 'resets related attributes' do diff --git a/spec/lib/model/job/test_spec.rb b/spec/lib/model/job/test_spec.rb index 95276d1d52..ce49cd4f84 100644 --- a/spec/lib/model/job/test_spec.rb +++ b/spec/lib/model/job/test_spec.rb @@ -52,7 +52,7 @@ }.to change { build.canceled_at } }.to change { build.repository.reload.last_build_state } - expect(build.reload.state).to eq('canceled') + expect(build.reload.state).to eq(:canceled) expect(build.repository.last_build_state).to eq('canceled') end diff --git a/spec/lib/services/update_job_spec.rb b/spec/lib/services/update_job_spec.rb index 1dac7c1ac8..db90d32c0a 100644 --- a/spec/lib/services/update_job_spec.rb +++ b/spec/lib/services/update_job_spec.rb @@ -63,7 +63,7 @@ it 'sets the build state to received' do service.run - expect(job.reload.source.state).to eq('received') + expect(job.reload.source.state).to eq(:received) end it 'sets the build received_at' do @@ -73,7 +73,7 @@ it 'sets the build state to received' do service.run - expect(job.reload.source.state).to eq('received') + expect(job.reload.source.state).to eq(:received) end end @@ -108,7 +108,7 @@ it 'sets the build state to started' do service.run - expect(job.reload.source.state).to eq('started') + expect(job.reload.source.state).to eq(:started) end it 'sets the build started_at' do @@ -118,7 +118,7 @@ it 'sets the build state to started' do service.run - expect(job.reload.source.state).to eq('started') + expect(job.reload.source.state).to eq(:started) end it 'sets the repository last_build_state to started' do @@ -162,7 +162,7 @@ it 'sets the build state to passed' do service.run - expect(job.reload.source.state).to eq('passed') + expect(job.reload.source.state).to eq(:passed) end it 'sets the build finished_at' do @@ -221,7 +221,7 @@ it 'resets the build state to started' do service.run - expect(job.reload.source.state).to eq('created') + expect(job.reload.source.state).to eq(:created) end it 'resets the build started_at' do @@ -231,7 +231,7 @@ it 'resets the build state to started' do service.run - expect(job.reload.source.state).to eq('created') + expect(job.reload.source.state).to eq(:created) end it 'resets the repository last_build_state to started' do diff --git a/spec/lib/travis/config_spec.rb b/spec/lib/travis/config_spec.rb index c70ca651b0..af26192eaa 100644 --- a/spec/lib/travis/config_spec.rb +++ b/spec/lib/travis/config_spec.rb @@ -79,7 +79,7 @@ :database => 'travis_test', :encoding => 'unicode', :min_messages => 'warning', - :variables => { :statement_timeout => 45000 } + :variables => { :statement_timeout => 10000 } }) end end From ad89c7bbe14b35362b8b65312000f5d77358c354 Mon Sep 17 00:00:00 2001 From: Sebastian Karpeta Date: Wed, 3 Apr 2024 14:40:42 +0200 Subject: [PATCH 39/46] TravisCI API. Adding libcurl library. --- Dockerfile.tcie | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.tcie b/Dockerfile.tcie index f48901bd0b..de770746d5 100644 --- a/Dockerfile.tcie +++ b/Dockerfile.tcie @@ -9,7 +9,7 @@ RUN ( \ chown -R travis:travis /app; \ apt-get update ; \ apt-get upgrade -y ; \ - apt-get install -y --no-install-recommends git make gcc g++ libpq-dev libjemalloc-dev xz-utils \ + apt-get install -y --no-install-recommends git make gcc g++ libpq-dev libjemalloc-dev xz-utils libcurl curl \ && rm -rf /var/lib/apt/lists/*; \ gem update --system; \ bundle config set app_config /app; \ From e4d67d7de31236dd64964eba2510c42d2ec576f5 Mon Sep 17 00:00:00 2001 From: GbArc Date: Thu, 4 Apr 2024 14:19:32 +0200 Subject: [PATCH 40/46] libcurl4 ship:docker --- Dockerfile.tcie | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.tcie b/Dockerfile.tcie index de770746d5..46e46d94bd 100644 --- a/Dockerfile.tcie +++ b/Dockerfile.tcie @@ -9,7 +9,7 @@ RUN ( \ chown -R travis:travis /app; \ apt-get update ; \ apt-get upgrade -y ; \ - apt-get install -y --no-install-recommends git make gcc g++ libpq-dev libjemalloc-dev xz-utils libcurl curl \ + apt-get install -y --no-install-recommends git make gcc g++ libpq-dev libjemalloc-dev xz-utils libcurl4 curl \ && rm -rf /var/lib/apt/lists/*; \ gem update --system; \ bundle config set app_config /app; \ From ec37998a8d6a3cd82737a6135466c8d04c4e1cc4 Mon Sep 17 00:00:00 2001 From: GbArc Date: Tue, 9 Apr 2024 10:39:44 +0200 Subject: [PATCH 41/46] allowance for tcie ship:docker --- lib/travis/api/v3/queries/allowance.rb | 2 ++ lib/travis/api/v3/queries/user.rb | 4 ++++ lib/travis/api/v3/renderer/owner.rb | 2 ++ 3 files changed, 8 insertions(+) diff --git a/lib/travis/api/v3/queries/allowance.rb b/lib/travis/api/v3/queries/allowance.rb index 3b341787f5..7b3a5ed9e5 100644 --- a/lib/travis/api/v3/queries/allowance.rb +++ b/lib/travis/api/v3/queries/allowance.rb @@ -3,6 +3,8 @@ class Queries::Allowance < Query params :login, :github_id, :provider def for_owner(owner, user_id) + return true if !!Travis.config.enterprise + client = BillingClient.new(user_id) client.allowance(owner_type(owner), owner.id) end diff --git a/lib/travis/api/v3/queries/user.rb b/lib/travis/api/v3/queries/user.rb index 8da30114bc..2fcacfe7b9 100644 --- a/lib/travis/api/v3/queries/user.rb +++ b/lib/travis/api/v3/queries/user.rb @@ -27,6 +27,7 @@ def collaborator?(id) user = Models::User.find_by_id(id) if id return false unless user + owners=[] user.organizations.each do |org| owners << { @@ -34,6 +35,9 @@ def collaborator?(id) :type => 'Organization' } end + + return owners.length > 0 if !!Travis.config.enterprise + Models::Repository.where(id: user.shared_repositories_ids).uniq.pluck(:owner_id, :owner_type).each do |owner| owners << { :id => owner[0], diff --git a/lib/travis/api/v3/renderer/owner.rb b/lib/travis/api/v3/renderer/owner.rb index 89f305cc37..7eec2a3a1f 100644 --- a/lib/travis/api/v3/renderer/owner.rb +++ b/lib/travis/api/v3/renderer/owner.rb @@ -31,6 +31,8 @@ def allow_migration end def allowance + return BillingClient.minimal_allowance_response(id) if !!Travis.config.enterprise + return BillingClient.default_allowance_response(id) if Travis.config.org? return BillingClient.default_allowance_response(id) unless access_control.user From 68eef36b8fe5e6d55f2df9628678edf888c2998c Mon Sep 17 00:00:00 2001 From: GbArc Date: Tue, 9 Apr 2024 13:25:18 +0200 Subject: [PATCH 42/46] allowance ship:docker --- lib/travis/api/v3/renderer/user.rb | 6 ++++++ lib/travis/api/v3/services/allowance/for_owner.rb | 3 +++ 2 files changed, 9 insertions(+) diff --git a/lib/travis/api/v3/renderer/user.rb b/lib/travis/api/v3/renderer/user.rb index bab6112d53..9ebcc65040 100644 --- a/lib/travis/api/v3/renderer/user.rb +++ b/lib/travis/api/v3/renderer/user.rb @@ -22,6 +22,12 @@ def secure_user_hash OpenSSL::HMAC.hexdigest('sha256', hmac_secret_key, @model.id.to_s) if @model.id && hmac_secret_key end + def confirmed_at + return Date.new(2000,1,1) if !!Travis.config.enterprise + + @model.confirmed_at + end + def ro_mode return false unless Travis.config.org? && Travis.config.read_only? diff --git a/lib/travis/api/v3/services/allowance/for_owner.rb b/lib/travis/api/v3/services/allowance/for_owner.rb index e70c6ca9dd..3e6e38e713 100644 --- a/lib/travis/api/v3/services/allowance/for_owner.rb +++ b/lib/travis/api/v3/services/allowance/for_owner.rb @@ -1,6 +1,9 @@ module Travis::API::V3 class Services::Allowance::ForOwner < Service def run! + + return result BillingClient.default_allowance_response if !!Travis.config.enterprise + return result BillingClient.default_allowance_response if Travis.config.org? raise LoginRequired unless access_control.logged_in? From 43ef552b1f1201bcf3747df5468b134496272241 Mon Sep 17 00:00:00 2001 From: GbArc Date: Fri, 12 Apr 2024 10:39:56 +0200 Subject: [PATCH 43/46] Dockerfile revert ship:docker --- Dockerfile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index d3e74bf295..b4644f3650 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,17 +2,13 @@ FROM ruby:3.2.2-slim LABEL maintainer Travis CI GmbH +# packages required for bundle install RUN ( \ - mkdir -p /app/vendor /app/cache; \ - groupadd -r travis -g 1000 && \ - useradd -u 1000 -r -g travis -s /bin/sh -c "travis user" -d "/app" travis;\ - chown -R travis:travis /app; \ apt-get update ; \ apt-get install -y --no-install-recommends git make gcc g++ libpq-dev libjemalloc-dev libcurl4\ && rm -rf /var/lib/apt/lists/* \ ) -USER travis ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 # throw errors if Gemfile has been modified since Gemfile.lock @@ -32,4 +28,4 @@ RUN gem install --user-install executable-hooks COPY . /app -CMD ["./script/server-buildpacks"] +CMD ./script/server-buildpacks From 45efe5c33f9a9f36a2ebe640b2c93f3af73c997c Mon Sep 17 00:00:00 2001 From: GbArc Date: Tue, 16 Apr 2024 15:18:44 +0200 Subject: [PATCH 44/46] endpoint updates ship:docker --- lib/travis/api/v3/remote_query.rb | 6 +++++- lib/travis/remote_log.rb | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/travis/api/v3/remote_query.rb b/lib/travis/api/v3/remote_query.rb index d13b7c0fc7..75cd52454b 100644 --- a/lib/travis/api/v3/remote_query.rb +++ b/lib/travis/api/v3/remote_query.rb @@ -80,7 +80,7 @@ def s3_connection s3_config[:secret_access_key] ), region: s3_config[:region] || 'us-east-2', - endpoint: s3_config[:hostname] + endpoint: endpoint ) else Aws::S3::Client.new( @@ -93,6 +93,10 @@ def s3_connection end end + def endpoint + s3_config[:hostname]&.index('http') == 0 ? s3_config[:hostname] : "https://#{s3_config[:hostname]}" + end + def s3_objects files = s3_connection.list_objects(bucket: s3_config[:bucket_name], prefix: prefix) files&.contents.map { |file| S3Wrapper.new(file, s3_get_body(file.key)) } diff --git a/lib/travis/remote_log.rb b/lib/travis/remote_log.rb index 95e97517ed..d08960f68a 100644 --- a/lib/travis/remote_log.rb +++ b/lib/travis/remote_log.rb @@ -320,10 +320,14 @@ def initialize(platform: :default) secret_access_key: archive_s3_config[:secret_access_key], bucket_name: archive_s3_config[:bucket] || archive_s3_config[:bucket_name] || archive_s3_bucket, region: archive_s3_config[:region] || 'us-east-2', - endpoint: archive_s3_config[:endpoint] + endpoint: endpoint ) end + private def endpoint + archive_s3_config[:endpoint]&.index('http') == 0 ? archive_s3_config[:endpoint] : "https://#{archive_s3_config[:endpoint]}" + end + private def archive_s3_bucket @archive_s3_bucket ||= [ Travis.env == 'staging' ? 'archive-staging' : 'archive', From f435814476c4a21edad96703e96346b57ffd7b04 Mon Sep 17 00:00:00 2001 From: AndriiMysko Date: Wed, 17 Apr 2024 10:31:02 +0300 Subject: [PATCH 45/46] Implement legacy roles option --- lib/travis/api/app/endpoint/builds.rb | 4 +- lib/travis/api/app/endpoint/hooks.rb | 2 +- lib/travis/api/app/endpoint/jobs.rb | 4 +- lib/travis/api/app/endpoint/logs.rb | 2 +- lib/travis/api/app/endpoint/repos.rb | 20 ++++----- .../api/app/endpoint/setting_endpoint.rb | 10 ++--- .../endpoint/singleton_settings_endpoint.rb | 4 +- .../api/enqueue/services/restart_model.rb | 6 +++ lib/travis/api/v3/permissions/build.rb | 6 +++ lib/travis/api/v3/permissions/cron.rb | 2 + lib/travis/api/v3/permissions/env_var.rb | 4 ++ lib/travis/api/v3/permissions/job.rb | 12 +++++ lib/travis/api/v3/permissions/key_pair.rb | 4 ++ lib/travis/api/v3/permissions/log.rb | 10 +++++ lib/travis/api/v3/permissions/organization.rb | 20 +++++++++ lib/travis/api/v3/permissions/repository.rb | 44 +++++++++++++++++++ lib/travis/api/v3/permissions/subscription.rb | 4 +- lib/travis/api/v3/permissions/trial.rb | 5 +-- lib/travis/api/v3/permissions/user_setting.rb | 4 ++ lib/travis/api/v3/services/caches/delete.rb | 2 +- lib/travis/api/v3/services/caches/find.rb | 2 +- lib/travis/api/v3/services/log/find.rb | 2 +- .../api/v3/services/repository/activate.rb | 2 +- .../api/v3/services/repository/deactivate.rb | 2 +- lib/travis/api/v3/services/v2_plans/all.rb | 2 +- lib/travis/config/defaults.rb | 3 +- 26 files changed, 147 insertions(+), 35 deletions(-) diff --git a/lib/travis/api/app/endpoint/builds.rb b/lib/travis/api/app/endpoint/builds.rb index 17549cb392..02b1c72d26 100644 --- a/lib/travis/api/app/endpoint/builds.rb +++ b/lib/travis/api/app/endpoint/builds.rb @@ -24,7 +24,7 @@ class Builds < Endpoint service = Travis::Enqueue::Services::CancelModel.new(current_user, { build_id: params[:id] }) - auth_for_repo(service&.target&.repository&.id, 'repository_build_cancel') + auth_for_repo(service&.target&.repository&.id, 'repository_build_cancel') unless Travis.config.legacy_roles if !service.authorized? json = { error: { @@ -60,7 +60,7 @@ class Builds < Endpoint service = Travis::Enqueue::Services::RestartModel.new(current_user, build_id: params[:id]) disallow_migrating!(service.repository) - auth_for_repo(service.repository.id, 'repository_build_restart') + auth_for_repo(service.repository.id, 'repository_build_restart') unless Travis.config.legacy_roles result = if !service.accept? status 400 diff --git a/lib/travis/api/app/endpoint/hooks.rb b/lib/travis/api/app/endpoint/hooks.rb index dd4efdb131..ca5024fc5e 100644 --- a/lib/travis/api/app/endpoint/hooks.rb +++ b/lib/travis/api/app/endpoint/hooks.rb @@ -11,7 +11,7 @@ class Hooks < Endpoint put '/:id?', scope: :private do service = service(:update_hook, id: params[:id] || params[:hook][:id], active: params[:hook][:active]) - auth_for_repo(params[:id] || params[:hook][:id], 'repository_state_update') + auth_for_repo(params[:id] || params[:hook][:id], 'repository_state_update') unless Travis.config.legacy_roles disallow_migrating!(service.repo) respond_with service end diff --git a/lib/travis/api/app/endpoint/jobs.rb b/lib/travis/api/app/endpoint/jobs.rb index 9fceafd73e..19b4ece341 100644 --- a/lib/travis/api/app/endpoint/jobs.rb +++ b/lib/travis/api/app/endpoint/jobs.rb @@ -32,7 +32,7 @@ class Jobs < Endpoint service = Travis::Enqueue::Services::CancelModel.new(current_user, { job_id: params[:id] }) - auth_for_repo(service&.target&.repository&.id, 'repository_build_cancel') + auth_for_repo(service&.target&.repository&.id, 'repository_build_cancel') unless Travis.config.legacy_roles if !service.authorized? json = { error: { @@ -65,7 +65,7 @@ class Jobs < Endpoint service = Travis::Enqueue::Services::RestartModel.new(current_user, { job_id: params[:id] }) - auth_for_repo(service&.repository&.id, 'repository_build_restart') + auth_for_repo(service&.repository&.id, 'repository_build_restart') unless Travis.config.legacy_roles disallow_migrating!(service.repository) result = if !service.accept? diff --git a/lib/travis/api/app/endpoint/logs.rb b/lib/travis/api/app/endpoint/logs.rb index e5938d0cd7..a784a2aa91 100644 --- a/lib/travis/api/app/endpoint/logs.rb +++ b/lib/travis/api/app/endpoint/logs.rb @@ -14,7 +14,7 @@ class Logs < Endpoint repo = Travis::API::V3::Models::Repository.find(job.repository.id) - auth_for_repo(repo.id, 'repository_log_view') + auth_for_repo(repo.id, 'repository_log_view') unless Travis.config.legacy_roles repo_can_write = current_user ? !!repo.users.where(id: current_user.id, permissions: { push: true }).first : false diff --git a/lib/travis/api/app/endpoint/repos.rb b/lib/travis/api/app/endpoint/repos.rb index 133264ba6b..550da15dab 100644 --- a/lib/travis/api/app/endpoint/repos.rb +++ b/lib/travis/api/app/endpoint/repos.rb @@ -71,7 +71,7 @@ class Repos < Endpoint # Get settings for a given repository # get '/:id/settings', scope: :private do - auth_for_repo(params['id'], 'repository_settings_read') + auth_for_repo(params['id'], 'repository_settings_read') unless Travis.config.legacy_roles settings = service(:find_repo_settings, params).run if settings respond_with({ settings: settings.simple_attributes }, version: :v2) @@ -83,7 +83,7 @@ class Repos < Endpoint patch '/:id/settings', scope: :private do payload = JSON.parse request.body.read - auth_for_repo(params['id'], 'repository_settings_update') + auth_for_repo(params['id'], 'repository_settings_update') unless Travis.config.legacy_roles if payload['settings'].blank? || !payload['settings'].is_a?(Hash) halt 422, { "error" => "Settings must be passed with a request" } end @@ -115,14 +115,14 @@ class Repos < Endpoint # # json(:repository_key) get '/:id/key' do - auth_for_repo(params['id'], 'repository_settings_read') + auth_for_repo(params['id'], 'repository_settings_read') unless Travis.config.legacy_roles respond_with service(:find_repo_key, params), version: :v2 respond_with service(:find_repo_key, params), type: :ssl_key, version: :v2 end post '/:id/key' do - auth_for_repo(params['id'], 'repository_settings_create') + auth_for_repo(params['id'], 'repository_settings_create') unless Travis.config.legacy_roles service = service(:regenerate_repo_key, params) disallow_migrating!(service.repo) respond_with service, version: :v2 @@ -141,14 +141,14 @@ class Repos < Endpoint # List caches for a given repo. Can be filtered with `branch` and `match` query parameter. get '/:repository_id/caches', scope: :private do - auth_for_repo(params['repository_id'], 'repository_cache_view') + auth_for_repo(params['repository_id'], 'repository_cache_view') unless Travis.config.legacy_roles respond_with service(:find_caches, params), type: :caches, version: :v2 end # Delete caches for a given repo. Can be filtered with `branch` and `match` query parameter. delete '/:repository_id/caches', scope: :private do - auth_for_repo(params['repository_id'], 'repository_cache_delete') + auth_for_repo(params['repository_id'], 'repository_cache_delete') unless Travis.config.legacy_roles respond_with service(:delete_caches, params), type: :caches, version: :v2 end @@ -197,7 +197,7 @@ class Repos < Endpoint repo = service(:find_repo, params).run halt 404 unless repo - auth_for_repo(repo&.id, 'repository_settings_read') + auth_for_repo(repo&.id, 'repository_settings_read') unless Travis.config.legacy_roles respond_with service(:find_repo_key, params), type: :ssl_key, version: :v2 end @@ -206,7 +206,7 @@ class Repos < Endpoint halt 404 unless repo - auth_for_repo(repo&.id, 'repository_settings_create') + auth_for_repo(repo&.id, 'repository_settings_create') unless Travis.config.legacy_roles service = service(:regenerate_repo_key, params) disallow_migrating!(service.repo) respond_with service, version: :v2 @@ -226,14 +226,14 @@ class Repos < Endpoint # List caches for a given repo. Can be filtered with `branch` and `match` query parameter. get '/:owner_name/:name/caches', scope: :private do repo = service(:find_repo, params).run - auth_for_repo(repo&.id, 'repository_cache_view') + auth_for_repo(repo&.id, 'repository_cache_view') unless Travis.config.legacy_roles respond_with service(:find_caches, params), type: :caches, version: :v2 end # Delete caches for a given repo. Can be filtered with `branch` and `match` query parameter. delete '/:owner_name/:name/caches', scope: :private do repo = service(:find_repo, params).run - auth_for_repo(repo&.id, 'repository_cache_delete') + auth_for_repo(repo&.id, 'repository_cache_delete') unless Travis.config.legacy_roles respond_with service(:delete_caches, params), type: :caches, version: :v2 end end diff --git a/lib/travis/api/app/endpoint/setting_endpoint.rb b/lib/travis/api/app/endpoint/setting_endpoint.rb index b4105d9b58..8b10a26213 100644 --- a/lib/travis/api/app/endpoint/setting_endpoint.rb +++ b/lib/travis/api/app/endpoint/setting_endpoint.rb @@ -39,20 +39,20 @@ def define_routes! # Rails style methods for easy overriding def index - auth_for_repo(repo.id, 'repository_settings_read') + auth_for_repo(repo.id, 'repository_settings_read') unless Travis.config.legacy_roles respond_with(collection, type: name, version: :v2) end def show - auth_for_repo(repo.id, 'repository_settings_read') + auth_for_repo(repo.id, 'repository_settings_read') unless Travis.config.legacy_roles respond_with(record, type: singular_name, version: :v2) end def update - auth_for_repo(repo.id, 'repository_settings_update') + auth_for_repo(repo.id, 'repository_settings_update') unless Travis.config.legacy_roles disallow_migrating!(repo) @@ -77,7 +77,7 @@ def update def create - auth_for_repo(repo.id, 'repository_settings_create') + auth_for_repo(repo.id, 'repository_settings_create') unless Travis.config.legacy_roles disallow_migrating!(repo) @@ -101,7 +101,7 @@ def create end def destroy - auth_for_repo(repo.id, 'repository_settings_delete') + auth_for_repo(repo.id, 'repository_settings_delete') unless Travis.config.legacy_roles disallow_migrating!(repo) diff --git a/lib/travis/api/app/endpoint/singleton_settings_endpoint.rb b/lib/travis/api/app/endpoint/singleton_settings_endpoint.rb index 81832a67d9..879fa0954c 100644 --- a/lib/travis/api/app/endpoint/singleton_settings_endpoint.rb +++ b/lib/travis/api/app/endpoint/singleton_settings_endpoint.rb @@ -16,7 +16,7 @@ def create_settings_class(name) end def update - auth_for_repo(parent.repository.id, 'repository_settings_update') + auth_for_repo(parent.repository.id, 'repository_settings_update') unless Travis.config.legacy_roles disallow_migrating!(parent.repository) @@ -32,7 +32,7 @@ def update end def destroy - auth_for_repo(parent.repository.id, 'repository_settings_delete') + auth_for_repo(parent.repository.id, 'repository_settings_delete') unless Travis.config.legacy_roles disallow_migrating!(parent.repository) diff --git a/lib/travis/api/enqueue/services/restart_model.rb b/lib/travis/api/enqueue/services/restart_model.rb index b7bdf2c92e..7ee56d1e84 100644 --- a/lib/travis/api/enqueue/services/restart_model.rb +++ b/lib/travis/api/enqueue/services/restart_model.rb @@ -109,11 +109,17 @@ def permission? end def build_permission? + return build_permission_legacy? if Travis.config.legacy_roles + # nil value is considered true return true if authorizer.for_repo(repository.id,'repository_build_restart') false rescue Travis::API::V3::AuthorizerError + build_permission_legacy? + end + + def build_permission_legacy? return false if repository.permissions.find_by(user_id: current_user.id).build == false return false if repository.owner_type == 'Organization' && repository.owner.memberships.find_by(user_id: current_user.id)&.build_permission == false diff --git a/lib/travis/api/v3/permissions/build.rb b/lib/travis/api/v3/permissions/build.rb index 71acdbad9f..513a5a9e7b 100644 --- a/lib/travis/api/v3/permissions/build.rb +++ b/lib/travis/api/v3/permissions/build.rb @@ -3,14 +3,20 @@ module Travis::API::V3 class Permissions::Build < Permissions::Generic def cancel? + return cancelable? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_build_cancel') end def restart? + return restartable? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_build_restart') end def prioritize? + return read? && build_priorities? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_build_create') && build_priorities? end end diff --git a/lib/travis/api/v3/permissions/cron.rb b/lib/travis/api/v3/permissions/cron.rb index 5ca222bf6c..ee3ffc3c25 100644 --- a/lib/travis/api/v3/permissions/cron.rb +++ b/lib/travis/api/v3/permissions/cron.rb @@ -3,6 +3,8 @@ module Travis::API::V3 class Permissions::Cron < Permissions::Generic def delete? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.branch.repository_id, 'repository_settings_delete') end diff --git a/lib/travis/api/v3/permissions/env_var.rb b/lib/travis/api/v3/permissions/env_var.rb index 3f17070e89..e76e6de365 100644 --- a/lib/travis/api/v3/permissions/env_var.rb +++ b/lib/travis/api/v3/permissions/env_var.rb @@ -1,10 +1,14 @@ module Travis::API::V3 class Permissions::EnvVar < Permissions::Generic def read? + return repository_permissions.read? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_settings_read') end def write? + return repository_permissions.write? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_settings_create') || authorizer.for_repo(object.repository_id, 'repository_settings_update') end diff --git a/lib/travis/api/v3/permissions/job.rb b/lib/travis/api/v3/permissions/job.rb index 03ede064a5..9fe93a2ec9 100644 --- a/lib/travis/api/v3/permissions/job.rb +++ b/lib/travis/api/v3/permissions/job.rb @@ -3,26 +3,38 @@ module Travis::API::V3 class Permissions::Job < Permissions::Generic def cancel? + return cancelable? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_build_cancel') end def restart? + return restartable? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_build_restart') end def debug? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_build_debug') end def delete_log? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_log_delete') end def view_log? + return read? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_log_view') end def prioritize? + return read? && build_priorities? if Travis.config.legacy_roles + authorizer.for_repo(object.repository_id, 'repository_build_create') && build_priorities? end end diff --git a/lib/travis/api/v3/permissions/key_pair.rb b/lib/travis/api/v3/permissions/key_pair.rb index 20c30f6345..c0f3f68b5e 100644 --- a/lib/travis/api/v3/permissions/key_pair.rb +++ b/lib/travis/api/v3/permissions/key_pair.rb @@ -1,10 +1,14 @@ module Travis::API::V3 class Permissions::KeyPair < Permissions::Generic def read? + return repository_permissions.read? if Travis.config.legacy_roles + authorizer.for_repo(object.repository.id, 'repository_settings_read') end def write? + return repository_permissions.write? if Travis.config.legacy_roles + authorizer.for_repo(object.repository.id, 'repository_settings_create') end diff --git a/lib/travis/api/v3/permissions/log.rb b/lib/travis/api/v3/permissions/log.rb index a627232a58..3a424cdcca 100644 --- a/lib/travis/api/v3/permissions/log.rb +++ b/lib/travis/api/v3/permissions/log.rb @@ -3,22 +3,32 @@ module Travis::API::V3 class Permissions::Log < Permissions::Generic def cancel? + return cancelable? if Travis.config.legacy_roles + authorizer.for_repo(object.job.repository_id, 'repository_build_cancel') end def restart? + return restartable? if Travis.config.legacy_roles + authorizer.for_repo(object.job.repository_id, 'repository_build_restart') end def debug? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.job.repository_id, 'repository_build_debug') end def delete_log? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.job.repository_id, 'repository_log_delete') end def view_log? + return read? if Travis.config.legacy_roles + authorizer.for_repo(object.job.repository_id, 'repository_log_view') end end diff --git a/lib/travis/api/v3/permissions/organization.rb b/lib/travis/api/v3/permissions/organization.rb index 599769e320..e9c45f1a25 100644 --- a/lib/travis/api/v3/permissions/organization.rb +++ b/lib/travis/api/v3/permissions/organization.rb @@ -3,42 +3,62 @@ module Travis::API::V3 class Permissions::Organization < Permissions::Generic def sync? + return write? if Travis.config.legacy_roles + authorizer.has_org_role?(object.id, 'account_admin') end def settings_delete? + return write? if Travis.config.legacy_roles + authorizer.for_org(object.id, 'account_settings_delete') end def settings_create? + return write? if Travis.config.legacy_roles + authorizer.for_org(object.id, 'account_settings_create') end def plan_invoices? + return write? if Travis.config.legacy_roles + authorizer.for_org(object.id, 'account_plan_invoices') end def plan_usage? + return write? if Travis.config.legacy_roles + authorizer.for_org(object.id, 'account_plan_usage') end def plan_view? + return write? if Travis.config.legacy_roles + authorizer.for_org(object.id, 'account_plan_view') end def plan_create? + return adminable? if Travis.config.legacy_roles + authorizer.for_org(object.id, 'account_plan_create') end def billing_update? + return write? if Travis.config.legacy_roles + authorizer.for_org(object.id, 'account_billing_update') end def billing_view? + return write? if Travis.config.legacy_roles + authorizer.for_org(object.id, 'account_billing_view') end def admin? + return adminable? if Travis.config.legacy_roles + authorizer.has_org_role?(object.id, 'account_admin') end diff --git a/lib/travis/api/v3/permissions/repository.rb b/lib/travis/api/v3/permissions/repository.rb index a30f1c197f..6895403140 100644 --- a/lib/travis/api/v3/permissions/repository.rb +++ b/lib/travis/api/v3/permissions/repository.rb @@ -3,16 +3,22 @@ module Travis::API::V3 class Permissions::Repository < Permissions::Generic def activate? + return write? if Travis.config.legacy_roles + notgit_allowance = object.server_type == nil || object.server_type == 'git' || admin? authorizer.for_repo(object.id, 'repository_state_update') && notgit_allowance end def deactivate? + return write? if Travis.config.legacy_roles + notgit_allowance = object.server_type == nil || object.server_type == 'git' || admin? authorizer.for_repo(object.id, 'repository_state_update') && notgit_allowance end def migrate? + return admin? && object.allow_migration? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_state_update') && object.allow_migration? end @@ -25,78 +31,116 @@ def unstar? end def create_cron? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_settings_create') && authorizer.for_repo(object.id, 'repository_build_create') end def create_env_var? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_settings_create') end def create_key_pair? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_settings_create') end def delete_key_pair? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_settings_delete') end def create_request? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_build_create') end def check_scan_results? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_scans_view') end def settings_create? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_settings_create') end def settings_delete? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_settings_delete') end def settings_update? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_settings_update') end def settings_read? + return read? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_settings_read') end def build_restart? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_build_restart') end def build_create? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_build_create') end def build_cancel? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_build_cancel') end def build_debug? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_build_debug') end def log_view? + return read? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_log_view') end def log_delete? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_log_delete') end def cache_delete? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_cache_delete') end def cache_view? + return write? if Travis.config.legacy_roles + authorizer.for_repo(object.id, 'repository_cache_view') end def admin? + return access_control.adminable? object if Travis.config.legacy_roles + authorizer.has_repo_role?(object.id, 'repository_admin') end end diff --git a/lib/travis/api/v3/permissions/subscription.rb b/lib/travis/api/v3/permissions/subscription.rb index 8ebb1dea46..88c92dc33c 100644 --- a/lib/travis/api/v3/permissions/subscription.rb +++ b/lib/travis/api/v3/permissions/subscription.rb @@ -1,13 +1,13 @@ module Travis::API::V3 class Permissions::Subscription < Permissions::Generic def read? - return object.permissions.read? if object.owner.is_a?(Travis::API::V3::Models::User) + return object.permissions.read? if Travis.config.legacy_roles || object.owner.is_a?(Travis::API::V3::Models::User) authorizer.for_org(object.owner.id, 'account_billing_view') end def write? - return object.permissions.write? if object.owner.is_a?(Travis::API::V3::Models::User) + return object.permissions.write? if Travis.config.legacy_roles || object.owner.is_a?(Travis::API::V3::Models::User) authorizer.for_org(object.owner.id, 'account_billing_update') end diff --git a/lib/travis/api/v3/permissions/trial.rb b/lib/travis/api/v3/permissions/trial.rb index 30e69afaf9..ea24ea29bd 100644 --- a/lib/travis/api/v3/permissions/trial.rb +++ b/lib/travis/api/v3/permissions/trial.rb @@ -1,14 +1,13 @@ module Travis::API::V3 class Permissions::Trial < Permissions::Generic def read? - - return object.permissions.read? if object.owner.is_a?(Travis::API::V3::Models::User) + return object.permissions.read? if Travis.config.legacy_roles || object.owner.is_a?(Travis::API::V3::Models::User) authorizer.for_org(object.owner.id, 'account_billing_view') end def write? - return object.permissions.write? if object.owner.is_a?(Travis::API::V3::Models::User) + return object.permissions.write? if Travis.config.legacy_roles || object.owner.is_a?(Travis::API::V3::Models::User) authorizer.for_org(object.owner.id, 'account_billing_update') end diff --git a/lib/travis/api/v3/permissions/user_setting.rb b/lib/travis/api/v3/permissions/user_setting.rb index 40e00a1cbb..9598574837 100644 --- a/lib/travis/api/v3/permissions/user_setting.rb +++ b/lib/travis/api/v3/permissions/user_setting.rb @@ -1,10 +1,14 @@ module Travis::API::V3 class Permissions::UserSetting < Permissions::Generic def read? + return repository_permissions.read? if Travis.config.legacy_roles + authorizer.for_repo(object.repository.id, 'repository_settings_read') end def write? + return repository_permissions.write? if Travis.config.legacy_roles + authorizer.for_repo(object.repository.id, 'repository_settings_create') end diff --git a/lib/travis/api/v3/services/caches/delete.rb b/lib/travis/api/v3/services/caches/delete.rb index ce52aa7dde..1598e8798e 100644 --- a/lib/travis/api/v3/services/caches/delete.rb +++ b/lib/travis/api/v3/services/caches/delete.rb @@ -4,7 +4,7 @@ class Services::Caches::Delete < Service def run! repo = check_login_and_find(:repository) - access_control.permissions(repo).cache_delete! + access_control.permissions(repo).cache_delete! unless Travis.config.legacy_roles raise InsufficientAccess unless access_control.user.permission?(:push, repository_id: repo.id) return repo_migrated if migrated?(repo) diff --git a/lib/travis/api/v3/services/caches/find.rb b/lib/travis/api/v3/services/caches/find.rb index 3ebebe9092..0e48860a25 100644 --- a/lib/travis/api/v3/services/caches/find.rb +++ b/lib/travis/api/v3/services/caches/find.rb @@ -4,7 +4,7 @@ class Services::Caches::Find < Service def run! repo = check_login_and_find(:repository) - access_control.permissions(repo).cache_view! + access_control.permissions(repo).cache_view! unless Travis.config.legacy_roles raise InsufficientAccess unless access_control.user.permission?(:push, repository_id: repo.id) result query.find(repo) diff --git a/lib/travis/api/v3/services/log/find.rb b/lib/travis/api/v3/services/log/find.rb index 93a67ee238..a02bb4e3da 100644 --- a/lib/travis/api/v3/services/log/find.rb +++ b/lib/travis/api/v3/services/log/find.rb @@ -11,7 +11,7 @@ def run! repo_can_write = access_control.repo_can_write elsif access_control.user repo_can_write = !!job.repository.users.where(id: access_control.user.id, permissions: { push: true }).first - raise LogAccessDenied unless access_control.permissions(job).view_log? + raise LogAccessDenied if !Travis.config.legacy_roles && !access_control.permissions(job).view_log? end raise(NotFound, :log) unless access_control.visible? log diff --git a/lib/travis/api/v3/services/repository/activate.rb b/lib/travis/api/v3/services/repository/activate.rb index 41bb051166..1a3faee4fd 100644 --- a/lib/travis/api/v3/services/repository/activate.rb +++ b/lib/travis/api/v3/services/repository/activate.rb @@ -8,7 +8,7 @@ def run! check_repo_key(repository) return repo_migrated if migrated?(repository) - admin = access_control.class.name == 'Travis::API::V3::AccessControl::Internal' ? + admin = Travis.config.legacy_roles || access_control.class.name == 'Travis::API::V3::AccessControl::Internal' ? access_control.admin_for(repository) : access_control.user diff --git a/lib/travis/api/v3/services/repository/deactivate.rb b/lib/travis/api/v3/services/repository/deactivate.rb index 5664999dfe..d2e8e4a95d 100644 --- a/lib/travis/api/v3/services/repository/deactivate.rb +++ b/lib/travis/api/v3/services/repository/deactivate.rb @@ -6,7 +6,7 @@ def run!(activate = false) return repo_migrated if migrated?(repository) - if access_control.class.name == 'Travis::API::V3::AccessControl::Internal' + if Travis.config.legacy_roles || access_control.class.name == 'Travis::API::V3::AccessControl::Internal' admin = access_control.admin_for(repository) else admin = access_control.user diff --git a/lib/travis/api/v3/services/v2_plans/all.rb b/lib/travis/api/v3/services/v2_plans/all.rb index a711fee631..7d476311dd 100644 --- a/lib/travis/api/v3/services/v2_plans/all.rb +++ b/lib/travis/api/v3/services/v2_plans/all.rb @@ -10,7 +10,7 @@ def run! end rescue AuthorizerError #nop - end if params.include?('organization_id') + end if !Travis.config.legacy_roles && params.include?('organization_id') result query(:v2_plans).all(access_control.user.id) end diff --git a/lib/travis/config/defaults.rb b/lib/travis/config/defaults.rb index b9a5d8ac0c..6936fa321a 100644 --- a/lib/travis/config/defaults.rb +++ b/lib/travis/config/defaults.rb @@ -93,7 +93,8 @@ def fallback_logs_api_auth_token insights: { endpoint: 'https://insights.travis-ci.dev/', auth_token: 'secret' }, authorizer: { url: 'http://authorizer', auth_key: 'secret' }, recaptcha: { endpoint: 'https://www.google.com', secret: ENV['RECAPTCHA_SECRET_KEY'] || '' }, - antifraud: { captcha_max_failed_attempts: 3, captcha_block_duration: 24, credit_card_max_failed_attempts: 3, credit_card_block_duration: 24 } + antifraud: { captcha_max_failed_attempts: 3, captcha_block_duration: 24, credit_card_max_failed_attempts: 3, credit_card_block_duration: 24 }, + legacy_roles: false default :_access => [:key] From b1921200aac1ebb0c6241aeec07168660a769774 Mon Sep 17 00:00:00 2001 From: GbArc Date: Wed, 17 Apr 2024 09:38:04 +0200 Subject: [PATCH 46/46] test --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7d62a5c0bc..39441a2254 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://travis-ci.com/travis-ci/travis-api.svg?branch=master)](https://travis-ci.com/travis-ci/travis-api) + https://api.travis-ci.org ## WARNING!!!!!