summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Fargher <proglottis@gmail.com>2019-07-18 15:45:12 +1200
committerJames Fargher <proglottis@gmail.com>2019-07-19 09:23:07 +1200
commit01431ae3076370bec1c014e326cdb20b47ae55b1 (patch)
treede042beee18387364ff8420322b31952822b35c1
parent34f5eb1b93b5c1e7d8ed8d578d8b94cd33d2dca3 (diff)
downloadgitlab-ce-auto_devops_detect2.tar.gz
Initial detection of Auto-DevOps buildable projectsauto_devops_detect2
-rw-r--r--app/models/ci/pipeline.rb7
-rw-r--r--app/models/project.rb6
-rw-r--r--lib/gitlab/auto_devops/buildable_detector.rb103
-rw-r--r--lib/gitlab/ci/pipeline/chain/validate/config.rb6
-rw-r--r--spec/lib/gitlab/auto_devops/buildable_detector_spec.rb36
5 files changed, 155 insertions, 3 deletions
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 2262282e647..c44f0a42585 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -809,11 +809,16 @@ module Ci
def implied_ci_yaml_file
return unless project
- if project.auto_devops_enabled?
+ if project.auto_devops_enabled? && auto_devops_buildable?
Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps').content
end
end
+ def auto_devops_buildable?
+ project.has_auto_devops_explicitly_enabled? ||
+ Gitlab::AutoDevops::BuildableDetector.new(project, sha).buildable?
+ end
+
def pipeline_data
Gitlab::DataBuilder::Pipeline.build(self)
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 2906aca75fc..e3e177c97e2 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -665,10 +665,14 @@ class Project < ApplicationRecord
if auto_devops&.enabled.nil?
has_auto_devops_implicitly_enabled?
else
- auto_devops.enabled?
+ has_auto_devops_explicitly_enabled?
end
end
+ def has_auto_devops_explicitly_enabled?
+ auto_devops&.enabled?
+ end
+
def has_auto_devops_implicitly_enabled?
auto_devops_config = first_auto_devops_config
diff --git a/lib/gitlab/auto_devops/buildable_detector.rb b/lib/gitlab/auto_devops/buildable_detector.rb
new file mode 100644
index 00000000000..39c3d29135b
--- /dev/null
+++ b/lib/gitlab/auto_devops/buildable_detector.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module AutoDevops
+ class BuildableDetector
+ VARIABLES = [
+ 'BUILDPACK_URL'
+ ].freeze
+
+ FILE_PATTERNS = [
+ 'Dockerfile',
+
+ # https://github.com/heroku/heroku-buildpack-clojure
+ 'project.clj',
+
+ # https://github.com/heroku/heroku-buildpack-go
+ 'go.mod',
+ 'Gopkg.mod',
+ 'Godeps/Godeps.json',
+ 'vendor/vendor.json',
+ 'glide.yaml',
+ 'src/**.go',
+
+ # https://github.com/heroku/heroku-buildpack-gradle
+ 'gradlew',
+ 'build.gradle',
+ 'settings.gradle',
+
+ # https://github.com/heroku/heroku-buildpack-java
+ 'pom.xml',
+ 'pom.atom',
+ 'pom.clj',
+ 'pom.groovy',
+ 'pom.rb',
+ 'pom.scala',
+ 'pom.yaml',
+ 'pom.yml',
+
+ # https://github.com/heroku/heroku-buildpack-multi
+ '.buildpacks',
+
+ # https://github.com/heroku/heroku-buildpack-nodejs
+ 'package.json',
+
+ # https://github.com/heroku/heroku-buildpack-php
+ 'composer.json',
+ 'index.php',
+
+ # https://github.com/heroku/heroku-buildpack-play
+ # TODO: detect script excludes some scala files
+ '*/conf/application.conf',
+ '*modules*',
+
+ # https://github.com/heroku/heroku-buildpack-python
+ # TODO: detect script checks that all of these exist, not any
+ 'requirements.txt',
+ 'setup.py',
+ 'Pipfile',
+
+ # https://github.com/heroku/heroku-buildpack-ruby
+ 'Gemfile',
+
+ # https://github.com/heroku/heroku-buildpack-scala
+ '*.sbt',
+ 'project/*.scala',
+ '.sbt/*.scala',
+ 'project/build.properties',
+
+ # https://github.com/dokku/buildpack-nginx
+ '.static'
+ ].freeze
+
+ def initialize(project, ref)
+ @project = project
+ @ref = ref
+ end
+
+ def buildable?
+ detected_variables? || detected_files?
+ end
+
+ private
+
+ attr_accessor :project, :ref
+
+ def detected_variables?
+ project.ci_variables_for(ref: ref).where(key: VARIABLES).exists?
+ end
+
+ def detected_files?
+ return unless tree = project.repository.tree(ref)
+
+ tree.blobs.find do |blob|
+ FILE_PATTERNS.any? do |pattern|
+ File.fnmatch?(pattern, blob.path, File::FNM_CASEFOLD)
+ end
+ end
+ rescue Gitlab::Git::Repository::NoRepository
+ # nop
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/pipeline/chain/validate/config.rb b/lib/gitlab/ci/pipeline/chain/validate/config.rb
index 28c38cc3d18..a6f63eabb80 100644
--- a/lib/gitlab/ci/pipeline/chain/validate/config.rb
+++ b/lib/gitlab/ci/pipeline/chain/validate/config.rb
@@ -11,7 +11,11 @@ module Gitlab
def perform!
unless @pipeline.config_processor
unless @pipeline.ci_yaml_file
- return error("Missing #{@pipeline.ci_yaml_file_path} file")
+ if @pipeline.project.auto_devops_enabled?
+ return error("Auto-DevOps enabled but no buildable files found")
+ else
+ return error("Missing #{@pipeline.ci_yaml_file_path} file")
+ end
end
if @command.save_incompleted && @pipeline.has_yaml_errors?
diff --git a/spec/lib/gitlab/auto_devops/buildable_detector_spec.rb b/spec/lib/gitlab/auto_devops/buildable_detector_spec.rb
new file mode 100644
index 00000000000..42187def844
--- /dev/null
+++ b/spec/lib/gitlab/auto_devops/buildable_detector_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::AutoDevops::BuildableDetector do
+ describe '#buildable?' do
+ let(:project) { create(:project) }
+ let(:ref) { :head }
+
+ subject(:detector) { described_class.new(project, ref) }
+
+ context 'no matching variables or files' do
+ it 'is not buildable' do
+ expect(detector).to_not be_buildable
+ end
+ end
+
+ context 'matching variable' do
+ before do
+ create(:ci_variable, project: project, key: 'BUILDPACK_URL')
+ end
+
+ it 'is buildable' do
+ expect(detector).to be_buildable
+ end
+ end
+
+ context 'matching file' do
+ let(:project) { create(:project, :custom_repo, files: { 'Dockerfile' => '' }) }
+
+ it 'is buildable' do
+ expect(detector).to be_buildable
+ end
+ end
+ end
+end