diff --git a/Gemfile b/Gemfile index da99c923..6d870806 100644 --- a/Gemfile +++ b/Gemfile @@ -46,6 +46,7 @@ group :test do gem 'factory_girl', '~> 2.4.0' gem 'mocha', '~> 0.12' gem 'database_cleaner', '~> 0.8.0' + gem 'timecop', '~> 0.8.0' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index d038c01b..f0c2b54b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -73,7 +73,7 @@ GIT GIT remote: git://github.com/travis-ci/travis-migrations.git - revision: fcf6eea3e3122a7cbb857826db835de69974c54d + revision: 3f6bb84800b0222ceba95a4b1368969eb5ede8e0 specs: travis-migrations (0.0.1) @@ -358,6 +358,7 @@ GEM thor (0.19.1) thread_safe (0.3.5) tilt (1.4.1) + timecop (0.8.0) timers (4.0.1) hitimes tool (0.2.3) @@ -414,6 +415,7 @@ DEPENDENCIES sinatra-contrib skylight (~> 0.6.0.beta.1) stackprof + timecop (~> 0.8.0) travis-amqp! travis-api! travis-config (~> 0.1.0) diff --git a/lib/travis/api/v3/access_control/generic.rb b/lib/travis/api/v3/access_control/generic.rb index 048ff7ec..0344b35b 100644 --- a/lib/travis/api/v3/access_control/generic.rb +++ b/lib/travis/api/v3/access_control/generic.rb @@ -59,6 +59,14 @@ module Travis::API::V3 visible? branch.repository end + def cron_visible?(cron) + Travis::Features.owner_active?(:cron, cron.branch.repository.owner) and visible? cron.branch.repository + end + + def cron_writable?(cron) + Travis::Features.owner_active?(:cron, cron.branch.repository.owner) and writable? cron.branch.repository + end + def job_visible?(job) visible? job.repository end diff --git a/lib/travis/api/v3/models/branch.rb b/lib/travis/api/v3/models/branch.rb index df66788e..147a8bfe 100644 --- a/lib/travis/api/v3/models/branch.rb +++ b/lib/travis/api/v3/models/branch.rb @@ -4,6 +4,7 @@ module Travis::API::V3 belongs_to :last_build, class_name: 'Travis::API::V3::Models::Build'.freeze has_many :builds, foreign_key: [:repository_id, :branch], primary_key: [:repository_id, :name], order: 'builds.id DESC'.freeze, conditions: { event_type: 'push' } has_many :commits, foreign_key: [:repository_id, :branch], primary_key: [:repository_id, :name], order: 'commits.id DESC'.freeze + has_one :cron, dependent: :delete def default_branch name == repository.default_branch_name diff --git a/lib/travis/api/v3/models/cron.rb b/lib/travis/api/v3/models/cron.rb new file mode 100644 index 00000000..68f664f2 --- /dev/null +++ b/lib/travis/api/v3/models/cron.rb @@ -0,0 +1,75 @@ +module Travis::API::V3 + class Models::Cron < Model + + belongs_to :branch + + LastBuild = -1 + ThisBuild = 0 + NextBuild = 1 + + def next_enqueuing + if disable_by_build && last_non_cron_build_date > planned_time(LastBuild) + planned_time(NextBuild) + elsif last_cron_build_date >= planned_time(LastBuild) + planned_time(ThisBuild) + else + Time.now + end + end + + def planned_time(in_builds = ThisBuild) + case interval + when 'daily' + planned_time_daily(in_builds) + when 'weekly' + planned_time_weekly(in_builds) + when 'monthly' + planned_time_monthly(in_builds) + end + end + + def planned_time_daily(in_builds) + now = DateTime.now + build_today = DateTime.new(now.year, now.month, now.day, created_at.hour) + return build_today + 1 + in_builds if (now > build_today) + build_today + in_builds + end + + def planned_time_weekly(in_builds) + now = DateTime.now + build_today = DateTime.new(now.year, now.month, now.day, created_at.hour) + next_time = build_today + ((created_at.wday - now.wday) % 7) + return build_today + 7 * (1 + in_builds) if (now > next_time) + next_time + 7 * in_builds + end + + def planned_time_monthly(in_builds) + now = DateTime.now + created = DateTime.new(created_at.year, created_at.month, created_at.day, created_at.hour) + month_since_creation = (now.year * 12 + now.month) - (created_at.year * 12 + created_at.month) + this_month = created >> month_since_creation + return created >> (month_since_creation + 1 + in_builds) if (now > this_month) + created >> (month_since_creation + in_builds) + end + + def last_cron_build_date + last_cron_build = Models::Build.where( + :repository_id => branch.repository.id, + :branch => branch.name, + :event_type => 'cron' + ).order("id DESC").first + return last_cron_build.created_at unless last_cron_build.nil? + Time.at(0) + end + + def last_non_cron_build_date + last_build = Models::Build.where( + :repository_id => branch.repository.id, + :branch => branch.name + ).where(['event_type NOT IN (?)', ['cron']]).order("id DESC").first + return last_build.created_at unless last_build.nil? + Time.at(0) + end + + end +end diff --git a/lib/travis/api/v3/permissions/cron.rb b/lib/travis/api/v3/permissions/cron.rb new file mode 100644 index 00000000..c94b5a70 --- /dev/null +++ b/lib/travis/api/v3/permissions/cron.rb @@ -0,0 +1,13 @@ +require 'travis/api/v3/permissions/generic' + +module Travis::API::V3 + class Permissions::Cron < Permissions::Generic + def delete? + write? and Travis::Features.owner_active?(:cron, object.branch.repository.owner) + end + + def start? + Travis::Features.owner_active?(:cron, object.branch.repository.owner) + end + end +end diff --git a/lib/travis/api/v3/permissions/repository.rb b/lib/travis/api/v3/permissions/repository.rb index 5cfbf5bd..81fb91a1 100644 --- a/lib/travis/api/v3/permissions/repository.rb +++ b/lib/travis/api/v3/permissions/repository.rb @@ -21,5 +21,9 @@ module Travis::API::V3 def create_request? write? end + + def create_cron? + Travis::Features.owner_active?(:cron, object.owner) and write? + end end end diff --git a/lib/travis/api/v3/queries/cron.rb b/lib/travis/api/v3/queries/cron.rb new file mode 100644 index 00000000..43d3cb5f --- /dev/null +++ b/lib/travis/api/v3/queries/cron.rb @@ -0,0 +1,21 @@ +module Travis::API::V3 + class Queries::Cron < Query + params :id + + sortable_by :id + + def find + return Models::Cron.find_by_id(id) if id + raise WrongParams, 'missing cron.id'.freeze + end + + def find_for_branch(branch) + branch.cron + end + + def create(branch, interval, disable_by_build) + branch.cron.destroy unless branch.cron.nil? + Models::Cron.create(branch: branch, interval: interval, disable_by_build: disable_by_build) + end + end +end diff --git a/lib/travis/api/v3/queries/crons.rb b/lib/travis/api/v3/queries/crons.rb new file mode 100644 index 00000000..aec65134 --- /dev/null +++ b/lib/travis/api/v3/queries/crons.rb @@ -0,0 +1,35 @@ +module Travis::API::V3 + class Queries::Crons < Query + + def find(repository) + Models::Cron.where(:branch_id => repository.branches) + end + + def start_all() + Models::Cron.all.select do |cron| + start(cron) if cron.next_enqueuing <= Time.now + end + end + + def start(cron) + branch = cron.branch + raise ServerError, 'repository does not have a github_id'.freeze unless branch.repository.github_id + unless branch.exists_on_github + cron.destroy + return false + end + + user_id = branch.repository.users.detect { |u| u.github_oauth_token }.id + + payload = { + repository: { id: branch.repository.github_id, owner_name: branch.repository.owner_name, name: branch.repository.name }, + branch: branch.name, + user: { id: user_id } + } + + class_name, queue = Query.sidekiq_queue(:build_request) + ::Sidekiq::Client.push('queue'.freeze => queue, 'class'.freeze => class_name, 'args'.freeze => [{type: 'cron'.freeze, payload: JSON.dump(payload), credentials: {}}]) + true + end + end +end diff --git a/lib/travis/api/v3/renderer.rb b/lib/travis/api/v3/renderer.rb index 2ee8ca15..637f937d 100644 --- a/lib/travis/api/v3/renderer.rb +++ b/lib/travis/api/v3/renderer.rb @@ -45,7 +45,7 @@ module Travis::API::V3 when Hash then value.map { |k, v| [k, render_value(v, **options)] }.to_h when Array then value.map { |v | render_value(v, **options) } when *PRIMITIVE then value - when Time then value.strftime('%Y-%m-%dT%H:%M:%SZ') + when Time, DateTime then value.strftime('%Y-%m-%dT%H:%M:%SZ') when Model then render_model(value, **options) when ActiveRecord::Relation then render_value(value.to_a, **options) when ActiveRecord::Associations::CollectionProxy then render_value(value.to_a, **options) diff --git a/lib/travis/api/v3/renderer/cron.rb b/lib/travis/api/v3/renderer/cron.rb new file mode 100644 index 00000000..fdad9263 --- /dev/null +++ b/lib/travis/api/v3/renderer/cron.rb @@ -0,0 +1,13 @@ +require 'travis/api/v3/renderer/model_renderer' + +module Travis::API::V3 + class Renderer::Cron < Renderer::ModelRenderer + representation(:minimal, :id) + representation(:standard, :id, :repository, :branch, :interval, :disable_by_build, :next_enqueuing) + + def repository + model.branch.repository + end + + end +end diff --git a/lib/travis/api/v3/renderer/crons.rb b/lib/travis/api/v3/renderer/crons.rb new file mode 100644 index 00000000..89215f16 --- /dev/null +++ b/lib/travis/api/v3/renderer/crons.rb @@ -0,0 +1,6 @@ +module Travis::API::V3 + class Renderer::Crons < Renderer::CollectionRenderer + type :crons + collection_key :crons + end +end diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb index c515ef56..d22edce9 100644 --- a/lib/travis/api/v3/routes.rb +++ b/lib/travis/api/v3/routes.rb @@ -27,6 +27,14 @@ module Travis::API::V3 end end + + resource :cron do + capture id: :digit + route '/cron/{cron.id}' + get :find + delete :delete + end + resource :job do capture id: :digit route '/job/{job.id}' @@ -81,6 +89,12 @@ module Travis::API::V3 resource :branch do route '/branch/{branch.name}' get :find + + resource :cron do + route '/cron' + get :for_branch + post :create + end end resource :branches do @@ -93,6 +107,11 @@ module Travis::API::V3 get :find end + resource :crons do + route '/crons' + get :for_repository + end + resource :requests do route '/requests' get :find diff --git a/lib/travis/api/v3/routes/dsl.rb b/lib/travis/api/v3/routes/dsl.rb index e71723d7..9a98ada0 100644 --- a/lib/travis/api/v3/routes/dsl.rb +++ b/lib/travis/api/v3/routes/dsl.rb @@ -60,6 +60,10 @@ module Travis::API::V3 current_resource.add_service('POST'.freeze, *args) end + def delete(*args) + current_resource.add_service('DELETE'.freeze, *args) + end + def draw_routes resources.each do |resource| prefix = resource.route diff --git a/lib/travis/api/v3/services.rb b/lib/travis/api/v3/services.rb index 985e9d4e..637ea337 100644 --- a/lib/travis/api/v3/services.rb +++ b/lib/travis/api/v3/services.rb @@ -9,6 +9,8 @@ module Travis::API::V3 Broadcasts = Module.new { extend Services } Build = Module.new { extend Services } Builds = Module.new { extend Services } + Cron = Module.new { extend Services } + Crons = Module.new { extend Services } Job = Module.new { extend Services } Jobs = Module.new { extend Services } Lint = Module.new { extend Services } diff --git a/lib/travis/api/v3/services/cron/create.rb b/lib/travis/api/v3/services/cron/create.rb new file mode 100644 index 00000000..dcbfffb8 --- /dev/null +++ b/lib/travis/api/v3/services/cron/create.rb @@ -0,0 +1,18 @@ +module Travis::API::V3 + class Services::Cron::Create < Service + result_type :cron + params :interval, :disable_by_build + + def run! + raise LoginRequired unless access_control.logged_in? or access_control.full_access? + raise NotFound unless repository = find(:repository) + raise NotFound unless branch = find(:branch, repository) + raise Error.new('Crons can only be set up for branches existing on GitHub!', status: 422) unless branch.exists_on_github + raise Error.new('Invalid value for interval. Interval must be "daily", "weekly" or "monthly"!', status: 422) unless ["daily", "weekly", "monthly"].include?(params["interval"]) + access_control.permissions(repository).create_cron! + access_control.permissions(branch.cron).delete! if branch.cron + query.create(branch, params["interval"], params["disable_by_build"] ? params["disable_by_build"] : false) + end + + end +end diff --git a/lib/travis/api/v3/services/cron/delete.rb b/lib/travis/api/v3/services/cron/delete.rb new file mode 100644 index 00000000..c5d9287d --- /dev/null +++ b/lib/travis/api/v3/services/cron/delete.rb @@ -0,0 +1,12 @@ +module Travis::API::V3 + class Services::Cron::Delete < Service + #params :id + + def run! + raise LoginRequired unless access_control.logged_in? or access_control.full_access? + cron = find + access_control.permissions(cron).delete! + cron.destroy + end + end +end diff --git a/lib/travis/api/v3/services/cron/find.rb b/lib/travis/api/v3/services/cron/find.rb new file mode 100644 index 00000000..6a191d7a --- /dev/null +++ b/lib/travis/api/v3/services/cron/find.rb @@ -0,0 +1,9 @@ +module Travis::API::V3 + class Services::Cron::Find < Service + #params :id + + def run! + find + end + end +end diff --git a/lib/travis/api/v3/services/cron/for_branch.rb b/lib/travis/api/v3/services/cron/for_branch.rb new file mode 100644 index 00000000..cdbc24db --- /dev/null +++ b/lib/travis/api/v3/services/cron/for_branch.rb @@ -0,0 +1,10 @@ +module Travis::API::V3 + class Services::Cron::ForBranch < Service + + def run! + repo = find(:repository) + raise InsufficientAccess unless Travis::Features.owner_active?(:cron, repo.owner) + query.find_for_branch(find(:branch, repo)) + end + end +end diff --git a/lib/travis/api/v3/services/crons/for_repository.rb b/lib/travis/api/v3/services/crons/for_repository.rb new file mode 100644 index 00000000..97fd4a81 --- /dev/null +++ b/lib/travis/api/v3/services/crons/for_repository.rb @@ -0,0 +1,11 @@ +module Travis::API::V3 + class Services::Crons::ForRepository < Service + paginate + + def run! + repo = find(:repository) + raise InsufficientAccess unless Travis::Features.owner_active?(:cron, repo.owner) + query.find(repo) + end + end +end diff --git a/lib/travis/api/v3/services/crons/start.rb b/lib/travis/api/v3/services/crons/start.rb new file mode 100644 index 00000000..104d43f5 --- /dev/null +++ b/lib/travis/api/v3/services/crons/start.rb @@ -0,0 +1,9 @@ +module Travis::API::V3 + class Services::Crons::Start < Service + + def run! + query.start_all() + end + + end +end diff --git a/spec/v3/models/cron_spec.rb b/spec/v3/models/cron_spec.rb new file mode 100644 index 00000000..0ce18c94 --- /dev/null +++ b/spec/v3/models/cron_spec.rb @@ -0,0 +1,231 @@ +require 'spec_helper' +require 'timecop' + +describe Travis::API::V3::Models::Cron do + let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } + let(:branch) { Travis::API::V3::Models::Branch.create(repository: repo, name: 'cron test') } + + describe "next build time is calculated correctly on year changes" do + + before do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + end + + after do + Timecop.return + end + + it "for daily builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'daily', disable_by_build: false) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 1, 16) + build.destroy + cron.destroy + end + + it "for weekly builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'weekly', disable_by_build: false) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 7, 16) + build.destroy + cron.destroy + end + + it "for monthly builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'monthly', disable_by_build: false) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 31, 16) + build.destroy + cron.destroy + end + + end + + describe "push build is ignored if disable by build is false" do + + before do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + end + + after do + Timecop.return + end + + it "for daily builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'daily', disable_by_build: false) + cron_build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + push_build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'push') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 1, 16) + cron_build.destroy + push_build.destroy + cron.destroy + end + + it "for weekly builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'weekly', disable_by_build: false) + cron_build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + push_build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'push') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 7, 16) + cron_build.destroy + push_build.destroy + cron.destroy + end + + it "for monthly builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'monthly', disable_by_build: false) + cron_build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + push_build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'push') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 31, 16) + cron_build.destroy + push_build.destroy + cron.destroy + end + + end + + describe "disable by build works with build" do + + before do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + end + + after do + Timecop.return + end + + it "for daily builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'daily', disable_by_build: true) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'push') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 2, 16) + build.destroy + cron.destroy + end + + it "for weekly builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'weekly', disable_by_build: true) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'push') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 14, 16) + build.destroy + cron.destroy + end + + it "for monthly builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'monthly', disable_by_build: true) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'push') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 2, 29, 16) # it's a leap year :-D + build.destroy + cron.destroy + end + + end + + describe "disable by build works without build" do + + before do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + end + + after do + Timecop.return + end + + it "for daily builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'daily', disable_by_build: true) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 1, 16) + build.destroy + cron.destroy + end + + it "for weekly builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'weekly', disable_by_build: true) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 7, 16) + build.destroy + cron.destroy + end + + it "for monthly builds" do + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'monthly', disable_by_build: true) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + expect(cron.next_enqueuing).to be == DateTime.new(2016, 1, 31, 16) + build.destroy + cron.destroy + end + + end + + describe "build starts now if next build time is in the past" do + + before do + # nothing, this time + # time freeze is performed in examples + end + + after do + Timecop.return + end + + it "for daily builds with disable_by_build true" do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'daily', disable_by_build: true) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + Timecop.freeze(DateTime.new(2016, 1, 1, 19)) + expect(cron.next_enqueuing).to be == DateTime.now + build.destroy + cron.destroy + end + + it "for daily builds with disable_by_build false" do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'daily', disable_by_build: false) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + Timecop.freeze(DateTime.new(2016, 1, 1, 19)) + expect(cron.next_enqueuing).to be == DateTime.now + build.destroy + cron.destroy + end + + it "for weekly builds with disable_by_build true" do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'weekly', disable_by_build: true) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + Timecop.freeze(DateTime.new(2016, 1, 7, 19)) + expect(cron.next_enqueuing).to be == DateTime.now + build.destroy + cron.destroy + end + + it "for weekly builds with disable_by_build false" do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'weekly', disable_by_build: false) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + Timecop.freeze(DateTime.new(2016, 1, 7, 19)) + expect(cron.next_enqueuing).to be == DateTime.now + build.destroy + cron.destroy + end + + it "for monthly builds with disable_by_build true" do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'monthly', disable_by_build: true) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + Timecop.freeze(DateTime.new(2016, 1, 31, 19)) + expect(cron.next_enqueuing).to be == DateTime.now + build.destroy + cron.destroy + end + + it "for monthly builds with disable_by_build false" do + Timecop.travel(DateTime.new(2015, 12, 31, 16)) + cron = Travis::API::V3::Models::Cron.create(branch_id: branch.id, interval: 'monthly', disable_by_build: false) + build = Travis::API::V3::Models::Build.create(:repository_id => repo.id, :branch_name => branch.name, :event_type => 'cron') + Timecop.freeze(DateTime.new(2016, 1, 31, 19)) + expect(cron.next_enqueuing).to be == DateTime.now + build.destroy + cron.destroy + end + + end + +end diff --git a/spec/v3/queries/cron_spec.rb b/spec/v3/queries/cron_spec.rb new file mode 100644 index 00000000..bb4c559a --- /dev/null +++ b/spec/v3/queries/cron_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe Travis::API::V3::Queries::Crons do + let(:user) { Travis::API::V3::Models::User.find_by_login('svenfuchs') } + let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } + let(:existing_branch) { Travis::API::V3::Models::Branch.create(repository: repo, name: 'cron-test-existing', exists_on_github: true) } + let(:non_existing_branch) { Travis::API::V3::Models::Branch.create(repository: repo, name: 'cron-test-non-existing', exists_on_github: false) } + let(:query) { Travis::API::V3::Queries::Crons.new({}, 'Overview') +} + + describe "start all" do + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } + + it "starts crons on existing branches" do + cron = Travis::API::V3::Models::Cron.create(branch_id: existing_branch.id, interval: 'daily', disable_by_build: false) + expect(query.start_all).to include(cron) + + end + + it "delete crons on branches not existing on GitHub" do + cron = Travis::API::V3::Models::Cron.create(branch_id: non_existing_branch.id, interval: 'daily', disable_by_build: false) + expect(query.start_all).to_not include(cron) + expect(Travis::API::V3::Models::Cron.where(id: cron.id).length).to equal(0) + end + end + +end diff --git a/spec/v3/services/cron/create_spec.rb b/spec/v3/services/cron/create_spec.rb new file mode 100644 index 00000000..dc578e80 --- /dev/null +++ b/spec/v3/services/cron/create_spec.rb @@ -0,0 +1,153 @@ +require 'spec_helper' + +describe Travis::API::V3::Services::Cron::Create do + let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } + let(:branch) { Travis::API::V3::Models::Branch.where(repository_id: repo).first } + let(:non_existing_branch) { Travis::API::V3::Models::Branch.create(repository: repo, name: 'cron-test', exists_on_github: false) } + let(:last_cron) {Travis::API::V3::Models::Cron.where(branch_id: branch.id).last} + let(:current_cron) {Travis::API::V3::Models::Cron.where(branch_id: branch.id).last} + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}", "Content-Type" => "application/json" }} + let(:options) {{ "interval" => "monthly", "disable_by_build" => false }} + let(:wrong_options) {{ "interval" => "notExisting", "disable_by_build" => false }} + let(:parsed_body) { JSON.load(body) } + + before do + Travis::Features.activate_owner(:cron, repo.owner) + end + + describe "creating a cron job with feature flag disabled" do + before { Travis::Features.deactivate_owner(:cron, repo.owner) } + before { post("/v3/repo/#{repo.id}/branch/#{branch.name}/cron", options, headers)} + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "insufficient_access", + "error_message" => "operation requires create_cron access to repository", + "resource_type" => "repository", + "permission" => "create_cron", + "repository" => { + "@type" => "repository", + "@href" => "/repo/#{repo.id}", # should be /v3/repo/#{repo.id} + "@representation" => "minimal", + "id" => repo.id, + "name" => "minimal", + "slug" => "svenfuchs/minimal" } + }} + end + + describe "creating a cron job" do + before { last_cron } + 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) } + example { expect(current_cron == last_cron).to be_falsey } + example { expect(last_response).to be_ok } + example { expect(parsed_body).to be == { + "@type" => "cron", + "@href" => "/v3/cron/#{current_cron.id}", + "@representation" => "standard", + "@permissions" => { + "read" => true, + "delete" => true, + "start" => true }, + "id" => current_cron.id, + "repository" => { + "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", + "@representation" => "minimal", + "id" => repo.id, + "name" => "minimal", + "slug" => "svenfuchs/minimal" }, + "branch" => { + "@type" => "branch", + "@href" => "/v3/repo/#{repo.id}/branch/#{branch.name}", + "@representation" => "minimal", + "name" => "#{branch.name}" }, + "interval" => "monthly", + "disable_by_build" => false, + "next_enqueuing" => current_cron.next_enqueuing.strftime('%Y-%m-%dT%H:%M:%SZ') + }} + end + + describe "creating multiple cron jobs for one branch" do + 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) } + before { post("/v3/repo/#{repo.id}/branch/#{branch.name}/cron", options, headers) } + it "only stores one" do + expect(Travis::API::V3::Models::Cron.where(branch_id: branch.id).count).to eq(1) + end + end + + describe "creating a cron job with a wrong interval" do + before { last_cron } + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } + before { post("/v3/repo/#{repo.id}/branch/#{branch.name}/cron", wrong_options, headers) } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "error", + "error_message" => "Invalid value for interval. Interval must be \"daily\", \"weekly\" or \"monthly\"!" + }} + end + + describe "creating a cron job on a branch not existing on GitHub" do + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } + before { post("/v3/repo/#{repo.id}/branch/#{non_existing_branch.name}/cron", options, headers) } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "error", + "error_message" => "Crons can only be set up for branches existing on GitHub!" + }} + end + + describe "try creating a cron job without login" do + before { post("/v3/repo/#{repo.id}/branch/#{branch.name}/cron", options) } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "login_required", + "error_message" => "login required" + }} + end + + describe "try creating a cron job with a user without permissions" do + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: false) } + before { post("/v3/repo/#{repo.id}/branch/#{branch.name}/cron", options, headers) } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "insufficient_access", + "error_message" => "operation requires create_cron access to repository", + "resource_type" => "repository", + "permission" => "create_cron", + "repository" => { + "@type" => "repository", + "@href" => "/repo/#{repo.id}", # should be /v3/repo/#{repo.id} + "@representation" => "minimal", + "id" => repo.id, + "name" => "minimal", + "slug" => "svenfuchs/minimal" } + }} + end + + describe "creating cron on a non-existing repository by slug" do + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: false) } + before { post("/v3/repo/svenfuchs%2Fminimal1/branch/master/cron", options, headers) } + example { expect(last_response).to be_not_found } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "repository not found (or insufficient access)", + "resource_type" => "repository" + }} + end + + describe "creating cron on a non-existing branch" do + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: false) } + before { post("/v3/repo/#{repo.id}/branch/hopefullyNonExistingBranch/cron", options, headers) } + example { expect(last_response).to be_not_found } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "branch not found (or insufficient access)", + "resource_type" => "branch" + }} + end + +end diff --git a/spec/v3/services/cron/delete_spec.rb b/spec/v3/services/cron/delete_spec.rb new file mode 100644 index 00000000..601d7bb9 --- /dev/null +++ b/spec/v3/services/cron/delete_spec.rb @@ -0,0 +1,98 @@ +require 'spec_helper' + +describe Travis::API::V3::Services::Cron::Delete do + let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } + let(:branch) { Travis::API::V3::Models::Branch.where(repository_id: repo).first } + let(:cron) { Travis::API::V3::Models::Cron.create(branch: branch, interval:'daily') } + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + let(:parsed_body) { JSON.load(body) } + + before do + Travis::Features.activate_owner(:cron, repo.owner) + end + + describe "deleting cron jobs with feature disabled" do + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } + before { Travis::Features.deactivate_owner(:cron, repo.owner) } + before { delete("/v3/cron/#{cron.id}", {}, headers)} + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "cron not found (or insufficient access)", + "resource_type" => "cron" + }} + end + + describe "deleting a cron job by id" do + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: true) } + before { delete("/v3/cron/#{cron.id}", {}, headers) } + example { expect(last_response).to be_ok } + example { expect(Travis::API::V3::Models::Cron.where(id: cron.id)).to be_empty } + example { expect(parsed_body).to be == { + "@type" => "cron", + "@href" => "/v3/cron/#{cron.id}", + "@representation" => "standard", + "@permissions" => { + "read" => true, + "delete" => true, + "start" => true }, + "id" => cron.id, + "repository" => { + "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", + "@representation" => "minimal", + "id" => repo.id, + "name" => "minimal", + "slug" => "svenfuchs/minimal" }, + "branch" => { + "@type" => "branch", + "@href" => "/v3/repo/#{repo.id}/branch/#{branch.name}", + "@representation" => "minimal", + "name" => branch.name }, + "interval" => "daily", + "disable_by_build" => true, + "next_enqueuing" => cron.next_enqueuing.strftime('%Y-%m-%dT%H:%M:%SZ') + }} + end + + describe "try deleting a cron job without login" do + before { delete("/v3/cron/#{cron.id}") } + example { expect(Travis::API::V3::Models::Cron.where(id: cron.id)).to exist } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "login_required", + "error_message" => "login required" + }} + end + + describe "try deleting a cron job with a user without permissions" do + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: false) } + before { delete("/v3/cron/#{cron.id}", {}, headers) } + example { expect(Travis::API::V3::Models::Cron.where(id: cron.id)).to exist } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "insufficient_access", + "error_message" => "operation requires delete access to cron", + "resource_type" => "cron", + "permission" => "delete", + "cron" => { + "@type" => "cron", + "@href" => "/cron/#{cron.id}", # should be /v3/cron/#{cron.id} + "@representation" => "minimal", + "id" => cron.id } + }} + end + + describe "try deleting a non-existing cron job" do + before { Travis::API::V3::Models::Permission.create(repository: repo, user: repo.owner, push: false) } + before { delete("/v3/cron/999999999999999", {}, headers) } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "cron not found (or insufficient access)", + "resource_type" => "cron" + }} + end + +end diff --git a/spec/v3/services/cron/find_spec.rb b/spec/v3/services/cron/find_spec.rb new file mode 100644 index 00000000..8ae7f2c6 --- /dev/null +++ b/spec/v3/services/cron/find_spec.rb @@ -0,0 +1,113 @@ +require 'spec_helper' + +describe Travis::API::V3::Services::Cron::Find do + let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } + let(:branch) { Travis::API::V3::Models::Branch.where(repository_id: repo).first } + let(:cron) { Travis::API::V3::Models::Cron.create(branch: branch, interval:'daily') } + let(:parsed_body) { JSON.load(body) } + + before do + Travis::Features.activate_owner(:cron, repo.owner) + end + + describe "find cron job with feature disabled" do + before { Travis::Features.deactivate_owner(:cron, repo.owner) } + before { get("/v3/cron/#{cron.id}") } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "cron not found (or insufficient access)", + "resource_type" => "cron" + }} + end + + describe "fetching a cron job by id" do + before { get("/v3/cron/#{cron.id}") } + example { expect(last_response).to be_ok } + example { expect(parsed_body).to be == { + "@type" => "cron", + "@href" => "/v3/cron/#{cron.id}", + "@representation" => "standard", + "@permissions" => { + "read" => true, + "delete" => false, + "start" => true }, + "id" => cron.id, + "repository" => { + "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", + "@representation" => "minimal", + "id" => repo.id, + "name" => "minimal", + "slug" => "svenfuchs/minimal" }, + "branch" => { + "@type" => "branch", + "@href" => "/v3/repo/#{repo.id}/branch/#{branch.name}", + "@representation" => "minimal", + "name" => branch.name }, + "interval" => "daily", + "disable_by_build" => true, + "next_enqueuing" => cron.next_enqueuing.strftime('%Y-%m-%dT%H:%M:%SZ') + }} + end + + describe "fetching a non-existing cron job by id" do + before { get("/v3/cron/999999999999999") } + example { expect(last_response).to be_not_found } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "cron not found (or insufficient access)", + "resource_type" => "cron" + }} + end + + describe "private cron, not authenticated" do + before { repo.update_attribute(:private, true) } + before { get("/v3/cron/#{cron.id}") } + after { repo.update_attribute(:private, false) } + example { expect(last_response).to be_not_found } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "cron not found (or insufficient access)", + "resource_type" => "cron" + }} + end + + describe "private cron, authenticated as user with access" 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 { repo.update_attribute(:private, true) } + before { get("/v3/cron/#{cron.id}", {}, headers) } + after { repo.update_attribute(:private, false) } + example { expect(last_response).to be_ok } + example { expect(parsed_body).to be == { + "@type" => "cron", + "@href" => "/v3/cron/#{cron.id}", + "@representation" => "standard", + "@permissions" => { + "read" => true, + "delete" => false, + "start" => true }, + "id" => cron.id, + "repository" => { + "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", + "@representation" => "minimal", + "id" => repo.id, + "name" => "minimal", + "slug" => "svenfuchs/minimal" }, + "branch" => { + "@type" => "branch", + "@href" => "/v3/repo/#{repo.id}/branch/#{branch.name}", + "@representation" => "minimal", + "name" => branch.name }, + "interval" => "daily", + "disable_by_build" => true, + "next_enqueuing" => cron.next_enqueuing.strftime('%Y-%m-%dT%H:%M:%SZ') + }} + end + +end diff --git a/spec/v3/services/cron/for_branch_spec.rb b/spec/v3/services/cron/for_branch_spec.rb new file mode 100644 index 00000000..32b0f76b --- /dev/null +++ b/spec/v3/services/cron/for_branch_spec.rb @@ -0,0 +1,90 @@ +require 'spec_helper' + +describe Travis::API::V3::Services::Cron::ForBranch do + let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } + let(:branch) { Travis::API::V3::Models::Branch.where(repository_id: repo).first } + let(:cron) { Travis::API::V3::Models::Cron.create(branch: branch, interval:'daily') } + let(:parsed_body) { JSON.load(body) } + + before do + Travis::Features.activate_owner(:cron, repo.owner) + end + + describe "find cron job for branch with feature disabled" do + before { cron } + before { Travis::Features.deactivate_owner(:cron, repo.owner) } + before { get("/v3/repo/#{repo.id}/branch/#{branch.name}/cron") } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "insufficient_access", + "error_message" => "forbidden" + }} + end + + describe "fetching all crons by repo id" do + before { cron } + before { get("/v3/repo/#{repo.id}/branch/#{branch.name}/cron") } + example { expect(last_response).to be_ok } + example { expect(parsed_body).to be == { + "@type" => "cron", + "@href" => "/v3/cron/#{cron.id}", + "@representation" => "standard", + "@permissions" => { + "read" => true, + "delete" => false, + "start" => true }, + "id" => cron.id, + "repository" => { + "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", + "@representation" => "minimal", + "id" => repo.id, + "name" => "minimal", + "slug" => "svenfuchs/minimal" }, + "branch" => { + "@type" => "branch", + "@href" => "/v3/repo/#{repo.id}/branch/#{branch.name}", + "@representation" => "minimal", + "name" => branch.name }, + "interval" => "daily", + "disable_by_build" => true, + "next_enqueuing" => cron.next_enqueuing.strftime('%Y-%m-%dT%H:%M:%SZ') + }} + end + + describe "fetching crons on a non-existing repository by slug" do + before { get("/v3/repo/svenfuchs%2Fminimal1/branch/master/cron") } + example { expect(last_response).to be_not_found } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "repository not found (or insufficient access)", + "resource_type" => "repository" + }} + end + + describe "fetching crons on a non-existing branch" do + before { get("/v3/repo/#{repo.id}/branch/hopefullyNonExistingBranch/cron") } + example { expect(last_response).to be_not_found } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "branch not found (or insufficient access)", + "resource_type" => "branch" + }} + end + + describe "fetching crons from private repo, not authenticated" do + before { repo.update_attribute(:private, true) } + before { get("/v3/repo/#{repo.id}/branch/#{branch.name}/cron") } + after { repo.update_attribute(:private, false) } + example { expect(last_response).to be_not_found } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "repository not found (or insufficient access)", + "resource_type" => "repository" + }} + end + +end diff --git a/spec/v3/services/crons/for_repository_spec.rb b/spec/v3/services/crons/for_repository_spec.rb new file mode 100644 index 00000000..05e37102 --- /dev/null +++ b/spec/v3/services/crons/for_repository_spec.rb @@ -0,0 +1,101 @@ +require 'spec_helper' + +describe Travis::API::V3::Services::Crons::ForRepository do + let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first } + let(:branch) { Travis::API::V3::Models::Branch.where(repository_id: repo).first } + let(:cron) { Travis::API::V3::Models::Cron.create(branch: branch, interval:'daily') } + let(:parsed_body) { JSON.load(body) } + + before do + Travis::Features.activate_owner(:cron, repo.owner) + end + + describe "fetching all crons by repo id with feature disabled" do + before { Travis::Features.deactivate_owner(:cron, repo.owner) } + before { get("/v3/repo/#{repo.id}/crons") } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "insufficient_access", + "error_message" => "forbidden" + }} + end + + describe "fetching all crons by repo id" do + before { cron } + before { get("/v3/repo/#{repo.id}/crons") } + example { expect(last_response).to be_ok } + example { expect(parsed_body).to be == { + "@type" => "crons", + "@href" => "/v3/repo/#{repo.id}/crons", + "@representation" => "standard", + "@pagination" => { + "limit" => 25, + "offset" => 0, + "count" => 1, + "is_first" => true, + "is_last" => true, + "next" => nil, + "prev" => nil, + "first" => { + "@href" => "/v3/repo/#{repo.id}/crons", + "offset" => 0, + "limit" => 25}, + "last" => { + "@href" => "/v3/repo/#{repo.id}/crons", + "offset" => 0, + "limit" => 25 }}, + "crons" => [ + { + "@type" => "cron", + "@href" => "/v3/cron/#{cron.id}", + "@representation" => "standard", + "@permissions" => { + "read" => true, + "delete" => false, + "start" => true }, + "id" => cron.id, + "repository" => { + "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", + "@representation" => "minimal", + "id" => repo.id, + "name" => "minimal", + "slug" => "svenfuchs/minimal" }, + "branch" => { + "@type" => "branch", + "@href" => "/v3/repo/#{repo.id}/branch/#{branch.name}", + "@representation" => "minimal", + "name" => "#{branch.name}" }, + "interval" => "daily", + "disable_by_build" => true, + "next_enqueuing" => cron.next_enqueuing.strftime('%Y-%m-%dT%H:%M:%SZ') + } + ] + }} + end + + describe "fetching crons on a non-existing repository by slug" do + before { get("/v3/repo/svenfuchs%2Fminimal1/crons") } + example { expect(last_response).to be_not_found } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "repository not found (or insufficient access)", + "resource_type" => "repository" + }} + end + + describe "fetching crons from private repo, not authenticated" do + before { repo.update_attribute(:private, true) } + before { get("/v3/repo/#{repo.id}/crons") } + after { repo.update_attribute(:private, false) } + example { expect(last_response).to be_not_found } + example { expect(parsed_body).to be == { + "@type" => "error", + "error_type" => "not_found", + "error_message" => "repository not found (or insufficient access)", + "resource_type" => "repository" + }} + end + +end diff --git a/spec/v3/services/owner/find_spec.rb b/spec/v3/services/owner/find_spec.rb index e48ecfb2..f47f0b89 100644 --- a/spec/v3/services/owner/find_spec.rb +++ b/spec/v3/services/owner/find_spec.rb @@ -66,7 +66,8 @@ describe Travis::API::V3::Services::Owner::Find do "disable" => false, "star" => false, "unstar" => false, - "create_request" => false}, + "create_request" => false, + "create_cron" => false}, "id" => repo.id, "name" => "example-repo", "slug" => "example-org/example-repo", @@ -113,7 +114,8 @@ describe Travis::API::V3::Services::Owner::Find do "disable" => false, "star" => false, "unstar" => false, - "create_request"=> false}, + "create_request"=> false, + "create_cron" => false}, "id" => repo.id, "name" => "example-repo", "slug" => "example-org/example-repo", diff --git a/spec/v3/services/repositories/for_current_user_spec.rb b/spec/v3/services/repositories/for_current_user_spec.rb index 399eaa9f..d414783a 100644 --- a/spec/v3/services/repositories/for_current_user_spec.rb +++ b/spec/v3/services/repositories/for_current_user_spec.rb @@ -44,7 +44,8 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do "disable" => true, "star" => true, "unstar" => true, - "create_request" => true}, + "create_request" => true, + "create_cron" => false}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", diff --git a/spec/v3/services/repositories/for_owner_spec.rb b/spec/v3/services/repositories/for_owner_spec.rb index 0c9ac6ab..953f57e1 100644 --- a/spec/v3/services/repositories/for_owner_spec.rb +++ b/spec/v3/services/repositories/for_owner_spec.rb @@ -45,7 +45,8 @@ describe Travis::API::V3::Services::Repositories::ForOwner do "disable" => false, "star" => false, "unstar" => false, - "create_request" => false}, + "create_request" => false, + "create_cron" => false}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -121,7 +122,8 @@ describe Travis::API::V3::Services::Repositories::ForOwner do "disable" => false, "star" => false, "unstar" => false, - "create_request"=> false }, + "create_request"=> false, + "create_cron" => false }, "id" => 1, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -149,7 +151,8 @@ describe Travis::API::V3::Services::Repositories::ForOwner do "disable" => false, "star" => false, "unstar" => false, - "create_request"=> false }, + "create_request"=> false, + "create_cron" => false }, "id" => repo2.id, "name" => "maximal", "slug" => "svenfuchs/maximal", diff --git a/spec/v3/services/repository/find_spec.rb b/spec/v3/services/repository/find_spec.rb index b5c0a10c..b3c03556 100644 --- a/spec/v3/services/repository/find_spec.rb +++ b/spec/v3/services/repository/find_spec.rb @@ -36,7 +36,8 @@ describe Travis::API::V3::Services::Repository::Find do "disable" => false, "star" => false, "unstar" => false, - "create_request" => false}, + "create_request" => false, + "create_cron" => false}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -113,7 +114,8 @@ describe Travis::API::V3::Services::Repository::Find do "disable" => false, "star" => false, "unstar" => false, - "create_request" => false}, + "create_request" => false, + "create_cron" => false}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -150,7 +152,7 @@ describe Travis::API::V3::Services::Repository::Find do }} end - describe "private repository, authenticated as internal application with full access" do + describe "private repository without cron feature, authenticated as internal application with full access" do let(:app_name) { 'travis-example' } let(:app_secret) { '12345678' } let(:sign_opts) { "a=#{app_name}" } @@ -175,7 +177,8 @@ describe Travis::API::V3::Services::Repository::Find do "disable" => true, "star" => true, "unstar" => true, - "create_request" => true}, + "create_request" => true, + "create_cron" => false}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -218,7 +221,7 @@ describe Travis::API::V3::Services::Repository::Find do }} end - describe "private repository, authenticated as internal application with full access, scoped to the right org" do + describe "private repository without cron feature, authenticated as internal application with full access, scoped to the right org" do let(:app_name) { 'travis-example' } let(:app_secret) { '12345678' } let(:sign_opts) { "a=#{app_name}:s=#{repo.owner_name}" } @@ -243,7 +246,8 @@ describe Travis::API::V3::Services::Repository::Find do "disable" => true, "star" => true, "unstar" => true, - "create_request" => true}, + "create_request" => true, + "create_cron" => false}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal",