Commit 479f4ccc authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'after-script' into 'master'

Implement after_script which allows to do cleanups as part of the build process

This implements `after_script` in global context.

The `after_script` will be executed always after the job, even if the job were canceled.

This requires changes on Runner side that will be implemented in 1.2.

cc @tmaczukin @grzesiek 


See merge request !3771
parents 51b777fa 0ce5cc99
...@@ -27,6 +27,7 @@ v 8.7.0 (unreleased) ...@@ -27,6 +27,7 @@ v 8.7.0 (unreleased)
- Make /profile/keys/new redirect to /profile/keys for back-compat. !3717 - Make /profile/keys/new redirect to /profile/keys for back-compat. !3717
- Preserve time notes/comments have been updated at when moving issue - Preserve time notes/comments have been updated at when moving issue
- Make HTTP(s) label consistent on clone bar (Stan Hu) - Make HTTP(s) label consistent on clone bar (Stan Hu)
- Add support for `after_script`, requires Runner 1.2 (Kamil Trzciński)
- Expose label description in API (Mariusz Jachimowicz) - Expose label description in API (Mariusz Jachimowicz)
- API: Ability to update a group (Robert Schilling) - API: Ability to update a group (Robert Schilling)
- API: Ability to move issues (Robert Schilling) - API: Ability to move issues (Robert Schilling)
......
...@@ -15,6 +15,7 @@ If you want a quick introduction to GitLab CI, follow our ...@@ -15,6 +15,7 @@ If you want a quick introduction to GitLab CI, follow our
- [.gitlab-ci.yml](#gitlab-ci-yml) - [.gitlab-ci.yml](#gitlab-ci-yml)
- [image and services](#image-and-services) - [image and services](#image-and-services)
- [before_script](#before_script) - [before_script](#before_script)
- [after_script](#after_script)
- [stages](#stages) - [stages](#stages)
- [types](#types) - [types](#types)
- [variables](#variables) - [variables](#variables)
...@@ -81,6 +82,9 @@ services: ...@@ -81,6 +82,9 @@ services:
before_script: before_script:
- bundle install - bundle install
after_script:
- rm secrets
stages: stages:
- build - build
- test - test
...@@ -105,6 +109,7 @@ There are a few reserved `keywords` that **cannot** be used as job names: ...@@ -105,6 +109,7 @@ There are a few reserved `keywords` that **cannot** be used as job names:
| stages | no | Define build stages | | stages | no | Define build stages |
| types | no | Alias for `stages` | | types | no | Alias for `stages` |
| before_script | no | Define commands that run before each job's script | | before_script | no | Define commands that run before each job's script |
| after_script | no | Define commands that run after each job's script |
| variables | no | Define build variables | | variables | no | Define build variables |
| cache | no | Define list of files that should be cached between subsequent runs | | cache | no | Define list of files that should be cached between subsequent runs |
...@@ -119,6 +124,14 @@ used for time of the build. The configuration of this feature is covered in ...@@ -119,6 +124,14 @@ used for time of the build. The configuration of this feature is covered in
`before_script` is used to define the command that should be run before all `before_script` is used to define the command that should be run before all
builds, including deploy builds. This can be an array or a multi-line string. builds, including deploy builds. This can be an array or a multi-line string.
### after_script
>**Note:**
Introduced in GitLab 8.7 and GitLab Runner v1.2.
`after_script` is used to define the command that will be run after for all
builds. This has to be an array or a multi-line string.
### stages ### stages
`stages` is used to define build stages that can be used by jobs. `stages` is used to define build stages that can be used by jobs.
......
...@@ -4,12 +4,12 @@ module Ci ...@@ -4,12 +4,12 @@ module Ci
DEFAULT_STAGES = %w(build test deploy) DEFAULT_STAGES = %w(build test deploy)
DEFAULT_STAGE = 'test' DEFAULT_STAGE = 'test'
ALLOWED_YAML_KEYS = [:before_script, :image, :services, :types, :stages, :variables, :cache] ALLOWED_YAML_KEYS = [:before_script, :after_script, :image, :services, :types, :stages, :variables, :cache]
ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services,
:allow_failure, :type, :stage, :when, :artifacts, :cache, :allow_failure, :type, :stage, :when, :artifacts, :cache,
:dependencies, :variables] :dependencies, :variables]
attr_reader :before_script, :image, :services, :path, :cache attr_reader :before_script, :after_script, :image, :services, :path, :cache
def initialize(config, path = nil) def initialize(config, path = nil)
@config = YAML.safe_load(config, [Symbol], [], true) @config = YAML.safe_load(config, [Symbol], [], true)
...@@ -55,6 +55,7 @@ module Ci ...@@ -55,6 +55,7 @@ module Ci
def initial_parsing def initial_parsing
@before_script = @config[:before_script] || [] @before_script = @config[:before_script] || []
@after_script = @config[:after_script]
@image = @config[:image] @image = @config[:image]
@services = @config[:services] @services = @config[:services]
@stages = @config[:stages] || @config[:types] @stages = @config[:stages] || @config[:types]
...@@ -96,6 +97,7 @@ module Ci ...@@ -96,6 +97,7 @@ module Ci
artifacts: job[:artifacts], artifacts: job[:artifacts],
cache: job[:cache] || @cache, cache: job[:cache] || @cache,
dependencies: job[:dependencies], dependencies: job[:dependencies],
after_script: @after_script,
}.compact }.compact
} }
end end
...@@ -109,10 +111,26 @@ module Ci ...@@ -109,10 +111,26 @@ module Ci
end end
def validate! def validate!
validate_global!
@jobs.each do |name, job|
validate_job!(name, job)
end
true
end
private
def validate_global!
unless validate_array_of_strings(@before_script) unless validate_array_of_strings(@before_script)
raise ValidationError, "before_script should be an array of strings" raise ValidationError, "before_script should be an array of strings"
end end
unless @after_script.nil? || validate_array_of_strings(@after_script)
raise ValidationError, "after_script should be an array of strings"
end
unless @image.nil? || @image.is_a?(String) unless @image.nil? || @image.is_a?(String)
raise ValidationError, "image should be a string" raise ValidationError, "image should be a string"
end end
...@@ -129,25 +147,21 @@ module Ci ...@@ -129,25 +147,21 @@ module Ci
raise ValidationError, "variables should be a map of key-value strings" raise ValidationError, "variables should be a map of key-value strings"
end end
if @cache validate_global_cache! if @cache
if @cache[:key] && !validate_string(@cache[:key]) end
raise ValidationError, "cache:key parameter should be a string"
end
if @cache[:untracked] && !validate_boolean(@cache[:untracked])
raise ValidationError, "cache:untracked parameter should be an boolean"
end
if @cache[:paths] && !validate_array_of_strings(@cache[:paths]) def validate_global_cache!
raise ValidationError, "cache:paths parameter should be an array of strings" if @cache[:key] && !validate_string(@cache[:key])
end raise ValidationError, "cache:key parameter should be a string"
end end
@jobs.each do |name, job| if @cache[:untracked] && !validate_boolean(@cache[:untracked])
validate_job!(name, job) raise ValidationError, "cache:untracked parameter should be an boolean"
end end
true if @cache[:paths] && !validate_array_of_strings(@cache[:paths])
raise ValidationError, "cache:paths parameter should be an array of strings"
end
end end
def validate_job!(name, job) def validate_job!(name, job)
...@@ -162,8 +176,6 @@ module Ci ...@@ -162,8 +176,6 @@ module Ci
validate_job_dependencies!(name, job) if job[:dependencies] validate_job_dependencies!(name, job) if job[:dependencies]
end end
private
def validate_job_name!(name) def validate_job_name!(name)
if name.blank? || !validate_string(name) if name.blank? || !validate_string(name)
raise ValidationError, "job name should be non-empty string" raise ValidationError, "job name should be non-empty string"
......
...@@ -286,6 +286,28 @@ module Ci ...@@ -286,6 +286,28 @@ module Ci
end end
end end
describe "Scripts handling" do
let(:config_data) { YAML.dump(config) }
let(:config_processor) { GitlabCiYamlProcessor.new(config_data, path) }
subject { config_processor.builds_for_stage_and_ref("test", "master").first }
describe "after_script" do
context "in global context" do
let(:config) do
{
after_script: ["after_script"],
test: { script: ["script"] }
}
end
it "return after_script in options" do
expect(subject[:options][:after_script]).to eq(["after_script"])
end
end
end
end
describe "Image and service handling" do describe "Image and service handling" do
it "returns image and service when defined" do it "returns image and service when defined" do
...@@ -663,6 +685,13 @@ EOT ...@@ -663,6 +685,13 @@ EOT
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script should be an array of strings") end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script should be an array of strings")
end end
it "returns errors if after_script parameter is invalid" do
config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "after_script should be an array of strings")
end
it "returns errors if image parameter is invalid" do it "returns errors if image parameter is invalid" do
config = YAML.dump({ image: ["test"], rspec: { script: "test" } }) config = YAML.dump({ image: ["test"], rspec: { script: "test" } })
expect do expect do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment