Commit aca1e14b authored by Kamil Trzcinski's avatar Kamil Trzcinski

Merge remote-tracking branch 'origin/master' into after-script

parents 39c2677e 5ae4fd21
...@@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.7.0 (unreleased) v 8.7.0 (unreleased)
- Method instrumentation now uses Module#prepend instead of aliasing methods - Method instrumentation now uses Module#prepend instead of aliasing methods
- Repository.clean_old_archives is now instrumented - Repository.clean_old_archives is now instrumented
- Add support for environment variables on a job level in CI configuration file
- The Projects::HousekeepingService class has extra instrumentation - The Projects::HousekeepingService class has extra instrumentation
- All service classes (those residing in app/services) are now instrumented - All service classes (those residing in app/services) are now instrumented
- Developers can now add custom tags to transactions - Developers can now add custom tags to transactions
...@@ -80,6 +81,7 @@ v 8.7.0 (unreleased) ...@@ -80,6 +81,7 @@ v 8.7.0 (unreleased)
- Add encrypted credentials for imported projects and migrate old ones - Add encrypted credentials for imported projects and migrate old ones
- Author and participants are displayed first on users autocompletion - Author and participants are displayed first on users autocompletion
- Show number sign on external issue reference text (Florent Baldino) - Show number sign on external issue reference text (Florent Baldino)
- Updated print style for issues
v 8.6.6 v 8.6.6
- Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413
......
...@@ -4,18 +4,33 @@ class @ImporterStatus ...@@ -4,18 +4,33 @@ class @ImporterStatus
this.setAutoUpdate() this.setAutoUpdate()
initStatusPage: -> initStatusPage: ->
$(".js-add-to-import").click (event) => $('.js-add-to-import')
new_namespace = null .off 'click'
tr = $(event.currentTarget).closest("tr") .on 'click', (e) =>
id = tr.attr("id").replace("repo_", "") new_namespace = null
if tr.find(".import-target input").length > 0 $btn = $(e.currentTarget)
new_namespace = tr.find(".import-target input").prop("value") $tr = $btn.closest('tr')
tr.find(".import-target").empty().append(new_namespace + "/" + tr.find(".import-target").data("project_name")) id = $tr.attr('id').replace('repo_', '')
$.post @import_url, {repo_id: id, new_namespace: new_namespace}, dataType: 'script' if $tr.find('.import-target input').length > 0
new_namespace = $tr.find('.import-target input').prop('value')
$(".js-import-all").click (event) => $tr.find('.import-target').empty().append("#{new_namespace} / #{$tr.find('.import-target').data('project_name')}")
$(".js-add-to-import").each ->
$(this).click() $btn
.disable()
.addClass 'is-loading'
$.post @import_url, {repo_id: id, new_namespace: new_namespace}, dataType: 'script'
$('.js-import-all')
.off 'click'
.on 'click', (e) ->
$btn = $(@)
$btn
.disable()
.addClass 'is-loading'
$('.js-add-to-import').each ->
$(this).trigger('click')
setAutoUpdate: -> setAutoUpdate: ->
setInterval (=> setInterval (=>
......
...@@ -39,8 +39,7 @@ ...@@ -39,8 +39,7 @@
.diff-file { .diff-file {
border: 1px solid $border-color; border: 1px solid $border-color;
border-bottom: none; border-bottom: none;
margin-left: 0; margin: 0;
margin-right: 0;
} }
} }
......
...@@ -16,3 +16,24 @@ i.icon-gitorious-big { ...@@ -16,3 +16,24 @@ i.icon-gitorious-big {
width: 18px; width: 18px;
height: 18px; height: 18px;
} }
.import-jobs-from-col,
.import-jobs-to-col {
width: 40%;
}
.import-jobs-status-col {
width: 20%;
}
.btn-import {
.loading-icon {
display: none;
}
&.is-loading {
.loading-icon {
display: inline-block;
}
}
}
...@@ -198,6 +198,12 @@ ul.notes { ...@@ -198,6 +198,12 @@ ul.notes {
color: $notes-light-color; color: $notes-light-color;
} }
.discussion-headline-light {
a {
color: $gl-link-color;
}
}
/** /**
* Actions for Discussions/Notes * Actions for Discussions/Notes
*/ */
...@@ -209,6 +215,17 @@ ul.notes { ...@@ -209,6 +215,17 @@ ul.notes {
color: $notes-action-color; color: $notes-action-color;
} }
.discussion-actions {
@media (max-width: $screen-sm-max) {
float: none;
margin-left: 0;
.note-action-button {
margin-left: 0;
}
}
}
.note-action-button, .note-action-button,
.discussion-action-button { .discussion-action-button {
display: inline-block; display: inline-block;
......
/* Generic print styles */
header, nav, nav.main-nav, nav.navbar-collapse, nav.navbar-collapse.collapse {display: none!important;}
.profiler-results {display: none;}
/* Styles targeted specifically at printing files */
.tree-ref-holder, .tree-holder .breadcrumb, .blob-commit-info {display: none;}
.file-title {display: none;}
.file-holder {border: none;}
.wiki h1, .wiki h2, .wiki h3, .wiki h4, .wiki h5, .wiki h6 {margin-top: 17px; } .wiki h1, .wiki h2, .wiki h3, .wiki h4, .wiki h5, .wiki h6 {margin-top: 17px; }
.wiki h1 {font-size: 30px;} .wiki h1 {font-size: 30px;}
.wiki h2 {font-size: 22px;} .wiki h2 {font-size: 22px;}
.wiki h3 {font-size: 18px; font-weight: bold; } .wiki h3 {font-size: 18px; font-weight: bold; }
.sidebar-wrapper { display: none; } header,
.nav { display: none; } nav,
.btn { display: none; } nav.main-nav,
nav.navbar-collapse,
nav.navbar-collapse.collapse,
.profiler-results,
.tree-ref-holder,
.tree-holder .breadcrumb,
.blob-commit-info,
.file-title,
.file-holder,
.sidebar-wrapper,
.nav,
.btn,
ul.notes-form,
.merge-request-ci-status .ci-status-link:after,
.issuable-gutter-toggle,
.gutter-toggle,
.issuable-details .content-block-small,
.edit-link,
.note-action-button {
display: none!important;
}
.page-gutter {
padding-top: 0;
padding-left: 0;
}
.right-sidebar {
top: 0;
}
...@@ -365,11 +365,23 @@ module Ci ...@@ -365,11 +365,23 @@ module Ci
self.update(erased_by: user, erased_at: Time.now) self.update(erased_by: user, erased_at: Time.now)
end end
private
def yaml_variables def yaml_variables
global_yaml_variables + job_yaml_variables
end
def global_yaml_variables
if commit.config_processor
commit.config_processor.global_variables.map do |key, value|
{ key: key, value: value, public: true }
end
else
[]
end
end
def job_yaml_variables
if commit.config_processor if commit.config_processor
commit.config_processor.variables.map do |key, value| commit.config_processor.job_variables(name).map do |key, value|
{ key: key, value: value, public: true } { key: key, value: value, public: true }
end end
else else
......
...@@ -20,10 +20,10 @@ ...@@ -20,10 +20,10 @@
job.attr("id", "project_#{@project.id}") job.attr("id", "project_#{@project.id}")
target_field = job.find(".import-target") target_field = job.find(".import-target")
target_field.empty() target_field.empty()
target_field.append('<strong>#{link_to @project.path_with_namespace, namespace_project_path(@project.namespace, @project)}</strong>') target_field.append('#{link_to @project.path_with_namespace, namespace_project_path(@project.namespace, @project)}')
$("table.import-jobs tbody").prepend(job) $("table.import-jobs tbody").prepend(job)
job.addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started") job.addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started")
- else - else
:plain :plain
job = $("tr#repo_#{@repo_id}") job = $("tr#repo_#{@repo_id}")
job.find(".import-actions").html("<i class='fa fa-exclamation-circle'> Error saving project: #{escape_javascript(@project.errors.full_messages.join(','))}</i>") job.find(".import-actions").html("<i class='fa fa-exclamation-circle'></i> Error saving project: #{escape_javascript(@project.errors.full_messages.join(','))}")
...@@ -10,13 +10,19 @@ ...@@ -10,13 +10,19 @@
%hr %hr
%p %p
- if @incompatible_repos.any? - if @incompatible_repos.any?
= button_tag 'Import all compatible projects', class: "btn btn-success js-import-all" = button_tag class: "btn btn-import btn-success js-import-all" do
Import all compatible projects
= icon("spinner spin", class: "loading-icon")
- else - else
= button_tag 'Import all projects', class: "btn btn-success js-import-all" = button_tag class: "btn btn-success js-import-all" do
Import all projects
= icon("spinner spin", class: "loading-icon")
.table-responsive
.table-holder
%table.table.import-jobs %table.table.import-jobs
%colgroup.import-jobs-from-col
%colgroup.import-jobs-to-col
%colgroup.import-jobs-status-col
%thead %thead
%tr %tr
%th From Bitbucket %th From Bitbucket
...@@ -28,7 +34,7 @@ ...@@ -28,7 +34,7 @@
%td %td
= link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: "_blank" = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: "_blank"
%td %td
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span
...@@ -47,7 +53,9 @@ ...@@ -47,7 +53,9 @@
%td.import-target %td.import-target
= "#{repo["owner"]}/#{repo["slug"]}" = "#{repo["owner"]}/#{repo["slug"]}"
%td.import-actions.job-status %td.import-actions.job-status
= button_tag "Import", class: "btn js-add-to-import" = button_tag class: "btn btn-import js-add-to-import" do
Import
= icon("spinner spin", class: "loading-icon")
- @incompatible_repos.each do |repo| - @incompatible_repos.each do |repo|
%tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"} %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
%td %td
......
...@@ -13,10 +13,15 @@ ...@@ -13,10 +13,15 @@
how FogBugz email addresses and usernames are imported into GitLab. how FogBugz email addresses and usernames are imported into GitLab.
%hr %hr
%p %p
= button_tag 'Import all projects', class: 'btn btn-success js-import-all' = button_tag class: 'btn btn-import btn-success js-import-all' do
Import all projects
= icon("spinner spin", class: "loading-icon")
.table-holder .table-responsive
%table.table.import-jobs %table.table.import-jobs
%colgroup.import-jobs-from-col
%colgroup.import-jobs-to-col
%colgroup.import-jobs-status-col
%thead %thead
%tr %tr
%th From FogBugz %th From FogBugz
...@@ -28,7 +33,7 @@ ...@@ -28,7 +33,7 @@
%td %td
= project.import_source = project.import_source
%td %td
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span
...@@ -47,7 +52,9 @@ ...@@ -47,7 +52,9 @@
%td.import-target %td.import-target
= "#{current_user.username}/#{repo.name}" = "#{current_user.username}/#{repo.name}"
%td.import-actions.job-status %td.import-actions.job-status
= button_tag "Import", class: "btn js-add-to-import" = button_tag class: "btn btn-import js-add-to-import" do
Import
= icon("spinner spin", class: "loading-icon")
:javascript :javascript
new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}"); new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}");
...@@ -8,10 +8,15 @@ ...@@ -8,10 +8,15 @@
Select projects you want to import. Select projects you want to import.
%hr %hr
%p %p
= button_tag 'Import all projects', class: "btn btn-success js-import-all" = button_tag class: "btn btn-import btn-success js-import-all" do
Import all projects
= icon("spinner spin", class: "loading-icon")
.table-holder .table-responsive
%table.table.import-jobs %table.table.import-jobs
%colgroup.import-jobs-from-col
%colgroup.import-jobs-to-col
%colgroup.import-jobs-status-col
%thead %thead
%tr %tr
%th From GitHub %th From GitHub
...@@ -23,7 +28,7 @@ ...@@ -23,7 +28,7 @@
%td %td
= link_to project.import_source, "https://github.com/#{project.import_source}", target: "_blank" = link_to project.import_source, "https://github.com/#{project.import_source}", target: "_blank"
%td %td
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span
...@@ -42,7 +47,9 @@ ...@@ -42,7 +47,9 @@
%td.import-target %td.import-target
= repo.full_name = repo.full_name
%td.import-actions.job-status %td.import-actions.job-status
= button_tag "Import", class: "btn js-add-to-import" = button_tag class: "btn btn-import js-add-to-import" do
Import
= icon("spinner spin", class: "loading-icon")
:javascript :javascript
new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}"); new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}");
...@@ -8,10 +8,15 @@ ...@@ -8,10 +8,15 @@
Select projects you want to import. Select projects you want to import.
%hr %hr
%p %p
= button_tag 'Import all projects', class: "btn btn-success js-import-all" = button_tag class: "btn btn-import btn-success js-import-all" do
Import all projects
= icon("spinner spin", class: "loading-icon")
.table-holder .table-responsive
%table.table.import-jobs %table.table.import-jobs
%colgroup.import-jobs-from-col
%colgroup.import-jobs-to-col
%colgroup.import-jobs-status-col
%thead %thead
%tr %tr
%th From GitLab.com %th From GitLab.com
...@@ -23,7 +28,7 @@ ...@@ -23,7 +28,7 @@
%td %td
= link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank" = link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
%td %td
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span
...@@ -42,7 +47,9 @@ ...@@ -42,7 +47,9 @@
%td.import-target %td.import-target
= repo["path_with_namespace"] = repo["path_with_namespace"]
%td.import-actions.job-status %td.import-actions.job-status
= button_tag "Import", class: "btn js-add-to-import" = button_tag class: "btn js-add-to-import" do
Import
= icon("spinner spin", class: "loading-icon")
:javascript :javascript
new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}"); new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}");
...@@ -8,10 +8,15 @@ ...@@ -8,10 +8,15 @@
Select projects you want to import. Select projects you want to import.
%hr %hr
%p %p
= button_tag 'Import all projects', class: "btn btn-success js-import-all" = button_tag class: "btn btn-import btn-success js-import-all" do
Import all projects
= icon("spinner spin", class: "loading-icon")
.table-holder .table-responsive
%table.table.import-jobs %table.table.import-jobs
%colgroup.import-jobs-from-col
%colgroup.import-jobs-to-col
%colgroup.import-jobs-status-col
%thead %thead
%tr %tr
%th From Gitorious.org %th From Gitorious.org
...@@ -23,7 +28,7 @@ ...@@ -23,7 +28,7 @@
%td %td
= link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank" = link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank"
%td %td
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span
...@@ -42,7 +47,9 @@ ...@@ -42,7 +47,9 @@
%td.import-target %td.import-target
= repo.full_name = repo.full_name
%td.import-actions.job-status %td.import-actions.job-status
= button_tag "Import", class: "btn js-add-to-import" = button_tag class: "btn btn-import js-add-to-import" do
Import
= icon("spinner spin", class: "loading-icon")
:javascript :javascript
new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}"); new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}");
...@@ -14,12 +14,19 @@ ...@@ -14,12 +14,19 @@
%hr %hr
%p %p
- if @incompatible_repos.any? - if @incompatible_repos.any?
= button_tag 'Import all compatible projects', class: "btn btn-success js-import-all" = button_tag class: "btn btn-import btn-success js-import-all" do
Import all compatible projects
= icon("spinner spin", class: "loading-icon")
- else - else
= button_tag 'Import all projects', class: "btn btn-success js-import-all" = button_tag class: "btn btn-import btn-success js-import-all" do
Import all projects
= icon("spinner spin", class: "loading-icon")
.table-holder .table-responsive
%table.table.import-jobs %table.table.import-jobs
%colgroup.import-jobs-from-col
%colgroup.import-jobs-to-col
%colgroup.import-jobs-status-col
%thead %thead
%tr %tr
%th From Google Code %th From Google Code
...@@ -31,7 +38,7 @@ ...@@ -31,7 +38,7 @@
%td %td
= link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank" = link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank"
%td %td
%strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span
...@@ -50,7 +57,9 @@ ...@@ -50,7 +57,9 @@
%td.import-target %td.import-target
= "#{current_user.username}/#{repo.name}" = "#{current_user.username}/#{repo.name}"
%td.import-actions.job-status %td.import-actions.job-status
= button_tag "Import", class: "btn js-add-to-import" = button_tag class: "btn btn-import js-add-to-import" do
Import
= icon("spinner spin", class: "loading-icon")
- @incompatible_repos.each do |repo| - @incompatible_repos.each do |repo|
%tr{id: "repo_#{repo.id}"} %tr{id: "repo_#{repo.id}"}
%td %td
......
$('aside.right-sidebar')[0].outerHTML = "#{escape_javascript(render 'shared/issuable/sidebar', issuable: @issue)}";
$('aside.right-sidebar').effect('highlight');
new IssuableContext();
$('aside.right-sidebar')[0].outerHTML = "#{escape_javascript(render 'shared/issuable/sidebar', issuable: @merge_request)}";
$('aside.right-sidebar').effect('highlight');
new IssuableContext();
- note = discussion_notes.first - note = discussion_notes.first
.timeline-entry %li.note.note-discussion.timeline-entry
.timeline-entry-inner .timeline-entry-inner
.timeline-icon .timeline-icon
= link_to user_path(note.author) do = link_to user_path(note.author) do
......
%ul#notes-list.notes.main-notes-list.timeline %ul#notes-list.notes.main-notes-list.timeline
= render "projects/notes/notes" = render "projects/notes/notes"
%ul.notes.timeline %ul.notes.notes-form.timeline
%li.timeline-entry %li.timeline-entry
- if can? current_user, :create_note, @project - if can? current_user, :create_note, @project
.timeline-icon.hidden-xs.hidden-sm .timeline-icon.hidden-xs.hidden-sm
......
...@@ -6,15 +6,11 @@ ...@@ -6,15 +6,11 @@
= "#{note.author.to_reference} started a discussion" = "#{note.author.to_reference} started a discussion"
= link_to diffs_namespace_project_merge_request_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code) do = link_to diffs_namespace_project_merge_request_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code) do
on the diff on the diff
= time_ago_with_tooltip(note.created_at, placement: "bottom", html_class: "discussion_updated_ago")
.discussion-actions .discussion-actions
= link_to "#", class: "discussion-action-button discussion-toggle-button js-toggle-button" do = link_to "#", class: "discussion-action-button discussion-toggle-button js-toggle-button" do
%i.fa.fa-chevron-up %i.fa.fa-chevron-up
Show/hide discussion Show/hide discussion
.last-update.hide.js-toggle-content
- last_note = discussion_notes.last
last updated by
= link_to_member(@project, last_note.author, avatar: false)
#{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')}
.discussion-body.js-toggle-content .discussion-body.js-toggle-content
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
...@@ -8,21 +8,18 @@ ...@@ -8,21 +8,18 @@
= "#{note.author.to_reference} started a discussion on #{commit_description}" = "#{note.author.to_reference} started a discussion on #{commit_description}"
- if commit - if commit
= link_to(commit.short_id, namespace_project_commit_path(note.project.namespace, note.project, note.noteable), class: 'monospace') = link_to(commit.short_id, namespace_project_commit_path(note.project.namespace, note.project, note.noteable), class: 'monospace')
= time_ago_with_tooltip(note.created_at, placement: "bottom", html_class: "discussion_updated_ago")
.discussion-actions .discussion-actions
= link_to "#", class: "note-action-button discussion-toggle-button js-toggle-button" do = link_to "#", class: "note-action-button discussion-toggle-button js-toggle-button" do
%i.fa.fa-chevron-up %i.fa.fa-chevron-up
Show/hide discussion Show/hide discussion
.last-update.hide.js-toggle-content
- last_note = discussion_notes.last
last updated by
= link_to_member(@project, last_note.author, avatar: false)
#{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')}
.discussion-body.js-toggle-content .discussion-body.js-toggle-content
- if note.for_diff_line? - if note.for_diff_line?
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
- else - else
.panel.panel-default .panel.panel-default
.notes{ data: { discussion_id: discussion_notes.first.discussion_id } } .notes{ data: { discussion_id: discussion_notes.first.discussion_id } }
= render discussion_notes %ul.notes.timeline
= render discussion_notes
.discussion-reply-holder .discussion-reply-holder
= link_to_reply_diff(discussion_notes.first) = link_to_reply_diff(discussion_notes.first)
...@@ -5,14 +5,10 @@ ...@@ -5,14 +5,10 @@
.inline.discussion-headline-light .inline.discussion-headline-light
= "#{note.author.to_reference} started a discussion" = "#{note.author.to_reference} started a discussion"
on the outdated diff on the outdated diff
= time_ago_with_tooltip(note.created_at, placement: "bottom", html_class: "discussion_updated_ago")
.discussion-actions .discussion-actions
= link_to "#", class: "note-action-button discussion-toggle-button js-toggle-button" do = link_to "#", class: "note-action-button discussion-toggle-button js-toggle-button" do
%i.fa.fa-chevron-down %i.fa.fa-chevron-down
Show/hide discussion Show/hide discussion
.last-update.hide.js-toggle-content
- last_note = discussion_notes.last
last updated by
= link_to_member(@project, last_note.author, avatar: false)
#{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')}
.discussion-body.js-toggle-content.hide .discussion-body.js-toggle-content.hide
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
## Variables ## Variables
When receiving a build from GitLab CI, the runner prepares the build environment. When receiving a build from GitLab CI, the runner prepares the build environment.
It starts by setting a list of **predefined variables** (Environment Variables) and a list of **user-defined variables** It starts by setting a list of **predefined variables** (Environment Variables) and a list of **user-defined variables**
The variables can be overwritten. They take precedence over each other in this order: The variables can be overwritten. They take precedence over each other in this order:
1. Trigger variables
1. Secure variables 1. Secure variables
1. YAML-defined variables 1. YAML-defined job-level variables
1. YAML-defined global variables
1. Predefined variables 1. Predefined variables
For example, if you define: For example, if you define:
1. API_TOKEN=SECURE as Secure Variable 1. `API_TOKEN=SECURE` as Secure Variable
1. API_TOKEN=YAML as YAML-defined variable 1. `API_TOKEN=YAML` as YAML-defined variable
The API_TOKEN will take the Secure Variable value: `SECURE`. The `API_TOKEN` will take the Secure Variable value: `SECURE`.
### Predefined variables (Environment Variables) ### Predefined variables (Environment Variables)
...@@ -70,15 +73,20 @@ These variables can be later used in all executed commands and scripts. ...@@ -70,15 +73,20 @@ These variables can be later used in all executed commands and scripts.
The YAML-defined variables are also set to all created service containers, thus allowing to fine tune them. The YAML-defined variables are also set to all created service containers, thus allowing to fine tune them.
Variables can be defined at a global level, but also at a job level.
More information about Docker integration can be found in [Using Docker Images](../docker/using_docker_images.md). More information about Docker integration can be found in [Using Docker Images](../docker/using_docker_images.md).
### User-defined variables (Secure Variables) ### User-defined variables (Secure Variables)
**This feature requires GitLab Runner 0.4.0 or higher** **This feature requires GitLab Runner 0.4.0 or higher**
GitLab CI allows you to define per-project **Secure Variables** that are set in build environment. GitLab CI allows you to define per-project **Secure Variables** that are set in
the build environment.
The secure variables are stored out of the repository (the `.gitlab-ci.yml`). The secure variables are stored out of the repository (the `.gitlab-ci.yml`).
The variables are securely passed to GitLab Runner and are available in build environment. The variables are securely passed to GitLab Runner and are available in the
It's desired method to use them for storing passwords, secret keys or whatever you want. build environment.
It's desired method to use them for storing passwords, secret keys or whatever
you want.
**The value of the variable can be shown in build log if explicitly asked to do so.** **The value of the variable can be shown in build log if explicitly asked to do so.**
If your project is public or internal you can make the builds private. If your project is public or internal you can make the builds private.
......
...@@ -24,6 +24,7 @@ If you want a quick introduction to GitLab CI, follow our ...@@ -24,6 +24,7 @@ If you want a quick introduction to GitLab CI, follow our
- [Jobs](#jobs) - [Jobs](#jobs)
- [script](#script) - [script](#script)
- [stage](#stage) - [stage](#stage)
- [job variables](#job-variables)
- [only and except](#only-and-except) - [only and except](#only-and-except)
- [tags](#tags) - [tags](#tags)
- [when](#when) - [when](#when)
...@@ -187,6 +188,8 @@ These variables can be later used in all executed commands and scripts. ...@@ -187,6 +188,8 @@ These variables can be later used in all executed commands and scripts.
The YAML-defined variables are also set to all created service containers, The YAML-defined variables are also set to all created service containers,
thus allowing to fine tune them. thus allowing to fine tune them.
Variables can be also defined on [job level](#job-variables).
### cache ### cache
>**Note:** >**Note:**
...@@ -337,6 +340,7 @@ job_name: ...@@ -337,6 +340,7 @@ job_name:
| services | no | Use docker services, covered in [Using Docker Images](../docker/using_docker_images.md#define-image-and-services-from-gitlab-ciyml) | | services | no | Use docker services, covered in [Using Docker Images](../docker/using_docker_images.md#define-image-and-services-from-gitlab-ciyml) |
| stage | no | Defines a build stage (default: `test`) | | stage | no | Defines a build stage (default: `test`) |
| type | no | Alias for `stage` | | type | no | Alias for `stage` |
| variables | no | Define build variables on a job level |
| only | no | Defines a list of git refs for which build is created | | only | no | Defines a list of git refs for which build is created |
| except | no | Defines a list of git refs for which build is not created | | except | no | Defines a list of git refs for which build is not created |
| tags | no | Defines a list of tags which are used to select Runner | | tags | no | Defines a list of tags which are used to select Runner |
...@@ -427,6 +431,18 @@ job: ...@@ -427,6 +431,18 @@ job:
The above example will run `job` for all branches on `gitlab-org/gitlab-ce`, The above example will run `job` for all branches on `gitlab-org/gitlab-ce`,
except master. except master.
### job variables
It is possible to define build variables using a `variables` keyword on a job
level. It works basically the same way as its global-level equivalent but
allows you to define job-specific build variables.
When the `variables` keyword is used on a job level, it overrides global YAML
build variables and predefined variables.
Build variables priority is defined in
[variables documentation](../variables/README.md).
### tags ### tags
`tags` is used to select specific Runners from the list of all Runners that are `tags` is used to select specific Runners from the list of all Runners that are
......
...@@ -7,9 +7,9 @@ module Ci ...@@ -7,9 +7,9 @@ module Ci
ALLOWED_YAML_KEYS = [:before_script, :after_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] :dependencies, :variables]
attr_reader :before_script, :after_script, :image, :services, :variables, :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)
...@@ -40,6 +40,17 @@ module Ci ...@@ -40,6 +40,17 @@ module Ci
@stages || DEFAULT_STAGES @stages || DEFAULT_STAGES
end end
def global_variables
@variables
end
def job_variables(name)
job = @jobs[name.to_sym]
return [] unless job
job.fetch(:variables, [])
end
private private
def initial_parsing def initial_parsing
...@@ -144,7 +155,7 @@ module Ci ...@@ -144,7 +155,7 @@ module Ci
end end
unless @variables.nil? || validate_variables(@variables) unless @variables.nil? || validate_variables(@variables)
raise ValidationError, "variables should be a map of key-valued strings" raise ValidationError, "variables should be a map of key-value strings"
end end
validate_global_cache! if @cache validate_global_cache! if @cache
...@@ -159,9 +170,25 @@ module Ci ...@@ -159,9 +170,25 @@ module Ci
raise ValidationError, "cache:untracked parameter should be an boolean" raise ValidationError, "cache:untracked parameter should be an boolean"
end end
<<<<<<< HEAD
if @cache[:paths] && !validate_array_of_strings(@cache[:paths]) if @cache[:paths] && !validate_array_of_strings(@cache[:paths])
raise ValidationError, "cache:paths parameter should be an array of strings" raise ValidationError, "cache:paths parameter should be an array of strings"
end end
=======
true
end
def validate_job!(name, job)
validate_job_name!(name)
validate_job_keys!(name, job)
validate_job_types!(name, job)
validate_job_stage!(name, job) if job[:stage]
validate_job_variables!(name, job) if job[:variables]
validate_job_cache!(name, job) if job[:cache]
validate_job_artifacts!(name, job) if job[:artifacts]
validate_job_dependencies!(name, job) if job[:dependencies]
>>>>>>> origin/master
end end
def validate_job_name!(name) def validate_job_name!(name)
...@@ -218,6 +245,13 @@ module Ci ...@@ -218,6 +245,13 @@ module Ci
end end
end end
def validate_job_variables!(name, job)
unless validate_variables(job[:variables])
raise ValidationError,
"#{name} job: variables should be a map of key-value strings"
end
end
def validate_job_cache!(name, job) def validate_job_cache!(name, job)
if job[:cache][:key] && !validate_string(job[:cache][:key]) if job[:cache][:key] && !validate_string(job[:cache][:key])
raise ValidationError, "#{name} job: cache:key parameter should be a string" raise ValidationError, "#{name} job: cache:key parameter should be a string"
......
...@@ -367,20 +367,76 @@ module Ci ...@@ -367,20 +367,76 @@ module Ci
end end
end end
describe "Variables" do describe 'Variables' do
it "returns variables when defined" do context 'when global variables are defined' do
variables = { it 'returns global variables' do
var1: "value1", variables = {
var2: "value2", VAR1: 'value1',
} VAR2: 'value2',
config = YAML.dump({ }
variables: variables,
before_script: ["pwd"],
rspec: { script: "rspec" }
})
config_processor = GitlabCiYamlProcessor.new(config, path) config = YAML.dump({
expect(config_processor.variables).to eq(variables) variables: variables,
before_script: ['pwd'],
rspec: { script: 'rspec' }
})
config_processor = GitlabCiYamlProcessor.new(config, path)
expect(config_processor.global_variables).to eq(variables)
end
end
context 'when job variables are defined' do
context 'when syntax is correct' do
it 'returns job variables' do
variables = {
KEY1: 'value1',
SOME_KEY_2: 'value2'
}
config = YAML.dump(
{ before_script: ['pwd'],
rspec: {
variables: variables,
script: 'rspec' }
})
config_processor = GitlabCiYamlProcessor.new(config, path)
expect(config_processor.job_variables(:rspec)).to eq variables
end
end
context 'when syntax is incorrect' do
it 'raises error' do
variables = [:KEY1, 'value1', :KEY2, 'value2']
config = YAML.dump(
{ before_script: ['pwd'],
rspec: {
variables: variables,
script: 'rspec' }
})
expect { GitlabCiYamlProcessor.new(config, path) }
.to raise_error(GitlabCiYamlProcessor::ValidationError,
/job: variables should be a map/)
end
end
end
context 'when job variables are not defined' do
it 'returns empty array' do
config = YAML.dump({
before_script: ['pwd'],
rspec: { script: 'rspec' }
})
config_processor = GitlabCiYamlProcessor.new(config, path)
expect(config_processor.job_variables(:rspec)).to eq []
end
end end
end end
...@@ -759,14 +815,14 @@ EOT ...@@ -759,14 +815,14 @@ EOT
config = YAML.dump({ variables: "test", rspec: { script: "test" } }) config = YAML.dump({ variables: "test", rspec: { script: "test" } })
expect do expect do
GitlabCiYamlProcessor.new(config, path) GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-value strings")
end end
it "returns errors if variables is not a map of key-valued strings" do it "returns errors if variables is not a map of key-value strings" do
config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } }) config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } })
expect do expect do
GitlabCiYamlProcessor.new(config, path) GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-value strings")
end end
it "returns errors if job when is not on_success, on_failure or always" do it "returns errors if job when is not on_success, on_failure or always" do
......
...@@ -238,6 +238,22 @@ describe Ci::Build, models: true do ...@@ -238,6 +238,22 @@ describe Ci::Build, models: true do
it { is_expected.to eq(predefined_variables + predefined_trigger_variable + yaml_variables + secure_variables + trigger_variables) } it { is_expected.to eq(predefined_variables + predefined_trigger_variable + yaml_variables + secure_variables + trigger_variables) }
end end
context 'when job variables are defined' do
##
# Job-level variables are defined in gitlab_ci.yml fixture
#
context 'when job variables are unique' do
let(:build) { create(:ci_build, name: 'staging') }
it 'includes job variables' do
expect(subject).to include(
{ key: :KEY1, value: 'value1', public: true },
{ key: :KEY2, value: 'value2', public: true }
)
end
end
end
end end
end end
end end
......
...@@ -4,7 +4,7 @@ services: ...@@ -4,7 +4,7 @@ services:
before_script: before_script:
- gem install bundler - gem install bundler
- bundle install - bundle install
- bundle exec rake db:create - bundle exec rake db:create
variables: variables:
...@@ -17,7 +17,7 @@ types: ...@@ -17,7 +17,7 @@ types:
rspec: rspec:
script: "rake spec" script: "rake spec"
tags: tags:
- ruby - ruby
- postgres - postgres
only: only:
...@@ -26,27 +26,32 @@ rspec: ...@@ -26,27 +26,32 @@ rspec:
spinach: spinach:
script: "rake spinach" script: "rake spinach"
allow_failure: true allow_failure: true
tags: tags:
- ruby - ruby
- mysql - mysql
except: except:
- tags - tags
staging: staging:
variables:
KEY1: value1
KEY2: value2
script: "cap deploy stating" script: "cap deploy stating"
type: deploy type: deploy
tags: tags:
- ruby - ruby
- mysql - mysql
except: except:
- stable - stable
production: production:
variables:
DB_NAME: mysql
type: deploy type: deploy
script: script:
- cap deploy production - cap deploy production
- cap notify - cap notify
tags: tags:
- ruby - ruby
- mysql - mysql
only: only:
......
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