Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
0dc2ca3a
Commit
0dc2ca3a
authored
Jul 08, 2017
by
Shinya Maeda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Port to EE
parent
9f2608ba
Changes
35
Show whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
954 additions
and
70 deletions
+954
-70
app/assets/javascripts/pipeline_schedules/pipeline_schedule_form_bundle.js
...ripts/pipeline_schedules/pipeline_schedule_form_bundle.js
+3
-0
app/assets/javascripts/pipeline_schedules/setup_pipeline_variable_list.js
...cripts/pipeline_schedules/setup_pipeline_variable_list.js
+71
-0
app/assets/stylesheets/framework/variables.scss
app/assets/stylesheets/framework/variables.scss
+8
-0
app/assets/stylesheets/pages/pipeline_schedules.scss
app/assets/stylesheets/pages/pipeline_schedules.scss
+81
-0
app/controllers/projects/pipeline_schedules_controller.rb
app/controllers/projects/pipeline_schedules_controller.rb
+14
-5
app/models/ci/build.rb
app/models/ci/build.rb
+1
-0
app/models/ci/pipeline_schedule.rb
app/models/ci/pipeline_schedule.rb
+8
-0
app/models/ci/pipeline_schedule_variable.rb
app/models/ci/pipeline_schedule_variable.rb
+8
-0
app/policies/ci/pipeline_schedule_policy.rb
app/policies/ci/pipeline_schedule_policy.rb
+10
-0
app/policies/project_policy.rb
app/policies/project_policy.rb
+0
-2
app/validators/variable_duplicates_validator.rb
app/validators/variable_duplicates_validator.rb
+13
-0
app/views/projects/pipeline_schedules/_form.html.haml
app/views/projects/pipeline_schedules/_form.html.haml
+8
-0
app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
.../projects/pipeline_schedules/_pipeline_schedule.html.haml
+1
-1
app/views/projects/pipeline_schedules/_variable_row.html.haml
...views/projects/pipeline_schedules/_variable_row.html.haml
+17
-0
changelogs/unreleased/feature-intermediate-32568-adding-variables-to-pipelines-schedules.yml
...mediate-32568-adding-variables-to-pipelines-schedules.yml
+4
-0
db/migrate/20170620064728_create_ci_pipeline_schedule_variables.rb
...e/20170620064728_create_ci_pipeline_schedule_variables.rb
+25
-0
db/migrate/20170620065449_add_foreign_key_to_ci_pipeline_schedule_variables.rb
...5449_add_foreign_key_to_ci_pipeline_schedule_variables.rb
+15
-0
db/schema.rb
db/schema.rb
+14
-0
doc/ci/variables/README.md
doc/ci/variables/README.md
+1
-1
doc/user/project/pipelines/img/pipeline_schedule_variables.png
...ser/project/pipelines/img/pipeline_schedule_variables.png
+0
-0
doc/user/project/pipelines/img/pipeline_schedules_new_form.png
...ser/project/pipelines/img/pipeline_schedules_new_form.png
+0
-0
doc/user/project/pipelines/schedules.md
doc/user/project/pipelines/schedules.md
+10
-0
lib/api/pipeline_schedules.rb
lib/api/pipeline_schedules.rb
+6
-3
locale/en/gitlab.po
locale/en/gitlab.po
+18
-0
locale/gitlab.pot
locale/gitlab.pot
+20
-2
spec/controllers/projects/pipeline_schedules_controller_spec.rb
...ontrollers/projects/pipeline_schedules_controller_spec.rb
+294
-36
spec/factories/ci/pipeline_schedule_variables.rb
spec/factories/ci/pipeline_schedule_variables.rb
+8
-0
spec/features/projects/pipeline_schedules_spec.rb
spec/features/projects/pipeline_schedules_spec.rb
+79
-18
spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js
...s/pipeline_schedules/setup_pipeline_variable_list_spec.js
+145
-0
spec/lib/gitlab/import_export/all_models.yml
spec/lib/gitlab/import_export/all_models.yml
+3
-0
spec/models/ci/build_spec.rb
spec/models/ci/build_spec.rb
+17
-0
spec/models/ci/pipeline_schedule_spec.rb
spec/models/ci/pipeline_schedule_spec.rb
+17
-0
spec/models/ci/pipeline_schedule_variable_spec.rb
spec/models/ci/pipeline_schedule_variable_spec.rb
+7
-0
spec/requests/api/pipeline_schedules_spec.rb
spec/requests/api/pipeline_schedules_spec.rb
+2
-0
spec/support/matchers/access_matchers_for_controller.rb
spec/support/matchers/access_matchers_for_controller.rb
+26
-2
No files found.
app/assets/javascripts/pipeline_schedules/pipeline_schedule_form_bundle.js
View file @
0dc2ca3a
...
...
@@ -3,6 +3,7 @@ import Translate from '../vue_shared/translate';
import
intervalPatternInput
from
'
./components/interval_pattern_input.vue
'
;
import
TimezoneDropdown
from
'
./components/timezone_dropdown
'
;
import
TargetBranchDropdown
from
'
./components/target_branch_dropdown
'
;
import
{
setupPipelineVariableList
}
from
'
./setup_pipeline_variable_list
'
;
Vue
.
use
(
Translate
);
...
...
@@ -39,4 +40,6 @@ document.addEventListener('DOMContentLoaded', () => {
gl
.
timezoneDropdown
=
new
TimezoneDropdown
();
gl
.
targetBranchDropdown
=
new
TargetBranchDropdown
();
gl
.
pipelineScheduleFieldErrors
=
new
gl
.
GlFieldErrors
(
formElement
);
setupPipelineVariableList
(
$
(
'
.js-pipeline-variable-list
'
));
});
app/assets/javascripts/pipeline_schedules/setup_pipeline_variable_list.js
0 → 100644
View file @
0dc2ca3a
function
insertRow
(
$row
)
{
const
$rowClone
=
$row
.
clone
();
$rowClone
.
removeAttr
(
'
data-is-persisted
'
);
$rowClone
.
find
(
'
input, textarea
'
).
val
(
''
);
$row
.
after
(
$rowClone
);
}
function
removeRow
(
$row
)
{
const
isPersisted
=
gl
.
utils
.
convertPermissionToBoolean
(
$row
.
attr
(
'
data-is-persisted
'
));
if
(
isPersisted
)
{
$row
.
hide
();
$row
.
find
(
'
.js-destroy-input
'
)
.
val
(
1
);
}
else
{
$row
.
remove
();
}
}
function
checkIfRowTouched
(
$row
)
{
return
$row
.
find
(
'
.js-user-input
'
).
toArray
().
some
(
el
=>
$
(
el
).
val
().
length
>
0
);
}
function
setupPipelineVariableList
(
parent
=
document
)
{
const
$parent
=
$
(
parent
);
$parent
.
on
(
'
click
'
,
'
.js-row-remove-button
'
,
(
e
)
=>
{
const
$row
=
$
(
e
.
currentTarget
).
closest
(
'
.js-row
'
);
removeRow
(
$row
);
e
.
preventDefault
();
});
// Remove any empty rows except the last r
$parent
.
on
(
'
blur
'
,
'
.js-user-input
'
,
(
e
)
=>
{
const
$row
=
$
(
e
.
currentTarget
).
closest
(
'
.js-row
'
);
const
isTouched
=
checkIfRowTouched
(
$row
);
if
(
$row
.
is
(
'
:not(:last-child)
'
)
&&
!
isTouched
)
{
removeRow
(
$row
);
}
});
// Always make sure there is an empty last row
$parent
.
on
(
'
input
'
,
'
.js-user-input
'
,
()
=>
{
const
$lastRow
=
$parent
.
find
(
'
.js-row
'
).
last
();
const
isTouched
=
checkIfRowTouched
(
$lastRow
);
if
(
isTouched
)
{
insertRow
(
$lastRow
);
}
});
// Clear out the empty last row so it
// doesn't get submitted and throw validation errors
$parent
.
closest
(
'
form
'
).
on
(
'
submit
'
,
()
=>
{
const
$lastRow
=
$parent
.
find
(
'
.js-row
'
).
last
();
const
isTouched
=
checkIfRowTouched
(
$lastRow
);
if
(
!
isTouched
)
{
$lastRow
.
find
(
'
input, textarea
'
).
attr
(
'
name
'
,
''
);
}
});
}
export
{
setupPipelineVariableList
,
insertRow
,
removeRow
,
};
app/assets/stylesheets/framework/variables.scss
View file @
0dc2ca3a
...
...
@@ -159,6 +159,7 @@ $code_line_height: 1.6;
* Padding
*/
$gl-padding
:
16px
;
$gl-col-padding
:
15px
;
$gl-btn-padding
:
10px
;
$gl-input-padding
:
10px
;
$gl-vert-padding
:
6px
;
...
...
@@ -454,6 +455,7 @@ $logs-p-color: #333;
/*
* Forms
*/
$input-height
:
34px
;
$input-danger-bg
:
#f2dede
;
$input-danger-border
:
$red-400
;
$input-group-addon-bg
:
#f7f8fa
;
...
...
@@ -585,6 +587,12 @@ $stage-hover-bg: #eaf3fc;
$stage-hover-border
:
#d1e7fc
;
$action-icon-color
:
#d6d6d6
;
/*
Pipeline Schedules
*/
$pipeline-variable-remove-button-width
:
calc
(
1em
+
#{
2
*
$gl-padding
}
);
/*
Filtered Search
*/
...
...
app/assets/stylesheets/pages/pipeline_schedules.scss
View file @
0dc2ca3a
...
...
@@ -74,3 +74,84 @@
margin-right
:
3px
;
}
}
.pipeline-variable-list
{
margin-left
:
0
;
margin-bottom
:
0
;
padding-left
:
0
;
list-style
:
none
;
clear
:
both
;
}
.pipeline-variable-row
{
display
:
flex
;
align-items
:
flex-end
;
&
:not
(
:last-child
)
{
margin-bottom
:
$gl-btn-padding
;
}
@media
(
max-width
:
$screen-sm-max
)
{
padding-right
:
$gl-col-padding
;
}
&
:last-child
{
&
.pipeline-variable-row-remove-button
{
display
:
none
;
}
@media
(
max-width
:
$screen-sm-max
)
{
&
.pipeline-variable-value-input
{
margin-right
:
$pipeline-variable-remove-button-width
;
}
}
@media
(
max-width
:
$screen-xs-max
)
{
.pipeline-variable-row-body
{
margin-right
:
$pipeline-variable-remove-button-width
;
}
}
}
}
.pipeline-variable-row-body
{
display
:
flex
;
width
:
calc
(
75%
-
#{
$gl-col-padding
}
);
padding-left
:
$gl-col-padding
;
@media
(
max-width
:
$screen-sm-max
)
{
width
:
100%
;
}
@media
(
max-width
:
$screen-xs-max
)
{
display
:
block
;
}
}
.pipeline-variable-key-input
{
margin-right
:
$gl-btn-padding
;
@media
(
max-width
:
$screen-xs-max
)
{
margin-bottom
:
$gl-btn-padding
;
}
}
.pipeline-variable-row-remove-button
{
flex-shrink
:
0
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
width
:
$pipeline-variable-remove-button-width
;
height
:
$input-height
;
padding
:
0
;
background
:
transparent
;
border
:
0
;
color
:
$gl-text-color-secondary
;
@include
transition
(
color
);
&
:hover
,
&
:focus
{
outline
:
none
;
color
:
$gl-text-color
;
}
}
app/controllers/projects/pipeline_schedules_controller.rb
View file @
0dc2ca3a
class
Projects::PipelineSchedulesController
<
Projects
::
ApplicationController
before_action
:schedule
,
except:
[
:index
,
:new
,
:create
]
before_action
:authorize_read_pipeline_schedule!
before_action
:authorize_create_pipeline_schedule!
,
only:
[
:new
,
:create
]
before_action
:authorize_update_pipeline_schedule!
,
only:
[
:edit
,
:take_ownership
,
:upd
ate
]
before_action
:authorize_update_pipeline_schedule!
,
except:
[
:index
,
:new
,
:cre
ate
]
before_action
:authorize_admin_pipeline_schedule!
,
only:
[
:destroy
]
before_action
:schedule
,
only:
[
:edit
,
:update
,
:destroy
,
:take_ownership
]
def
index
@scope
=
params
[
:scope
]
@all_schedules
=
PipelineSchedulesFinder
.
new
(
@project
).
execute
...
...
@@ -53,7 +53,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
redirect_to
pipeline_schedules_path
(
@project
),
status:
302
else
redirect_to
pipeline_schedules_path
(
@project
),
status:
302
,
status:
:forbidden
,
alert:
_
(
"Failed to remove the pipeline schedule"
)
end
end
...
...
@@ -66,6 +66,15 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
def
schedule_params
params
.
require
(
:schedule
)
.
permit
(
:description
,
:cron
,
:cron_timezone
,
:ref
,
:active
)
.
permit
(
:description
,
:cron
,
:cron_timezone
,
:ref
,
:active
,
variables_attributes:
[
:id
,
:key
,
:value
,
:_destroy
]
)
end
def
authorize_update_pipeline_schedule!
return
access_denied!
unless
can?
(
current_user
,
:update_pipeline_schedule
,
schedule
)
end
def
authorize_admin_pipeline_schedule!
return
access_denied!
unless
can?
(
current_user
,
:admin_pipeline_schedule
,
schedule
)
end
end
app/models/ci/build.rb
View file @
0dc2ca3a
...
...
@@ -207,6 +207,7 @@ module Ci
variables
+=
project
.
group
.
secret_variables_for
(
ref
,
project
).
map
(
&
:to_runner_variable
)
if
project
.
group
variables
+=
secret_variables
(
environment:
environment
)
variables
+=
trigger_request
.
user_variables
if
trigger_request
variables
+=
pipeline
.
pipeline_schedule
.
job_variables
if
pipeline
.
pipeline_schedule
variables
+=
persisted_environment_variables
if
environment
variables
...
...
app/models/ci/pipeline_schedule.rb
View file @
0dc2ca3a
...
...
@@ -9,17 +9,21 @@ module Ci
belongs_to
:owner
,
class_name:
'User'
has_one
:last_pipeline
,
->
{
order
(
id: :desc
)
},
class_name:
'Ci::Pipeline'
has_many
:pipelines
has_many
:variables
,
class_name:
'Ci::PipelineScheduleVariable'
validates
:cron
,
unless: :importing?
,
cron:
true
,
presence:
{
unless: :importing?
}
validates
:cron_timezone
,
cron_timezone:
true
,
presence:
{
unless: :importing?
}
validates
:ref
,
presence:
{
unless: :importing?
}
validates
:description
,
presence:
true
validates
:variables
,
variable_duplicates:
true
before_save
:set_next_run_at
scope
:active
,
->
{
where
(
active:
true
)
}
scope
:inactive
,
->
{
where
(
active:
false
)
}
accepts_nested_attributes_for
:variables
,
allow_destroy:
true
def
owned_by?
(
current_user
)
owner
==
current_user
end
...
...
@@ -56,5 +60,9 @@ module Ci
Gitlab
::
Ci
::
CronParser
.
new
(
worker_cron
,
worker_time_zone
)
.
next_time_from
(
next_run_at
)
end
def
job_variables
variables
&
.
map
(
&
:to_runner_variable
)
||
[]
end
end
end
app/models/ci/pipeline_schedule_variable.rb
0 → 100644
View file @
0dc2ca3a
module
Ci
class
PipelineScheduleVariable
<
ActiveRecord
::
Base
extend
Ci
::
Model
include
HasVariable
belongs_to
:pipeline_schedule
end
end
app/policies/ci/pipeline_schedule_policy.rb
View file @
0dc2ca3a
module
Ci
class
PipelineSchedulePolicy
<
PipelinePolicy
alias_method
:pipeline_schedule
,
:subject
condition
(
:owner_of_schedule
)
do
can?
(
:developer_access
)
&&
pipeline_schedule
.
owned_by?
(
@user
)
end
rule
{
can?
(
:master_access
)
|
owner_of_schedule
}.
policy
do
enable
:update_pipeline_schedule
enable
:admin_pipeline_schedule
end
end
end
app/policies/project_policy.rb
View file @
0dc2ca3a
...
...
@@ -164,7 +164,6 @@ class ProjectPolicy < BasePolicy
enable
:create_pipeline
enable
:update_pipeline
enable
:create_pipeline_schedule
enable
:update_pipeline_schedule
enable
:create_merge_request
enable
:create_wiki
enable
:push_code
...
...
@@ -190,7 +189,6 @@ class ProjectPolicy < BasePolicy
enable
:admin_build
enable
:admin_container_image
enable
:admin_pipeline
enable
:admin_pipeline_schedule
enable
:admin_environment
enable
:admin_deployment
enable
:admin_pages
...
...
app/validators/variable_duplicates_validator.rb
0 → 100644
View file @
0dc2ca3a
# VariableDuplicatesValidator
#
# This validtor is designed for especially the following condition
# - Use `accepts_nested_attributes_for :xxx` in a parent model
# - Use `validates :xxx, uniqueness: { scope: :xxx_id }` in a child model
class
VariableDuplicatesValidator
<
ActiveModel
::
EachValidator
def
validate_each
(
record
,
attribute
,
value
)
duplicates
=
value
.
reject
(
&
:marked_for_destruction?
).
group_by
(
&
:key
).
select
{
|
_
,
v
|
v
.
many?
}.
map
(
&
:first
)
if
duplicates
.
any?
record
.
errors
.
add
(
attribute
,
"Duplicate variables:
#{
duplicates
.
join
(
", "
)
}
"
)
end
end
end
app/views/projects/pipeline_schedules/_form.html.haml
View file @
0dc2ca3a
...
...
@@ -22,6 +22,14 @@
=
f
.
label
:ref
,
_
(
'Target Branch'
),
class:
'label-light'
=
dropdown_tag
(
_
(
"Select target branch"
),
options:
{
toggle_class:
'btn js-target-branch-dropdown'
,
dropdown_class:
'git-revision-dropdown'
,
title:
_
(
"Select target branch"
),
filter:
true
,
placeholder:
s_
(
"OfSearchInADropdown|Filter"
),
data:
{
data:
@project
.
repository
.
branch_names
,
default_branch:
@project
.
default_branch
}
}
)
=
f
.
text_field
:ref
,
value:
@schedule
.
ref
,
id:
'schedule_ref'
,
class:
'hidden'
,
name:
'schedule[ref]'
,
required:
true
.form-group
.col-md-9
%label
.label-light
#{
s_
(
'PipelineSchedules|Variables'
)
}
%ul
.js-pipeline-variable-list.pipeline-variable-list
-
@schedule
.
variables
.
each
do
|
variable
|
=
render
'variable_row'
,
id:
variable
.
id
,
key:
variable
.
key
,
value:
variable
.
value
=
render
'variable_row'
.form-group
.col-md-9
=
f
.
label
:active
,
s_
(
'PipelineSchedules|Activated'
),
class:
'label-light'
...
...
app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
View file @
0dc2ca3a
...
...
@@ -26,7 +26,7 @@
=
pipeline_schedule
.
owner
&
.
name
%td
.pull-right.btn-group
-
if
can?
(
current_user
,
:update_pipeline_schedule
,
@project
)
&&
!
pipeline_schedule
.
owned_by?
(
current_user
)
-
if
can?
(
current_user
,
:update_pipeline_schedule
,
pipeline_schedule
)
=
link_to
take_ownership_pipeline_schedule_path
(
pipeline_schedule
),
method: :post
,
title:
s_
(
'PipelineSchedules|Take ownership'
),
class:
'btn'
do
=
s_
(
'PipelineSchedules|Take ownership'
)
-
if
can?
(
current_user
,
:update_pipeline_schedule
,
pipeline_schedule
)
...
...
app/views/projects/pipeline_schedules/_variable_row.html.haml
0 → 100644
View file @
0dc2ca3a
-
id
=
local_assigns
.
fetch
(
:id
,
nil
)
-
key
=
local_assigns
.
fetch
(
:key
,
""
)
-
value
=
local_assigns
.
fetch
(
:value
,
""
)
%li
.js-row.pipeline-variable-row
{
data:
{
is_persisted:
"#{!id.nil?}"
}
}
.pipeline-variable-row-body
%input
{
type:
"hidden"
,
name:
"schedule[variables_attributes][][id]"
,
value:
id
}
%input
.js-destroy-input
{
type:
"hidden"
,
name:
"schedule[variables_attributes][][_destroy]"
}
%input
.js-user-input.pipeline-variable-key-input.form-control
{
type:
"text"
,
name:
"schedule[variables_attributes][][key]"
,
value:
key
,
placeholder:
s_
(
'PipelineSchedules|Input variable key'
)
}
%textarea
.js-user-input.pipeline-variable-value-input.form-control
{
rows:
1
,
name:
"schedule[variables_attributes][][value]"
,
placeholder:
s_
(
'PipelineSchedules|Input variable value'
)
}
=
value
%button
.js-row-remove-button.pipeline-variable-row-remove-button
{
'aria-label'
:
s_
(
'PipelineSchedules|Remove variable row'
)
}
%i
.fa.fa-minus-circle
{
'aria-hidden'
:
"true"
}
changelogs/unreleased/feature-intermediate-32568-adding-variables-to-pipelines-schedules.yml
0 → 100644
View file @
0dc2ca3a
---
title
:
Add variables to pipelines schedules
merge_request
:
12372
author
:
db/migrate/20170620064728_create_ci_pipeline_schedule_variables.rb
0 → 100644
View file @
0dc2ca3a
class
CreateCiPipelineScheduleVariables
<
ActiveRecord
::
Migration
DOWNTIME
=
false
def
up
create_table
:ci_pipeline_schedule_variables
do
|
t
|
t
.
string
:key
,
null:
false
t
.
text
:value
t
.
text
:encrypted_value
t
.
string
:encrypted_value_salt
t
.
string
:encrypted_value_iv
t
.
integer
:pipeline_schedule_id
,
null:
false
t
.
timestamps_with_timezone
null:
true
end
add_index
:ci_pipeline_schedule_variables
,
[
:pipeline_schedule_id
,
:key
],
name:
"index_ci_pipeline_schedule_variables_on_schedule_id_and_key"
,
unique:
true
end
def
down
drop_table
:ci_pipeline_schedule_variables
end
end
db/migrate/20170620065449_add_foreign_key_to_ci_pipeline_schedule_variables.rb
0 → 100644
View file @
0dc2ca3a
class
AddForeignKeyToCiPipelineScheduleVariables
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
disable_ddl_transaction!
def
up
add_concurrent_foreign_key
(
:ci_pipeline_schedule_variables
,
:ci_pipeline_schedules
,
column: :pipeline_schedule_id
)
end
def
down
remove_foreign_key
(
:ci_pipeline_schedule_variables
,
column: :pipeline_schedule_id
)
end
end
db/schema.rb
View file @
0dc2ca3a
...
...
@@ -312,6 +312,19 @@ ActiveRecord::Schema.define(version: 20170706151212) do
add_index
"ci_builds"
,
[
"updated_at"
],
name:
"index_ci_builds_on_updated_at"
,
using: :btree
add_index
"ci_builds"
,
[
"user_id"
],
name:
"index_ci_builds_on_user_id"
,
using: :btree
create_table
"ci_pipeline_schedule_variables"
,
force: :cascade
do
|
t
|
t
.
string
"key"
,
null:
false
t
.
text
"value"
t
.
text
"encrypted_value"
t
.
string
"encrypted_value_salt"
t
.
string
"encrypted_value_iv"
t
.
integer
"pipeline_schedule_id"
,
null:
false
t
.
datetime
"created_at"
,
null:
false
t
.
datetime
"updated_at"
,
null:
false
end
add_index
"ci_pipeline_schedule_variables"
,
[
"pipeline_schedule_id"
,
"key"
],
name:
"index_ci_pipeline_schedule_variables_on_schedule_id_and_key"
,
unique:
true
,
using: :btree
create_table
"ci_group_variables"
,
force: :cascade
do
|
t
|
t
.
string
"key"
,
null:
false
t
.
text
"value"
...
...
@@ -1885,6 +1898,7 @@ ActiveRecord::Schema.define(version: 20170706151212) do
add_foreign_key
"ci_builds"
,
"ci_pipelines"
,
column:
"auto_canceled_by_id"
,
name:
"fk_a2141b1522"
,
on_delete: :nullify
add_foreign_key
"ci_builds"
,
"ci_stages"
,
column:
"stage_id"
,
name:
"fk_3a9eaa254d"
,
on_delete: :cascade
add_foreign_key
"ci_builds"
,
"projects"
,
name:
"fk_befce0568a"
,
on_delete: :cascade
add_foreign_key
"ci_pipeline_schedule_variables"
,
"ci_pipeline_schedules"
,
column:
"pipeline_schedule_id"
,
name:
"fk_41c35fda51"
,
on_delete: :cascade
add_foreign_key
"ci_group_variables"
,
"namespaces"
,
column:
"group_id"
,
name:
"fk_33ae4d58d8"
,
on_delete: :cascade
add_foreign_key
"ci_pipeline_schedules"
,
"projects"
,
name:
"fk_8ead60fcc4"
,
on_delete: :cascade
add_foreign_key
"ci_pipeline_schedules"
,
"users"
,
column:
"owner_id"
,
name:
"fk_9ea99f58d2"
,
on_delete: :nullify
...
...
doc/ci/variables/README.md
View file @
0dc2ca3a
...
...
@@ -9,7 +9,7 @@ and a list of **user-defined variables**.
The variables can be overwritten and they take precedence over each other in
this order:
1.
[
Trigger variables
][
triggers
]
(take precedence over all)
1.
[
Trigger variables
][
triggers
]
or
[
scheduled pipeline variables
](
../../user/project/pipelines/schedules.md#making-use-of-scheduled-pipeline-variables
)
(
take
precedence over all)
1.
Project-level
[
secret variables
](
#secret-variables
)
or
[
protected secret variables
](
#protected-secret-variables
)
1.
Group-level
[
secret variables
](
#secret-variables
)
or
[
protected secret variables
](
#protected-secret-variables
)
1.
YAML-defined
[
job-level variables
](
../yaml/README.md#job-variables
)
...
...
doc/user/project/pipelines/img/pipeline_schedule_variables.png
0 → 100644
View file @
0dc2ca3a
13.2 KB
doc/user/project/pipelines/img/pipeline_schedules_new_form.png
View replaced file @
9f2608ba
View file @
0dc2ca3a
48.7 KB
|
W:
|
H:
70.8 KB
|
W:
|
H:
2-up
Swipe
Onion skin
doc/user/project/pipelines/schedules.md
View file @
0dc2ca3a
...
...
@@ -31,6 +31,15 @@ is installed on.
![
Schedules list
](
img/pipeline_schedules_list.png
)
### Making use of scheduled pipeline variables
> [Introduced][ce-12328] in GitLab 9.4.
You can pass any number of arbitrary variables and they will be available in
GitLab CI so that they can be used in your
`.gitlab-ci.yml`
file.
![
Scheduled pipeline variables
](
img/pipeline_schedule_variables.png
)
## Using only and except
To configure that a job can be executed only when the pipeline has been
...
...
@@ -79,4 +88,5 @@ don't have admin access to the server, ask your administrator.
[
ce-10533
]:
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10533
[
ce-10853
]:
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10853
[
ce-12328
]:
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12328
[
settings
]:
https://about.gitlab.com/gitlab-com/settings/#cron-jobs
lib/api/pipeline_schedules.rb
View file @
0dc2ca3a
...
...
@@ -74,9 +74,10 @@ module API
optional
:active
,
type:
Boolean
,
desc:
'The activation of pipeline schedule'
end
put
':id/pipeline_schedules/:pipeline_schedule_id'
do
authorize!
:
update
_pipeline_schedule
,
user_project
authorize!
:
read
_pipeline_schedule
,
user_project
not_found!
(
'PipelineSchedule'
)
unless
pipeline_schedule
authorize!
:update_pipeline_schedule
,
pipeline_schedule
if
pipeline_schedule
.
update
(
declared_params
(
include_missing:
false
))
present
pipeline_schedule
,
with:
Entities
::
PipelineScheduleDetails
...
...
@@ -92,9 +93,10 @@ module API
requires
:pipeline_schedule_id
,
type:
Integer
,
desc:
'The pipeline schedule id'
end
post
':id/pipeline_schedules/:pipeline_schedule_id/take_ownership'
do
authorize!
:
update
_pipeline_schedule
,
user_project
authorize!
:
read
_pipeline_schedule
,
user_project
not_found!
(
'PipelineSchedule'
)
unless
pipeline_schedule
authorize!
:update_pipeline_schedule
,
pipeline_schedule
if
pipeline_schedule
.
own!
(
current_user
)
present
pipeline_schedule
,
with:
Entities
::
PipelineScheduleDetails
...
...
@@ -110,9 +112,10 @@ module API
requires
:pipeline_schedule_id
,
type:
Integer
,
desc:
'The pipeline schedule id'
end
delete
':id/pipeline_schedules/:pipeline_schedule_id'
do
authorize!
:
admin
_pipeline_schedule
,
user_project
authorize!
:
read
_pipeline_schedule
,
user_project
not_found!
(
'PipelineSchedule'
)
unless
pipeline_schedule
authorize!
:admin_pipeline_schedule
,
pipeline_schedule
status
:accepted
present
pipeline_schedule
.
destroy
,
with:
Entities
::
PipelineScheduleDetails
...
...
locale/en/gitlab.po
View file @
0dc2ca3a
...
...
@@ -619,6 +619,12 @@ msgstr ""
msgid "PipelineSchedules|Inactive"
msgstr ""
msgid "PipelineSchedules|Input variable key"
msgstr ""
msgid "PipelineSchedules|Input variable value"
msgstr ""
msgid "PipelineSchedules|Next Run"
msgstr ""
...
...
@@ -628,12 +634,18 @@ msgstr ""
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Remove variable row"
msgstr ""
msgid "PipelineSchedules|Take ownership"
msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
msgid "PipelineSchedules|Variables"
msgstr ""
msgid "PipelineSheduleIntervalPattern|Custom"
msgstr ""
...
...
@@ -1056,6 +1068,12 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr ""
msgid ""
"You are going to remove %{group_name}.\n"
"Removed groups CANNOT be restored!\n"
"Are you ABSOLUTELY sure?"
msgstr ""
msgid ""
"You are going to remove %{project_name_with_namespace}.\n"
"Removed project CANNOT be restored!\n"
...
...
locale/gitlab.pot
View file @
0dc2ca3a
...
...
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-0
6-28 13:32+02
00\n"
"PO-Revision-Date: 2017-0
6-28 13:32+02
00\n"
"POT-Creation-Date: 2017-0
7-05 08:50-05
00\n"
"PO-Revision-Date: 2017-0
7-05 08:50-05
00\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
...
...
@@ -620,6 +620,12 @@ msgstr ""
msgid "PipelineSchedules|Inactive"
msgstr ""
msgid "PipelineSchedules|Input variable key"
msgstr ""
msgid "PipelineSchedules|Input variable value"
msgstr ""
msgid "PipelineSchedules|Next Run"
msgstr ""
...
...
@@ -629,12 +635,18 @@ msgstr ""
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Remove variable row"
msgstr ""
msgid "PipelineSchedules|Take ownership"
msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
msgid "PipelineSchedules|Variables"
msgstr ""
msgid "PipelineSheduleIntervalPattern|Custom"
msgstr ""
...
...
@@ -1057,6 +1069,12 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr ""
msgid ""
"You are going to remove %{group_name}.\n"
"Removed groups CANNOT be restored!\n"
"Are you ABSOLUTELY sure?"
msgstr ""
msgid ""
"You are going to remove %{project_name_with_namespace}.\n"
"Removed project CANNOT be restored!\n"
...
...
spec/controllers/projects/pipeline_schedules_controller_spec.rb
View file @
0dc2ca3a
require
'spec_helper'
describe
Projects
::
PipelineSchedulesController
do
include
AccessMatchersForController
set
(
:project
)
{
create
(
:empty_project
,
:public
)
}
let!
(
:pipeline_schedule
)
{
create
(
:ci_pipeline_schedule
,
project:
project
)
}
...
...
@@ -17,6 +19,14 @@ describe Projects::PipelineSchedulesController do
expect
(
response
).
to
render_template
(
:index
)
end
it
'avoids N + 1 queries'
do
control_count
=
ActiveRecord
::
QueryRecorder
.
new
{
visit_pipelines_schedules
}.
count
create_list
(
:ci_pipeline_schedule
,
2
,
project:
project
)
expect
{
visit_pipelines_schedules
}.
not_to
exceed_query_limit
(
control_count
)
end
context
'when the scope is set to active'
do
let
(
:scope
)
{
'active'
}
...
...
@@ -36,104 +46,352 @@ describe Projects::PipelineSchedulesController do
end
end
describe
'GET
edit
'
do
l
et
(
:user
)
{
create
(
:user
)
}
describe
'GET
#new
'
do
s
et
(
:user
)
{
create
(
:user
)
}
before
do
project
.
add_master
(
user
)
project
.
add_developer
(
user
)
sign_in
(
user
)
end
it
'
loads the pipeline schedule
'
do
get
:
edit
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
it
'
initializes a pipeline schedule model
'
do
get
:
new
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
expect
(
response
).
to
have_http_status
(
:ok
)
expect
(
assigns
(
:schedule
)).
to
eq
(
pipeline_s
chedule
)
expect
(
assigns
(
:schedule
)).
to
be_a_new
(
Ci
::
PipelineS
chedule
)
end
end
describe
'DELETE #destroy'
do
describe
'POST #create'
do
describe
'functionality'
do
set
(
:user
)
{
create
(
:user
)
}
context
'when a developer makes the request'
do
before
do
project
.
add_developer
(
user
)
sign_in
(
user
)
end
delete
:destroy
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
let
(
:basic_param
)
do
attributes_for
(
:ci_pipeline_schedule
)
end
it
'does not delete the pipeline schedule'
do
expect
(
response
).
not_to
have_http_status
(
:ok
)
context
'when variables_attributes has one variable'
do
let
(
:schedule
)
do
basic_param
.
merge
({
variables_attributes:
[{
key:
'AAA'
,
value:
'AAA123'
}]
})
end
it
'creates a new schedule'
do
expect
{
go
}
.
to
change
{
Ci
::
PipelineSchedule
.
count
}.
by
(
1
)
.
and
change
{
Ci
::
PipelineScheduleVariable
.
count
}.
by
(
1
)
expect
(
response
).
to
have_http_status
(
:found
)
Ci
::
PipelineScheduleVariable
.
last
.
tap
do
|
v
|
expect
(
v
.
key
).
to
eq
(
"AAA"
)
expect
(
v
.
value
).
to
eq
(
"AAA123"
)
end
end
end
context
'when a master makes the request'
do
context
'when variables_attributes has two variables and duplicted'
do
let
(
:schedule
)
do
basic_param
.
merge
({
variables_attributes:
[{
key:
'AAA'
,
value:
'AAA123'
},
{
key:
'AAA'
,
value:
'BBB123'
}]
})
end
it
'returns an error that the keys of variable are duplicated'
do
expect
{
go
}
.
to
change
{
Ci
::
PipelineSchedule
.
count
}.
by
(
0
)
.
and
change
{
Ci
::
PipelineScheduleVariable
.
count
}.
by
(
0
)
expect
(
assigns
(
:schedule
).
errors
[
'variables'
]).
not_to
be_empty
end
end
end
describe
'security'
do
let
(
:schedule
)
{
attributes_for
(
:ci_pipeline_schedule
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:admin
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:owner
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:master
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:developer
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:reporter
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:guest
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:user
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:external
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:visitor
)
}
end
def
go
post
:create
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
schedule:
schedule
end
end
describe
'PUT #update'
do
describe
'functionality'
do
set
(
:user
)
{
create
(
:user
)
}
let!
(
:pipeline_schedule
)
{
create
(
:ci_pipeline_schedule
,
project:
project
,
owner:
user
)
}
before
do
project
.
add_
mast
er
(
user
)
project
.
add_
develop
er
(
user
)
sign_in
(
user
)
end
it
'destroys the pipeline schedule
'
do
expect
do
delete
:destroy
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
end
.
to
change
{
project
.
pipeline_schedules
.
count
}.
by
(
-
1
)
context
'when a pipeline schedule has no variables
'
do
let
(
:basic_param
)
do
{
description:
'updated_desc'
,
cron:
'0 1 * * *'
,
cron_timezone:
'UTC'
,
ref:
'patch-x'
,
active:
true
}
end
expect
(
response
).
to
have_http_status
(
302
)
context
'when params include one variable'
do
let
(
:schedule
)
do
basic_param
.
merge
({
variables_attributes:
[{
key:
'AAA'
,
value:
'AAA123'
}]
})
end
it
'inserts new variable to the pipeline schedule'
do
expect
{
go
}.
to
change
{
Ci
::
PipelineScheduleVariable
.
count
}.
by
(
1
)
pipeline_schedule
.
reload
expect
(
response
).
to
have_http_status
(
:found
)
expect
(
pipeline_schedule
.
variables
.
last
.
key
).
to
eq
(
'AAA'
)
expect
(
pipeline_schedule
.
variables
.
last
.
value
).
to
eq
(
'AAA123'
)
end
end
context
'when params include two duplicated variables'
do
let
(
:schedule
)
do
basic_param
.
merge
({
variables_attributes:
[{
key:
'AAA'
,
value:
'AAA123'
},
{
key:
'AAA'
,
value:
'BBB123'
}]
})
end
it
'returns an error that variables are duplciated'
do
go
expect
(
assigns
(
:schedule
).
errors
[
'variables'
]).
not_to
be_empty
end
end
end
context
'when a pipeline schedule has one variable'
do
let
(
:basic_param
)
do
{
description:
'updated_desc'
,
cron:
'0 1 * * *'
,
cron_timezone:
'UTC'
,
ref:
'patch-x'
,
active:
true
}
end
let!
(
:pipeline_schedule_variable
)
do
create
(
:ci_pipeline_schedule_variable
,
key:
'CCC'
,
pipeline_schedule:
pipeline_schedule
)
end
context
'when adds a new variable'
do
let
(
:schedule
)
do
basic_param
.
merge
({
variables_attributes:
[{
key:
'AAA'
,
value:
'AAA123'
}]
})
end
it
'adds the new variable'
do
expect
{
go
}.
to
change
{
Ci
::
PipelineScheduleVariable
.
count
}.
by
(
1
)
pipeline_schedule
.
reload
expect
(
pipeline_schedule
.
variables
.
last
.
key
).
to
eq
(
'AAA'
)
end
end
context
'when adds a new duplicated variable'
do
let
(
:schedule
)
do
basic_param
.
merge
({
variables_attributes:
[{
key:
'CCC'
,
value:
'AAA123'
}]
})
end
it
'returns an error'
do
expect
{
go
}.
not_to
change
{
Ci
::
PipelineScheduleVariable
.
count
}
pipeline_schedule
.
reload
expect
(
assigns
(
:schedule
).
errors
[
'variables'
]).
not_to
be_empty
end
end
context
'when updates a variable'
do
let
(
:schedule
)
do
basic_param
.
merge
({
variables_attributes:
[{
id:
pipeline_schedule_variable
.
id
,
value:
'new_value'
}]
})
end
it
'updates the variable'
do
expect
{
go
}.
not_to
change
{
Ci
::
PipelineScheduleVariable
.
count
}
pipeline_schedule_variable
.
reload
expect
(
pipeline_schedule_variable
.
value
).
to
eq
(
'new_value'
)
end
end
context
'when deletes a variable'
do
let
(
:schedule
)
do
basic_param
.
merge
({
variables_attributes:
[{
id:
pipeline_schedule_variable
.
id
,
_destroy:
true
}]
})
end
it
'delete the existsed variable'
do
expect
{
go
}.
to
change
{
Ci
::
PipelineScheduleVariable
.
count
}.
by
(
-
1
)
end
end
context
'when deletes and creates a same key simultaneously'
do
let
(
:schedule
)
do
basic_param
.
merge
({
variables_attributes:
[{
id:
pipeline_schedule_variable
.
id
,
_destroy:
true
},
{
key:
'CCC'
,
value:
'CCC123'
}]
})
end
it
'updates the variable'
do
expect
{
go
}.
not_to
change
{
Ci
::
PipelineScheduleVariable
.
count
}
pipeline_schedule
.
reload
expect
(
pipeline_schedule
.
variables
.
last
.
key
).
to
eq
(
'CCC'
)
expect
(
pipeline_schedule
.
variables
.
last
.
value
).
to
eq
(
'CCC123'
)
end
end
end
end
describe
'security'
do
include
AccessMatchersForController
let
(
:schedule
)
{
{
description:
'updated_desc'
}
}
describe
'GET edit'
do
it
{
expect
{
go
}.
to
be_allowed_for
(
:admin
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:owner
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:master
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:developer
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:developer
).
of
(
project
)
.
own
(
pipeline_schedule
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:reporter
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:guest
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:user
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:external
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:visitor
)
}
context
'when a developer created a pipeline schedule'
do
let
(
:developer_1
)
{
create
(
:user
)
}
let!
(
:pipeline_schedule
)
{
create
(
:ci_pipeline_schedule
,
project:
project
,
owner:
developer_1
)
}
before
do
project
.
add_developer
(
developer_1
)
end
it
{
expect
{
go
}.
to
be_allowed_for
(
developer_1
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:developer
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:master
).
of
(
project
)
}
end
context
'when a master created a pipeline schedule'
do
let
(
:master_1
)
{
create
(
:user
)
}
let!
(
:pipeline_schedule
)
{
create
(
:ci_pipeline_schedule
,
project:
project
,
owner:
master_1
)
}
before
do
project
.
add_master
(
master_1
)
end
it
{
expect
{
go
}.
to
be_allowed_for
(
master_1
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:master
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:developer
).
of
(
project
)
}
end
end
def
go
put
:update
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
,
schedule:
schedule
end
end
describe
'GET #edit'
do
describe
'functionality'
do
let
(
:user
)
{
create
(
:user
)
}
before
do
project
.
add_master
(
user
)
sign_in
(
user
)
end
it
'loads the pipeline schedule'
do
get
:edit
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
expect
(
response
).
to
have_http_status
(
:ok
)
expect
(
assigns
(
:schedule
)).
to
eq
(
pipeline_schedule
)
end
end
describe
'
GET take_ownership
'
do
describe
'
security
'
do
it
{
expect
{
go
}.
to
be_allowed_for
(
:admin
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:owner
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:master
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:developer
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:developer
).
of
(
project
)
.
own
(
pipeline_schedule
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:reporter
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:guest
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:user
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:external
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:visitor
)
}
end
def
go
post
:take_ownership
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
get
:edit
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
end
end
describe
'PUT update'
do
describe
'GET #take_ownership'
do
describe
'security'
do
it
{
expect
{
go
}.
to
be_allowed_for
(
:admin
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:owner
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:master
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:developer
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:developer
).
of
(
project
)
.
own
(
pipeline_schedule
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:reporter
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:guest
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:user
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:external
)
}
it
{
expect
{
go
}.
to
be_denied_for
(
:visitor
)
}
end
def
go
put
:update
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
,
schedule:
{
description:
'a'
}
post
:take_ownership
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
end
end
describe
'DELETE #destroy'
do
set
(
:user
)
{
create
(
:user
)
}
context
'when a developer makes the request'
do
before
do
project
.
add_developer
(
user
)
sign_in
(
user
)
delete
:destroy
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
end
it
'does not delete the pipeline schedule'
do
expect
(
response
).
to
have_http_status
(
:not_found
)
end
end
context
'when a master makes the request'
do
before
do
project
.
add_master
(
user
)
sign_in
(
user
)
end
it
'destroys the pipeline schedule'
do
expect
do
delete
:destroy
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
end
.
to
change
{
project
.
pipeline_schedules
.
count
}.
by
(
-
1
)
expect
(
response
).
to
have_http_status
(
302
)
end
end
end
...
...
spec/factories/ci/pipeline_schedule_variables.rb
0 → 100644
View file @
0dc2ca3a
FactoryGirl
.
define
do
factory
:ci_pipeline_schedule_variable
,
class:
Ci
::
PipelineScheduleVariable
do
sequence
(
:key
)
{
|
n
|
"VARIABLE_
#{
n
}
"
}
value
'VARIABLE_VALUE'
pipeline_schedule
factory: :ci_pipeline_schedule
end
end
spec/features/projects/pipeline_schedules_spec.rb
View file @
0dc2ca3a
require
'spec_helper'
feature
'Pipeline Schedules'
,
:feature
do
feature
'Pipeline Schedules'
,
:feature
,
js:
true
do
include
PipelineSchedulesHelper
let!
(
:project
)
{
create
(
:project
)
}
...
...
@@ -11,27 +11,20 @@ feature 'Pipeline Schedules', :feature do
before
do
project
.
add_master
(
user
)
sign_in
(
user
)
visit_page
gitlab_sign_in
(
user
)
end
describe
'GET /projects/pipeline_schedules'
do
let
(
:visit_page
)
{
visit_pipelines_schedules
}
it
'avoids N + 1 queries'
do
control_count
=
ActiveRecord
::
QueryRecorder
.
new
{
visit_pipelines_schedules
}.
count
create_list
(
:ci_pipeline_schedule
,
2
,
project:
project
)
expect
{
visit_pipelines_schedules
}.
not_to
exceed_query_limit
(
control_count
)
before
do
visit_pipelines_schedules
end
describe
'The view'
do
it
'displays the required information description'
do
page
.
within
(
'.pipeline-schedule-table-row'
)
do
expect
(
page
).
to
have_content
(
'pipeline schedule'
)
expect
(
page
).
to
have_content
(
pipeline_schedule
.
real_next_run
.
strftime
(
'%b %d, %Y'
))
expect
(
find
(
".next-run-cell time"
)[
'data-original-title'
])
.
to
include
(
pipeline_schedule
.
real_next_run
.
strftime
(
'%b %-d, %Y'
))
expect
(
page
).
to
have_link
(
'master'
)
expect
(
page
).
to
have_link
(
"#
#{
pipeline
.
id
}
"
)
end
...
...
@@ -62,7 +55,7 @@ feature 'Pipeline Schedules', :feature do
it
'deletes the pipeline'
do
click_link
'Delete'
expect
(
page
).
not_to
have_c
ontent
(
'pipeline schedule'
)
expect
(
page
).
not_to
have_c
ss
(
".pipeline-schedule-table-row"
)
end
end
...
...
@@ -78,8 +71,10 @@ feature 'Pipeline Schedules', :feature do
end
end
describe
'POST /projects/pipeline_schedules/new'
,
js:
true
do
let
(
:visit_page
)
{
visit_new_pipeline_schedule
}
describe
'POST /projects/pipeline_schedules/new'
do
before
do
visit_new_pipeline_schedule
end
it
'sets defaults for timezone and target branch'
do
expect
(
page
).
to
have_button
(
'master'
)
...
...
@@ -100,8 +95,8 @@ feature 'Pipeline Schedules', :feature do
end
end
describe
'PATCH /projects/pipelines_schedules/:id/edit'
,
js:
true
do
let
(
:visit_page
)
do
describe
'PATCH /projects/pipelines_schedules/:id/edit'
do
before
do
edit_pipeline_schedule
end
...
...
@@ -134,6 +129,72 @@ feature 'Pipeline Schedules', :feature do
end
end
context
'when user creates a new pipeline schedule with variables'
do
background
do
visit_pipelines_schedules
click_link
'New schedule'
fill_in_schedule_form
all
(
'[name="schedule[variables_attributes][][key]"]'
)[
0
].
set
(
'AAA'
)
all
(
'[name="schedule[variables_attributes][][value]"]'
)[
0
].
set
(
'AAA123'
)
all
(
'[name="schedule[variables_attributes][][key]"]'
)[
1
].
set
(
'BBB'
)
all
(
'[name="schedule[variables_attributes][][value]"]'
)[
1
].
set
(
'BBB123'
)
save_pipeline_schedule
end
scenario
'user sees the new variable in edit window'
do
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
page
.
within
(
'.pipeline-variable-list'
)
do
expect
(
find
(
".pipeline-variable-row:nth-child(1) .pipeline-variable-key-input"
).
value
).
to
eq
(
'AAA'
)
expect
(
find
(
".pipeline-variable-row:nth-child(1) .pipeline-variable-value-input"
).
value
).
to
eq
(
'AAA123'
)
expect
(
find
(
".pipeline-variable-row:nth-child(2) .pipeline-variable-key-input"
).
value
).
to
eq
(
'BBB'
)
expect
(
find
(
".pipeline-variable-row:nth-child(2) .pipeline-variable-value-input"
).
value
).
to
eq
(
'BBB123'
)
end
end
end
context
'when user edits a variable of a pipeline schedule'
do
background
do
create
(
:ci_pipeline_schedule
,
project:
project
,
owner:
user
).
tap
do
|
pipeline_schedule
|
create
(
:ci_pipeline_schedule_variable
,
key:
'AAA'
,
value:
'AAA123'
,
pipeline_schedule:
pipeline_schedule
)
end
visit_pipelines_schedules
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
all
(
'[name="schedule[variables_attributes][][key]"]'
)[
0
].
set
(
'foo'
)
all
(
'[name="schedule[variables_attributes][][value]"]'
)[
0
].
set
(
'bar'
)
click_button
'Save pipeline schedule'
end
scenario
'user sees the updated variable in edit window'
do
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
page
.
within
(
'.pipeline-variable-list'
)
do
expect
(
find
(
".pipeline-variable-row:nth-child(1) .pipeline-variable-key-input"
).
value
).
to
eq
(
'foo'
)
expect
(
find
(
".pipeline-variable-row:nth-child(1) .pipeline-variable-value-input"
).
value
).
to
eq
(
'bar'
)
end
end
end
context
'when user removes a variable of a pipeline schedule'
do
background
do
create
(
:ci_pipeline_schedule
,
project:
project
,
owner:
user
).
tap
do
|
pipeline_schedule
|
create
(
:ci_pipeline_schedule_variable
,
key:
'AAA'
,
value:
'AAA123'
,
pipeline_schedule:
pipeline_schedule
)
end
visit_pipelines_schedules
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
find
(
'.pipeline-variable-list .pipeline-variable-row-remove-button'
).
click
click_button
'Save pipeline schedule'
end
scenario
'user does not see the removed variable in edit window'
do
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
page
.
within
(
'.pipeline-variable-list'
)
do
expect
(
find
(
".pipeline-variable-row:nth-child(1) .pipeline-variable-key-input"
).
value
).
to
eq
(
''
)
expect
(
find
(
".pipeline-variable-row:nth-child(1) .pipeline-variable-value-input"
).
value
).
to
eq
(
''
)
end
end
end
def
visit_new_pipeline_schedule
visit
new_project_pipeline_schedule_path
(
project
,
pipeline_schedule
)
end
...
...
spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js
0 → 100644
View file @
0dc2ca3a
import
{
setupPipelineVariableList
,
insertRow
,
removeRow
,
}
from
'
~/pipeline_schedules/setup_pipeline_variable_list
'
;
describe
(
'
Pipeline Variable List
'
,
()
=>
{
let
$markup
;
describe
(
'
insertRow
'
,
()
=>
{
it
(
'
should insert another row
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row">
<input>
<textarea></textarea>
</li>
</div>`
);
insertRow
(
$markup
.
find
(
'
.js-row
'
));
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
});
it
(
'
should clear `data-is-persisted` on cloned row
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row" data-is-persisted="true"></li>
</div>`
);
insertRow
(
$markup
.
find
(
'
.js-row
'
));
const
$lastRow
=
$markup
.
find
(
'
.js-row
'
).
last
();
expect
(
$lastRow
.
attr
(
'
data-is-persisted
'
)).
toBe
(
undefined
);
});
it
(
'
should clear inputs on cloned row
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row">
<input value="foo">
<textarea>bar</textarea>
</li>
</div>`
);
insertRow
(
$markup
.
find
(
'
.js-row
'
));
const
$lastRow
=
$markup
.
find
(
'
.js-row
'
).
last
();
expect
(
$lastRow
.
find
(
'
input
'
).
val
()).
toBe
(
''
);
expect
(
$lastRow
.
find
(
'
textarea
'
).
val
()).
toBe
(
''
);
});
});
describe
(
'
removeRow
'
,
()
=>
{
it
(
'
should remove dynamic row
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row">
<input>
<textarea></textarea>
</li>
</div>`
);
removeRow
(
$markup
.
find
(
'
.js-row
'
));
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
0
);
});
it
(
'
should hide and mark to destroy with already persisted rows
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row" data-is-persisted="true">
<input class="js-destroy-input">
</li>
</div>`
);
const
$row
=
$markup
.
find
(
'
.js-row
'
);
removeRow
(
$row
);
expect
(
$row
.
find
(
'
.js-destroy-input
'
).
val
()).
toBe
(
'
1
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
1
);
});
});
describe
(
'
setupPipelineVariableList
'
,
()
=>
{
beforeEach
(()
=>
{
$markup
=
$
(
`<form>
<li class="js-row">
<input class="js-user-input" name="schedule[variables_attributes][][key]">
<textarea class="js-user-input" name="schedule[variables_attributes][][value]"></textarea>
<button class="js-row-remove-button"></button>
<button class="js-row-add-button"></button>
</li>
</form>`
);
setupPipelineVariableList
(
$markup
);
});
it
(
'
should remove the row when clicking the remove button
'
,
()
=>
{
$markup
.
find
(
'
.js-row-remove-button
'
).
trigger
(
'
click
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
0
);
});
it
(
'
should add another row when editing the last rows key input
'
,
()
=>
{
const
$row
=
$markup
.
find
(
'
.js-row
'
);
$row
.
find
(
'
input.js-user-input
'
)
.
val
(
'
foo
'
)
.
trigger
(
'
input
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
});
it
(
'
should add another row when editing the last rows value textarea
'
,
()
=>
{
const
$row
=
$markup
.
find
(
'
.js-row
'
);
$row
.
find
(
'
textarea.js-user-input
'
)
.
val
(
'
foo
'
)
.
trigger
(
'
input
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
});
it
(
'
should remove empty row after blurring
'
,
()
=>
{
const
$row
=
$markup
.
find
(
'
.js-row
'
);
$row
.
find
(
'
input.js-user-input
'
)
.
val
(
'
foo
'
)
.
trigger
(
'
input
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
$row
.
find
(
'
input.js-user-input
'
)
.
val
(
''
)
.
trigger
(
'
input
'
)
.
trigger
(
'
blur
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
1
);
});
it
(
'
should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)
'
,
()
=>
{
const
$row
=
$markup
.
find
(
'
.js-row
'
);
expect
(
$row
.
find
(
'
input
'
).
attr
(
'
name
'
)).
toBe
(
'
schedule[variables_attributes][][key]
'
);
expect
(
$row
.
find
(
'
textarea
'
).
attr
(
'
name
'
)).
toBe
(
'
schedule[variables_attributes][][value]
'
);
$markup
.
filter
(
'
form
'
).
submit
();
expect
(
$row
.
find
(
'
input
'
).
attr
(
'
name
'
)).
toBe
(
''
);
expect
(
$row
.
find
(
'
textarea
'
).
attr
(
'
name
'
)).
toBe
(
''
);
});
});
});
spec/lib/gitlab/import_export/all_models.yml
View file @
0dc2ca3a
...
...
@@ -141,8 +141,11 @@ pipeline_schedules:
-
owner
-
pipelines
-
last_pipeline
-
variables
pipeline_schedule
:
-
pipelines
pipeline_schedule_variables
:
-
pipeline_schedule
deploy_keys
:
-
user
-
deploy_keys_projects
...
...
spec/models/ci/build_spec.rb
View file @
0dc2ca3a
...
...
@@ -1446,6 +1446,23 @@ describe Ci::Build, :models do
it
{
is_expected
.
to
include
(
predefined_trigger_variable
)
}
end
context
'when a job was triggered by a pipeline schedule'
do
let
(
:pipeline_schedule
)
{
create
(
:ci_pipeline_schedule
,
project:
project
)
}
let!
(
:pipeline_schedule_variable
)
do
create
(
:ci_pipeline_schedule_variable
,
key:
'SCHEDULE_VARIABLE_KEY'
,
pipeline_schedule:
pipeline_schedule
)
end
before
do
pipeline_schedule
.
pipelines
<<
pipeline
pipeline_schedule
.
reload
end
it
{
is_expected
.
to
include
(
pipeline_schedule_variable
.
to_runner_variable
)
}
end
context
'when yaml_variables are undefined'
do
before
do
build
.
yaml_variables
=
nil
...
...
spec/models/ci/pipeline_schedule_spec.rb
View file @
0dc2ca3a
...
...
@@ -5,6 +5,7 @@ describe Ci::PipelineSchedule, models: true do
it
{
is_expected
.
to
belong_to
(
:owner
)
}
it
{
is_expected
.
to
have_many
(
:pipelines
)
}
it
{
is_expected
.
to
have_many
(
:variables
)
}
it
{
is_expected
.
to
respond_to
(
:ref
)
}
it
{
is_expected
.
to
respond_to
(
:cron
)
}
...
...
@@ -117,4 +118,20 @@ describe Ci::PipelineSchedule, models: true do
end
end
end
describe
'#job_variables'
do
let!
(
:pipeline_schedule
)
{
create
(
:ci_pipeline_schedule
)
}
let!
(
:pipeline_schedule_variables
)
do
create_list
(
:ci_pipeline_schedule_variable
,
2
,
pipeline_schedule:
pipeline_schedule
)
end
subject
{
pipeline_schedule
.
job_variables
}
before
do
pipeline_schedule
.
reload
end
it
{
is_expected
.
to
contain_exactly
(
*
pipeline_schedule_variables
.
map
(
&
:to_runner_variable
))
}
end
end
spec/models/ci/pipeline_schedule_variable_spec.rb
0 → 100644
View file @
0dc2ca3a
require
'spec_helper'
describe
Ci
::
PipelineScheduleVariable
,
models:
true
do
subject
{
build
(
:ci_pipeline_schedule_variable
)
}
it
{
is_expected
.
to
include_module
(
HasVariable
)
}
end
spec/requests/api/pipeline_schedules_spec.rb
View file @
0dc2ca3a
...
...
@@ -279,6 +279,8 @@ describe API::PipelineSchedules do
end
context
'authenticated user with invalid permissions'
do
let!
(
:pipeline_schedule
)
{
create
(
:ci_pipeline_schedule
,
project:
project
,
owner:
master
)
}
it
'does not delete pipeline_schedule'
do
delete
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
developer
)
...
...
spec/support/matchers/access_matchers_for_controller.rb
View file @
0dc2ca3a
...
...
@@ -50,9 +50,24 @@ module AccessMatchersForController
"be
#{
type
}
for
#{
role
}
. Expected:
#{
expected
.
join
(
','
)
}
Got:
#{
result
}
"
end
def
update_owner
(
objects
,
user
)
return
unless
objects
objects
.
each
do
|
object
|
if
object
.
respond_to?
(
:owner
)
object
.
update_attribute
(
:owner
,
user
)
elsif
object
.
respond_to?
(
:user
)
object
.
update_attribute
(
:user
,
user
)
else
raise
ArgumentError
,
"cannot own this object
#{
object
}
"
end
end
end
matcher
:be_allowed_for
do
|
role
|
match
do
|
action
|
emulate_user
(
role
,
@membership
)
user
=
emulate_user
(
role
,
@membership
)
update_owner
(
@objects
,
user
)
action
.
call
EXPECTED_STATUS_CODE_ALLOWED
.
include?
(
response
.
status
)
...
...
@@ -62,13 +77,18 @@ module AccessMatchersForController
@membership
=
membership
end
chain
:own
do
|*
objects
|
@objects
=
objects
end
description
{
description_for
(
role
,
'allowed'
,
EXPECTED_STATUS_CODE_ALLOWED
,
response
.
status
)
}
supports_block_expectations
end
matcher
:be_denied_for
do
|
role
|
match
do
|
action
|
emulate_user
(
role
,
@membership
)
user
=
emulate_user
(
role
,
@membership
)
update_owner
(
@objects
,
user
)
action
.
call
EXPECTED_STATUS_CODE_DENIED
.
include?
(
response
.
status
)
...
...
@@ -78,6 +98,10 @@ module AccessMatchersForController
@membership
=
membership
end
chain
:own
do
|*
objects
|
@objects
=
objects
end
description
{
description_for
(
role
,
'denied'
,
EXPECTED_STATUS_CODE_DENIED
,
response
.
status
)
}
supports_block_expectations
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment