summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Vosmaer <contact@jacobvosmaer.nl>2015-12-15 16:24:14 +0100
committerJacob Vosmaer <contact@jacobvosmaer.nl>2015-12-15 16:24:14 +0100
commitd27befe64dd0d55bec2472ef641c4733cc669215 (patch)
tree623db3d658408b42d8b25e923eb9ccf68016d9fa
parent447e598ec4ee0d2fae29303d4359ffe6a06d3ba5 (diff)
parent4493d3fd556af6ded47f940f258b0fc26c9eb3e8 (diff)
downloadgitlab-ce-d27befe64dd0d55bec2472ef641c4733cc669215.tar.gz
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into workhorse-passthrough
-rw-r--r--.gitlab-ci.yml3
-rw-r--r--CHANGELOG10
-rw-r--r--CONTRIBUTING.md372
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock2
-rw-r--r--PROCESS.md16
-rw-r--r--README.md2
-rw-r--r--app/assets/javascripts/issuable_context.js.coffee12
-rw-r--r--app/assets/javascripts/notes.js.coffee24
-rw-r--r--app/assets/stylesheets/framework/common.scss6
-rw-r--r--app/assets/stylesheets/framework/selects.scss2
-rw-r--r--app/assets/stylesheets/pages/awards.scss86
-rw-r--r--app/assets/stylesheets/pages/issuable.scss158
-rw-r--r--app/assets/stylesheets/pages/issues.scss20
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss4
-rw-r--r--app/controllers/admin/application_settings_controller.rb6
-rw-r--r--app/controllers/admin/builds_controller.rb23
-rw-r--r--app/controllers/admin/runner_projects_controller.rb35
-rw-r--r--app/controllers/admin/runners_controller.rb63
-rw-r--r--app/controllers/ci/admin/application_controller.rb10
-rw-r--r--app/controllers/ci/admin/application_settings_controller.rb31
-rw-r--r--app/controllers/ci/admin/builds_controller.rb18
-rw-r--r--app/controllers/ci/admin/events_controller.rb9
-rw-r--r--app/controllers/ci/admin/projects_controller.rb19
-rw-r--r--app/controllers/ci/admin/runner_projects_controller.rb34
-rw-r--r--app/controllers/ci/admin/runners_controller.rb73
-rw-r--r--app/controllers/ci/application_controller.rb18
-rw-r--r--app/controllers/ci/lints_controller.rb2
-rw-r--r--app/controllers/ci/projects_controller.rb11
-rw-r--r--app/controllers/ci/runner_projects_controller.rb34
-rw-r--r--app/controllers/projects/application_controller.rb4
-rw-r--r--app/controllers/projects/builds_controller.rb11
-rw-r--r--app/controllers/projects/ci_services_controller.rb49
-rw-r--r--app/controllers/projects/ci_settings_controller.rb36
-rw-r--r--app/controllers/projects/ci_web_hooks_controller.rb45
-rw-r--r--app/controllers/projects/commit_controller.rb1
-rw-r--r--app/controllers/projects/graphs_controller.rb10
-rw-r--r--app/controllers/projects/hooks_controller.rb3
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb5
-rw-r--r--app/controllers/projects/notes_controller.rb3
-rw-r--r--app/controllers/projects/runner_projects_controller.rb26
-rw-r--r--app/controllers/projects/runners_controller.rb15
-rw-r--r--app/controllers/projects/services_controller.rb4
-rw-r--r--app/controllers/projects/triggers_controller.rb9
-rw-r--r--app/controllers/projects/variables_controller.rb5
-rw-r--r--app/controllers/projects_controller.rb4
-rw-r--r--app/helpers/ci/gitlab_helper.rb17
-rw-r--r--app/helpers/ci/projects_helper.rb36
-rw-r--r--app/helpers/ci_badge_helper.rb13
-rw-r--r--app/helpers/ci_status_helper.rb11
-rw-r--r--app/helpers/graph_helper.rb10
-rw-r--r--app/helpers/runners_helper.rb2
-rw-r--r--app/helpers/triggers_helper.rb4
-rw-r--r--app/mailers/ci/emails/builds.rb17
-rw-r--r--app/mailers/ci/notify.rb46
-rw-r--r--app/mailers/emails/builds.rb15
-rw-r--r--app/mailers/notify.rb1
-rw-r--r--app/models/application_setting.rb7
-rw-r--r--app/models/ci/application_setting.rb38
-rw-r--r--app/models/ci/build.rb67
-rw-r--r--app/models/ci/commit.rb38
-rw-r--r--app/models/ci/event.rb27
-rw-r--r--app/models/ci/project.rb192
-rw-r--r--app/models/ci/project_status.rb31
-rw-r--r--app/models/ci/runner.rb6
-rw-r--r--app/models/ci/runner_project.rb4
-rw-r--r--app/models/ci/service.rb105
-rw-r--r--app/models/ci/trigger.rb2
-rw-r--r--app/models/ci/variable.rb4
-rw-r--r--app/models/ci/web_hook.rb43
-rw-r--r--app/models/commit_status.rb6
-rw-r--r--app/models/concerns/token_authenticatable.rb44
-rw-r--r--app/models/hooks/project_hook.rb1
-rw-r--r--app/models/hooks/web_hook.rb1
-rw-r--r--app/models/issue.rb8
-rw-r--r--app/models/project.rb77
-rw-r--r--app/models/project_services/builds_email_service.rb90
-rw-r--r--app/models/project_services/ci/hip_chat_message.rb73
-rw-r--r--app/models/project_services/ci/hip_chat_service.rb93
-rw-r--r--app/models/project_services/ci/mail_service.rb84
-rw-r--r--app/models/project_services/ci/slack_message.rb92
-rw-r--r--app/models/project_services/ci/slack_service.rb81
-rw-r--r--app/models/project_services/gitlab_ci_service.rb73
-rw-r--r--app/models/project_services/hipchat_service.rb49
-rw-r--r--app/models/project_services/slack_service.rb29
-rw-r--r--app/models/project_services/slack_service/base_message.rb3
-rw-r--r--app/models/project_services/slack_service/build_message.rb82
-rw-r--r--app/models/service.rb21
-rw-r--r--app/models/user.rb11
-rw-r--r--app/services/ci/create_builds_service.rb6
-rw-r--r--app/services/ci/create_commit_service.rb28
-rw-r--r--app/services/ci/create_trigger_request_service.rb6
-rw-r--r--app/services/ci/event_service.rb31
-rw-r--r--app/services/ci/image_for_build_service.rb4
-rw-r--r--app/services/ci/register_build_service.rb9
-rw-r--r--app/services/ci/test_hook_service.rb7
-rw-r--r--app/services/create_commit_builds_service.rb28
-rw-r--r--app/services/git_push_service.rb1
-rw-r--r--app/services/git_tag_push_service.rb1
-rw-r--r--app/services/projects/fork_service.rb15
-rw-r--r--app/views/admin/builds/_build.html.haml73
-rw-r--r--app/views/admin/builds/index.html.haml50
-rw-r--r--app/views/admin/runners/_runner.html.haml (renamed from app/views/ci/admin/runners/_runner.html.haml)12
-rw-r--r--app/views/admin/runners/index.html.haml (renamed from app/views/ci/admin/runners/index.html.haml)22
-rw-r--r--app/views/admin/runners/show.html.haml (renamed from app/views/ci/admin/runners/show.html.haml)39
-rw-r--r--app/views/admin/runners/update.js.haml (renamed from app/views/ci/admin/runners/update.js.haml)0
-rw-r--r--app/views/ci/admin/application_settings/_form.html.haml24
-rw-r--r--app/views/ci/admin/application_settings/show.html.haml3
-rw-r--r--app/views/ci/admin/builds/_build.html.haml34
-rw-r--r--app/views/ci/admin/builds/index.html.haml28
-rw-r--r--app/views/ci/admin/events/index.html.haml18
-rw-r--r--app/views/ci/admin/projects/_project.html.haml29
-rw-r--r--app/views/ci/admin/projects/index.html.haml16
-rw-r--r--app/views/ci/admin/runner_projects/index.html.haml57
-rw-r--r--app/views/ci/commits/_commit.html.haml5
-rw-r--r--app/views/ci/shared/_guide.html.haml8
-rw-r--r--app/views/ci/user_sessions/new.html.haml7
-rw-r--r--app/views/layouts/ci/_nav_admin.html.haml35
-rw-r--r--app/views/layouts/ci/_nav_project.html.haml12
-rw-r--r--app/views/layouts/ci/admin.html.haml11
-rw-r--r--app/views/layouts/ci/application.html.haml11
-rw-r--r--app/views/layouts/nav/_admin.html.haml15
-rw-r--r--app/views/layouts/nav/_project.html.haml2
-rw-r--r--app/views/layouts/nav/_project_settings.html.haml15
-rw-r--r--app/views/notify/_note_message.html.haml2
-rw-r--r--app/views/notify/build_fail_email.html.haml (renamed from app/views/ci/notify/build_fail_email.html.haml)6
-rw-r--r--app/views/notify/build_fail_email.text.erb (renamed from app/views/ci/notify/build_fail_email.text.erb)2
-rw-r--r--app/views/notify/build_success_email.html.haml (renamed from app/views/ci/notify/build_success_email.html.haml)6
-rw-r--r--app/views/notify/build_success_email.text.erb (renamed from app/views/ci/notify/build_success_email.text.erb)2
-rw-r--r--app/views/projects/blob/_editor.html.haml3
-rw-r--r--app/views/projects/builds/index.html.haml4
-rw-r--r--app/views/projects/builds/show.html.haml4
-rw-r--r--app/views/projects/ci_services/_form.html.haml54
-rw-r--r--app/views/projects/ci_services/edit.html.haml2
-rw-r--r--app/views/projects/ci_services/index.html.haml23
-rw-r--r--app/views/projects/ci_settings/_form.html.haml120
-rw-r--r--app/views/projects/ci_settings/_no_runners.html.haml8
-rw-r--r--app/views/projects/ci_settings/edit.html.haml6
-rw-r--r--app/views/projects/ci_web_hooks/index.html.haml94
-rw-r--r--app/views/projects/commit/_builds.html.haml19
-rw-r--r--app/views/projects/commit/_commit_box.html.haml2
-rw-r--r--app/views/projects/commit_statuses/_commit_status.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml4
-rw-r--r--app/views/projects/edit.html.haml56
-rw-r--r--app/views/projects/graphs/ci/_overall.haml11
-rw-r--r--app/views/projects/hooks/index.html.haml9
-rw-r--r--app/views/projects/issues/_discussion.html.haml22
-rw-r--r--app/views/projects/issues/_merge_requests.html.haml25
-rw-r--r--app/views/projects/issues/show.html.haml45
-rw-r--r--app/views/projects/issues/update.js.haml4
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml23
-rw-r--r--app/views/projects/merge_requests/_show.html.haml126
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml4
-rw-r--r--app/views/projects/merge_requests/update.js.haml4
-rw-r--r--app/views/projects/merge_requests/widget/_merged.html.haml2
-rw-r--r--app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml2
-rw-r--r--app/views/projects/notes/_notes_with_form.html.haml2
-rw-r--r--app/views/projects/runners/_runner.html.haml6
-rw-r--r--app/views/projects/runners/_shared_runners.html.haml10
-rw-r--r--app/views/projects/runners/_specific_runners.html.haml2
-rw-r--r--app/views/projects/triggers/index.html.haml8
-rw-r--r--app/views/projects/variables/show.html.haml6
-rw-r--r--app/views/shared/_service_settings.html.haml9
-rw-r--r--app/views/shared/issuable/_context.html.haml57
-rw-r--r--app/views/shared/issuable/_participants.html.haml8
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml83
-rw-r--r--app/workers/build_email_worker.rb19
-rw-r--r--app/workers/ci/hip_chat_notifier_worker.rb19
-rw-r--r--app/workers/ci/slack_notifier_worker.rb10
-rw-r--r--app/workers/ci/web_hook_worker.rb9
-rw-r--r--config/initializers/4_ci_app.rb2
-rw-r--r--config/routes.rb67
-rw-r--r--db/migrate/20151203162134_add_build_events_to_services.rb6
-rw-r--r--db/migrate/20151209144329_migrate_ci_web_hooks.rb13
-rw-r--r--db/migrate/20151209145909_migrate_ci_emails.rb45
-rw-r--r--db/migrate/20151210072243_add_runners_registration_token_to_application_settings.rb5
-rw-r--r--db/migrate/20151210125232_migrate_ci_slack_service.rb33
-rw-r--r--db/migrate/20151210125927_migrate_ci_hip_chat_service.rb34
-rw-r--r--db/migrate/20151210125928_add_ci_to_project.rb11
-rw-r--r--db/migrate/20151210125929_add_project_id_to_ci.rb8
-rw-r--r--db/migrate/20151210125930_migrate_ci_to_project.rb37
-rw-r--r--db/migrate/20151210125931_add_index_to_ci_tables.rb12
-rw-r--r--db/migrate/20151210125932_drop_null_for_ci_tables.rb9
-rw-r--r--db/schema.rb38
-rw-r--r--doc/api/projects.md3
-rw-r--r--doc/ci/yaml/README.md3
-rw-r--r--doc/install/installation.md69
-rw-r--r--doc/integration/saml.md5
-rw-r--r--doc/update/8.1-to-8.2.md2
-rw-r--r--doc/update/8.2-to-8.3.md184
-rw-r--r--features/project/commits/commits.feature3
-rw-r--r--features/project/issues/issues.feature6
-rw-r--r--features/project/merge_requests.feature10
-rw-r--r--features/project/service.feature6
-rw-r--r--features/project/source/browse_files.feature11
-rw-r--r--features/steps/admin/settings.rb2
-rw-r--r--features/steps/project/commits/commits.rb6
-rw-r--r--features/steps/project/issues/issues.rb10
-rw-r--r--features/steps/project/merge_requests.rb21
-rw-r--r--features/steps/project/services.rb10
-rw-r--r--features/steps/project/source/browse_files.rb8
-rw-r--r--features/steps/shared/project.rb2
-rw-r--r--features/support/capybara.rb2
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/commit_statuses.rb2
-rw-r--r--lib/api/entities.rb10
-rw-r--r--lib/api/helpers.rb7
-rw-r--r--lib/api/project_hooks.rb2
-rw-r--r--lib/api/projects.rb6
-rw-r--r--lib/api/triggers.rb48
-rw-r--r--lib/ci/api/api.rb2
-rw-r--r--lib/ci/api/commits.rb66
-rw-r--r--lib/ci/api/entities.rb9
-rw-r--r--lib/ci/api/helpers.rb10
-rw-r--r--lib/ci/api/projects.rb195
-rw-r--r--lib/ci/api/runners.rb15
-rw-r--r--lib/ci/api/triggers.rb2
-rw-r--r--lib/ci/charts.rb2
-rw-r--r--lib/ci/current_settings.rb22
-rw-r--r--lib/ci/git.rb5
-rw-r--r--lib/ci/scheduler.rb16
-rw-r--r--lib/gitlab/backend/grack_auth.rb4
-rw-r--r--lib/gitlab/build_data_builder.rb64
-rw-r--r--lib/gitlab/database.rb18
-rw-r--r--lib/tasks/ci/schedule_builds.rake6
-rw-r--r--lib/tasks/gitlab/check.rake2
-rw-r--r--spec/factories/ci/builds.rb4
-rw-r--r--spec/factories/ci/commits.rb2
-rw-r--r--spec/factories/ci/events.rb24
-rw-r--r--spec/factories/ci/projects.rb50
-rw-r--r--spec/factories/ci/runner_projects.rb2
-rw-r--r--spec/factories/ci/web_hook.rb6
-rw-r--r--spec/features/admin/admin_builds_spec.rb (renamed from spec/features/ci/admin/builds_spec.rb)35
-rw-r--r--spec/features/admin/admin_runners_spec.rb (renamed from spec/features/ci/admin/runners_spec.rb)32
-rw-r--r--spec/features/atom/users_spec.rb2
-rw-r--r--spec/features/builds_spec.rb24
-rw-r--r--spec/features/ci/admin/events_spec.rb20
-rw-r--r--spec/features/ci/admin/projects_spec.rb19
-rw-r--r--spec/features/ci_settings_spec.rb22
-rw-r--r--spec/features/ci_web_hooks_spec.rb27
-rw-r--r--spec/features/commits_spec.rb112
-rw-r--r--spec/features/issues/note_polling_spec.rb16
-rw-r--r--spec/features/issues_spec.rb29
-rw-r--r--spec/features/lint_spec.rb (renamed from spec/features/ci/lint_spec.rb)0
-rw-r--r--spec/features/merge_requests/merge_when_build_succeeds_spec.rb4
-rw-r--r--spec/features/runners_spec.rb28
-rw-r--r--spec/features/triggers_spec.rb7
-rw-r--r--spec/features/variables_spec.rb7
-rw-r--r--spec/lib/gitlab/backend/grack_auth_spec.rb9
-rw-r--r--spec/lib/gitlab/build_data_builder_spec.rb20
-rw-r--r--spec/mailers/ci/notify_spec.rb35
-rw-r--r--spec/mailers/notify_spec.rb29
-rw-r--r--spec/models/application_setting_spec.rb22
-rw-r--r--spec/models/build_spec.rb83
-rw-r--r--spec/models/ci/commit_spec.rb28
-rw-r--r--spec/models/ci/project_services/hip_chat_message_spec.rb39
-rw-r--r--spec/models/ci/project_services/hip_chat_service_spec.rb73
-rw-r--r--spec/models/ci/project_services/mail_service_spec.rb177
-rw-r--r--spec/models/ci/project_services/slack_message_spec.rb43
-rw-r--r--spec/models/ci/project_services/slack_service_spec.rb57
-rw-r--r--spec/models/ci/project_spec.rb246
-rw-r--r--spec/models/ci/runner_spec.rb8
-rw-r--r--spec/models/ci/service_spec.rb48
-rw-r--r--spec/models/ci/trigger_spec.rb2
-rw-r--r--spec/models/ci/web_hook_spec.rb63
-rw-r--r--spec/models/commit_status_spec.rb3
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb57
-rw-r--r--spec/models/project_services/gitlab_ci_service_spec.rb57
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb49
-rw-r--r--spec/models/project_services/slack_service/build_message_spec.rb46
-rw-r--r--spec/models/project_spec.rb89
-rw-r--r--spec/requests/api/project_hooks_spec.rb12
-rw-r--r--spec/requests/api/projects_spec.rb12
-rw-r--r--spec/requests/api/triggers_spec.rb80
-rw-r--r--spec/requests/ci/api/builds_spec.rb40
-rw-r--r--spec/requests/ci/api/commits_spec.rb65
-rw-r--r--spec/requests/ci/api/projects_spec.rb232
-rw-r--r--spec/requests/ci/api/runners_spec.rb37
-rw-r--r--spec/requests/ci/api/triggers_spec.rb21
-rw-r--r--spec/services/ci/create_commit_service_spec.rb172
-rw-r--r--spec/services/ci/create_trigger_request_service_spec.rb5
-rw-r--r--spec/services/ci/event_service_spec.rb34
-rw-r--r--spec/services/ci/image_for_build_service_spec.rb8
-rw-r--r--spec/services/ci/register_build_service_spec.rb10
-rw-r--r--spec/services/ci/web_hook_service_spec.rb37
-rw-r--r--spec/services/create_commit_builds_service_spec.rb170
-rw-r--r--spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb2
-rw-r--r--spec/support/stub_gitlab_calls.rb4
-rw-r--r--spec/workers/build_email_worker_spec.rb35
290 files changed, 3393 insertions, 5131 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c614e14e243..a8da3de83f8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -117,9 +117,10 @@ flay:
- mysql
bundler:audit:
- script:
+ script:
- "bundle exec bundle-audit update"
- "bundle exec bundle-audit check"
tags:
- ruby
- mysql
+ allow_failure: true
diff --git a/CHANGELOG b/CHANGELOG
index 61068d3efb1..7f9dfd98cd7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,6 +11,7 @@ v 8.3.0 (unreleased)
- Update project repositorize size and commit count during import:repos task (Stan Hu)
- Fix API setting of 'public' attribute to false will make a project private (Stan Hu)
- Handle and report SSL errors in Web hook test (Stan Hu)
+ - Bump Redis requirement to 2.8 for Sidekiq 4 (Stan Hu)
- Fix: Assignee selector is empty when 'Unassigned' is selected (Jose Corcuera)
- Add rake tasks for git repository maintainance (Zeger-Jan van de Weg)
- Fix 500 error when update group member permission
@@ -20,6 +21,7 @@ v 8.3.0 (unreleased)
- Fire update hook from GitLab
- Style warning about mentioning many people in a comment
- Fix: sort milestones by due date once again (Greg Smethells)
+ - Migrate all CI::Services and CI::WebHooks to Services and WebHooks
- Don't show project fork event as "imported"
- Add API endpoint to fetch merge request commits list
- Expose events API with comment information and author info
@@ -45,6 +47,14 @@ v 8.3.0 (unreleased)
- Accept COPYING,COPYING.lesser, and licence as license file (Zeger-Jan van de Weg)
- Fix emoji aliases problem
- Fix award-emojis Flash alert's width
+ - Fix deleting notes on a merge request diff
+ - Display referenced merge request statuses in the issue description (Greg Smethells)
+ - Implement new sidebar for issue and merge request pages
+ - Emoji picker improvements
+ - Suppress warning about missing `.gitlab-ci.yml` if builds are disabled
+ - Do not show build status unless builds are enabled and `.gitlab-ci.yml` is present
+ - Persist runners registration token in database
+ - Fix online editor should not remove newlines at the end of the file
v 8.2.3
- Fix application settings cache not expiring after changes (Stan Hu)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7f5da063fd4..7ced7c57889 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,113 +1,243 @@
# Contribute to GitLab
-Thank you for your interest in contributing to GitLab.
-This guide details how contribute to GitLab in a way that is efficient for everyone.
-If you have read this guide and want to know how the GitLab core-team operates please see [the GitLab contributing process](PROCESS.md).
+Thank you for your interest in contributing to GitLab. This guide details how
+to contribute to GitLab in a way that is efficient for everyone.
+
+GitLab comes into two flavors, GitLab Community Edition (CE) our free and open
+source edition, and GitLab Enterprise Edition (EE) which is our commercial
+edition. Throughout this guide you will see references to CE and EE for
+abbreviation.
+
+If you have read this guide and want to know how the GitLab [core-team][]
+operates please see [the GitLab contributing process](PROCESS.md).
## Contributor license agreement
-By submitting code as an individual you agree to the [individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md). By submitting code as an entity you agree to the [corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md).
+By submitting code as an individual you agree to the
+[individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md).
+By submitting code as an entity you agree to the
+[corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md).
## Security vulnerability disclosure
-Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](https://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
+Please report suspected security vulnerabilities in private to
+`support@gitlab.com`, also see the
+[disclosure section on the GitLab.com website](https://about.gitlab.com/disclosure/).
+Please do **NOT** create publicly viewable issues for suspected security
+vulnerabilities.
## Closing policy for issues and merge requests
-GitLab is a popular open source project and the capacity to deal with issues and merge requests is limited. Out of respect for our volunteers, issues and merge requests not in line with the guidelines listed in this document may be closed without notice.
+GitLab is a popular open source project and the capacity to deal with issues
+and merge requests is limited. Out of respect for our volunteers, issues and
+merge requests not in line with the guidelines listed in this document may be
+closed without notice.
-Please treat our volunteers with courtesy and respect, it will go a long way towards getting your issue resolved.
+Please treat our volunteers with courtesy and respect, it will go a long way
+towards getting your issue resolved.
-Issues and merge requests should be in English and contain appropriate language for audiences of all ages.
+Issues and merge requests should be in English and contain appropriate language
+for audiences of all ages.
## Helping others
-Please help other GitLab users when you can.
-The channels people will reach out on can be found on the [getting help page](https://about.gitlab.com/getting-help/).
-Sign up for the mailinglist, answer GitLab questions on StackOverflow or respond in the IRC channel.
-You can also sign up on [CodeTriage](http://www.codetriage.com/gitlabhq/gitlabhq) to help with one issue every day.
+Please help other GitLab users when you can. The channels people will reach out
+on can be found on the [getting help page][].
+
+Sign up for the mailing list, answer GitLab questions on StackOverflow or
+respond in the IRC channel. You can also sign up on [CodeTriage][] to help with
+the remaining issues on the GitHub issue tracker.
## I want to contribute!
If you want to contribute to GitLab, but are not sure where to start,
-look for [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues?milestone_id=&scope=all&sort=created_desc&state=opened&utf8=%E2%9C%93&assignee_id=&author_id=&milestone_title=&label_name=up-for-grabs)
-with the label `up-for-grabs`.
-These issues will be of reasonable size and challenge, for anyone to start
-contributing to GitLab.
+look for [issues with the label `up-for-grabs`][up-for-grabs]. These issues
+will be of reasonable size and challenge, for anyone to start contributing to
+GitLab.
-This was inspired by [an article by Kent C. Dodds](https://medium.com/@kentcdodds/first-timers-only-78281ea47455#.i2f363mx4).
+This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
## Issue tracker
-To get support for your particular problem please use the [getting help channels](https://about.gitlab.com/getting-help/).
+To get support for your particular problem please use the
+[getting help channels](https://about.gitlab.com/getting-help/).
+
+The [GitLab CE issue tracker on GitLab.com][ce-tracker] is for bugs concerning
+the latest GitLab release and [feature proposals](#feature-proposals).
+
+When submitting an issue please conform to the issue submission guidelines
+listed below. Not all issues will be addressed and your issue is more likely to
+be addressed if you submit a merge request which partially or fully solves
+the issue.
+
+If you're unsure where to post, post to the [mailing list][google-group] or
+[Stack Overflow][stackoverflow] first. There are a lot of helpful GitLab users
+there who may be able to help you quickly. If your particular issue turns out
+to be a bug, it will find its way from there.
+
+If it happens that you know the solution to an existing bug, please first
+open the issue in order to keep track of it and then open the relevant merge
+request that potentially fixes it.
+
+### Feature proposals
+
+To create a feature proposal for CE and CI, open an issue on the
+[issue tracker of CE][ce-tracker].
+
+For feature proposals for EE, open an issue on the
+[issue tracker of EE][ee-tracker].
-The [GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues) is only for obvious errors in the latest [stable or development release of GitLab](MAINTENANCE.md). If something is wrong but it is not a regression compared to older versions of GitLab please do not open an issue but a feature request. When submitting an issue please conform to the issue submission guidelines listed below. Not all issues will be addressed and your issue is more likely to be addressed if you submit a merge request which partially or fully addresses the issue.
+In order to help track the feature proposals, we have created a
+[`feature proposal`][fpl] label. For the time being, users that are not members
+of the project cannot add labels. You can instead ask one of the [core team][]
+members to add the label `feature proposal` to the issue.
-Do not use the issue tracker for feature requests. We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose. Please keep feature requests as small and simple as possible, complex ones might be edited to make them small and simple.
+Please keep feature proposals as small and simple as possible, complex ones
+might be edited to make them small and simple.
-Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](https://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
+For changes in the interface, it can be helpful to create a mockup first.
+If you want to create something yourself, consider opening an issue first to
+discuss whether it is interesting to include this in GitLab.
### Issue tracker guidelines
-**[Search the issues](https://gitlab.com/gitlab-org/gitlab-ce/issues)** for similar entries before submitting your own, there's a good chance somebody else had the same issue. Show your support with `:+1:` and/or join the discussion. Please submit issues in the following format (as the first post):
+**[Search the issue tracker][ce-tracker]** for similar entries before
+submitting your own, there's a good chance somebody else had the same issue or
+feature proposal. Show your support with an award emoji and/or join the
+discussion.
+
+Please submit bugs using the following template in the issue description area.
+The text in the parenthesis is there to help you with what to include. Omit it
+when submitting the actual issue. You can copy-paste it and then edit as you
+see fit.
+
+```
+## Summary
+
+(Summarize your issue in one sentence - what goes wrong, what did you expect to happen)
+
+## Steps to reproduce
+
+(How one can reproduce the issue - this is very important)
+
+## Expected behavior
+
+(What you should see instead)
+
+## Relevant logs and/or screenshots
+
+(Paste any relevant logs - please use code blocks (```) to format console output,
+logs, and code as it's very hard to read otherwise.)
+
+## Output of checks
-1. **Summary:** Summarize your issue in one sentence (what goes wrong, what did you expect to happen)
-1. **Steps to reproduce:** How can we reproduce the issue
-1. **Expected behavior:** Describe your issue in detail
-1. **Observed behavior**
-1. **Relevant logs and/or screenshots:** Please use code blocks (\`\`\`) to format console output, logs, and code as it's very hard to read otherwise.
-1. **Output of checks**
- * Results of GitLab [Application Check](doc/install/installation.md#check-application-status) (For installations with omnibus-gitlab package: `sudo gitlab-rake gitlab:check SANITIZE=true`); For installations from source: `sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`); we will only investigate if the tests are passing
- * Version of GitLab you are running; we will only investigate issues in the latest stable and development releases as per the [maintenance policy](MAINTENANCE.md)
- * Add the last commit SHA-1 of the GitLab version you used to replicate the issue (obtainable from the help page)
- * Describe your setup (use relevant parts from the env info: For installations with omnibus-gitlab package: `sudo gitlab-rake gitlab:env:info`; For installations from source: `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
-1. **Possible fixes**: If you can, link to the line of code that might be responsible for the problem
+### Results of GitLab Application Check
+
+(For installations with omnibus-gitlab package run and paste the output of:
+sudo gitlab-rake gitlab:check SANITIZE=true)
+
+(For installations from source run and paste the output of:
+sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true)
+
+(we will only investigate if the tests are passing)
+
+### Results of GitLab Environment Info
+
+(For installations with omnibus-gitlab package run and paste the output of:
+sudo gitlab-rake gitlab:env:info)
+
+(For installations from source run and paste the output of:
+sudo -u git -H bundle exec rake gitlab:env:info)
+
+## Possible fixes
+
+(If you can, link to the line of code that might be responsible for the problem)
+
+```
## Merge requests
-We welcome merge requests with fixes and improvements to GitLab code, tests, and/or documentation. The features we would really like a merge request for are listed with the [status 'accepting merge requests' on our feature request forum](http://feedback.gitlab.com/forums/176466-general/status/796455) but other improvements are also welcome. If you want to add a new feature that is not marked it is best to first create a feedback issue (if there isn't one already) and leave a comment asking for it to be marked accepting merge requests. Please include screenshots or wireframes if the feature will also change the UI.
+We welcome merge requests with fixes and improvements to GitLab code, tests,
+and/or documentation. The features we would really like a merge request for are
+listed with the label [`Accepting Merge Requests` on our issue tracker for CE][accepting-mrs-ce]
+and [EE][accepting-mrs-ee] but other improvements are also welcome.
+
+If you want to add a new feature that is not labeled it is best to first create
+a feedback issue (if there isn't one already) and leave a comment asking for it
+to be marked as `Accepting merge requests`. Please include screenshots or
+wireframes if the feature will also change the UI.
-Merge requests can be filed either at [gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests) or [github.com](https://github.com/gitlabhq/gitlabhq/pulls).
+Merge requests can be filed either at [GitLab.com][gitlab-mr-tracker] or at
+[github.com][github-mr-tracker].
-If you are new to GitLab development (or web development in general), search for the label `easyfix` ([GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=easyfix), [GitHub](https://github.com/gitlabhq/gitlabhq/labels/easyfix)). Those are issues easy to fix, marked by the GitLab core-team. If you are unsure how to proceed but want to help, mention one of the core-team members to give you a hint.
+If you are new to GitLab development (or web development in general), see the
+[I want to contribute!](#i-want-to-contribute) section to get you started with
+some potentially easy issues.
-To start with GitLab download the [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit) and see [Development section](doc/development/README.md) in the help file.
+To start with GitLab development download the [GitLab Development Kit][gdk] and
+see the [Development section](doc/development/README.md) for some guidelines.
### Merge request guidelines
-If you can, please submit a merge request with the fix or improvements including tests. If you don't know how to fix the issue but can write a test that exposes the issue we will accept that as well. In general bug fixes that include a regression test are merged quickly while new features without proper tests are least likely to receive timely feedback. The workflow to make a merge request is as follows:
+If you can, please submit a merge request with the fix or improvements
+including tests. If you don't know how to fix the issue but can write a test
+that exposes the issue we will accept that as well. In general bug fixes that
+include a regression test are merged quickly while new features without proper
+tests are least likely to receive timely feedback. The workflow to make a merge
+request is as follows:
1. Fork the project into your personal space on GitLab.com
1. Create a feature branch
1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
1. Add your changes to the [CHANGELOG](CHANGELOG)
-1. If you are changing the README, some documentation or other things which have no effect on the tests, add `[ci skip]` somewhere in the commit message
-1. If you have multiple commits please combine them into one commit by [squashing them](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
-1. Push the commit to your fork
+1. If you are changing the README, some documentation or other things which
+ have no effect on the tests, add `[ci skip]` somewhere in the commit message
+1. If you have multiple commits please combine them into one commit by
+ [squashing them][git-squash]
+1. Push the commit(s) to your fork
1. Submit a merge request (MR) to the master branch
1. The MR title should describe the change you want to make
-1. The MR description should give a motive for your change and the method you used to achieve it
+1. The MR description should give a motive for your change and the method you
+ used to achieve it
1. If the MR changes the UI it should include before and after screenshots
-1. If the MR changes CSS classes please include the list of affected pages `grep css-class ./app -R`
-1. Link relevant [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues) and/or [feature requests](http://feedback.gitlab.com/) from the merge request description and leave a comment on them with a link back to the MR
-1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submission
-1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
-1. Also have a look at the [shell command guidelines](doc/development/shell_commands.md) if your code reads or opens files, or handles paths to files on disk.
-1. If your code creates new files on disk please read the [shared files guidelines](doc/development/shared_files.md).
-
-The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast.
-Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as regressions requiring patch releases.
-After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
-
-Please keep the change in a single MR **as small as possible**. If you want to contribute a large feature think very hard what the minimum viable change is. Can you split functionality? Can you only submit the backend/API code? Can you start with a very simple UI? Can you do part of the refactor? The increased reviewability of small MR's that leads to higher code quality is more important to us than having a minimal commit log. The smaller a MR is the more likely it is it will be merged (quickly), after that you can send more MR's to enhance it.
-
-For examples of feedback on merge requests please look at already [closed merge requests](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed). If you would like quick feedback on your merge request feel free to mention one of the Merge Marshalls of [the core-team](https://about.gitlab.com/core-team/). Please ensure that your merge request meets the contribution acceptance criteria.
+1. If the MR changes CSS classes please include the list of affected pages
+ `grep css-class ./app -R`
+1. Link any relevant [issues][ce-tracker] in the merge request description and
+ leave a comment on them with a link back to the MR
+1. Be prepared to answer questions and incorporate feedback even if requests
+ for this arrive weeks or months after your MR submission
+1. If your MR touches code that executes shell commands, reads or opens files or
+ handles paths to files on disk, make sure it adheres to the
+ [shell command guidelines](doc/development/shell_commands.md)
+1. If your code creates new files on disk please read the
+ [shared files guidelines](doc/development/shared_files.md).
+
+The **official merge window** is in the beginning of the month from the 1st to
+the 7th day of the month. This is the best time to submit an MR and get
+feedback fast. Before this time the GitLab Inc. team is still dealing with work
+that is created by the monthly release such as regressions requiring patch
+releases. After the 7th it is already getting closer to the release date of the
+next version. This means there is less time to fix the issues created by
+merging large new features.
+
+Please keep the change in a single MR **as small as possible**. If you want to
+contribute a large feature think very hard what the minimum viable change is.
+Can you split the functionality? Can you only submit the backend/API code? Can
+you start with a very simple UI? Can you do part of the refactor? The increased
+reviewability of small MRs that leads to higher code quality is more important
+to us than having a minimal commit log. The smaller an MR is the more likely it
+is it will be merged (quickly). After that you can send more MRs to enhance it.
+
+For examples of feedback on merge requests please look at already
+[closed merge requests][]. If you would like quick feedback on your merge
+request feel free to mention one of the Merge Marshalls of the [core team][].
+Please ensure that your merge request meets the contribution acceptance criteria.
## Definition of done
-If you contribute to GitLab please know that changes involve more than just code.
-We have the following [definition of done](http://guide.agilealliance.org/guide/definition-of-done.html).
-Please ensure you support the feature you contribute through all of these steps.
+If you contribute to GitLab please know that changes involve more than just
+code. We have the following [definition of done][]. Please ensure you support
+the feature you contribute through all of these steps.
1. Description explaining the relevancy (see following item)
1. Working and clean code that is commented where needed
@@ -121,14 +251,16 @@ Please ensure you support the feature you contribute through all of these steps.
1. Community questions answered
1. Answers to questions radiated (in docs/wiki/etc.)
-If you add a dependency in GitLab (such as an operating system package) please consider updating the following and note the applicability of each in your merge request:
+If you add a dependency in GitLab (such as an operating system package) please
+consider updating the following and note the applicability of each in your
+merge request:
1. Note the addition in the release blog post (create one if it doesn't exist yet) https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/
1. Upgrade guide, for example https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/7.5-to-7.6.md
1. Upgrader https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/upgrader.md#2-run-gitlab-upgrade-tool
1. Installation guide https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies
1. GitLab Development Kit https://gitlab.com/gitlab-org/gitlab-development-kit
-1. Test suite https://gitlab.com/gitlab-org/gitlab-ci/blob/master/doc/examples/configure_a_runner_to_run_the_gitlab_ce_test_suite.md
+1. Test suite https://gitlab.com/gitlab-org/gitlab-ce/blob/master/scripts/prepare_build.sh
1. Omnibus package creator https://gitlab.com/gitlab-org/omnibus-gitlab
## Merge request description format
@@ -136,59 +268,111 @@ If you add a dependency in GitLab (such as an operating system package) please c
1. What does this MR do?
1. Are there points in the code the reviewer needs to double check?
1. Why was this MR needed?
-1. What are the relevant issue numbers / [Feature requests](http://feedback.gitlab.com/)?
+1. What are the relevant issue numbers?
1. Screenshots (if relevant)
## Contribution acceptance criteria
1. The change is as small as possible (see the above paragraph for details)
-1. Include proper tests and make all tests pass (unless it contains a test exposing a bug in existing code)
-1. All tests have to pass, if you suspect a failing CI build is unrelated to your contribution ask for tests to be restarted. See [the CI setup document](http://doc.gitlab.com/ce/development/ci_setup.html) on who you can ask for test restart.
-1. Initially contains a single commit (please use `git rebase -i` to squash commits)
-1. Can merge without problems (if not please merge `master`, never rebase commits pushed to the remote server)
+1. Include proper tests and make all tests pass (unless it contains a test
+ exposing a bug in existing code)
+1. If you suspect a failing CI build is unrelated to your contribution, you may
+ try and restart the failing CI job or ask a developer to fix the
+ aforementioned failing test
+1. Your MR initially contains a single commit (please use `git rebase -i` to
+ squash commits)
+1. Your changes can merge without problems (if not please merge `master`, never
+ rebase commits pushed to the remote server)
1. Does not break any existing functionality
-1. Fixes one specific issue or implements one specific feature (do not combine things, send separate merge requests if needed)
-1. Migrations should do only one thing (eg: either create a table, move data to a new table or remove an old table) to aid retrying on failure
+1. Fixes one specific issue or implements one specific feature (do not combine
+ things, send separate merge requests if needed)
+1. Migrations should do only one thing (eg: either create a table, move data to
+ a new table or remove an old table) to aid retrying on failure
1. Keeps the GitLab code base clean and well structured
1. Contains functionality we think other users will benefit from too
1. Doesn't add configuration options since they complicate future changes
-1. Changes after submitting the merge request should be in separate commits (no squashing). You will be asked to squash when the review is over, before merging.
-1. It conforms to the following style guides.
- If your change touches a line that does not follow the style,
- modify the entire line to follow it. This prevents linting tools from generating warnings.
- Don't touch neighbouring lines. As an exception, automatic mass refactoring modifications
- may leave style non-compliant.
+1. Changes after submitting the merge request should be in separate commits
+ (no squashing). If necessary, you will be asked to squash when the review is
+ over, before merging.
+1. It conforms to the following style guides:
+ * If your change touches a line that does not follow the style, modify the
+ entire line to follow it. This prevents linting tools from generating warnings.
+ * Don't touch neighbouring lines. As an exception, automatic mass
+ refactoring modifications may leave style non-compliant.
## Style guides
1. [Ruby](https://github.com/bbatsov/ruby-style-guide).
- Important sections include [Source Code Layout](https://github.com/bbatsov/ruby-style-guide#source-code-layout)
- and [Naming](https://github.com/bbatsov/ruby-style-guide#naming). Use:
+ Important sections include [Source Code Layout][rss-source] and
+ [Naming][rss-naming]. Use:
- multi-line method chaining style **Option B**: dot `.` on previous line
- string literal quoting style **Option A**: single quoted by default
1. [Rails](https://github.com/bbatsov/rails-style-guide)
-1. [Testing](https://github.com/thoughtbot/guides/tree/master/style#testing)
-1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style#coffeescript)
-1. [Shell commands](doc/development/shell_commands.md) created by GitLab contributors to enhance security
+1. [Testing](https://github.com/thoughtbot/guides/tree/master/style/testing)
+1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style/coffeescript)
+1. [Shell commands](doc/development/shell_commands.md) created by GitLab
+ contributors to enhance security
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
1. [Database Migrations](doc/development/migration_style_guide.md)
1. [Documentation styleguide](doc_styleguide.md)
-1. Interface text should be written subjectively instead of objectively. It should be the GitLab core team addressing a person. It should be written in present time and never use past tense (has been/was). For example instead of "prohibited this user from being saved due to the following errors:" the text should be "sorry, we could not create your account because:". Also these [excellent writing guidelines](https://github.com/NARKOZ/guides#writing).
+1. Interface text should be written subjectively instead of objectively. It
+ should be the GitLab core team addressing a person. It should be written in
+ present time and never use past tense (has been/was). For example instead
+ of _prohibited this user from being saved due to the following errors:_ the
+ text should be _sorry, we could not create your account because:_
-This is also the style used by linting tools such as [RuboCop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
+This is also the style used by linting tools such as
+[RuboCop](https://github.com/bbatsov/rubocop),
+[PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
## Code of conduct
-As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
-
-We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
-
-Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
-
-This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior can be reported by emailing contact@gitlab.com
-
-This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)
+As contributors and maintainers of this project, we pledge to respect all
+people who contribute through reporting issues, posting feature requests,
+updating documentation, submitting pull requests or patches, and other
+activities.
+
+We are committed to making participation in this project a harassment-free
+experience for everyone, regardless of level of experience, gender, gender
+identity and expression, sexual orientation, disability, personal appearance,
+body size, race, ethnicity, age, or religion.
+
+Examples of unacceptable behavior by participants include the use of sexual
+language or imagery, derogatory comments or personal attacks, trolling, public
+or private harassment, insults, or other unprofessional conduct.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct. Project maintainers who do not
+follow the Code of Conduct may be removed from the project team.
+
+This code of conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior can be
+reported by emailing `contact@gitlab.com`.
+
+This Code of Conduct is adapted from the [Contributor Covenant][], version 1.1.0,
+available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/).
+
+[core team]: https://about.gitlab.com/core-team/
+[getting help page]: https://about.gitlab.com/getting-help/
+[Codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq
+[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up+for+grabs
+[medium-up-for-grabs]: https://medium.com/@kentcdodds/first-timers-only-78281ea47455
+[ce-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/issues
+[ee-tracker]: https://gitlab.com/gitlab-org/gitlab-ee/issues
+[google-group]: https://groups.google.com/forum/#!forum/gitlabhq
+[stackoverflow]: https://stackoverflow.com/questions/tagged/gitlab
+[fpl]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=feature+proposal
+[accepting-mrs-ce]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=Accepting+Merge+Requests
+[accepting-mrs-ee]: https://gitlab.com/gitlab-org/gitlab-ee/issues?label_name=Accepting+Merge+Requests
+[gitlab-mr-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests
+[github-mr-tracker]: https://github.com/gitlabhq/gitlabhq/pulls
+[gdk]: https://gitlab.com/gitlab-org/gitlab-development-kit
+[git-squash]: https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits
+[closed merge requests]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed
+[definition of done]: http://guide.agilealliance.org/guide/definition-of-done.html
+[Contributor Covenant]: http://contributor-covenant.org
+[rss-source]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#source-code-layout
+[rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming
diff --git a/Gemfile b/Gemfile
index 582a1624f05..7298e21ce66 100644
--- a/Gemfile
+++ b/Gemfile
@@ -93,6 +93,7 @@ gem 'html-pipeline', '~> 1.11.0'
gem 'task_list', '~> 1.0.2', require: 'task_list/railtie'
gem 'github-markup', '~> 1.3.1'
gem 'redcarpet', '~> 3.3.3'
+gem 'RedCloth', '~> 4.2.9'
gem 'rdoc', '~>3.6'
gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 0db1c6760f8..ff57460f5bb 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -2,6 +2,7 @@ GEM
remote: https://rubygems.org/
specs:
CFPropertyList (2.3.2)
+ RedCloth (4.2.9)
ace-rails-ap (2.0.1)
actionmailer (4.2.4)
actionpack (= 4.2.4)
@@ -826,6 +827,7 @@ PLATFORMS
ruby
DEPENDENCIES
+ RedCloth (~> 4.2.9)
ace-rails-ap (~> 2.0.1)
activerecord-deprecated_finders (~> 1.0.3)
activerecord-session_store (~> 0.1.0)
diff --git a/PROCESS.md b/PROCESS.md
index 72fc3481447..5f4d67bc10e 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -8,7 +8,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
### Issue team
- Looks for issues without [workflow labels](#how-we-handle-issues) and triages issue
-- Closes invalid issues with a comment (duplicates, [feature requests](#feature-requests), [fixed in newer version](#issue-fixed-in-newer-version), [issue report for old version](#issue-report-for-old-version), not a problem in GitLab, etc.)
+- Closes invalid issues with a comment (duplicates, [fixed in newer version](#issue-fixed-in-newer-version), [issue report for old version](#issue-report-for-old-version), not a problem in GitLab, etc.)
- Asks for feedback from issue reporter ([invalid issue reports](#improperly-formatted-issue), [format code](#code-format), etc.)
- Monitors all issues for feedback (but especially ones commented on since automatically watching them)
- Closes issues with no feedback from the reporter for two weeks
@@ -45,6 +45,8 @@ Workflow labels are purposely not very detailed since that would be hard to keep
- *Frontend* needs help from a Front-end engineer
- *Graphics* needs help from a Graphics designer
- *up-for-grabs* is an issue suitable for first-time contributors, of reasonable difficulty and size. Not exclusive with other labels.
+- *feature proposal* is a proposal for a new feature for GitLab. People are encouraged to vote
+in support or comment for further detail. Do not use `feature request`.
Example workflow: when a UX designer provided a design but it needs frontend work they remove the UX label and add the frontend label.
@@ -62,7 +64,6 @@ If an issue is complex and needs the attention of a specific person, assignment
- Bright orange `#eb6420`: workflow labels for core team members (attached MR, awaiting developer action/feedback)
- Light blue `#82C5FF`: functional labels
- Green labels `#009800`: issues that can generally be ignored. For example, issues given the following labels normally can be closed immediately:
- - Feature request (see copy & paste response: [Feature requests](#feature-requests))
- Support (see copy & paste response: [Support requests and configuration questions](#support-requests-and-configuration-questions)
## Be kind
@@ -75,10 +76,6 @@ Be kind to people trying to contribute. Be aware that people may be a non-native
Thanks for the issue report. Please reformat your issue to conform to the issue tracker guidelines found in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
-### Feature requests
-
-Thank you for your interest in improving GitLab. We don't use the issue tracker for feature requests. Things that are wrong but are not a regression compared to older versions of GitLab are considered feature requests and not issues. Please use the \[feature request forum\]\(http://feedback.gitlab.com/) for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
-
### Issue report for old version
Thanks for the issue report but we only support issues for the latest stable version of GitLab. I'm closing this issue but if you still experience this problem in the latest stable version, please open a new issue (but also reference the old issue(s)). Make sure to also include the necessary debugging information conforming to the issue tracker guidelines found in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
@@ -113,7 +110,12 @@ This merge request has been closed because a request for more information has no
### Accepting merge requests
-Is there a request on [the feature request forum](http://feedback.gitlab.com/forums/176466-general) that is similar to this? If so, can you make a comment with a link to it? Please be aware that new functionality that is not marked [accepting merge/pull requests](http://feedback.gitlab.com/forums/176466-general/status/796455) on the forum might not make it into GitLab. You might be asked to make changes and even after implementing them your feature might still be declined. If you want to reduce the chance of this happening please have a discussion in the forum first.
+Is there an issue on the [issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues)
+that is similar to this?
+Could you please link it here?
+Please be aware that new functionality that is not marked
+[accepting merge requests](https://gitlab.com/gitlab-org/gitlab-ce/issues?milestone_id=&scope=all&sort=created_desc&state=opened&utf8=%E2%9C%93&assignee_id=&author_id=&milestone_title=&label_name=Accepting+Merge+Requests)
+might not make it into GitLab.
### Only accepting merge requests with green tests
diff --git a/README.md b/README.md
index c459e67baa1..3ec1d4a776c 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.1
- Git 1.7.10+
-- Redis 2.4+
+- Redis 2.8+
- MySQL or PostgreSQL
For more information please see the [architecture documentation](http://doc.gitlab.com/ce/development/architecture.html).
diff --git a/app/assets/javascripts/issuable_context.js.coffee b/app/assets/javascripts/issuable_context.js.coffee
index c4d3e619f5e..01bd515cc02 100644
--- a/app/assets/javascripts/issuable_context.js.coffee
+++ b/app/assets/javascripts/issuable_context.js.coffee
@@ -5,9 +5,9 @@ class @IssuableContext
new UsersSelect()
$('select.select2').select2({width: 'resolve', dropdownAutoWidth: true})
- $(".context .inline-update").on "change", "select", ->
+ $(".issuable-sidebar .inline-update").on "change", "select", ->
$(this).submit()
- $(".context .inline-update").on "change", ".js-assignee", ->
+ $(".issuable-sidebar .inline-update").on "change", ".js-assignee", ->
$(this).submit()
$('.issuable-details').waitForImages ->
@@ -18,6 +18,12 @@ class @IssuableContext
$('.issuable-affix').affix offset:
top: ->
- @top = ($('.issuable-affix').offset().top - 70)
+ @top = ($('.issuable-affix').offset().top - 60)
bottom: ->
@bottom = $('.footer').outerHeight(true)
+
+ $(".edit-link").click (e) ->
+ block = $(@).parents('.block')
+ block.find('.selectbox').show()
+ block.find('.value').hide()
+ block.find('.js-select2').select2("open")
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index a7d720fff4b..35dc7829da2 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -350,18 +350,26 @@ class @Notes
###
removeNote: ->
note = $(this).closest(".note")
- notes = note.closest(".notes")
+ note_id = note.attr('id')
- # check if this is the last note for this line
- if notes.find(".note").length is 1
+ $('.note[id="' + note_id + '"]').each ->
+ note = $(this)
+ notes = note.closest(".notes")
+ count = notes.closest(".notes_holder").find(".discussion-notes-count")
- # for discussions
- notes.closest(".discussion").remove()
+ # check if this is the last note for this line
+ if notes.find(".note").length is 1
- # for diff lines
- notes.closest("tr").remove()
+ # for discussions
+ notes.closest(".discussion").remove()
- note.remove()
+ # for diff lines
+ notes.closest("tr").remove()
+ else
+ # update notes count
+ count.get(0).lastChild.nodeValue = " #{notes.children().length - 1}"
+
+ note.remove()
###
Called in response to clicking the delete attachment link
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 2e8515668f6..88da799ee2b 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -461,3 +461,9 @@ table {
visibility: hidden;
}
}
+
+.content-separator {
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+ border-top: 1px solid $border-color;
+}
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index c01e1e32e41..af145191bc8 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -181,4 +181,4 @@
.ajax-users-dropdown {
min-width: 250px !important;
-} \ No newline at end of file
+}
diff --git a/app/assets/stylesheets/pages/awards.scss b/app/assets/stylesheets/pages/awards.scss
new file mode 100644
index 00000000000..041b811a606
--- /dev/null
+++ b/app/assets/stylesheets/pages/awards.scss
@@ -0,0 +1,86 @@
+.awards {
+ @include clearfix;
+ line-height: 34px;
+
+ .award {
+ @include border-radius(5px);
+
+ border: 1px solid;
+ padding: 0px 10px;
+ float: left;
+ margin-right: 5px;
+ border-color: $border-color;
+ cursor: pointer;
+
+ &:hover {
+ background-color: #dce0e5;
+ }
+
+ &.active {
+ border-color: $border-gray-light;
+ background-color: $gray-light;
+
+ &:hover {
+ background-color: #dce0e5;
+ }
+
+ .counter {
+ font-weight: bold;
+ }
+ }
+
+ .icon {
+ float: left;
+ margin-right: 10px;
+ }
+
+ .counter {
+ float: left;
+ }
+ }
+
+ .awards-controls {
+ margin-left: 10px;
+ float: left;
+
+ .add-award {
+ font-size: 24px;
+ color: $gl-gray;
+ position: relative;
+ top: 2px;
+
+ &:hover,
+ &:link {
+ text-decoration: none;
+ }
+ }
+
+ .awards-menu {
+ padding: $gl-padding;
+ min-width: 214px;
+
+ > li {
+ cursor: pointer;
+ width: 30px;
+ height: 30px;
+ text-align: center;
+ @include border-radius(5px);
+
+ img {
+ margin-bottom: 2px;
+ }
+
+ &:hover {
+ background-color: #ccc;
+ }
+ }
+ }
+ }
+
+ .awards-menu{
+ li {
+ float: left;
+ margin: 3px;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 957da5c182e..797a0af3720 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -18,26 +18,12 @@
&.affix {
position: fixed;
- top: 70px;
+ top: 60px;
margin-right: 35px;
}
}
}
-.issuable-context-title {
- margin-bottom: 5px;
-
- .avatar {
- margin-left: 0;
- }
-
- label {
- color: $gl-gray;
- font-weight: normal;
- margin-right: 4px;
- }
-}
-
.project-issuable-filter {
.controls {
float: right;
@@ -50,23 +36,6 @@
}
.issuable-details {
- .page-title {
- margin-top: -$gl-padding;
- padding: 7px 0;
- margin-bottom: 0;
- color: #5c5d5e;
- font-size: 16px;
- line-height: 42px;
-
- .author {
- color: #5c5d5e;
- }
-
- .issue-id {
- color: #5c5d5e;
- }
- }
-
.issue-title {
margin: 0;
font-size: 23px;
@@ -80,6 +49,21 @@
margin-bottom: 0;
}
}
+
+ section {
+ border-right: 1px solid #ECEEF1;
+
+ > .tab-content {
+ margin-right: 1px;
+ }
+
+ .issue-discussion > .gray-content-block,
+ > .gray-content-block {
+ margin-top: 0;
+ border-top: none;
+ margin-right: -15px;
+ }
+ }
}
.issuable-filter-count {
@@ -101,84 +85,72 @@
}
}
-.cross-project-reference {
- text-align: center;
- width: 100%;
-
- .slead {
- padding: 5px;
- }
+.issuable-sidebar {
+ .block {
+ @include clearfix;
+ padding: $gl-padding 0;
+ border-bottom: 1px solid #F0F0F0;
- span, button {
- background-color: $background-color;
+ &:last-child {
+ border: none;
+ }
}
-}
-.awards {
- @include clearfix;
- line-height: 34px;
- margin: 2px 0;
+ .title {
+ color: $gl-text-color;
+ margin-bottom: 8px;
- .award {
- @include border-radius(5px);
-
- border: 1px solid;
- padding: 0px 10px;
- float: left;
- margin: 0 5px;
- border-color: $border-color;
- cursor: pointer;
-
- &.active {
- border-color: $border-gray-light;
- background-color: $gray-light;
+ .avatar {
+ margin-left: 0;
+ }
- .counter {
- font-weight: bold;
- }
+ label {
+ font-weight: normal;
+ margin-right: 4px;
}
- .icon {
- float: left;
- margin-right: 10px;
+ .edit-link {
+ color: $gl-gray;
}
+ }
+
+ .cross-project-reference {
+ font-weight: bold;
+ color: $gl-link-color;
- .counter {
- float: left;
+ button {
+ float: right;
}
}
- .awards-controls {
- margin-left: 10px;
- float: left;
+ .selectbox {
+ display: none
+ }
- .add-award {
- font-size: 24px;
- color: $gl-gray;
- position: relative;
- top: 2px;
+ .btn-clipboard {
+ color: $gl-gray;
+ }
- &:hover,
- &:link {
- text-decoration: none;
- }
- }
+ .participants .avatar {
+ margin-top: 6px;
+ margin-right: 2px;
+ }
+}
- .awards-menu {
- padding: $gl-padding;
- min-width: 214px;
+.issuable-title {
+ margin: -$gl-padding;
+ padding: 7px $gl-padding;
+ margin-bottom: 0px;
+ border-bottom: 1px solid $border-color;
+ color: #5c5d5e;
+ font-size: 16px;
+ line-height: 42px;
- > li {
- cursor: pointer;
- margin: 5px;
- }
- }
+ .author {
+ color: #5c5d5e;
}
- .awards-menu{
- li {
- float: left;
- margin: 3px;
- }
+ .issuable-id {
+ color: #5c5d5e;
}
}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index f5548c5b88b..a652b65502f 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -60,6 +60,26 @@ form.edit-issue {
margin: 0;
}
+.merge-requests-title {
+ font-size: 16px;
+ font-weight: 600;
+}
+
+.merge-request-id {
+ display: inline-block;
+ width: 3em;
+}
+
+.merge-request-info {
+ padding-left: 5px;
+}
+
+.merge-request-status {
+ color: $gl-gray;
+ font-size: 15px;
+ font-weight: bold;
+}
+
.merge-request,
.issue {
&.today {
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index fc8c7161991..502e9552acd 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -121,10 +121,6 @@
}
}
-.merge-request-details {
- margin-bottom: $gl-padding;
-}
-
.mr_source_commit,
.mr_target_commit {
.commit {
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index a9bcfc7456a..9dd16f8c735 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -13,6 +13,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end
end
+ def reset_runners_token
+ @application_setting.reset_runners_registration_token!
+ flash[:notice] = 'New runners registration token has been generated!'
+ redirect_to admin_runners_path
+ end
+
private
def set_application_setting
diff --git a/app/controllers/admin/builds_controller.rb b/app/controllers/admin/builds_controller.rb
new file mode 100644
index 00000000000..83d9684c706
--- /dev/null
+++ b/app/controllers/admin/builds_controller.rb
@@ -0,0 +1,23 @@
+class Admin::BuildsController < Admin::ApplicationController
+ def index
+ @scope = params[:scope]
+ @all_builds = Ci::Build
+ @builds = @all_builds.order('created_at DESC')
+ @builds =
+ case @scope
+ when 'all'
+ @builds
+ when 'finished'
+ @builds.finished
+ else
+ @builds.running_or_pending.reverse_order
+ end
+ @builds = @builds.page(params[:page]).per(30)
+ end
+
+ def cancel_all
+ Ci::Build.running_or_pending.each(&:cancel)
+
+ redirect_to admin_builds_path
+ end
+end
diff --git a/app/controllers/admin/runner_projects_controller.rb b/app/controllers/admin/runner_projects_controller.rb
new file mode 100644
index 00000000000..d25619d94e0
--- /dev/null
+++ b/app/controllers/admin/runner_projects_controller.rb
@@ -0,0 +1,35 @@
+class Admin::RunnerProjectsController < Admin::ApplicationController
+ before_action :project, only: [:create]
+
+ def index
+ @runner_projects = project.runner_projects.all
+ @runner_project = project.runner_projects.new
+ end
+
+ def create
+ @runner = Ci::Runner.find(params[:runner_project][:runner_id])
+
+ if @runner.assign_to(@project, current_user)
+ redirect_to admin_runner_path(@runner)
+ else
+ redirect_to admin_runner_path(@runner), alert: 'Failed adding runner to project'
+ end
+ end
+
+ def destroy
+ rp = Ci::RunnerProject.find(params[:id])
+ runner = rp.runner
+ rp.destroy
+
+ redirect_to admin_runner_path(runner)
+ end
+
+ private
+
+ def project
+ @project = Project.find_with_namespace(
+ [params[:namespace_id], '/', params[:project_id]].join('')
+ )
+ @project || render_404
+ end
+end
diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb
new file mode 100644
index 00000000000..a701d49b844
--- /dev/null
+++ b/app/controllers/admin/runners_controller.rb
@@ -0,0 +1,63 @@
+class Admin::RunnersController < Admin::ApplicationController
+ before_action :runner, except: :index
+
+ def index
+ @runners = Ci::Runner.order('id DESC')
+ @runners = @runners.search(params[:search]) if params[:search].present?
+ @runners = @runners.page(params[:page]).per(30)
+ @active_runners_cnt = Ci::Runner.online.count
+ end
+
+ def show
+ @builds = @runner.builds.order('id DESC').first(30)
+ @projects =
+ if params[:search].present?
+ ::Project.search(params[:search])
+ else
+ Project.all
+ end
+ @projects = @projects.where.not(id: @runner.projects.select(:id)) if @runner.projects.any?
+ @projects = @projects.page(params[:page]).per(30)
+ end
+
+ def update
+ @runner.update_attributes(runner_params)
+
+ respond_to do |format|
+ format.js
+ format.html { redirect_to admin_runner_path(@runner) }
+ end
+ end
+
+ def destroy
+ @runner.destroy
+
+ redirect_to admin_runners_path
+ end
+
+ def resume
+ if @runner.update_attributes(active: true)
+ redirect_to admin_runners_path, notice: 'Runner was successfully updated.'
+ else
+ redirect_to admin_runners_path, alert: 'Runner was not updated.'
+ end
+ end
+
+ def pause
+ if @runner.update_attributes(active: false)
+ redirect_to admin_runners_path, notice: 'Runner was successfully updated.'
+ else
+ redirect_to admin_runners_path, alert: 'Runner was not updated.'
+ end
+ end
+
+ private
+
+ def runner
+ @runner ||= Ci::Runner.find(params[:id])
+ end
+
+ def runner_params
+ params.require(:runner).permit(:token, :description, :tag_list, :active)
+ end
+end
diff --git a/app/controllers/ci/admin/application_controller.rb b/app/controllers/ci/admin/application_controller.rb
deleted file mode 100644
index 4ec2dc9c2cf..00000000000
--- a/app/controllers/ci/admin/application_controller.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-module Ci
- module Admin
- class ApplicationController < Ci::ApplicationController
- before_action :authenticate_user!
- before_action :authenticate_admin!
-
- layout "ci/admin"
- end
- end
-end
diff --git a/app/controllers/ci/admin/application_settings_controller.rb b/app/controllers/ci/admin/application_settings_controller.rb
deleted file mode 100644
index 71e253fac67..00000000000
--- a/app/controllers/ci/admin/application_settings_controller.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-module Ci
- class Admin::ApplicationSettingsController < Ci::Admin::ApplicationController
- before_action :set_application_setting
-
- def show
- end
-
- def update
- if @application_setting.update_attributes(application_setting_params)
- redirect_to ci_admin_application_settings_path,
- notice: 'Application settings saved successfully'
- else
- render :show
- end
- end
-
- private
-
- def set_application_setting
- @application_setting = Ci::ApplicationSetting.current
- @application_setting ||= Ci::ApplicationSetting.create_from_defaults
- end
-
- def application_setting_params
- params.require(:application_setting).permit(
- :all_broken_builds,
- :add_pusher,
- )
- end
- end
-end
diff --git a/app/controllers/ci/admin/builds_controller.rb b/app/controllers/ci/admin/builds_controller.rb
deleted file mode 100644
index 38abfdeafbf..00000000000
--- a/app/controllers/ci/admin/builds_controller.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-module Ci
- class Admin::BuildsController < Ci::Admin::ApplicationController
- def index
- @scope = params[:scope]
- @builds = Ci::Build.order('created_at DESC').page(params[:page]).per(30)
-
- @builds =
- case @scope
- when "pending"
- @builds.pending
- when "running"
- @builds.running
- else
- @builds
- end
- end
- end
-end
diff --git a/app/controllers/ci/admin/events_controller.rb b/app/controllers/ci/admin/events_controller.rb
deleted file mode 100644
index 5939efff980..00000000000
--- a/app/controllers/ci/admin/events_controller.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module Ci
- class Admin::EventsController < Ci::Admin::ApplicationController
- EVENTS_PER_PAGE = 50
-
- def index
- @events = Ci::Event.admin.order('created_at DESC').page(params[:page]).per(EVENTS_PER_PAGE)
- end
- end
-end
diff --git a/app/controllers/ci/admin/projects_controller.rb b/app/controllers/ci/admin/projects_controller.rb
deleted file mode 100644
index 5bbd0ce7396..00000000000
--- a/app/controllers/ci/admin/projects_controller.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module Ci
- class Admin::ProjectsController < Ci::Admin::ApplicationController
- def index
- @projects = Ci::Project.ordered_by_last_commit_date.page(params[:page]).per(30)
- end
-
- def destroy
- project.destroy
-
- redirect_to ci_projects_url
- end
-
- protected
-
- def project
- @project ||= Ci::Project.find(params[:id])
- end
- end
-end
diff --git a/app/controllers/ci/admin/runner_projects_controller.rb b/app/controllers/ci/admin/runner_projects_controller.rb
deleted file mode 100644
index e7de6eb12ca..00000000000
--- a/app/controllers/ci/admin/runner_projects_controller.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-module Ci
- class Admin::RunnerProjectsController < Ci::Admin::ApplicationController
- layout 'ci/project'
-
- def index
- @runner_projects = project.runner_projects.all
- @runner_project = project.runner_projects.new
- end
-
- def create
- @runner = Ci::Runner.find(params[:runner_project][:runner_id])
-
- if @runner.assign_to(project, current_user)
- redirect_to ci_admin_runner_path(@runner)
- else
- redirect_to ci_admin_runner_path(@runner), alert: 'Failed adding runner to project'
- end
- end
-
- def destroy
- rp = Ci::RunnerProject.find(params[:id])
- runner = rp.runner
- rp.destroy
-
- redirect_to ci_admin_runner_path(runner)
- end
-
- private
-
- def project
- @project ||= Ci::Project.find(params[:project_id])
- end
- end
-end
diff --git a/app/controllers/ci/admin/runners_controller.rb b/app/controllers/ci/admin/runners_controller.rb
deleted file mode 100644
index 0cafad27418..00000000000
--- a/app/controllers/ci/admin/runners_controller.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-module Ci
- class Admin::RunnersController < Ci::Admin::ApplicationController
- before_action :runner, except: :index
-
- def index
- @runners = Ci::Runner.order('id DESC')
- @runners = @runners.search(params[:search]) if params[:search].present?
- @runners = @runners.page(params[:page]).per(30)
- @active_runners_cnt = Ci::Runner.online.count
- end
-
- def show
- @builds = @runner.builds.order('id DESC').first(30)
- @projects = Ci::Project.all
- if params[:search].present?
- @gl_projects = ::Project.search(params[:search])
- @projects = @projects.where(gitlab_id: @gl_projects.select(:id))
- end
- @projects = @projects.where("ci_projects.id NOT IN (?)", @runner.projects.pluck(:id)) if @runner.projects.any?
- @projects = @projects.joins(:gl_project)
- @projects = @projects.page(params[:page]).per(30)
- end
-
- def update
- @runner.update_attributes(runner_params)
-
- respond_to do |format|
- format.js
- format.html { redirect_to ci_admin_runner_path(@runner) }
- end
- end
-
- def destroy
- @runner.destroy
-
- redirect_to ci_admin_runners_path
- end
-
- def resume
- if @runner.update_attributes(active: true)
- redirect_to ci_admin_runners_path, notice: 'Runner was successfully updated.'
- else
- redirect_to ci_admin_runners_path, alert: 'Runner was not updated.'
- end
- end
-
- def pause
- if @runner.update_attributes(active: false)
- redirect_to ci_admin_runners_path, notice: 'Runner was successfully updated.'
- else
- redirect_to ci_admin_runners_path, alert: 'Runner was not updated.'
- end
- end
-
- def assign_all
- Ci::Project.unassigned(@runner).all.each do |project|
- @runner.assign_to(project, current_user)
- end
-
- redirect_to ci_admin_runner_path(@runner), notice: "Runner was assigned to all projects"
- end
-
- private
-
- def runner
- @runner ||= Ci::Runner.find(params[:id])
- end
-
- def runner_params
- params.require(:runner).permit(:token, :description, :tag_list, :active)
- end
- end
-end
diff --git a/app/controllers/ci/application_controller.rb b/app/controllers/ci/application_controller.rb
index 848f2b4e314..c420b59c3a2 100644
--- a/app/controllers/ci/application_controller.rb
+++ b/app/controllers/ci/application_controller.rb
@@ -4,24 +4,16 @@ module Ci
"app/helpers/ci"
end
- helper_method :gl_project
-
private
- def authenticate_token!
- unless project.valid_token?(params[:token])
- return head(403)
- end
- end
-
def authorize_access_project!
- unless can?(current_user, :read_project, gl_project)
+ unless can?(current_user, :read_project, project)
return page_404
end
end
def authorize_manage_builds!
- unless can?(current_user, :manage_builds, gl_project)
+ unless can?(current_user, :manage_builds, project)
return page_404
end
end
@@ -31,7 +23,7 @@ module Ci
end
def authorize_manage_project!
- unless can?(current_user, :admin_project, gl_project)
+ unless can?(current_user, :admin_project, project)
return page_404
end
end
@@ -58,9 +50,5 @@ module Ci
count: count
}
end
-
- def gl_project
- ::Project.find(@project.gitlab_id)
- end
end
end
diff --git a/app/controllers/ci/lints_controller.rb b/app/controllers/ci/lints_controller.rb
index a4f6aff49b4..7ed78ff8e98 100644
--- a/app/controllers/ci/lints_controller.rb
+++ b/app/controllers/ci/lints_controller.rb
@@ -1,5 +1,5 @@
module Ci
- class LintsController < Ci::ApplicationController
+ class LintsController < ApplicationController
before_action :authenticate_user!
def show
diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb
index 8406399fb60..3004c2d27f0 100644
--- a/app/controllers/ci/projects_controller.rb
+++ b/app/controllers/ci/projects_controller.rb
@@ -3,13 +3,12 @@ module Ci
before_action :project, except: [:index]
before_action :authenticate_user!, except: [:index, :build, :badge]
before_action :authorize_access_project!, except: [:index, :badge]
- before_action :authorize_manage_project!, only: [:toggle_shared_runners, :dumped_yaml]
before_action :no_cache, only: [:badge]
protect_from_forgery
def show
# Temporary compatibility with CI badges pointing to CI project page
- redirect_to namespace_project_path(project.gl_project.namespace, project.gl_project)
+ redirect_to namespace_project_path(project.namespace, project)
end
# Project status badge
@@ -20,16 +19,10 @@ module Ci
send_file image.path, filename: image.name, disposition: 'inline', type:"image/svg+xml"
end
- def toggle_shared_runners
- project.toggle!(:shared_runners_enabled)
-
- redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project)
- end
-
protected
def project
- @project ||= Ci::Project.find(params[:id])
+ @project ||= Project.find_by(ci_id: params[:id].to_i)
end
def no_cache
diff --git a/app/controllers/ci/runner_projects_controller.rb b/app/controllers/ci/runner_projects_controller.rb
deleted file mode 100644
index 9d555313369..00000000000
--- a/app/controllers/ci/runner_projects_controller.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-module Ci
- class RunnerProjectsController < Ci::ApplicationController
- before_action :authenticate_user!
- before_action :project
- before_action :authorize_manage_project!
-
- def create
- @runner = Ci::Runner.find(params[:runner_project][:runner_id])
-
- return head(403) unless current_user.ci_authorized_runners.include?(@runner)
-
- path = runners_path(@project.gl_project)
-
- if @runner.assign_to(project, current_user)
- redirect_to path
- else
- redirect_to path, alert: 'Failed adding runner to project'
- end
- end
-
- def destroy
- runner_project = project.runner_projects.find(params[:id])
- runner_project.destroy
-
- redirect_to runners_path(@project.gl_project)
- end
-
- private
-
- def project
- @project ||= Ci::Project.find(params[:project_id])
- end
- end
-end
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 7d0d57858e0..dd32d509191 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -31,8 +31,4 @@ class Projects::ApplicationController < ApplicationController
def builds_enabled
return render_404 unless @project.builds_enabled?
end
-
- def ci_project
- @ci_project ||= @project.ensure_gitlab_ci_project
- end
end
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 4638f77b887..26ba12520c7 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -1,5 +1,4 @@
class Projects::BuildsController < Projects::ApplicationController
- before_action :ci_project
before_action :build, except: [:index, :cancel_all]
before_action :authorize_manage_builds!, except: [:index, :show, :status]
@@ -9,7 +8,7 @@ class Projects::BuildsController < Projects::ApplicationController
def index
@scope = params[:scope]
- @all_builds = project.ci_builds
+ @all_builds = project.builds
@builds = @all_builds.order('created_at DESC')
@builds =
case @scope
@@ -24,13 +23,13 @@ class Projects::BuildsController < Projects::ApplicationController
end
def cancel_all
- @project.ci_builds.running_or_pending.each(&:cancel)
+ @project.builds.running_or_pending.each(&:cancel)
redirect_to namespace_project_builds_path(project.namespace, project)
end
def show
- @builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC')
+ @builds = @project.ci_commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id)
@commit = @build.commit
@@ -77,7 +76,7 @@ class Projects::BuildsController < Projects::ApplicationController
private
def build
- @build ||= ci_project.builds.unscoped.find_by!(id: params[:id])
+ @build ||= project.builds.unscoped.find_by!(id: params[:id])
end
def artifacts_file
@@ -85,7 +84,7 @@ class Projects::BuildsController < Projects::ApplicationController
end
def build_path(build)
- namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
+ namespace_project_build_path(build.project.namespace, build.project, build)
end
def authorize_manage_builds!
diff --git a/app/controllers/projects/ci_services_controller.rb b/app/controllers/projects/ci_services_controller.rb
deleted file mode 100644
index 550a019e8e2..00000000000
--- a/app/controllers/projects/ci_services_controller.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-class Projects::CiServicesController < Projects::ApplicationController
- before_action :ci_project
- before_action :authorize_admin_project!
-
- layout "project_settings"
-
- def index
- @ci_project.build_missing_services
- @services = @ci_project.services.reload
- end
-
- def edit
- service
- end
-
- def update
- if service.update_attributes(service_params)
- redirect_to edit_namespace_project_ci_service_path(@project.namespace, @project, service.to_param)
- else
- render 'edit'
- end
- end
-
- def test
- last_build = @project.ci_builds.last
-
- if service.execute(last_build)
- message = { notice: 'We successfully tested the service' }
- else
- message = { alert: 'We tried to test the service but error occurred' }
- end
-
- redirect_back_or_default(options: message)
- end
-
- private
-
- def service
- @service ||= @ci_project.services.find { |service| service.to_param == params[:id] }
- end
-
- def service_params
- params.require(:service).permit(
- :type, :active, :webhook, :notify_only_broken_builds,
- :email_recipients, :email_only_broken_builds, :email_add_pusher,
- :hipchat_token, :hipchat_room, :hipchat_server
- )
- end
-end
diff --git a/app/controllers/projects/ci_settings_controller.rb b/app/controllers/projects/ci_settings_controller.rb
deleted file mode 100644
index a263242a850..00000000000
--- a/app/controllers/projects/ci_settings_controller.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-class Projects::CiSettingsController < Projects::ApplicationController
- before_action :ci_project
- before_action :authorize_admin_project!
-
- layout "project_settings"
-
- def edit
- end
-
- def update
- if ci_project.update_attributes(project_params)
- Ci::EventService.new.change_project_settings(current_user, ci_project)
-
- redirect_to edit_namespace_project_ci_settings_path(project.namespace, project), notice: 'Project was successfully updated.'
- else
- render action: "edit"
- end
- end
-
- def destroy
- ci_project.destroy
- Ci::EventService.new.remove_project(current_user, ci_project)
- project.gitlab_ci_service.update_attributes(active: false)
-
- redirect_to project_path(project), notice: "CI was disabled for this project"
- end
-
- protected
-
- def project_params
- params.require(:project).permit(:path, :timeout, :timeout_in_minutes, :default_ref, :always_build,
- :polling_interval, :public, :ssh_url_to_repo, :allow_git_fetch, :email_recipients,
- :email_add_pusher, :email_only_broken_builds, :coverage_regex, :shared_runners_enabled, :token,
- { variables_attributes: [:id, :key, :value, :_destroy] })
- end
-end
diff --git a/app/controllers/projects/ci_web_hooks_controller.rb b/app/controllers/projects/ci_web_hooks_controller.rb
deleted file mode 100644
index a2d470d4a69..00000000000
--- a/app/controllers/projects/ci_web_hooks_controller.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-class Projects::CiWebHooksController < Projects::ApplicationController
- before_action :ci_project
- before_action :authorize_admin_project!
-
- layout "project_settings"
-
- def index
- @web_hooks = @ci_project.web_hooks
- @web_hook = Ci::WebHook.new
- end
-
- def create
- @web_hook = @ci_project.web_hooks.new(web_hook_params)
- @web_hook.save
-
- if @web_hook.valid?
- redirect_to namespace_project_ci_web_hooks_path(@project.namespace, @project)
- else
- @web_hooks = @ci_project.web_hooks.select(&:persisted?)
- render :index
- end
- end
-
- def test
- Ci::TestHookService.new.execute(hook, current_user)
-
- redirect_back_or_default(default: { action: 'index' })
- end
-
- def destroy
- hook.destroy
-
- redirect_to namespace_project_ci_web_hooks_path(@project.namespace, @project)
- end
-
- private
-
- def hook
- @web_hook ||= @ci_project.web_hooks.find(params[:id])
- end
-
- def web_hook_params
- params.require(:web_hook).permit(:url)
- end
-end
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index e8af205b788..0aaba3792bf 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -31,7 +31,6 @@ class Projects::CommitController < Projects::ApplicationController
end
def builds
- @ci_project = @project.gitlab_ci_project
end
def cancel_builds
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index a8f47069bb4..d13ea9f34b6 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -25,13 +25,11 @@ class Projects::GraphsController < Projects::ApplicationController
end
def ci
- ci_project = @project.gitlab_ci_project
-
@charts = {}
- @charts[:week] = Ci::Charts::WeekChart.new(ci_project)
- @charts[:month] = Ci::Charts::MonthChart.new(ci_project)
- @charts[:year] = Ci::Charts::YearChart.new(ci_project)
- @charts[:build_times] = Ci::Charts::BuildTime.new(ci_project)
+ @charts[:week] = Ci::Charts::WeekChart.new(project)
+ @charts[:month] = Ci::Charts::MonthChart.new(project)
+ @charts[:year] = Ci::Charts::YearChart.new(project)
+ @charts[:build_times] = Ci::Charts::BuildTime.new(project)
end
def languages
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 6a62880cb71..5fd4f855dec 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -53,6 +53,7 @@ class Projects::HooksController < Projects::ApplicationController
def hook_params
params.require(:hook).permit(:url, :push_events, :issues_events,
- :merge_requests_events, :tag_push_events, :note_events, :enable_ssl_verification)
+ :merge_requests_events, :tag_push_events, :note_events,
+ :build_events, :enable_ssl_verification)
end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index ae474cf8d68..b59b52291fb 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -58,10 +58,10 @@ class Projects::IssuesController < Projects::ApplicationController
end
def show
- @participants = @issue.participants(current_user)
@note = @project.notes.new(noteable: @issue)
@notes = @issue.notes.nonawards.with_associations.fresh
@noteable = @issue
+ @merge_requests = @issue.referenced_merge_requests
respond_with(@issue)
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 530f3d3dcb8..fffd90d87eb 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -81,8 +81,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def builds
- @ci_project = @merge_request.source_project.gitlab_ci_project
-
respond_to do |format|
format.html { render 'show' }
format.json { render json: { html: view_to_html_string('projects/merge_requests/show/_builds') } }
@@ -106,7 +104,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@first_commit = @merge_request.first_commit
@diffs = @merge_request.compare_diffs
- @ci_project = @source_project.gitlab_ci_project
@ci_commit = @merge_request.ci_commit
@statuses = @ci_commit.statuses if @ci_commit
@@ -279,8 +276,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def define_show_vars
- @participants = @merge_request.participants(current_user)
-
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
@notes = @merge_request.mr_and_commit_notes.nonawards.inc_author.fresh
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 88b949a27ab..ae6e9f6fd38 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -13,7 +13,8 @@ class Projects::NotesController < Projects::ApplicationController
@notes.each do |note|
notes_json[:notes] << {
id: note.id,
- html: note_to_html(note)
+ html: note_to_html(note),
+ valid: note.valid?
}
end
diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb
new file mode 100644
index 00000000000..e2785caa2fb
--- /dev/null
+++ b/app/controllers/projects/runner_projects_controller.rb
@@ -0,0 +1,26 @@
+class Projects::RunnerProjectsController < Projects::ApplicationController
+ before_action :authorize_admin_project!
+
+ layout 'project_settings'
+
+ def create
+ @runner = Ci::Runner.find(params[:runner_project][:runner_id])
+
+ return head(403) unless current_user.ci_authorized_runners.include?(@runner)
+
+ path = runners_path(project)
+
+ if @runner.assign_to(project, current_user)
+ redirect_to path
+ else
+ redirect_to path, alert: 'Failed adding runner to project'
+ end
+ end
+
+ def destroy
+ runner_project = project.runner_projects.find(params[:id])
+ runner_project.destroy
+
+ redirect_to runners_path(project)
+ end
+end
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index bfbcf2567f3..4993b2648a5 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -1,14 +1,13 @@
class Projects::RunnersController < Projects::ApplicationController
- before_action :ci_project
before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
before_action :authorize_admin_project!
layout 'project_settings'
def index
- @runners = @ci_project.runners.ordered
+ @runners = project.runners.ordered
@specific_runners = current_user.ci_authorized_runners.
- where.not(id: @ci_project.runners).
+ where.not(id: project.runners).
ordered.page(params[:page]).per(20)
@shared_runners = Ci::Runner.shared.active
@shared_runners_count = @shared_runners.count(:all)
@@ -26,7 +25,7 @@ class Projects::RunnersController < Projects::ApplicationController
end
def destroy
- if @runner.only_for?(@ci_project)
+ if @runner.only_for?(project)
@runner.destroy
end
@@ -52,10 +51,16 @@ class Projects::RunnersController < Projects::ApplicationController
def show
end
+ def toggle_shared_runners
+ project.toggle!(:shared_runners_enabled)
+
+ redirect_to namespace_project_runners_path(project.namespace, project)
+ end
+
protected
def set_runner
- @runner ||= @ci_project.runners.find(params[:id])
+ @runner ||= project.runners.find(params[:id])
end
def runner_params
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 42dbb497e01..6e7590260ff 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -6,7 +6,9 @@ class Projects::ServicesController < Projects::ApplicationController
:description, :issues_url, :new_issue_url, :restrict_to_branch, :channel,
:colorize_messages, :channels,
:push_events, :issues_events, :merge_requests_events, :tag_push_events,
- :note_events, :send_from_committer_email, :disable_diffs, :external_wiki_url,
+ :note_events, :build_events,
+ :notify_only_broken_builds, :add_pusher,
+ :send_from_committer_email, :disable_diffs, :external_wiki_url,
:notify, :color,
:server_host, :server_port, :default_irc_uri, :enable_ssl_verification]
diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb
index 782ebd01b05..30adfad1daa 100644
--- a/app/controllers/projects/triggers_controller.rb
+++ b/app/controllers/projects/triggers_controller.rb
@@ -1,22 +1,21 @@
class Projects::TriggersController < Projects::ApplicationController
- before_action :ci_project
before_action :authorize_admin_project!
layout 'project_settings'
def index
- @triggers = @ci_project.triggers
+ @triggers = project.triggers
@trigger = Ci::Trigger.new
end
def create
- @trigger = @ci_project.triggers.new
+ @trigger = project.triggers.new
@trigger.save
if @trigger.valid?
redirect_to namespace_project_triggers_path(@project.namespace, @project)
else
- @triggers = @ci_project.triggers.select(&:persisted?)
+ @triggers = project.triggers.select(&:persisted?)
render :index
end
end
@@ -30,6 +29,6 @@ class Projects::TriggersController < Projects::ApplicationController
private
def trigger
- @trigger ||= @ci_project.triggers.find(params[:id])
+ @trigger ||= project.triggers.find(params[:id])
end
end
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index d6561a45a70..10efafea9db 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -1,5 +1,4 @@
class Projects::VariablesController < Projects::ApplicationController
- before_action :ci_project
before_action :authorize_admin_project!
layout 'project_settings'
@@ -8,9 +7,7 @@ class Projects::VariablesController < Projects::ApplicationController
end
def update
- if ci_project.update_attributes(project_params)
- Ci::EventService.new.change_project_settings(current_user, ci_project)
-
+ if project.update_attributes(project_params)
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variables were successfully updated.'
else
render action: 'show'
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 10c75370d7b..bf5e25ff895 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -210,10 +210,10 @@ class ProjectsController < ApplicationController
def project_params
params.require(:project).permit(
- :name, :path, :description, :issues_tracker, :tag_list,
+ :name, :path, :description, :issues_tracker, :tag_list, :runners_token,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
- :builds_enabled
+ :builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
)
end
diff --git a/app/helpers/ci/gitlab_helper.rb b/app/helpers/ci/gitlab_helper.rb
deleted file mode 100644
index e34c8be1dfc..00000000000
--- a/app/helpers/ci/gitlab_helper.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module Ci
- module GitlabHelper
- def no_turbolink
- { :"data-no-turbolink" => "data-no-turbolink" }
- end
-
- def yaml_web_editor_link(project)
- commits = project.commits
-
- if commits.any? && commits.last.ci_yaml_file
- "#{project.gitlab_url}/edit/master/.gitlab-ci.yml"
- else
- "#{project.gitlab_url}/new/master"
- end
- end
- end
-end
diff --git a/app/helpers/ci/projects_helper.rb b/app/helpers/ci/projects_helper.rb
deleted file mode 100644
index fd991a4165a..00000000000
--- a/app/helpers/ci/projects_helper.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-module Ci
- module ProjectsHelper
- def ref_tab_class ref = nil
- 'active' if ref == @ref
- end
-
- def success_ratio(success_builds, failed_builds)
- failed_builds = failed_builds.count(:all)
- success_builds = success_builds.count(:all)
-
- return 100 if failed_builds.zero?
-
- ratio = (success_builds.to_f / (success_builds + failed_builds)) * 100
- ratio.to_i
- end
-
- def markdown_badge_code(project, ref)
- url = status_ci_project_url(project, ref: ref, format: 'png')
- "[![build status](#{url})](#{ci_project_url(project, ref: ref)})"
- end
-
- def html_badge_code(project, ref)
- url = status_ci_project_url(project, ref: ref, format: 'png')
- "<a href='#{ci_project_url(project, ref: ref)}'><img src='#{url}' /></a>"
- end
-
- def project_uses_specific_runner?(project)
- project.runners.any?
- end
-
- def no_runners_for_project?(project)
- project.runners.blank? &&
- Ci::Runner.shared.blank?
- end
- end
-end
diff --git a/app/helpers/ci_badge_helper.rb b/app/helpers/ci_badge_helper.rb
new file mode 100644
index 00000000000..27386133e36
--- /dev/null
+++ b/app/helpers/ci_badge_helper.rb
@@ -0,0 +1,13 @@
+module CiBadgeHelper
+ def markdown_badge_code(project, ref)
+ url = status_ci_project_url(project, ref: ref, format: 'png')
+ link = namespace_project_commits_path(project.namespace, project, ref)
+ "[![build status](#{url})](#{link})"
+ end
+
+ def html_badge_code(project, ref)
+ url = status_ci_project_url(project, ref: ref, format: 'png')
+ link = namespace_project_commits_path(project.namespace, project, ref)
+ "<a href='#{link}'><img src='#{url}' /></a>"
+ end
+end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index 8e1f8f9ba6d..8554074d619 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -1,6 +1,6 @@
module CiStatusHelper
def ci_status_path(ci_commit)
- project = ci_commit.gl_project
+ project = ci_commit.project
builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
end
@@ -52,15 +52,20 @@ module CiStatusHelper
'circle'
end
- icon(icon_name)
+ icon(icon_name + ' fw')
end
def render_ci_status(ci_commit)
link_to ci_status_path(ci_commit),
- class: "c#{ci_status_color(ci_commit)}",
+ class: "ci-status-link c#{ci_status_color(ci_commit)}",
title: "Build #{ci_status_label(ci_commit)}",
data: { toggle: 'tooltip', placement: 'left' } do
ci_status_icon(ci_commit)
end
end
+
+ def no_runners_for_project?(project)
+ project.runners.blank? &&
+ Ci::Runner.shared.blank?
+ end
end
diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb
index 1e372d5631d..c2ab80f2e0d 100644
--- a/app/helpers/graph_helper.rb
+++ b/app/helpers/graph_helper.rb
@@ -16,4 +16,14 @@ module GraphHelper
ids = parents.map { |p| p.id }
ids.zip(parent_spaces)
end
+
+ def success_ratio(success_builds, failed_builds)
+ failed_builds = failed_builds.count(:all)
+ success_builds = success_builds.count(:all)
+
+ return 100 if failed_builds.zero?
+
+ ratio = (success_builds.to_f / (success_builds + failed_builds)) * 100
+ ratio.to_i
+ end
end
diff --git a/app/helpers/runners_helper.rb b/app/helpers/runners_helper.rb
index 46eb82a354f..9fb42487a75 100644
--- a/app/helpers/runners_helper.rb
+++ b/app/helpers/runners_helper.rb
@@ -19,7 +19,7 @@ module RunnersHelper
id = "\##{runner.id}"
if current_user && current_user.admin
- link_to ci_admin_runner_path(runner) do
+ link_to admin_runner_path(runner) do
display_name + id
end
else
diff --git a/app/helpers/triggers_helper.rb b/app/helpers/triggers_helper.rb
index 2a3a7e80fca..8cad994d10f 100644
--- a/app/helpers/triggers_helper.rb
+++ b/app/helpers/triggers_helper.rb
@@ -1,5 +1,5 @@
module TriggersHelper
- def ci_build_trigger_url(project_id, ref_name)
- "#{Settings.gitlab_ci.url}/ci/api/v1/projects/#{project_id}/refs/#{ref_name}/trigger"
+ def builds_trigger_url(project_id)
+ "#{Settings.gitlab.url}/api/v3/projects/#{project_id}/trigger/builds"
end
end
diff --git a/app/mailers/ci/emails/builds.rb b/app/mailers/ci/emails/builds.rb
deleted file mode 100644
index 6fb4fba85e5..00000000000
--- a/app/mailers/ci/emails/builds.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module Ci
- module Emails
- module Builds
- def build_fail_email(build_id, to)
- @build = Ci::Build.find(build_id)
- @project = @build.project
- mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
- end
-
- def build_success_email(build_id, to)
- @build = Ci::Build.find(build_id)
- @project = @build.project
- mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha))
- end
- end
- end
-end
diff --git a/app/mailers/ci/notify.rb b/app/mailers/ci/notify.rb
deleted file mode 100644
index 404842cf213..00000000000
--- a/app/mailers/ci/notify.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-module Ci
- class Notify < ActionMailer::Base
- include Ci::Emails::Builds
-
- add_template_helper Ci::GitlabHelper
-
- default_url_options[:host] = Gitlab.config.gitlab.host
- default_url_options[:protocol] = Gitlab.config.gitlab.protocol
- default_url_options[:port] = Gitlab.config.gitlab.port unless Gitlab.config.gitlab_on_standard_port?
- default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root
-
- default from: Gitlab.config.gitlab.email_from
-
- # Just send email with 3 seconds delay
- def self.delay
- delay_for(2.seconds)
- end
-
- private
-
- # Formats arguments into a String suitable for use as an email subject
- #
- # extra - Extra Strings to be inserted into the subject
- #
- # Examples
- #
- # >> subject('Lorem ipsum')
- # => "GitLab-CI | Lorem ipsum"
- #
- # # Automatically inserts Project name when @project is set
- # >> @project = Project.last
- # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
- # >> subject('Lorem ipsum')
- # => "GitLab-CI | Ruby on Rails | Lorem ipsum "
- #
- # # Accepts multiple arguments
- # >> subject('Lorem ipsum', 'Dolor sit amet')
- # => "GitLab-CI | Lorem ipsum | Dolor sit amet"
- def subject(*extra)
- subject = "GitLab-CI"
- subject << (@project ? " | #{@project.name}" : "")
- subject << " | " + extra.join(' | ') if extra.present?
- subject
- end
- end
-end
diff --git a/app/mailers/emails/builds.rb b/app/mailers/emails/builds.rb
new file mode 100644
index 00000000000..d58609a2de5
--- /dev/null
+++ b/app/mailers/emails/builds.rb
@@ -0,0 +1,15 @@
+module Emails
+ module Builds
+ def build_fail_email(build_id, to)
+ @build = Ci::Build.find(build_id)
+ @project = @build.project
+ mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
+ end
+
+ def build_success_email(build_id, to)
+ @build = Ci::Build.find(build_id)
+ @project = @build.project
+ mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha))
+ end
+ end
+end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 0534eb025cd..9beb0de68f3 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -7,6 +7,7 @@ class Notify < BaseMailer
include Emails::Projects
include Emails::Profile
include Emails::Groups
+ include Emails::Builds
add_template_helper MergeRequestsHelper
add_template_helper EmailsHelper
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 1880ad9f33c..faa0bdf840b 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -27,9 +27,13 @@
# admin_notification_email :string(255)
# shared_runners_enabled :boolean default(TRUE), not null
# max_artifacts_size :integer default(100), not null
+# runners_registration_token :string(255)
#
class ApplicationSetting < ActiveRecord::Base
+ include TokenAuthenticatable
+ add_authentication_token_field :runners_registration_token
+
CACHE_KEY = 'application_setting.last'
serialize :restricted_visibility_levels
@@ -74,6 +78,8 @@ class ApplicationSetting < ActiveRecord::Base
end
end
+ before_save :ensure_runners_registration_token
+
after_commit do
Rails.cache.write(CACHE_KEY, self)
end
@@ -128,5 +134,4 @@ class ApplicationSetting < ActiveRecord::Base
/x)
self.restricted_signup_domains.reject! { |d| d.empty? }
end
-
end
diff --git a/app/models/ci/application_setting.rb b/app/models/ci/application_setting.rb
deleted file mode 100644
index 7f5df8ce6c4..00000000000
--- a/app/models/ci/application_setting.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_application_settings
-#
-# id :integer not null, primary key
-# all_broken_builds :boolean
-# add_pusher :boolean
-# created_at :datetime
-# updated_at :datetime
-#
-
-module Ci
- class ApplicationSetting < ActiveRecord::Base
- extend Ci::Model
- CACHE_KEY = 'ci_application_setting.last'
-
- after_commit do
- Rails.cache.write(CACHE_KEY, self)
- end
-
- def self.expire
- Rails.cache.delete(CACHE_KEY)
- end
-
- def self.current
- Rails.cache.fetch(CACHE_KEY) do
- Ci::ApplicationSetting.last
- end
- end
-
- def self.create_from_defaults
- create(
- all_broken_builds: Settings.gitlab_ci['all_broken_builds'],
- add_pusher: Settings.gitlab_ci['add_pusher'],
- )
- end
- end
-end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 52ce1b920fa..6d9cdb95295 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -84,6 +84,7 @@ module Ci
new_build.options = build.options
new_build.commands = build.commands
new_build.tag_list = build.tag_list
+ new_build.gl_project_id = build.gl_project_id
new_build.commit_id = build.commit_id
new_build.name = build.name
new_build.allow_failure = build.allow_failure
@@ -96,21 +97,16 @@ module Ci
end
state_machine :status, initial: :pending do
- after_transition any => [:success, :failed, :canceled] do |build, transition|
- return unless build.gl_project
-
- project = build.project
+ after_transition pending: :running do |build, transition|
+ build.execute_hooks
+ end
- if project.web_hooks?
- Ci::WebHookService.new.build_end(build)
- end
+ after_transition any => [:success, :failed, :canceled] do |build, transition|
+ return unless build.project
+ build.update_coverage
build.commit.create_next_builds(build)
- project.execute_services(build)
-
- if project.coverage_enabled?
- build.update_coverage
- end
+ build.execute_hooks
end
end
@@ -119,7 +115,7 @@ module Ci
end
def retryable?
- commands.present?
+ project.builds_enabled? && commands.present?
end
def retried?
@@ -132,7 +128,7 @@ module Ci
end
def timeout
- project.timeout
+ project.build_timeout
end
def variables
@@ -151,26 +147,21 @@ module Ci
project.name
end
- def project_recipients
- recipients = project.email_recipients.split(' ')
-
- if project.email_add_pusher? && user.present? && user.notification_email.present?
- recipients << user.notification_email
- end
-
- recipients.uniq
- end
-
def repo_url
- project.repo_url_with_auth
+ auth = "gitlab-ci-token:#{token}@"
+ project.http_url_to_repo.sub(/^https?:\/\//) do |prefix|
+ prefix + auth
+ end
end
def allow_git_fetch
- project.allow_git_fetch
+ project.build_allow_git_fetch
end
def update_coverage
- coverage = extract_coverage(trace, project.coverage_regex)
+ coverage_regex = project.build_coverage_regex
+ return unless coverage_regex
+ coverage = extract_coverage(trace, coverage_regex)
if coverage.is_a? Numeric
update_attributes(coverage: coverage)
@@ -203,7 +194,7 @@ module Ci
def trace
trace = raw_trace
if project && trace.present?
- trace.gsub(project.token, 'xxxxxx')
+ trace.gsub(project.runners_token, 'xxxxxx')
else
trace
end
@@ -230,29 +221,29 @@ module Ci
end
def token
- project.token
+ project.runners_token
end
def valid_token? token
- project.valid_token? token
+ project.valid_runners_token? token
end
def target_url
Gitlab::Application.routes.url_helpers.
- namespace_project_build_url(gl_project.namespace, gl_project, self)
+ namespace_project_build_url(project.namespace, project, self)
end
def cancel_url
if active?
Gitlab::Application.routes.url_helpers.
- cancel_namespace_project_build_path(gl_project.namespace, gl_project, self)
+ cancel_namespace_project_build_path(project.namespace, project, self)
end
end
def retry_url
if retryable?
Gitlab::Application.routes.url_helpers.
- retry_namespace_project_build_path(gl_project.namespace, gl_project, self)
+ retry_namespace_project_build_path(project.namespace, project, self)
end
end
@@ -271,10 +262,18 @@ module Ci
def download_url
if artifacts_file.exists?
Gitlab::Application.routes.url_helpers.
- download_namespace_project_build_path(gl_project.namespace, gl_project, self)
+ download_namespace_project_build_path(project.namespace, project, self)
end
end
+ def execute_hooks
+ build_data = Gitlab::BuildDataBuilder.build(self)
+ project.execute_hooks(build_data.dup, :build_hooks)
+ project.execute_services(build_data.dup, :build_hooks)
+ end
+
+
+
private
def yaml_variables
diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb
index 75465685e98..6bf596e5d3e 100644
--- a/app/models/ci/commit.rb
+++ b/app/models/ci/commit.rb
@@ -20,8 +20,8 @@ module Ci
class Commit < ActiveRecord::Base
extend Ci::Model
- belongs_to :gl_project, class_name: '::Project', foreign_key: :gl_project_id
- has_many :statuses, dependent: :destroy, class_name: 'CommitStatus'
+ belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
+ has_many :statuses, class_name: 'CommitStatus'
has_many :builds, class_name: 'Ci::Build'
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
@@ -38,10 +38,6 @@ module Ci
sha
end
- def project
- @project ||= gl_project.ensure_gitlab_ci_project
- end
-
def project_id
project.id
end
@@ -57,7 +53,7 @@ module Ci
end
def valid_commit_sha
- if self.sha == Ci::Git::BLANK_SHA
+ if self.sha == Gitlab::Git::BLANK_SHA
self.errors.add(:sha, " cant be 00000000 (branch removal)")
end
end
@@ -79,7 +75,7 @@ module Ci
end
def commit_data
- @commit ||= gl_project.commit(sha)
+ @commit ||= project.commit(sha)
rescue
nil
end
@@ -178,16 +174,18 @@ module Ci
duration_array.reduce(:+).to_i
end
+ def started_at
+ @started_at ||= statuses.order('started_at ASC').first.try(:started_at)
+ end
+
def finished_at
@finished_at ||= statuses.order('finished_at DESC').first.try(:finished_at)
end
def coverage
- if project.coverage_enabled?
- coverage_array = latest_builds.map(&:coverage).compact
- if coverage_array.size >= 1
- '%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
- end
+ coverage_array = latest_builds.map(&:coverage).compact
+ if coverage_array.size >= 1
+ '%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
end
end
@@ -197,7 +195,7 @@ module Ci
def config_processor
return nil unless ci_yaml_file
- @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, gl_project.path_with_namespace)
+ @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace)
rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
save_yaml_error(e.message)
nil
@@ -207,7 +205,7 @@ module Ci
end
def ci_yaml_file
- @ci_yaml_file ||= gl_project.repository.blob_at(sha, '.gitlab-ci.yml').data
+ @ci_yaml_file ||= project.repository.blob_at(sha, '.gitlab-ci.yml').data
rescue
nil
end
@@ -220,6 +218,16 @@ module Ci
update!(committed_at: DateTime.now)
end
+ ##
+ # This method checks if build status should be displayed.
+ #
+ # Build status should be available only if builds are enabled
+ # on project level and `.gitlab-ci.yml` file is present.
+ #
+ def show_build_status?
+ project.builds_enabled? && ci_yaml_file
+ end
+
private
def save_yaml_error(error)
diff --git a/app/models/ci/event.rb b/app/models/ci/event.rb
deleted file mode 100644
index 8c39be42677..00000000000
--- a/app/models/ci/event.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_events
-#
-# id :integer not null, primary key
-# project_id :integer
-# user_id :integer
-# is_admin :integer
-# description :text
-# created_at :datetime
-# updated_at :datetime
-#
-
-module Ci
- class Event < ActiveRecord::Base
- extend Ci::Model
-
- belongs_to :project, class_name: 'Ci::Project'
-
- validates :description,
- presence: true,
- length: { in: 5..200 }
-
- scope :admin, ->(){ where(is_admin: true) }
- scope :project_wide, ->(){ where(is_admin: false) }
- end
-end
diff --git a/app/models/ci/project.rb b/app/models/ci/project.rb
deleted file mode 100644
index 669ee1cc0d2..00000000000
--- a/app/models/ci/project.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_projects
-#
-# id :integer not null, primary key
-# name :string(255)
-# timeout :integer default(3600), not null
-# created_at :datetime
-# updated_at :datetime
-# token :string(255)
-# default_ref :string(255)
-# path :string(255)
-# always_build :boolean default(FALSE), not null
-# polling_interval :integer
-# public :boolean default(FALSE), not null
-# ssh_url_to_repo :string(255)
-# gitlab_id :integer
-# allow_git_fetch :boolean default(TRUE), not null
-# email_recipients :string(255) default(""), not null
-# email_add_pusher :boolean default(TRUE), not null
-# email_only_broken_builds :boolean default(TRUE), not null
-# skip_refs :string(255)
-# coverage_regex :string(255)
-# shared_runners_enabled :boolean default(FALSE)
-# generated_yaml_config :text
-#
-
-module Ci
- class Project < ActiveRecord::Base
- extend Ci::Model
-
- include Ci::ProjectStatus
-
- belongs_to :gl_project, class_name: '::Project', foreign_key: :gitlab_id
-
- has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
- has_many :runners, through: :runner_projects, class_name: 'Ci::Runner'
- has_many :web_hooks, dependent: :destroy, class_name: 'Ci::WebHook'
- has_many :events, dependent: :destroy, class_name: 'Ci::Event'
- has_many :variables, dependent: :destroy, class_name: 'Ci::Variable'
- has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger'
-
- # Project services
- has_many :services, dependent: :destroy, class_name: 'Ci::Service'
- has_one :hip_chat_service, dependent: :destroy, class_name: 'Ci::HipChatService'
- has_one :slack_service, dependent: :destroy, class_name: 'Ci::SlackService'
- has_one :mail_service, dependent: :destroy, class_name: 'Ci::MailService'
-
- accepts_nested_attributes_for :variables, allow_destroy: true
-
- delegate :name_with_namespace, :path_with_namespace, :web_url, :http_url_to_repo, :ssh_url_to_repo, to: :gl_project
-
- #
- # Validations
- #
- validates_presence_of :timeout, :token, :default_ref, :gitlab_id
-
- validates_uniqueness_of :gitlab_id
-
- validates :polling_interval,
- presence: true,
- if: ->(project) { project.always_build.present? }
-
- before_validation :set_default_values
-
- class << self
- include Ci::CurrentSettings
-
- def unassigned(runner)
- joins("LEFT JOIN #{Ci::RunnerProject.table_name} ON #{Ci::RunnerProject.table_name}.project_id = #{Ci::Project.table_name}.id " \
- "AND #{Ci::RunnerProject.table_name}.runner_id = #{runner.id}").
- where("#{Ci::RunnerProject.table_name}.project_id" => nil)
- end
-
- def ordered_by_last_commit_date
- last_commit_subquery = "(SELECT gl_project_id, MAX(committed_at) committed_at FROM #{Ci::Commit.table_name} GROUP BY gl_project_id)"
- joins("LEFT JOIN #{last_commit_subquery} AS last_commit ON #{Ci::Project.table_name}.gitlab_id = last_commit.gl_project_id").
- joins(:gl_project).
- order("CASE WHEN last_commit.committed_at IS NULL THEN 1 ELSE 0 END, last_commit.committed_at DESC")
- end
- end
-
- def name
- name_with_namespace
- end
-
- def path
- path_with_namespace
- end
-
- def gitlab_url
- web_url
- end
-
- def any_runners?(&block)
- if runners.active.any?(&block)
- return true
- end
-
- shared_runners_enabled && Ci::Runner.shared.active.any?(&block)
- end
-
- def set_default_values
- self.token = SecureRandom.hex(15) if self.token.blank?
- self.default_ref ||= 'master'
- end
-
- def tracked_refs
- @tracked_refs ||= default_ref.split(",").map { |ref| ref.strip }
- end
-
- def valid_token? token
- self.token && self.token == token
- end
-
- def no_running_builds?
- # Get running builds not later than 3 days ago to ignore hangs
- builds.running.where("updated_at > ?", 3.days.ago).empty?
- end
-
- def email_notification?
- email_add_pusher || email_recipients.present?
- end
-
- def web_hooks?
- web_hooks.any?
- end
-
- def services?
- services.any?
- end
-
- def timeout_in_minutes
- timeout / 60
- end
-
- def timeout_in_minutes=(value)
- self.timeout = value.to_i * 60
- end
-
- def coverage_enabled?
- coverage_regex.present?
- end
-
- # Build a clone-able repo url
- # using http and basic auth
- def repo_url_with_auth
- auth = "gitlab-ci-token:#{token}@"
- http_url_to_repo.sub(/^https?:\/\//) do |prefix|
- prefix + auth
- end
- end
-
- def available_services_names
- %w(slack mail hip_chat)
- end
-
- def build_missing_services
- available_services_names.each do |service_name|
- service = services.find { |service| service.to_param == service_name }
-
- # If service is available but missing in db
- # we should create an instance. Ex `create_gitlab_ci_service`
- self.send :"create_#{service_name}_service" if service.nil?
- end
- end
-
- def execute_services(data)
- services.each do |service|
-
- # Call service hook only if it is active
- begin
- service.execute(data) if service.active && service.can_execute?(data)
- rescue => e
- logger.error(e)
- end
- end
- end
-
- def setup_finished?
- commits.any?
- end
-
- def commits
- gl_project.ci_commits.ordered
- end
-
- def builds
- gl_project.ci_builds
- end
- end
-end
diff --git a/app/models/ci/project_status.rb b/app/models/ci/project_status.rb
deleted file mode 100644
index 2d35aeac225..00000000000
--- a/app/models/ci/project_status.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-module Ci
- module ProjectStatus
- def status
- last_commit.status if last_commit
- end
-
- def broken?
- last_commit.failed? if last_commit
- end
-
- def success?
- last_commit.success? if last_commit
- end
-
- def broken_or_success?
- broken? || success?
- end
-
- def last_commit
- @last_commit ||= commits.last if commits.any?
- end
-
- def last_commit_date
- last_commit.try(:created_at)
- end
-
- def human_status
- status
- end
- end
-end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 89710485811..38b20cd7faa 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -25,7 +25,7 @@ module Ci
has_many :builds, class_name: 'Ci::Build'
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
- has_many :projects, through: :runner_projects, class_name: 'Ci::Project'
+ has_many :projects, through: :runner_projects, class_name: '::Project', foreign_key: :gl_project_id
has_one :last_build, ->() { order('id DESC') }, class_name: 'Ci::Build'
@@ -45,10 +45,6 @@ module Ci
query: "%#{query.try(:downcase)}%")
end
- def gl_projects_ids
- projects.select(:gitlab_id)
- end
-
def set_default_values
self.token = SecureRandom.hex(15) if self.token.blank?
end
diff --git a/app/models/ci/runner_project.rb b/app/models/ci/runner_project.rb
index 3f4fc43873e..93d9be144e8 100644
--- a/app/models/ci/runner_project.rb
+++ b/app/models/ci/runner_project.rb
@@ -14,8 +14,8 @@ module Ci
extend Ci::Model
belongs_to :runner, class_name: 'Ci::Runner'
- belongs_to :project, class_name: 'Ci::Project'
+ belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
- validates_uniqueness_of :runner_id, scope: :project_id
+ validates_uniqueness_of :runner_id, scope: :gl_project_id
end
end
diff --git a/app/models/ci/service.rb b/app/models/ci/service.rb
deleted file mode 100644
index 8063c51e82b..00000000000
--- a/app/models/ci/service.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-# To add new service you should build a class inherited from Service
-# and implement a set of methods
-module Ci
- class Service < ActiveRecord::Base
- extend Ci::Model
-
- serialize :properties, JSON
-
- default_value_for :active, false
-
- after_initialize :initialize_properties
-
- belongs_to :project, class_name: 'Ci::Project'
-
- validates :project_id, presence: true
-
- def activated?
- active
- end
-
- def category
- :common
- end
-
- def initialize_properties
- self.properties = {} if properties.nil?
- end
-
- def title
- # implement inside child
- end
-
- def description
- # implement inside child
- end
-
- def help
- # implement inside child
- end
-
- def to_param
- # implement inside child
- end
-
- def fields
- # implement inside child
- []
- end
-
- def can_test?
- project.builds.any?
- end
-
- def can_execute?(build)
- true
- end
-
- def execute(build)
- # implement inside child
- end
-
- # Provide convenient accessor methods
- # for each serialized property.
- def self.prop_accessor(*args)
- args.each do |arg|
- class_eval %{
- def #{arg}
- (properties || {})['#{arg}']
- end
-
- def #{arg}=(value)
- self.properties ||= {}
- self.properties['#{arg}'] = value
- end
- }
- end
- end
-
- def self.boolean_accessor(*args)
- self.prop_accessor(*args)
-
- args.each do |arg|
- class_eval %{
- def #{arg}?
- ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(#{arg})
- end
- }
- end
- end
- end
-end
diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb
index b73c35d5ae5..23516709a41 100644
--- a/app/models/ci/trigger.rb
+++ b/app/models/ci/trigger.rb
@@ -16,7 +16,7 @@ module Ci
acts_as_paranoid
- belongs_to :project, class_name: 'Ci::Project'
+ belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
validates_presence_of :token
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index b3d2b809e03..56759d3e50f 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -15,10 +15,10 @@ module Ci
class Variable < ActiveRecord::Base
extend Ci::Model
- belongs_to :project, class_name: 'Ci::Project'
+ belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
validates_presence_of :key
- validates_uniqueness_of :key, scope: :project_id
+ validates_uniqueness_of :key, scope: :gl_project_id
attr_encrypted :value, mode: :per_attribute_iv_and_salt, key: Gitlab::Application.secrets.db_key_base
end
diff --git a/app/models/ci/web_hook.rb b/app/models/ci/web_hook.rb
deleted file mode 100644
index 0dc15eb6683..00000000000
--- a/app/models/ci/web_hook.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_web_hooks
-#
-# id :integer not null, primary key
-# url :string(255) not null
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-#
-
-module Ci
- class WebHook < ActiveRecord::Base
- extend Ci::Model
-
- include HTTParty
-
- belongs_to :project, class_name: 'Ci::Project'
-
- # HTTParty timeout
- default_timeout 10
-
- validates :url, presence: true, url: true
-
- def execute(data)
- parsed_url = URI.parse(url)
- if parsed_url.userinfo.blank?
- Ci::WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }, verify: false)
- else
- post_url = url.gsub("#{parsed_url.userinfo}@", "")
- auth = {
- username: URI.decode(parsed_url.user),
- password: URI.decode(parsed_url.password),
- }
- Ci::WebHook.post(post_url,
- body: data.to_json,
- headers: { "Content-Type" => "application/json" },
- verify: false,
- basic_auth: auth)
- end
- end
- end
-end
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index ff619965a57..21c5c87bc3d 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -30,6 +30,7 @@
class CommitStatus < ActiveRecord::Base
self.table_name = 'ci_builds'
+ belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
belongs_to :commit, class_name: 'Ci::Commit'
belongs_to :user
@@ -76,7 +77,7 @@ class CommitStatus < ActiveRecord::Base
end
after_transition [:pending, :running] => :success do |build, transition|
- MergeRequests::MergeWhenBuildSucceedsService.new(build.commit.gl_project, nil).trigger(build)
+ MergeRequests::MergeWhenBuildSucceedsService.new(build.commit.project, nil).trigger(build)
end
state :pending, value: 'pending'
@@ -86,8 +87,7 @@ class CommitStatus < ActiveRecord::Base
state :canceled, value: 'canceled'
end
- delegate :sha, :short_sha, :gl_project,
- to: :commit, prefix: false
+ delegate :sha, :short_sha, to: :commit, prefix: false
# TODO: this should be removed with all references
def before_sha
diff --git a/app/models/concerns/token_authenticatable.rb b/app/models/concerns/token_authenticatable.rb
index 9b88ec1cc38..56d38fe8250 100644
--- a/app/models/concerns/token_authenticatable.rb
+++ b/app/models/concerns/token_authenticatable.rb
@@ -1,31 +1,43 @@
module TokenAuthenticatable
extend ActiveSupport::Concern
- module ClassMethods
- def find_by_authentication_token(authentication_token = nil)
- if authentication_token
- where(authentication_token: authentication_token).first
- end
+ class_methods do
+ def authentication_token_fields
+ @token_fields || []
end
- end
- def ensure_authentication_token
- if authentication_token.blank?
- self.authentication_token = generate_authentication_token
- end
- end
+ private
+
+ def add_authentication_token_field(token_field)
+ @token_fields = [] unless @token_fields
+ @token_fields << token_field
- def reset_authentication_token!
- self.authentication_token = generate_authentication_token
- save
+ define_singleton_method("find_by_#{token_field}") do |token|
+ where(token_field => token).first if token
+ end
+
+ define_method("ensure_#{token_field}") do
+ current_token = read_attribute(token_field)
+ if current_token.blank?
+ write_attribute(token_field, generate_token_for(token_field))
+ else
+ current_token
+ end
+ end
+
+ define_method("reset_#{token_field}!") do
+ write_attribute(token_field, generate_token_for(token_field))
+ save!
+ end
+ end
end
private
- def generate_authentication_token
+ def generate_token_for(token_field)
loop do
token = Devise.friendly_token
- break token unless self.class.unscoped.where(authentication_token: token).first
+ break token unless self.class.unscoped.where(token_field => token).first
end
end
end
diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb
index 337b3097126..22638057773 100644
--- a/app/models/hooks/project_hook.rb
+++ b/app/models/hooks/project_hook.rb
@@ -25,4 +25,5 @@ class ProjectHook < WebHook
scope :issue_hooks, -> { where(issues_events: true) }
scope :note_hooks, -> { where(note_events: true) }
scope :merge_request_hooks, -> { where(merge_requests_events: true) }
+ scope :build_hooks, -> { where(build_events: true) }
end
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index 715ec5908b7..40eb0e20b4b 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -26,6 +26,7 @@ class WebHook < ActiveRecord::Base
default_value_for :note_events, false
default_value_for :merge_requests_events, false
default_value_for :tag_push_events, false
+ default_value_for :build_events, false
default_value_for :enable_ssl_verification, true
# HTTParty timeout
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 187b6482b6c..e04035b3af8 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -83,6 +83,14 @@ class Issue < ActiveRecord::Base
reference
end
+ def referenced_merge_requests
+ references = [self, *notes].flat_map do |note|
+ note.all_references(load_lazy_references: false).merge_requests
+ end.uniq
+
+ Gitlab::Markdown::ReferenceFilter::LazyReference.load(references).uniq.sort_by(&:iid)
+ end
+
# Reset issue events cache
#
# Since we do cache @event we need to reset cache in special cases:
diff --git a/app/models/project.rb b/app/models/project.rb
index e78868af1cc..e1f7bf971e3 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -56,6 +56,7 @@ class Project < ActiveRecord::Base
default_value_for :wiki_enabled, gitlab_config_features.wiki
default_value_for :wall_enabled, false
default_value_for :snippets_enabled, gitlab_config_features.snippets
+ default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled }
# set last_activity_at to the same as created_at
after_create :set_last_activity_at
@@ -77,10 +78,10 @@ class Project < ActiveRecord::Base
# Project services
has_many :services
- has_one :gitlab_ci_service, dependent: :destroy
has_one :campfire_service, dependent: :destroy
has_one :drone_ci_service, dependent: :destroy
has_one :emails_on_push_service, dependent: :destroy
+ has_one :builds_email_service, dependent: :destroy
has_one :irker_service, dependent: :destroy
has_one :pivotaltracker_service, dependent: :destroy
has_one :hipchat_service, dependent: :destroy
@@ -121,14 +122,21 @@ class Project < ActiveRecord::Base
has_many :deploy_keys, through: :deploy_keys_projects
has_many :users_star_projects, dependent: :destroy
has_many :starrers, through: :users_star_projects, source: :user
- has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id
- has_many :ci_builds, through: :ci_commits, source: :builds, dependent: :destroy, class_name: 'Ci::Build'
has_many :releases, dependent: :destroy
has_many :lfs_objects_projects, dependent: :destroy
has_many :lfs_objects, through: :lfs_objects_projects
has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
- has_one :gitlab_ci_project, dependent: :destroy, class_name: "Ci::Project", foreign_key: :gitlab_id
+
+ has_many :commit_statuses, dependent: :destroy, class_name: 'CommitStatus', foreign_key: :gl_project_id
+ has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id
+ has_many :builds, class_name: 'Ci::Build', foreign_key: :gl_project_id # the builds are created from the commit_statuses
+ has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject', foreign_key: :gl_project_id
+ has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'
+ has_many :variables, dependent: :destroy, class_name: 'Ci::Variable', foreign_key: :gl_project_id
+ has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger', foreign_key: :gl_project_id
+
+ accepts_nested_attributes_for :variables, allow_destroy: true
delegate :name, to: :owner, allow_nil: true, prefix: true
delegate :members, to: :team, prefix: true
@@ -161,6 +169,11 @@ class Project < ActiveRecord::Base
if: ->(project) { project.avatar.present? && project.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
+ before_validation :set_runners_token_token
+ def set_runners_token_token
+ self.runners_token = SecureRandom.hex(15) if self.runners_token.blank?
+ end
+
mount_uploader :avatar, AvatarUploader
# Scopes
@@ -256,6 +269,10 @@ class Project < ActiveRecord::Base
projects.iwhere('projects.path' => project_path).take
end
+ def find_by_ci_id(id)
+ find_by(ci_id: id.to_i)
+ end
+
def visibility_levels
Gitlab::VisibilityLevel.options
end
@@ -790,28 +807,6 @@ class Project < ActiveRecord::Base
ci_commit(sha) || ci_commits.create(sha: sha)
end
- def ensure_gitlab_ci_project
- gitlab_ci_project || create_gitlab_ci_project(
- shared_runners_enabled: current_application_settings.shared_runners_enabled
- )
- end
-
- # TODO: this should be migrated to Project table,
- # the same as issues_enabled
- def builds_enabled
- gitlab_ci_service && gitlab_ci_service.active
- end
-
- def builds_enabled?
- builds_enabled
- end
-
- def builds_enabled=(value)
- service = gitlab_ci_service || create_gitlab_ci_service
- service.active = value
- service.save
- end
-
def enable_ci
self.builds_enabled = true
end
@@ -825,4 +820,34 @@ class Project < ActiveRecord::Base
forked_project_link.destroy
end
end
+
+ def any_runners?(&block)
+ if runners.active.any?(&block)
+ return true
+ end
+
+ shared_runners_enabled? && Ci::Runner.shared.active.any?(&block)
+ end
+
+ def valid_runners_token? token
+ self.runners_token && self.runners_token == token
+ end
+
+ # TODO (ayufan): For now we use runners_token (backward compatibility)
+ # In 8.4 every build will have its own individual token valid for time of build
+ def valid_build_token? token
+ self.builds_enabled? && self.runners_token && self.runners_token == token
+ end
+
+ def build_coverage_enabled?
+ build_coverage_regex.present?
+ end
+
+ def build_timeout_in_minutes
+ build_timeout / 60
+ end
+
+ def build_timeout_in_minutes=(value)
+ self.build_timeout = value.to_i * 60
+ end
end
diff --git a/app/models/project_services/builds_email_service.rb b/app/models/project_services/builds_email_service.rb
new file mode 100644
index 00000000000..8247c79fc33
--- /dev/null
+++ b/app/models/project_services/builds_email_service.rb
@@ -0,0 +1,90 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
+#
+
+class BuildsEmailService < Service
+ prop_accessor :recipients
+ boolean_accessor :add_pusher
+ boolean_accessor :notify_only_broken_builds
+ validates :recipients, presence: true, if: :activated?
+
+ def initialize_properties
+ if properties.nil?
+ self.properties = {}
+ self.notify_only_broken_builds = true
+ end
+ end
+
+ def title
+ 'Builds emails'
+ end
+
+ def description
+ 'Email the builds status to a list of recipients.'
+ end
+
+ def to_param
+ 'builds_email'
+ end
+
+ def supported_events
+ %w(build)
+ end
+
+ def execute(push_data)
+ return unless supported_events.include?(push_data[:object_kind])
+
+ if should_build_be_notified?(push_data)
+ BuildEmailWorker.perform_async(
+ push_data[:build_id],
+ all_recipients(push_data),
+ push_data,
+ )
+ end
+ end
+
+ def fields
+ [
+ { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by comma' },
+ { type: 'checkbox', name: 'add_pusher', label: 'Add pusher to recipients list' },
+ { type: 'checkbox', name: 'notify_only_broken_builds' },
+ ]
+ end
+
+ def should_build_be_notified?(data)
+ case data[:build_status]
+ when 'success'
+ !notify_only_broken_builds?
+ when 'failed'
+ true
+ else
+ false
+ end
+ end
+
+ def all_recipients(data)
+ all_recipients = recipients.split(',')
+
+ if add_pusher? && data[:user][:email]
+ all_recipients << "#{data[:user][:email]}"
+ end
+
+ all_recipients
+ end
+end
diff --git a/app/models/project_services/ci/hip_chat_message.rb b/app/models/project_services/ci/hip_chat_message.rb
deleted file mode 100644
index d89466b689f..00000000000
--- a/app/models/project_services/ci/hip_chat_message.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-module Ci
- class HipChatMessage
- include Gitlab::Application.routes.url_helpers
-
- attr_reader :build
-
- def initialize(build)
- @build = build
- end
-
- def to_s
- lines = Array.new
- lines.push("<a href=\"#{ci_project_url(project)}\">#{project.name}</a> - ")
- lines.push("<a href=\"#{builds_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}\">Commit ##{commit.id}</a></br>")
- lines.push("#{commit.short_sha} #{commit.git_author_name} - #{commit.git_commit_message}</br>")
- lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).")
- lines.join('')
- end
-
- def status_color(build_or_commit=nil)
- build_or_commit ||= commit_status
- case build_or_commit
- when :success
- 'green'
- when :failed, :canceled
- 'red'
- else # :pending, :running or unknown
- 'yellow'
- end
- end
-
- def notify?
- [:failed, :canceled].include?(commit_status)
- end
-
-
- private
-
- def commit
- build.commit
- end
-
- def project
- commit.project
- end
-
- def build_status
- build.status.to_sym
- end
-
- def commit_status
- commit.status.to_sym
- end
-
- def humanized_status(build_or_commit=nil)
- build_or_commit ||= commit_status
- case build_or_commit
- when :pending
- "Pending"
- when :running
- "Running"
- when :failed
- "Failed"
- when :success
- "Successful"
- when :canceled
- "Canceled"
- else
- "Unknown"
- end
- end
- end
-end
diff --git a/app/models/project_services/ci/hip_chat_service.rb b/app/models/project_services/ci/hip_chat_service.rb
deleted file mode 100644
index 0df03890efb..00000000000
--- a/app/models/project_services/ci/hip_chat_service.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-module Ci
- class HipChatService < Ci::Service
- prop_accessor :hipchat_token, :hipchat_room, :hipchat_server
- boolean_accessor :notify_only_broken_builds
- validates :hipchat_token, presence: true, if: :activated?
- validates :hipchat_room, presence: true, if: :activated?
- default_value_for :notify_only_broken_builds, true
-
- def title
- "HipChat"
- end
-
- def description
- "Private group chat, video chat, instant messaging for teams"
- end
-
- def help
- end
-
- def to_param
- 'hip_chat'
- end
-
- def fields
- [
- { type: 'text', name: 'hipchat_token', label: 'Token', placeholder: '' },
- { type: 'text', name: 'hipchat_room', label: 'Room', placeholder: '' },
- { type: 'text', name: 'hipchat_server', label: 'Server', placeholder: 'https://hipchat.example.com', help: 'Leave blank for default' },
- { type: 'checkbox', name: 'notify_only_broken_builds', label: 'Notify only broken builds' }
- ]
- end
-
- def can_execute?(build)
- return if build.allow_failure?
-
- commit = build.commit
- return unless commit
- return unless commit.latest_builds.include? build
-
- case commit.status.to_sym
- when :failed
- true
- when :success
- true unless notify_only_broken_builds?
- else
- false
- end
- end
-
- def execute(build)
- msg = Ci::HipChatMessage.new(build)
- opts = default_options.merge(
- token: hipchat_token,
- room: hipchat_room,
- server: server_url,
- color: msg.status_color,
- notify: msg.notify?
- )
- Ci::HipChatNotifierWorker.perform_async(msg.to_s, opts)
- end
-
- private
-
- def default_options
- {
- service_name: 'GitLab CI',
- message_format: 'html'
- }
- end
-
- def server_url
- if hipchat_server.blank?
- 'https://api.hipchat.com'
- else
- hipchat_server
- end
- end
- end
-end
diff --git a/app/models/project_services/ci/mail_service.rb b/app/models/project_services/ci/mail_service.rb
deleted file mode 100644
index bb961d06972..00000000000
--- a/app/models/project_services/ci/mail_service.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-module Ci
- class MailService < Ci::Service
- delegate :email_recipients, :email_recipients=,
- :email_add_pusher, :email_add_pusher=,
- :email_only_broken_builds, :email_only_broken_builds=, to: :project, prefix: false
-
- before_save :update_project
-
- default_value_for :active, true
-
- def title
- 'Mail'
- end
-
- def description
- 'Email notification'
- end
-
- def to_param
- 'mail'
- end
-
- def fields
- [
- { type: 'text', name: 'email_recipients', label: 'Recipients', help: 'Whitespace-separated list of recipient addresses' },
- { type: 'checkbox', name: 'email_add_pusher', label: 'Add pusher to recipients list' },
- { type: 'checkbox', name: 'email_only_broken_builds', label: 'Notify only broken builds' }
- ]
- end
-
- def can_execute?(build)
- return if build.allow_failure?
-
- # it doesn't make sense to send emails for retried builds
- commit = build.commit
- return unless commit
- return unless commit.latest_builds.include?(build)
-
- case build.status.to_sym
- when :failed
- true
- when :success
- true unless email_only_broken_builds
- else
- false
- end
- end
-
- def execute(build)
- build.project_recipients.each do |recipient|
- case build.status.to_sym
- when :success
- mailer.build_success_email(build.id, recipient).deliver_later
- when :failed
- mailer.build_fail_email(build.id, recipient).deliver_later
- end
- end
- end
-
- private
-
- def update_project
- project.save!
- end
-
- def mailer
- Ci::Notify
- end
- end
-end
diff --git a/app/models/project_services/ci/slack_message.rb b/app/models/project_services/ci/slack_message.rb
deleted file mode 100644
index 1a6ff8e34c9..00000000000
--- a/app/models/project_services/ci/slack_message.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-require 'slack-notifier'
-
-module Ci
- class SlackMessage
- include Gitlab::Application.routes.url_helpers
-
- def initialize(commit)
- @commit = commit
- end
-
- def pretext
- ''
- end
-
- def color
- attachment_color
- end
-
- def fallback
- format(attachment_message)
- end
-
- def attachments
- fields = []
-
- commit.latest_builds.each do |build|
- next if build.allow_failure?
- next unless build.failed?
- fields << {
- title: build.name,
- value: "Build <#{namespace_project_build_url(build.gl_project.namespace, build.gl_project, build)}|\##{build.id}> failed in #{build.duration.to_i} second(s)."
- }
- end
-
- [{
- text: attachment_message,
- color: attachment_color,
- fields: fields
- }]
- end
-
- private
-
- attr_reader :commit
-
- def attachment_message
- out = "<#{ci_project_url(project)}|#{project_name}>: "
- out << "Commit <#{builds_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}|\##{commit.id}> "
- out << "(<#{commit_sha_link}|#{commit.short_sha}>) "
- out << "of <#{commit_ref_link}|#{commit.ref}> "
- out << "by #{commit.git_author_name} " if commit.git_author_name
- out << "#{commit_status} in "
- out << "#{commit.duration} second(s)"
- end
-
- def format(string)
- Slack::Notifier::LinkFormatter.format(string)
- end
-
- def project
- commit.project
- end
-
- def project_name
- project.name
- end
-
- def commit_sha_link
- "#{project.gitlab_url}/commit/#{commit.sha}"
- end
-
- def commit_ref_link
- "#{project.gitlab_url}/commits/#{commit.ref}"
- end
-
- def attachment_color
- if commit.success?
- 'good'
- else
- 'danger'
- end
- end
-
- def commit_status
- if commit.success?
- 'succeeded'
- else
- 'failed'
- end
- end
- end
-end
diff --git a/app/models/project_services/ci/slack_service.rb b/app/models/project_services/ci/slack_service.rb
deleted file mode 100644
index 7064bfe78db..00000000000
--- a/app/models/project_services/ci/slack_service.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-module Ci
- class SlackService < Ci::Service
- prop_accessor :webhook
- boolean_accessor :notify_only_broken_builds
- validates :webhook, presence: true, if: :activated?
-
- default_value_for :notify_only_broken_builds, true
-
- def title
- 'Slack'
- end
-
- def description
- 'A team communication tool for the 21st century'
- end
-
- def to_param
- 'slack'
- end
-
- def help
- 'Visit https://www.slack.com/services/new/incoming-webhook. Then copy link and save project!' unless webhook.present?
- end
-
- def fields
- [
- { type: 'text', name: 'webhook', label: 'Webhook URL', placeholder: '' },
- { type: 'checkbox', name: 'notify_only_broken_builds', label: 'Notify only broken builds' }
- ]
- end
-
- def can_execute?(build)
- return if build.allow_failure?
-
- commit = build.commit
- return unless commit
- return unless commit.latest_builds.include?(build)
-
- case commit.status.to_sym
- when :failed
- true
- when :success
- true unless notify_only_broken_builds?
- else
- false
- end
- end
-
- def execute(build)
- message = Ci::SlackMessage.new(build.commit)
- options = default_options.merge(
- color: message.color,
- fallback: message.fallback,
- attachments: message.attachments
- )
- Ci::SlackNotifierWorker.perform_async(webhook, message.pretext, options)
- end
-
- private
-
- def default_options
- {
- username: 'GitLab CI'
- }
- end
- end
-end
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index 234e8e8b580..d73182d40ac 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -19,76 +19,5 @@
#
class GitlabCiService < CiService
- include Gitlab::Application.routes.url_helpers
-
- after_save :compose_service_hook, if: :activated?
- after_save :ensure_gitlab_ci_project, if: :activated?
-
- def compose_service_hook
- hook = service_hook || build_service_hook
- hook.save
- end
-
- def ensure_gitlab_ci_project
- return unless project
- project.ensure_gitlab_ci_project
- end
-
- def supported_events
- %w(push tag_push)
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
-
- ci_project = project.gitlab_ci_project
- if ci_project
- current_user = User.find_by(id: data[:user_id])
- Ci::CreateCommitService.new.execute(ci_project, current_user, data)
- end
- end
-
- def token
- if project.gitlab_ci_project.present?
- project.gitlab_ci_project.token
- end
- end
-
- def get_ci_commit(sha, ref)
- Ci::Project.find(project.gitlab_ci_project.id).commits.find_by_sha!(sha)
- end
-
- def commit_status(sha, ref)
- get_ci_commit(sha, ref).status
- rescue ActiveRecord::RecordNotFound
- :error
- end
-
- def commit_coverage(sha, ref)
- get_ci_commit(sha, ref).coverage
- rescue ActiveRecord::RecordNotFound
- :error
- end
-
- def build_page(sha, ref)
- if project.gitlab_ci_project.present?
- builds_namespace_project_commit_url(project.namespace, project, sha)
- end
- end
-
- def title
- 'GitLab CI'
- end
-
- def description
- 'Continuous integration server from GitLab'
- end
-
- def to_param
- 'gitlab_ci'
- end
-
- def fields
- []
- end
+ # this is no longer used
end
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index af2840a57f0..1e1686a11c6 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -22,8 +22,16 @@ class HipchatService < Service
MAX_COMMITS = 3
prop_accessor :token, :room, :server, :notify, :color, :api_version
+ boolean_accessor :notify_only_broken_builds
validates :token, presence: true, if: :activated?
+ def initialize_properties
+ if properties.nil?
+ self.properties = {}
+ self.notify_only_broken_builds = true
+ end
+ end
+
def title
'HipChat'
end
@@ -45,12 +53,13 @@ class HipchatService < Service
{ type: 'text', name: 'api_version',
placeholder: 'Leave blank for default (v2)' },
{ type: 'text', name: 'server',
- placeholder: 'Leave blank for default. https://hipchat.example.com' }
+ placeholder: 'Leave blank for default. https://hipchat.example.com' },
+ { type: 'checkbox', name: 'notify_only_broken_builds' },
]
end
def supported_events
- %w(push issue merge_request note tag_push)
+ %w(push issue merge_request note tag_push build)
end
def execute(data)
@@ -94,6 +103,8 @@ class HipchatService < Service
create_merge_request_message(data) unless is_update?(data)
when "note"
create_note_message(data)
+ when "build"
+ create_build_message(data) if should_build_be_notified?(data)
end
end
@@ -235,6 +246,20 @@ class HipchatService < Service
message
end
+ def create_build_message(data)
+ ref_type = data[:tag] ? 'tag' : 'branch'
+ ref = data[:ref]
+ sha = data[:sha]
+ user_name = data[:commit][:author_name]
+ status = data[:commit][:status]
+ duration = data[:commit][:duration]
+
+ branch_link = "<a href=\"#{project_url}/commits/#{URI.escape(ref)}\">#{ref}</a>"
+ commit_link = "<a href=\"#{project_url}/commit/#{URI.escape(sha)}/builds\">#{Commit.truncate_sha(sha)}</a>"
+
+ "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)"
+ end
+
def project_name
project.name_with_namespace.gsub(/\s/, '')
end
@@ -250,4 +275,24 @@ class HipchatService < Service
def is_update?(data)
data[:object_attributes][:action] == 'update'
end
+
+ def humanized_status(status)
+ case status
+ when 'success'
+ 'passed'
+ else
+ status
+ end
+ end
+
+ def should_build_be_notified?(data)
+ case data[:commit][:status]
+ when 'success'
+ !notify_only_broken_builds?
+ when 'failed'
+ true
+ else
+ false
+ end
+ end
end
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index 7cd5e892507..375b4534d07 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -20,8 +20,16 @@
class SlackService < Service
prop_accessor :webhook, :username, :channel
+ boolean_accessor :notify_only_broken_builds
validates :webhook, presence: true, if: :activated?
+ def initialize_properties
+ if properties.nil?
+ self.properties = {}
+ self.notify_only_broken_builds = true
+ end
+ end
+
def title
'Slack'
end
@@ -45,12 +53,13 @@ class SlackService < Service
{ type: 'text', name: 'webhook',
placeholder: 'https://hooks.slack.com/services/...' },
{ type: 'text', name: 'username', placeholder: 'username' },
- { type: 'text', name: 'channel', placeholder: '#channel' }
+ { type: 'text', name: 'channel', placeholder: '#channel' },
+ { type: 'checkbox', name: 'notify_only_broken_builds' },
]
end
def supported_events
- %w(push issue merge_request note tag_push)
+ %w(push issue merge_request note tag_push build)
end
def execute(data)
@@ -78,6 +87,8 @@ class SlackService < Service
MergeMessage.new(data) unless is_update?(data)
when "note"
NoteMessage.new(data)
+ when "build"
+ BuildMessage.new(data) if should_build_be_notified?(data)
end
opt = {}
@@ -86,7 +97,7 @@ class SlackService < Service
if message
notifier = Slack::Notifier.new(webhook, opt)
- notifier.ping(message.pretext, attachments: message.attachments)
+ notifier.ping(message.pretext, attachments: message.attachments, fallback: message.fallback)
end
end
@@ -103,9 +114,21 @@ class SlackService < Service
def is_update?(data)
data[:object_attributes][:action] == 'update'
end
+
+ def should_build_be_notified?(data)
+ case data[:commit][:status]
+ when 'success'
+ !notify_only_broken_builds?
+ when 'failed'
+ true
+ else
+ false
+ end
+ end
end
require "slack_service/issue_message"
require "slack_service/push_message"
require "slack_service/merge_message"
require "slack_service/note_message"
+require "slack_service/build_message"
diff --git a/app/models/project_services/slack_service/base_message.rb b/app/models/project_services/slack_service/base_message.rb
index aa00d6061a1..f1182824687 100644
--- a/app/models/project_services/slack_service/base_message.rb
+++ b/app/models/project_services/slack_service/base_message.rb
@@ -10,6 +10,9 @@ class SlackService
format(message)
end
+ def fallback
+ end
+
def attachments
raise NotImplementedError
end
diff --git a/app/models/project_services/slack_service/build_message.rb b/app/models/project_services/slack_service/build_message.rb
new file mode 100644
index 00000000000..c124cad4afd
--- /dev/null
+++ b/app/models/project_services/slack_service/build_message.rb
@@ -0,0 +1,82 @@
+class SlackService
+ class BuildMessage < BaseMessage
+ attr_reader :sha
+ attr_reader :ref_type
+ attr_reader :ref
+ attr_reader :status
+ attr_reader :project_name
+ attr_reader :project_url
+ attr_reader :user_name
+ attr_reader :duration
+
+ def initialize(params, commit = true)
+ @sha = params[:sha]
+ @ref_type = params[:tag] ? 'tag' : 'branch'
+ @ref = params[:ref]
+ @project_name = params[:project_name]
+ @project_url = params[:project_url]
+ @status = params[:commit][:status]
+ @user_name = params[:commit][:author_name]
+ @duration = params[:commit][:duration]
+ end
+
+ def pretext
+ ''
+ end
+
+ def fallback
+ format(message)
+ end
+
+ def attachments
+ [{ text: format(message), color: attachment_color }]
+ end
+
+ private
+
+ def message
+ "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status} in #{duration} second(s)"
+ end
+
+ def format(string)
+ Slack::Notifier::LinkFormatter.format(string)
+ end
+
+ def humanized_status
+ case status
+ when 'success'
+ 'passed'
+ else
+ status
+ end
+ end
+
+ def attachment_color
+ if status == 'success'
+ 'good'
+ else
+ 'danger'
+ end
+ end
+
+ def branch_url
+ "#{project_url}/commits/#{ref}"
+ end
+
+ def branch_link
+ "[#{ref}](#{branch_url})"
+ end
+
+ def project_link
+ "[#{project_name}](#{project_url})"
+ end
+
+ def commit_url
+ "#{project_url}/commit/#{sha}/builds"
+ end
+
+ def commit_link
+ "[#{Commit.truncate_sha(sha)}](#{commit_url})"
+ end
+ end
+end
diff --git a/app/models/service.rb b/app/models/service.rb
index d610abd1683..d3bf7f0ebd1 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -30,6 +30,7 @@ class Service < ActiveRecord::Base
default_value_for :merge_requests_events, true
default_value_for :tag_push_events, true
default_value_for :note_events, true
+ default_value_for :build_events, true
after_initialize :initialize_properties
@@ -40,13 +41,14 @@ class Service < ActiveRecord::Base
validates :project_id, presence: true, unless: Proc.new { |service| service.template? }
- scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
+ scope :visible, -> { where.not(type: ['GitlabIssueTrackerService', 'GitlabCiService']) }
scope :push_hooks, -> { where(push_events: true, active: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) }
scope :issue_hooks, -> { where(issues_events: true, active: true) }
scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) }
scope :note_hooks, -> { where(note_events: true, active: true) }
+ scope :build_hooks, -> { where(build_events: true, active: true) }
def activated?
active
@@ -133,6 +135,21 @@ class Service < ActiveRecord::Base
end
end
+ # Provide convenient boolean accessor methods
+ # for each serialized property.
+ # Also keep track of updated properties in a similar way as ActiveModel::Dirty
+ def self.boolean_accessor(*args)
+ self.prop_accessor(*args)
+
+ args.each do |arg|
+ class_eval %{
+ def #{arg}?
+ ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(#{arg})
+ end
+ }
+ end
+ end
+
# Returns a hash of the properties that have been assigned a new value since last save,
# indicating their original values (attr => original value).
# ActiveRecord does not provide a mechanism to track changes in serialized keys,
@@ -163,6 +180,7 @@ class Service < ActiveRecord::Base
assembla
bamboo
buildkite
+ builds_email
campfire
custom_issue_tracker
drone_ci
@@ -170,7 +188,6 @@ class Service < ActiveRecord::Base
external_wiki
flowdock
gemnasium
- gitlab_ci
hipchat
irker
jira
diff --git a/app/models/user.rb b/app/models/user.rb
index 7155dd2bea7..fdd14f4571d 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -69,8 +69,10 @@ class User < ActiveRecord::Base
include Gitlab::CurrentSettings
include Referable
include Sortable
- include TokenAuthenticatable
include CaseSensitivity
+ include TokenAuthenticatable
+
+ add_authentication_token_field :authentication_token
default_value_for :admin, false
default_value_for :can_create_group, gitlab_config.default_can_create_group
@@ -134,7 +136,7 @@ class User < ActiveRecord::Base
has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy
has_one :abuse_report, dependent: :destroy
- has_many :ci_builds, dependent: :nullify, class_name: 'Ci::Build'
+ has_many :builds, dependent: :nullify, class_name: 'Ci::Build'
#
@@ -769,10 +771,9 @@ class User < ActiveRecord::Base
def ci_authorized_runners
@ci_authorized_runners ||= begin
- runner_ids = Ci::RunnerProject.joins(:project).
- where("ci_projects.gitlab_id IN (#{ci_projects_union.to_sql})").
+ runner_ids = Ci::RunnerProject.
+ where("ci_runner_projects.gl_project_id IN (#{ci_projects_union.to_sql})").
select(:runner_id)
-
Ci::Runner.specific.where(id: runner_ids)
end
end
diff --git a/app/services/ci/create_builds_service.rb b/app/services/ci/create_builds_service.rb
index 912eb6258a4..ad901f2da5d 100644
--- a/app/services/ci/create_builds_service.rb
+++ b/app/services/ci/create_builds_service.rb
@@ -29,9 +29,11 @@ module Ci
build_attrs.merge!(ref: ref,
tag: tag,
trigger_request: trigger_request,
- user: user)
+ user: user,
+ project: commit.project)
- commit.builds.create!(build_attrs)
+ build = commit.builds.create!(build_attrs)
+ build.execute_hooks
end
end
end
diff --git a/app/services/ci/create_commit_service.rb b/app/services/ci/create_commit_service.rb
deleted file mode 100644
index 479a2d6defc..00000000000
--- a/app/services/ci/create_commit_service.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-module Ci
- class CreateCommitService
- def execute(project, user, params)
- sha = params[:checkout_sha] || params[:after]
- origin_ref = params[:ref]
-
- unless origin_ref && sha.present?
- return false
- end
-
- ref = origin_ref.gsub(/\Arefs\/(tags|heads)\//, '')
-
- # Skip branch removal
- if sha == Ci::Git::BLANK_SHA
- return false
- end
-
- tag = origin_ref.start_with?('refs/tags/')
- commit = project.gl_project.ensure_ci_commit(sha)
- unless commit.skip_ci?
- commit.update_committed!
- commit.create_builds(ref, tag, user)
- end
-
- commit
- end
- end
-end
diff --git a/app/services/ci/create_trigger_request_service.rb b/app/services/ci/create_trigger_request_service.rb
index 4b86cb0a1f5..b3dfc707221 100644
--- a/app/services/ci/create_trigger_request_service.rb
+++ b/app/services/ci/create_trigger_request_service.rb
@@ -1,13 +1,13 @@
module Ci
class CreateTriggerRequestService
def execute(project, trigger, ref, variables = nil)
- commit = project.gl_project.commit(ref)
+ commit = project.commit(ref)
return unless commit
# check if ref is tag
- tag = project.gl_project.repository.find_tag(ref).present?
+ tag = project.repository.find_tag(ref).present?
- ci_commit = project.gl_project.ensure_ci_commit(commit.sha)
+ ci_commit = project.ensure_ci_commit(commit.sha)
trigger_request = trigger.trigger_requests.create!(
variables: variables,
diff --git a/app/services/ci/event_service.rb b/app/services/ci/event_service.rb
deleted file mode 100644
index 3f4e02dd26c..00000000000
--- a/app/services/ci/event_service.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-module Ci
- class EventService
- def remove_project(user, project)
- create(
- description: "Project \"#{project.name}\" has been removed by #{user.username}",
- user_id: user.id,
- is_admin: true
- )
- end
-
- def create_project(user, project)
- create(
- description: "Project \"#{project.name}\" has been created by #{user.username}",
- user_id: user.id,
- is_admin: true
- )
- end
-
- def change_project_settings(user, project)
- create(
- project_id: project.id,
- user_id: user.id,
- description: "User \"#{user.username}\" updated projects settings"
- )
- end
-
- def create(*args)
- Ci::Event.create!(*args)
- end
- end
-end
diff --git a/app/services/ci/image_for_build_service.rb b/app/services/ci/image_for_build_service.rb
index b8d24193035..f469b13e902 100644
--- a/app/services/ci/image_for_build_service.rb
+++ b/app/services/ci/image_for_build_service.rb
@@ -4,10 +4,10 @@ module Ci
sha = params[:sha]
sha ||=
if params[:ref]
- project.gl_project.commit(params[:ref]).try(:sha)
+ project.commit(params[:ref]).try(:sha)
end
- commit = project.commits.ordered.find_by(sha: sha)
+ commit = project.ci_commits.ordered.find_by(sha: sha)
image_name = image_for_commit(commit)
image_path = Rails.root.join('public/ci', image_name)
diff --git a/app/services/ci/register_build_service.rb b/app/services/ci/register_build_service.rb
index 7beb098659c..4ff268a6f06 100644
--- a/app/services/ci/register_build_service.rb
+++ b/app/services/ci/register_build_service.rb
@@ -8,10 +8,10 @@ module Ci
builds =
if current_runner.shared?
# don't run projects which have not enables shared runners
- builds.joins(commit: { gl_project: :gitlab_ci_project }).where(ci_projects: { shared_runners_enabled: true })
+ builds.joins(:project).where(projects: { builds_enabled: true, shared_runners_enabled: true })
else
# do run projects which are only assigned to this runner
- builds.joins(:commit).where(ci_commits: { gl_project_id: current_runner.gl_projects_ids })
+ builds.where(project: current_runner.projects.where(builds_enabled: true))
end
builds = builds.order('created_at ASC')
@@ -20,10 +20,9 @@ module Ci
build.can_be_served?(current_runner)
end
-
if build
# In case when 2 runners try to assign the same build, second runner will be declined
- # with StateMachine::InvalidTransition in run! method.
+ # with StateMachines::InvalidTransition in run! method.
build.with_lock do
build.runner_id = current_runner.id
build.save!
@@ -33,7 +32,7 @@ module Ci
build
- rescue StateMachine::InvalidTransition
+ rescue StateMachines::InvalidTransition
nil
end
end
diff --git a/app/services/ci/test_hook_service.rb b/app/services/ci/test_hook_service.rb
deleted file mode 100644
index 3a17596aaeb..00000000000
--- a/app/services/ci/test_hook_service.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-module Ci
- class TestHookService
- def execute(hook, current_user)
- Ci::WebHookService.new.build_end(hook.project.commits.last.last_build)
- end
- end
-end
diff --git a/app/services/create_commit_builds_service.rb b/app/services/create_commit_builds_service.rb
new file mode 100644
index 00000000000..759c334ebe9
--- /dev/null
+++ b/app/services/create_commit_builds_service.rb
@@ -0,0 +1,28 @@
+class CreateCommitBuildsService
+ def execute(project, user, params)
+ return false unless project.builds_enabled?
+
+ sha = params[:checkout_sha] || params[:after]
+ origin_ref = params[:ref]
+
+ unless origin_ref && sha.present?
+ return false
+ end
+
+ ref = Gitlab::Git.ref_name(origin_ref)
+
+ # Skip branch removal
+ if sha == Gitlab::Git::BLANK_SHA
+ return false
+ end
+
+ tag = Gitlab::Git.tag_ref?(origin_ref)
+ commit = project.ensure_ci_commit(sha)
+ unless commit.skip_ci?
+ commit.update_committed!
+ commit.create_builds(ref, tag, user)
+ end
+
+ commit
+ end
+end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index f11690aa3f4..d7ea30bc315 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -61,6 +61,7 @@ class GitPushService
EventCreateService.new.push(project, user, @push_data)
project.execute_hooks(@push_data.dup, :push_hooks)
project.execute_services(@push_data.dup, :push_hooks)
+ CreateCommitBuildsService.new.execute(project, @user, @push_data)
ProjectCacheWorker.perform_async(project.id)
end
diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb
index 1cc42b0b0ad..4144c7111d0 100644
--- a/app/services/git_tag_push_service.rb
+++ b/app/services/git_tag_push_service.rb
@@ -10,6 +10,7 @@ class GitTagPushService
EventCreateService.new.push(project, user, @push_data)
project.execute_hooks(@push_data.dup, :tag_push_hooks)
project.execute_services(@push_data.dup, :tag_push_hooks)
+ CreateCommitBuildsService.new.execute(project, @user, @push_data)
ProjectCacheWorker.perform_async(project.id)
true
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index 5da1c7afd92..0577ae778d5 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -7,6 +7,8 @@ module Projects
description: @project.description,
name: @project.name,
path: @project.path,
+ shared_runners_enabled: @project.shared_runners_enabled,
+ builds_enabled: @project.builds_enabled,
namespace_id: @params[:namespace].try(:id) || current_user.namespace.id
}
@@ -15,19 +17,6 @@ module Projects
end
new_project = CreateService.new(current_user, new_params).execute
-
- if new_project.persisted?
- if @project.builds_enabled?
- new_project.enable_ci
-
- settings = @project.gitlab_ci_project.attributes.select do |attr_name, value|
- ["public", "shared_runners_enabled", "allow_git_fetch"].include? attr_name
- end
-
- new_project.gitlab_ci_project.update(settings)
- end
- end
-
new_project
end
end
diff --git a/app/views/admin/builds/_build.html.haml b/app/views/admin/builds/_build.html.haml
new file mode 100644
index 00000000000..6936e614346
--- /dev/null
+++ b/app/views/admin/builds/_build.html.haml
@@ -0,0 +1,73 @@
+- project = build.project
+%tr.build
+ %td.status
+ = ci_status_with_icon(build.status)
+
+ %td.build-link
+ - if build.target_url
+ = link_to build.target_url do
+ %strong Build ##{build.id}
+ - else
+ %strong Build ##{build.id}
+
+ - if build.show_warning?
+ %i.fa.fa-warning.text-warning
+
+ %td
+ - if project
+ = link_to project.name_with_namespace, admin_namespace_project_path(project.namespace, project), class: "monospace"
+
+ %td
+ = link_to build.short_sha, namespace_project_commit_path(project.namespace, project, build.sha), class: "monospace"
+
+ %td
+ - if build.ref
+ = link_to build.ref, namespace_project_commits_path(project.namespace, project, build.ref)
+ - else
+ .light none
+
+ %td
+ - if build.try(:runner)
+ = runner_link(build.runner)
+ - else
+ .light none
+
+ %td
+ #{build.stage} / #{build.name}
+
+ .pull-right
+ - if build.tags.any?
+ - build.tags.each do |tag|
+ %span.label.label-primary
+ = tag
+ - if build.try(:trigger_request)
+ %span.label.label-info triggered
+ - if build.try(:allow_failure)
+ %span.label.label-danger allowed to fail
+
+ %td.duration
+ - if build.duration
+ #{duration_in_words(build.finished_at, build.started_at)}
+
+ %td.timestamp
+ - if build.finished_at
+ %span #{time_ago_with_tooltip(build.finished_at)}
+
+ - if defined?(coverage) && coverage
+ %td.coverage
+ - if build.try(:coverage)
+ #{build.coverage}%
+
+ %td
+ .pull-right
+ - if current_user && can?(current_user, :download_build_artifacts, project) && build.download_url
+ = link_to build.download_url, title: 'Download artifacts' do
+ %i.fa.fa-download
+ - if current_user && can?(current_user, :manage_builds, build.project)
+ - if build.active?
+ - if build.cancel_url
+ = link_to build.cancel_url, method: :post, title: 'Cancel' do
+ %i.fa.fa-remove.cred
+ - elsif defined?(allow_retry) && allow_retry && build.retry_url
+ = link_to build.retry_url, method: :post, title: 'Retry' do
+ %i.fa.fa-repeat
diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml
new file mode 100644
index 00000000000..55da06a7fe9
--- /dev/null
+++ b/app/views/admin/builds/index.html.haml
@@ -0,0 +1,50 @@
+.project-issuable-filter
+ .controls
+ .pull-left.hidden-xs
+ - if @all_builds.running_or_pending.any?
+ = link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
+
+ %ul.center-top-menu
+ %li{class: ('active' if @scope.nil?)}
+ = link_to admin_builds_path do
+ Running
+ %span.badge.js-running-count= @all_builds.running_or_pending.count(:id)
+
+ %li{class: ('active' if @scope == 'finished')}
+ = link_to admin_builds_path(scope: :finished) do
+ Finished
+ %span.badge.js-running-count= @all_builds.finished.count(:id)
+
+ %li{class: ('active' if @scope == 'all')}
+ = link_to admin_builds_path(scope: :all) do
+ All
+ %span.badge.js-totalbuilds-count= @all_builds.count(:id)
+
+.gray-content-block
+ #{(@scope || 'running').capitalize} builds
+
+%ul.content-list
+ - if @builds.blank?
+ %li
+ .nothing-here-block No builds to show
+ - else
+ .table-holder
+ %table.table.builds
+ %thead
+ %tr
+ %th Status
+ %th Build ID
+ %th Project
+ %th Commit
+ %th Ref
+ %th Runner
+ %th Name
+ %th Duration
+ %th Finished at
+ %th
+
+ - @builds.each do |build|
+ = render "admin/builds/build", build: build
+
+ = paginate @builds, theme: 'gitlab'
+
diff --git a/app/views/ci/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml
index 701782d26bb..6745e58deca 100644
--- a/app/views/ci/admin/runners/_runner.html.haml
+++ b/app/views/admin/runners/_runner.html.haml
@@ -8,14 +8,14 @@
%span.label.label-danger paused
%td
- = link_to ci_admin_runner_path(runner) do
+ = link_to admin_runner_path(runner) do
= runner.short_sha
%td
.runner-description
= runner.description
%span (#{link_to 'edit', '#', class: 'edit-runner-link'})
.runner-description-form.hide
- = form_for [:ci, :admin, runner], remote: true, html: { class: 'form-inline' } do |f|
+ = form_for [:admin, runner], remote: true, html: { class: 'form-inline' } do |f|
.form-group
= f.text_field :description, class: 'form-control'
= f.submit 'Save', class: 'btn'
@@ -38,11 +38,11 @@
Never
%td
.pull-right
- = link_to 'Edit', ci_admin_runner_path(runner), class: 'btn btn-sm'
+ = link_to 'Edit', admin_runner_path(runner), class: 'btn btn-sm'
&nbsp;
- if runner.active?
- = link_to 'Pause', [:pause, :ci, :admin, runner], data: { confirm: "Are you sure?" }, method: :get, class: 'btn btn-danger btn-sm'
+ = link_to 'Pause', [:pause, :admin, runner], data: { confirm: "Are you sure?" }, method: :get, class: 'btn btn-danger btn-sm'
- else
- = link_to 'Resume', [:resume, :ci, :admin, runner], method: :get, class: 'btn btn-success btn-sm'
- = link_to 'Remove', [:ci, :admin, runner], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
+ = link_to 'Resume', [:resume, :admin, runner], method: :get, class: 'btn btn-success btn-sm'
+ = link_to 'Remove', [:admin, runner], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
diff --git a/app/views/ci/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index bacaccfbffa..c5fb3c95506 100644
--- a/app/views/ci/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -1,6 +1,20 @@
%p.lead
- %span To register a new runner you should enter the following registration token. With this token the runner will request a unique runner token and use that for future communication.
- %code #{GitlabCi::REGISTRATION_TOKEN}
+ %span
+ To register a new runner you should enter the following registration token.
+ With this token the runner will request a unique runner token and use that for future communication.
+ Registration token is
+ %code{ id: 'runners-token' } #{current_application_settings.ensure_runners_registration_token}
+
+.bs-callout.clearfix
+ .pull-left
+ %p
+ You can reset runners registration token by pressing a button below.
+ %p
+ = button_to reset_runners_token_admin_application_settings_path,
+ method: :put, class: 'btn btn-default',
+ data: { confirm: 'Are you sure you want to reset registration token?' } do
+ = icon('refresh')
+ Reset runners registration token
.bs-callout
%p
@@ -25,7 +39,7 @@
.append-bottom-20.clearfix
.pull-left
- = form_tag ci_admin_runners_path, id: 'runners-search', class: 'form-inline', method: :get do
+ = form_tag admin_runners_path, id: 'runners-search', class: 'form-inline', method: :get do
.form-group
= search_field_tag :search, params[:search], class: 'form-control', placeholder: 'Runner description or token', spellcheck: false
= submit_tag 'Search', class: 'btn'
@@ -49,5 +63,5 @@
%th
- @runners.each do |runner|
- = render "ci/admin/runners/runner", runner: runner
+ = render "admin/runners/runner", runner: runner
= paginate @runners
diff --git a/app/views/ci/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml
index fd3d33d657b..8700b4820cd 100644
--- a/app/views/ci/admin/runners/show.html.haml
+++ b/app/views/admin/runners/show.html.haml
@@ -22,7 +22,7 @@
%h4 This runner will process builds only from ASSIGNED projects
%p You can't make this a shared runner.
%hr
-= form_for @runner, url: ci_admin_runner_path(@runner), html: { class: 'form-horizontal' } do |f|
+= form_for @runner, url: admin_runner_path(@runner), html: { class: 'form-horizontal' } do |f|
.form-group
= label_tag :token, class: 'control-label' do
Token
@@ -53,29 +53,24 @@
%th
- @runner.runner_projects.each do |runner_project|
- project = runner_project.project
- - if project.gl_project
+ - if project
%tr.alert-info
%td
%strong
- = project.name
+ = project.name_with_namespace
%td
.pull-right
- = link_to 'Disable', [:ci, :admin, project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
+ = link_to 'Disable', [:admin, project.namespace.becomes(Namespace), project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
%table.table
%thead
%tr
%th Project
%th
- .pull-right
- = link_to 'Assign to all', assign_all_ci_admin_runner_path(@runner),
- class: 'btn btn-sm assign-all-runner',
- title: 'Assign runner to all projects',
- method: :put
%tr
%td
- = form_tag ci_admin_runner_path(@runner), id: 'runner-projects-search', class: 'form-inline', method: :get do
+ = form_tag admin_runner_path(@runner), id: 'runner-projects-search', class: 'form-inline', method: :get do
.form-group
= search_field_tag :search, params[:search], class: 'form-control', spellcheck: false
= submit_tag 'Search', class: 'btn'
@@ -84,44 +79,44 @@
- @projects.each do |project|
%tr
%td
- = project.name
+ = project.name_with_namespace
%td
.pull-right
- = form_for [:ci, :admin, project, project.runner_projects.new] do |f|
+ = form_for [:admin, project.namespace.becomes(Namespace), project, project.runner_projects.new] do |f|
= f.hidden_field :runner_id, value: @runner.id
= f.submit 'Enable', class: 'btn btn-xs'
= paginate @projects
.col-md-6
%h4 Recent builds served by this runner
- %table.builds.runner-builds
+ %table.table.builds.runner-builds
%thead
%tr
- %th Build ID
+ %th Build
%th Status
%th Project
%th Commit
%th Finished at
- @builds.each do |build|
- - gl_project = build.gl_project
+ - project = build.project
%tr.build
%td.id
- - if gl_project
- = link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
- = build.id
+ - if project
+ = link_to namespace_project_build_path(project.namespace, project, build) do
+ %strong ##{build.id}
- else
- = build.id
+ %strong ##{build.id}
%td.status
= ci_status_with_icon(build.status)
%td.status
- - if gl_project
- = gl_project.name_with_namespace
+ - if project
+ = project.name_with_namespace
%td.build-link
- - if gl_project
+ - if project
= link_to ci_status_path(build.commit) do
%strong #{build.commit.short_sha}
diff --git a/app/views/ci/admin/runners/update.js.haml b/app/views/admin/runners/update.js.haml
index 2b7d3067e20..2b7d3067e20 100644
--- a/app/views/ci/admin/runners/update.js.haml
+++ b/app/views/admin/runners/update.js.haml
diff --git a/app/views/ci/admin/application_settings/_form.html.haml b/app/views/ci/admin/application_settings/_form.html.haml
deleted file mode 100644
index 634c9daa477..00000000000
--- a/app/views/ci/admin/application_settings/_form.html.haml
+++ /dev/null
@@ -1,24 +0,0 @@
-= form_for @application_setting, url: ci_admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
- - if @application_setting.errors.any?
- #error_explanation
- .alert.alert-danger
- - @application_setting.errors.full_messages.each do |msg|
- %p= msg
-
- %fieldset
- %legend Default Project Settings
- .form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :all_broken_builds do
- = f.check_box :all_broken_builds
- Send emails only on broken builds
- .form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :add_pusher do
- = f.check_box :add_pusher
- Add pusher to recipients list
-
- .form-actions
- = f.submit 'Save', class: 'btn btn-primary'
diff --git a/app/views/ci/admin/application_settings/show.html.haml b/app/views/ci/admin/application_settings/show.html.haml
deleted file mode 100644
index 7ef0aa89ed6..00000000000
--- a/app/views/ci/admin/application_settings/show.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-%h3.page-title Settings
-%hr
-= render 'form'
diff --git a/app/views/ci/admin/builds/_build.html.haml b/app/views/ci/admin/builds/_build.html.haml
deleted file mode 100644
index 2df58713214..00000000000
--- a/app/views/ci/admin/builds/_build.html.haml
+++ /dev/null
@@ -1,34 +0,0 @@
-- gl_project = build.project.gl_project
-- if build.commit && build.project
- %tr.build
- %td.build-link
- = link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
- %strong #{build.id}
-
- %td.status
- = ci_status_with_icon(build.status)
-
- %td.commit-link
- = link_to ci_status_path(build.commit) do
- %strong #{build.commit.short_sha}
-
- %td.runner
- - if build.runner
- = link_to build.runner.id, ci_admin_runner_path(build.runner)
-
- %td.build-project
- = truncate build.project.name, length: 30
-
- %td.build-message
- %span= truncate(build.commit.git_commit_message, length: 30)
-
- %td.build-branch
- %span= truncate(build.ref, length: 25)
-
- %td.duration
- - if build.duration
- #{duration_in_words(build.finished_at, build.started_at)}
-
- %td.timestamp
- - if build.finished_at
- %span #{time_ago_in_words build.finished_at} ago
diff --git a/app/views/ci/admin/builds/index.html.haml b/app/views/ci/admin/builds/index.html.haml
deleted file mode 100644
index d23119162cc..00000000000
--- a/app/views/ci/admin/builds/index.html.haml
+++ /dev/null
@@ -1,28 +0,0 @@
-%ul.nav.nav-tabs.append-bottom-20
- %li{class: ("active" if @scope.nil?)}
- = link_to 'All builds', ci_admin_builds_path
-
- %li{class: ("active" if @scope == "pending")}
- = link_to "Pending", ci_admin_builds_path(scope: :pending)
-
- %li{class: ("active" if @scope == "running")}
- = link_to "Running", ci_admin_builds_path(scope: :running)
-
-
-%table.builds
- %thead
- %tr
- %th Build
- %th Status
- %th Commit
- %th Runner
- %th Project
- %th Message
- %th Branch
- %th Duration
- %th Finished at
-
- - @builds.each do |build|
- = render "ci/admin/builds/build", build: build
-
-= paginate @builds
diff --git a/app/views/ci/admin/events/index.html.haml b/app/views/ci/admin/events/index.html.haml
deleted file mode 100644
index 5a5b4dc7c35..00000000000
--- a/app/views/ci/admin/events/index.html.haml
+++ /dev/null
@@ -1,18 +0,0 @@
-.table-holder
- %table.table
- %thead
- %tr
- %th User ID
- %th Description
- %th When
- - @events.each do |event|
- %tr
- %td
- = event.user_id
- %td
- = event.description
- %td.light
- = time_ago_in_words event.updated_at
- ago
-
-= paginate @events
diff --git a/app/views/ci/admin/projects/_project.html.haml b/app/views/ci/admin/projects/_project.html.haml
deleted file mode 100644
index a342d6e1cf0..00000000000
--- a/app/views/ci/admin/projects/_project.html.haml
+++ /dev/null
@@ -1,29 +0,0 @@
-- last_commit = project.commits.last
-%tr
- %td
- = project.id
- %td
- = link_to [:ci, project] do
- %strong= project.name
- %td
- - if last_commit
- = ci_status_with_icon(last_commit.status)
- - if project.last_commit_date
- &middot;
- = time_ago_in_words project.last_commit_date
- ago
- - else
- No builds yet
- %td
- - if project.public
- %i.fa.fa-globe
- Public
- - else
- %i.fa.fa-lock
- Private
- %td
- = project.commits.count
- %td
- = link_to [:ci, :admin, project], method: :delete, class: 'btn btn-danger btn-sm' do
- %i.fa.fa-remove
- Remove
diff --git a/app/views/ci/admin/projects/index.html.haml b/app/views/ci/admin/projects/index.html.haml
deleted file mode 100644
index 0da8547924b..00000000000
--- a/app/views/ci/admin/projects/index.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-.table-holder
- %table.table
- %thead
- %tr
- %th ID
- %th Name
- %th Last build
- %th Access
- %th Builds
- %th
-
- - @projects.each do |project|
- = render "ci/admin/projects/project", project: project
-
-= paginate @projects
-
diff --git a/app/views/ci/admin/runner_projects/index.html.haml b/app/views/ci/admin/runner_projects/index.html.haml
deleted file mode 100644
index 6b4e3b2cb38..00000000000
--- a/app/views/ci/admin/runner_projects/index.html.haml
+++ /dev/null
@@ -1,57 +0,0 @@
-%p.lead
- To register a new runner visit #{link_to 'this page ', ci_runners_path}
-
-.row
- .col-md-8
- %h5 Activated:
- %table.table
- %tr
- %th Runner ID
- %th Runner Description
- %th Last build
- %th Builds Stats
- %th Registered
- %th
-
- - @runner_projects.each do |runner_project|
- - runner = runner_project.runner
- - builds = runner.builds.where(project_id: @project.id)
- %tr
- %td
- %span.badge.badge-info= runner.id
- %td
- = runner.display_name
- %td
- - last_build = builds.last
- - if last_build
- = link_to last_build.short_sha, [last_build.project, last_build]
- - else
- unknown
- %td
- %span.badge.badge-success
- #{builds.success.count}
- %span /
- %span.badge.badge-important
- #{builds.failed.count}
- %td
- #{time_ago_in_words(runner_project.created_at)} ago
- %td
- = link_to 'Disable', [:ci, @project, runner_project], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm right'
- .col-md-4
- %h5 Available
- %table.table
- %tr
- %th ID
- %th Token
- %th
-
- - (Ci::Runner.all - @project.runners).each do |runner|
- %tr
- %td
- = runner.id
- %td
- = runner.token
- %td
- = form_for [:ci, @project, @runner_project] do |f|
- = f.hidden_field :runner_id, value: runner.id
- = f.submit 'Add', class: 'btn btn-sm'
diff --git a/app/views/ci/commits/_commit.html.haml b/app/views/ci/commits/_commit.html.haml
index b24a3b826cf..11163813f3e 100644
--- a/app/views/ci/commits/_commit.html.haml
+++ b/app/views/ci/commits/_commit.html.haml
@@ -27,7 +27,6 @@
- if commit.finished_at
%span #{time_ago_in_words commit.finished_at} ago
- - if commit.project.coverage_enabled?
+ - if commit.coverage
%td.coverage
- - if commit.coverage
- #{commit.coverage}%
+ #{commit.coverage}%
diff --git a/app/views/ci/shared/_guide.html.haml b/app/views/ci/shared/_guide.html.haml
index db2d7f2f4b6..09e7e653521 100644
--- a/app/views/ci/shared/_guide.html.haml
+++ b/app/views/ci/shared/_guide.html.haml
@@ -4,12 +4,10 @@
%ol
%li
Add at least one runner to the project.
- Go to #{link_to 'Runners page', runners_path(@project.gl_project), target: :blank} for instructions.
+ Go to #{link_to 'Runners page', runners_path(@project), target: :blank} for instructions.
%li
- Put the .gitlab-ci.yml in the root of your repository. Examples can be found in #{link_to "Configuring project (.gitlab-ci.yml)", "http://doc.gitlab.com/ci/yaml/README.html", target: :blank}.
+ Put the .gitlab-ci.yml in the root of your repository. Examples can be found in
+ #{link_to "Configuring project (.gitlab-ci.yml)", "http://doc.gitlab.com/ci/yaml/README.html", target: :blank}.
You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
%li
- Visit #{link_to 'GitLab project settings', @project.gitlab_url + "/services/gitlab_ci/edit", target: :blank}
- and press the "Test settings" button.
- %li
Return to this page and refresh it, it should show a new build.
diff --git a/app/views/ci/user_sessions/new.html.haml b/app/views/ci/user_sessions/new.html.haml
deleted file mode 100644
index b8d9a1d7089..00000000000
--- a/app/views/ci/user_sessions/new.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-.login-block
- %h2 Login using GitLab account
- %p.light
- Make sure you have an account on the GitLab server
- = link_to GitlabCi.config.gitlab_server.url, GitlabCi.config.gitlab_server.url, no_turbolink
- %hr
- = link_to "Login with GitLab", auth_ci_user_sessions_path(state: params[:state]), no_turbolink.merge( class: 'btn btn-login btn-success' )
diff --git a/app/views/layouts/ci/_nav_admin.html.haml b/app/views/layouts/ci/_nav_admin.html.haml
deleted file mode 100644
index dcda04a4638..00000000000
--- a/app/views/layouts/ci/_nav_admin.html.haml
+++ /dev/null
@@ -1,35 +0,0 @@
-%ul.nav.nav-sidebar
- = nav_link do
- = link_to admin_root_path, title: 'Back to admin', data: {placement: 'right'}, class: 'back-link' do
- = icon('caret-square-o-left fw')
- %span
- Back to admin
-
- %li.separate-item
- = nav_link path: 'projects#index' do
- = link_to ci_admin_projects_path do
- = icon('list-alt fw')
- %span
- Projects
- = nav_link path: 'events#index' do
- = link_to ci_admin_events_path do
- = icon('book fw')
- %span
- Events
- = nav_link path: ['runners#index', 'runners#show'] do
- = link_to ci_admin_runners_path do
- = icon('cog fw')
- %span
- Runners
- %span.count= Ci::Runner.count(:all)
- = nav_link path: 'builds#index' do
- = link_to ci_admin_builds_path do
- = icon('link fw')
- %span
- Builds
- %span.count= Ci::Build.count(:all)
- = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
- = link_to ci_admin_application_settings_path do
- = icon('cogs fw')
- %span
- Settings
diff --git a/app/views/layouts/ci/_nav_project.html.haml b/app/views/layouts/ci/_nav_project.html.haml
deleted file mode 100644
index f094edbfa87..00000000000
--- a/app/views/layouts/ci/_nav_project.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-%ul.nav.nav-sidebar
- = nav_link do
- = link_to project_path(@project.gl_project), title: 'Back to project', data: {placement: 'right'}, class: 'back-link' do
- = icon('caret-square-o-left fw')
- %span
- Back to project
- %li.separate-item
- = nav_link path: 'events#index' do
- = link_to ci_project_events_path(@project) do
- = icon('book fw')
- %span
- Events
diff --git a/app/views/layouts/ci/admin.html.haml b/app/views/layouts/ci/admin.html.haml
deleted file mode 100644
index c8cb185d28c..00000000000
--- a/app/views/layouts/ci/admin.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-!!! 5
-%html{ lang: "en"}
- = render 'layouts/head'
- %body{class: "ci-body #{user_application_theme}", 'data-page' => body_data_page}
- - header_title = "Admin area"
- - if current_user
- = render "layouts/header/default", title: header_title
- - else
- = render "layouts/header/public", title: header_title
-
- = render 'layouts/ci/page', sidebar: 'nav_admin'
diff --git a/app/views/layouts/ci/application.html.haml b/app/views/layouts/ci/application.html.haml
deleted file mode 100644
index 38023468d0b..00000000000
--- a/app/views/layouts/ci/application.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-!!! 5
-%html{ lang: "en"}
- = render 'layouts/head'
- %body{class: "ci-body #{user_application_theme}", 'data-page' => body_data_page}
- - header_title = "Continuous Integration"
- - if current_user
- = render "layouts/header/default", title: header_title
- - else
- = render "layouts/header/public", title: header_title
-
- = render 'layouts/ci/page'
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index d04a3d1f227..c60ac5eefac 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -24,11 +24,18 @@
= icon('key fw')
%span
Deploy Keys
- = nav_link do
- = link_to ci_admin_projects_path, title: 'Continuous Integration' do
- = icon('building fw')
+ = nav_link path: ['runners#index', 'runners#show'] do
+ = link_to admin_runners_path do
+ = icon('cog fw')
+ %span
+ Runners
+ %span.count= Ci::Runner.count(:all)
+ = nav_link path: 'builds#index' do
+ = link_to admin_builds_path do
+ = icon('link fw')
%span
- Continuous Integration
+ Builds
+ %span.count= Ci::Build.count(:all)
= nav_link(controller: :logs) do
= link_to admin_logs_path, title: 'Logs' do
= icon('file-text fw')
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 2fcba7bd672..c0d62028639 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -44,7 +44,7 @@
= icon('cubes fw')
%span
Builds
- %span.count.builds_counter= @project.ci_builds.running_or_pending.count(:all)
+ %span.count.builds_counter= @project.builds.running_or_pending.count(:all)
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml
index f0b3f27b626..970da78a5c9 100644
--- a/app/views/layouts/nav/_project_settings.html.haml
+++ b/app/views/layouts/nav/_project_settings.html.haml
@@ -50,18 +50,3 @@
= icon('retweet fw')
%span
Triggers
- = nav_link path: 'ci_web_hooks#index' do
- = link_to namespace_project_ci_web_hooks_path(@project.namespace, @project), title: 'CI Web Hooks' do
- = icon('link fw')
- %span
- CI Web Hooks
- = nav_link path: 'ci_settings#edit' do
- = link_to edit_namespace_project_ci_settings_path(@project.namespace, @project), title: 'CI Settings' do
- = icon('building fw')
- %span
- CI Settings
- = nav_link controller: 'ci_services' do
- = link_to namespace_project_ci_services_path(@project.namespace, @project), title: 'CI Services' do
- = icon('share fw')
- %span
- CI Services
diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml
index 00cb4aa24cc..27112c6745a 100644
--- a/app/views/notify/_note_message.html.haml
+++ b/app/views/notify/_note_message.html.haml
@@ -1,2 +1,4 @@
%div
+ "#{link_to @note.author_name, user_url(@note.author)} wrote:"
+%div
= markdown(@note.note, pipeline: :email)
diff --git a/app/views/ci/notify/build_fail_email.html.haml b/app/views/notify/build_fail_email.html.haml
index de6291aa914..f4e9749e5c7 100644
--- a/app/views/ci/notify/build_fail_email.html.haml
+++ b/app/views/notify/build_fail_email.html.haml
@@ -1,13 +1,13 @@
- content_for :header do
%h1{style: "background: #c40834; color: #FFF; font: normal 20px Helvetica, Arial, sans-serif; margin: 0; padding: 5px 10px; line-height: 32px; font-size: 16px;"}
- GitLab CI (build failed)
+ GitLab (build failed)
%h3
Project:
= link_to ci_project_url(@project) do
= @project.name
%p
- Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.gl_project.namespace, @build.gl_project, @build.sha)}
+ Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)}
%p
Author: #{@build.commit.git_author_name}
%p
@@ -20,4 +20,4 @@
Message: #{@build.commit.git_commit_message}
%p
- Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
+ Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
diff --git a/app/views/ci/notify/build_fail_email.text.erb b/app/views/notify/build_fail_email.text.erb
index 17a3b9b1d33..675acea60a1 100644
--- a/app/views/ci/notify/build_fail_email.text.erb
+++ b/app/views/notify/build_fail_email.text.erb
@@ -8,4 +8,4 @@ Stage: <%= @build.stage %>
Job: <%= @build.name %>
Message: <%= @build.commit.git_commit_message %>
-Url: <%= namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build) %>
+Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %>
diff --git a/app/views/ci/notify/build_success_email.html.haml b/app/views/notify/build_success_email.html.haml
index 6ef1fd67d89..8b004d34cca 100644
--- a/app/views/ci/notify/build_success_email.html.haml
+++ b/app/views/notify/build_success_email.html.haml
@@ -1,6 +1,6 @@
- content_for :header do
%h1{style: "background: #38CF5B; color: #FFF; font: normal 20px Helvetica, Arial, sans-serif; margin: 0; padding: 5px 10px; line-height: 32px; font-size: 16px;"}
- GitLab CI (build successful)
+ GitLab (build successful)
%h3
Project:
@@ -8,7 +8,7 @@
= @project.name
%p
- Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.gl_project.namespace, @build.gl_project, @build.sha)}
+ Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)}
%p
Author: #{@build.commit.git_author_name}
%p
@@ -21,4 +21,4 @@
Message: #{@build.commit.git_commit_message}
%p
- Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
+ Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
diff --git a/app/views/ci/notify/build_success_email.text.erb b/app/views/notify/build_success_email.text.erb
index bc8b978c3d7..747da44acae 100644
--- a/app/views/ci/notify/build_success_email.text.erb
+++ b/app/views/notify/build_success_email.text.erb
@@ -8,4 +8,4 @@ Stage: <%= @build.stage %>
Job: <%= @build.name %>
Message: <%= @build.commit.git_commit_message %>
-Url: <%= namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build) %>
+Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %>
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
index 333f5d470ed..10b02813733 100644
--- a/app/views/projects/blob/_editor.html.haml
+++ b/app/views/projects/blob/_editor.html.haml
@@ -16,8 +16,7 @@
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'select2'
.file-content.code
- %pre.js-edit-mode-pane#editor
- = params[:content] || local_assigns[:blob_data]
+ %pre.js-edit-mode-pane#editor #{params[:content] || local_assigns[:blob_data]}
- if local_assigns[:path]
.js-edit-mode-pane#preview.hide
.center
diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml
index fbf2c293db8..1a26908ab11 100644
--- a/app/views/projects/builds/index.html.haml
+++ b/app/views/projects/builds/index.html.haml
@@ -3,7 +3,7 @@
.project-issuable-filter
.controls
- - if @ci_project && can?(current_user, :manage_builds, @project)
+ - if can?(current_user, :manage_builds, @project)
.pull-left.hidden-xs
- if @all_builds.running_or_pending.any?
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
@@ -40,7 +40,7 @@
%thead
%tr
%th Status
- %th Build ID
+ %th Runner
%th Commit
%th Ref
%th Stage
diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
index d5e81f84b56..20a5b6a66e7 100644
--- a/app/views/projects/builds/show.html.haml
+++ b/app/views/projects/builds/show.html.haml
@@ -56,7 +56,7 @@
%br
Go to
- = link_to namespace_project_runners_path(@build.gl_project.namespace, @build.gl_project) do
+ = link_to namespace_project_runners_path(@build.project.namespace, @build.project) do
Runners page
.row.prepend-top-default
@@ -113,7 +113,7 @@
%p
%span.attr-name Runner:
- if @build.runner && current_user && current_user.admin
- = link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id)
+ = link_to "##{@build.runner.id}", admin_runner_path(@build.runner.id)
- elsif @build.runner
\##{@build.runner.id}
diff --git a/app/views/projects/ci_services/_form.html.haml b/app/views/projects/ci_services/_form.html.haml
deleted file mode 100644
index 397832e56db..00000000000
--- a/app/views/projects/ci_services/_form.html.haml
+++ /dev/null
@@ -1,54 +0,0 @@
-%h3.page-title
- = @service.title
- = boolean_to_icon @service.activated?
-
-%p= @service.description
-
-
-%hr
-
-= form_for(@service, as: :service, url: namespace_project_ci_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |f|
- - if @service.errors.any?
- .alert.alert-danger
- %ul
- - @service.errors.full_messages.each do |msg|
- %li= msg
-
- - if @service.help.present?
- .bs-callout
- = @service.help
-
- .form-group
- = f.label :active, "Active", class: "control-label"
- .col-sm-10
- = f.check_box :active
-
- - @service.fields.each do |field|
- - name = field[:name]
- - label = field[:label] || name
- - value = @service.send(name)
- - type = field[:type]
- - placeholder = field[:placeholder]
- - choices = field[:choices]
- - default_choice = field[:default_choice]
- - help = field[:help]
-
- .form-group
- = f.label label, class: "control-label"
- .col-sm-10
- - if type == 'text'
- = f.text_field name, class: "form-control", placeholder: placeholder
- - elsif type == 'textarea'
- = f.text_area name, rows: 5, class: "form-control", placeholder: placeholder
- - elsif type == 'checkbox'
- = f.check_box name
- - elsif type == 'select'
- = f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
- - if help
- .light #{help}
-
- .form-actions
- = f.submit 'Save', class: 'btn btn-save'
- &nbsp;
- - if @service.valid? && @service.activated? && @service.can_test?
- = link_to 'Test settings', test_namespace_project_ci_service_path(@project.namespace, @project, @service.to_param), class: 'btn'
diff --git a/app/views/projects/ci_services/edit.html.haml b/app/views/projects/ci_services/edit.html.haml
deleted file mode 100644
index dacb6b4f6f4..00000000000
--- a/app/views/projects/ci_services/edit.html.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-- page_title @service.title, "CI Services"
-= render 'form'
diff --git a/app/views/projects/ci_services/index.html.haml b/app/views/projects/ci_services/index.html.haml
deleted file mode 100644
index 3f26c7851d8..00000000000
--- a/app/views/projects/ci_services/index.html.haml
+++ /dev/null
@@ -1,23 +0,0 @@
-- page_title "CI Services"
-%h3.page-title Project services
-%p.light Project services allow you to integrate GitLab CI with other applications
-
-%table.table
- %thead
- %tr
- %th
- %th Service
- %th Description
- %th Last edit
- - @services.sort_by(&:title).each do |service|
- %tr
- %td
- = boolean_to_icon service.activated?
- %td
- = link_to edit_namespace_project_ci_service_path(@project.namespace, @project, service.to_param) do
- %strong= service.title
- %td
- = service.description
- %td.light
- = time_ago_in_words service.updated_at
- ago
diff --git a/app/views/projects/ci_settings/_form.html.haml b/app/views/projects/ci_settings/_form.html.haml
deleted file mode 100644
index ee6b8885e2d..00000000000
--- a/app/views/projects/ci_settings/_form.html.haml
+++ /dev/null
@@ -1,120 +0,0 @@
-%h3.page-title
- CI settings
-%hr
-.bs-callout.help-callout
- %p
- If you want to test your .gitlab-ci.yml, you can use special tool - #{link_to "Lint", ci_lint_path}
- %p
- Edit your
- #{link_to ".gitlab-ci.yml using web-editor", yaml_web_editor_link(@ci_project)}
-
-- unless @project.empty_repo?
- %p
- Paste build status image for #{@repository.root_ref} with next link
- = link_to '#', class: 'badge-codes-toggle btn btn-default btn-xs' do
- Status Badge
- .badge-codes-block.bs-callout.bs-callout-info.hide
- %p
- Status badge for
- %span.label.label-info #{@ref}
- branch
- %div
- %label Markdown:
- = text_field_tag 'badge_md', markdown_badge_code(@ci_project, @repository.root_ref), readonly: true, class: 'form-control'
- %label Html:
- = text_field_tag 'badge_html', html_badge_code(@ci_project, @repository.root_ref), readonly: true, class: 'form-control'
-
-= nested_form_for @ci_project, url: namespace_project_ci_settings_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f|
- - if @ci_project.errors.any?
- #error_explanation
- %p.lead= "#{pluralize(@ci_project.errors.count, "error")} prohibited this project from being saved:"
- .alert.alert-error
- %ul
- - @ci_project.errors.full_messages.each do |msg|
- %li= msg
-
- %fieldset
- %legend Build settings
- .form-group
- = label_tag nil, class: 'control-label' do
- Get code
- .col-sm-10
- %p Get recent application code using the following command:
- .radio
- = label_tag do
- = f.radio_button :allow_git_fetch, 'false'
- %strong git clone
- .light Slower but makes sure you have a clean dir before every build
- .radio
- = label_tag do
- = f.radio_button :allow_git_fetch, 'true'
- %strong git fetch
- .light Faster
- .form-group
- = f.label :timeout_in_minutes, 'Timeout', class: 'control-label'
- .col-sm-10
- = f.number_field :timeout_in_minutes, class: 'form-control', min: '0'
- .light per build in minutes
-
-
- %fieldset
- %legend Build Schedule
- .form-group
- = f.label :always_build, 'Schedule build', class: 'control-label'
- .col-sm-10
- .checkbox
- = f.label :always_build do
- = f.check_box :always_build
- %span.light Repeat last build after X hours if no builds
- .form-group
- = f.label :polling_interval, "Build interval", class: 'control-label'
- .col-sm-10
- = f.number_field :polling_interval, placeholder: '5', min: '0', class: 'form-control'
- .light In hours
-
- %fieldset
- %legend Project settings
- .form-group
- = f.label :default_ref, "Make tabs for the following branches", class: 'control-label'
- .col-sm-10
- = f.text_field :default_ref, class: 'form-control', placeholder: 'master, stable'
- .light You will be able to filter builds by the following branches
- .form-group
- = f.label :public, 'Public mode', class: 'control-label'
- .col-sm-10
- .checkbox
- = f.label :public do
- = f.check_box :public
- %span.light Anyone can see project and builds
- .form-group
- = f.label :coverage_regex, "Test coverage parsing", class: 'control-label'
- .col-sm-10
- .input-group
- %span.input-group-addon /
- = f.text_field :coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
- %span.input-group-addon /
- .light We will use this regular expression to find test coverage output in build trace. Leave blank if you want to disable this feature
- .bs-callout.bs-callout-info
- %p Below are examples of regex for existing tools:
- %ul
- %li
- Simplecov (Ruby) -
- %code \(\d+.\d+\%\) covered
- %li
- pytest-cov (Python) -
- %code \d+\%\s*$
- %li
- phpunit --coverage-text --colors=never (PHP) -
- %code ^\s*Lines:\s*\d+.\d+\%
-
- %fieldset
- %legend Advanced settings
- .form-group
- = f.label :token, "CI token", class: 'control-label'
- .col-sm-10
- = f.text_field :token, class: 'form-control', placeholder: 'xEeFCaDAB89'
-
- .form-actions
- = f.submit 'Save changes', class: 'btn btn-save'
- - unless @ci_project.new_record?
- = link_to 'Remove Project', ci_project_path(@ci_project), method: :delete, data: { confirm: 'Project will be removed. Are you sure?' }, class: 'btn btn-danger pull-right'
diff --git a/app/views/projects/ci_settings/_no_runners.html.haml b/app/views/projects/ci_settings/_no_runners.html.haml
deleted file mode 100644
index 1374e6680f9..00000000000
--- a/app/views/projects/ci_settings/_no_runners.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-.alert.alert-danger
- %p
- There are NO runners to build this project.
- %br
- You can add Specific runner for this project on Runners page
-
- - if current_user.admin
- or add Shared runner for whole application in admin area.
diff --git a/app/views/projects/ci_settings/edit.html.haml b/app/views/projects/ci_settings/edit.html.haml
deleted file mode 100644
index acc912d4596..00000000000
--- a/app/views/projects/ci_settings/edit.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- page_title "CI Settings"
-
-- if no_runners_for_project?(@ci_project)
- = render 'no_runners'
-
-= render 'form'
diff --git a/app/views/projects/ci_web_hooks/index.html.haml b/app/views/projects/ci_web_hooks/index.html.haml
deleted file mode 100644
index 2998fb08ff1..00000000000
--- a/app/views/projects/ci_web_hooks/index.html.haml
+++ /dev/null
@@ -1,94 +0,0 @@
-- page_title "CI Web Hooks"
-%h3.page-title
- CI Web hooks
-
-%p.light
- Web Hooks can be used for binding events when build completed.
-
-%hr.clearfix
-
-= form_for @web_hook, url: namespace_project_ci_web_hooks_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f|
- -if @web_hook.errors.any?
- .alert.alert-danger
- - @web_hook.errors.full_messages.each do |msg|
- %p= msg
- .form-group
- = f.label :url, "URL", class: 'control-label'
- .col-sm-10
- = f.text_field :url, class: "form-control", placeholder: 'http://example.com/trigger-ci.json'
- .form-actions
- = f.submit "Add Web Hook", class: "btn btn-create"
-
--if @web_hooks.any?
- %h4 Activated web hooks (#{@web_hooks.count})
- .table-holder
- %table.table
- - @web_hooks.each do |hook|
- %tr
- %td
- .clearfix
- %span.monospace= hook.url
- %td
- .pull-right
- - if @ci_project.commits.any?
- = link_to 'Test Hook', test_namespace_project_ci_web_hook_path(@project.namespace, @project, hook), class: "btn btn-sm btn-grouped"
- = link_to 'Remove', namespace_project_ci_web_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
-
-%h4 Web Hook data example
-
-:erb
- <pre>
- <code>
- {
- "build_id": 2,
- "build_name":"rspec_linux"
- "build_status": "failed",
- "build_started_at": "2014-05-05T18:01:02.563Z",
- "build_finished_at": "2014-05-05T18:01:07.611Z",
- "project_id": 1,
- "project_name": "Brightbox \/ Brightbox Cli",
- "gitlab_url": "http:\/\/localhost:3000\/brightbox\/brightbox-cli",
- "ref": "master",
- "sha": "a26cf5de9ed9827746d4970872376b10d9325f40",
- "before_sha": "34f57f6ba3ed0c21c5e361bbb041c3591411176c",
- "push_data": {
- "before": "34f57f6ba3ed0c21c5e361bbb041c3591411176c",
- "after": "a26cf5de9ed9827746d4970872376b10d9325f40",
- "ref": "refs\/heads\/master",
- "user_id": 1,
- "user_name": "Administrator",
- "project_id": 5,
- "repository": {
- "name": "Brightbox Cli",
- "url": "dzaporozhets@localhost:brightbox\/brightbox-cli.git",
- "description": "Voluptatibus quae error consectetur voluptas dolores vel excepturi possimus.",
- "homepage": "http:\/\/localhost:3000\/brightbox\/brightbox-cli"
- },
- "commits": [
- {
- "id": "a26cf5de9ed9827746d4970872376b10d9325f40",
- "message": "Release v1.2.2",
- "timestamp": "2014-04-22T16:46:42+03:00",
- "url": "http:\/\/localhost:3000\/brightbox\/brightbox-cli\/commit\/a26cf5de9ed9827746d4970872376b10d9325f40",
- "author": {
- "name": "Paul Thornthwaite",
- "email": "tokengeek@gmail.com"
- }
- },
- {
- "id": "34f57f6ba3ed0c21c5e361bbb041c3591411176c",
- "message": "Fix server user data update\n\nIncorrect condition was being used so Base64 encoding option was having\nopposite effect from desired.",
- "timestamp": "2014-04-11T18:17:26+03:00",
- "url": "http:\/\/localhost:3000\/brightbox\/brightbox-cli\/commit\/34f57f6ba3ed0c21c5e361bbb041c3591411176c",
- "author": {
- "name": "Paul Thornthwaite",
- "email": "tokengeek@gmail.com"
- }
- }
- ],
- "total_commits_count": 2,
- "ci_yaml_file":"rspec_linux:\r\n script: ls\r\n"
- }
- }
- </code>
- </pre>
diff --git a/app/views/projects/commit/_builds.html.haml b/app/views/projects/commit/_builds.html.haml
index e4d81182c1a..329aaa0bb8b 100644
--- a/app/views/projects/commit/_builds.html.haml
+++ b/app/views/projects/commit/_builds.html.haml
@@ -1,17 +1,17 @@
.gray-content-block.middle-block
.pull-right
- - if @ci_project && can?(current_user, :manage_builds, @ci_commit.gl_project)
+ - if can?(current_user, :manage_builds, @ci_commit.project)
- if @ci_commit.builds.latest.failed.any?(&:retryable?)
- = link_to "Retry failed", retry_builds_namespace_project_commit_path(@ci_commit.gl_project.namespace, @ci_commit.gl_project, @ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post
+ = link_to "Retry failed", retry_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post
- if @ci_commit.builds.running_or_pending.any?
- = link_to "Cancel running", cancel_builds_namespace_project_commit_path(@ci_commit.gl_project.namespace, @ci_commit.gl_project, @ci_commit.sha), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
+ = link_to "Cancel running", cancel_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
.oneline
= pluralize @statuses.count(:id), "build"
- if defined?(link_to_commit) && link_to_commit
for commit
- = link_to @ci_commit.short_sha, namespace_project_commit_path(@ci_commit.gl_project.namespace, @ci_commit.gl_project, @ci_commit.sha), class: "monospace"
+ = link_to @ci_commit.short_sha, namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: "monospace"
- if @ci_commit.duration > 0
in
= time_interval_in_words @ci_commit.duration
@@ -22,8 +22,9 @@
%ul
- @ci_commit.yaml_errors.split(",").each do |error|
%li= error
+ You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
-- if @ci_commit.gl_project.builds_enabled? && !@ci_commit.ci_yaml_file
+- if @ci_commit.project.builds_enabled? && !@ci_commit.ci_yaml_file
.bs-callout.bs-callout-warning
\.gitlab-ci.yml not found in this commit
@@ -38,12 +39,12 @@
%th Name
%th Duration
%th Finished at
- - if @ci_project && @ci_project.coverage_enabled?
+ - if @ci_commit.project.build_coverage_enabled?
%th Coverage
%th
- @ci_commit.refs.each do |ref|
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered,
- locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true, allow_retry: true }
+ locals: { coverage: @ci_commit.project.build_coverage_enabled?, stage: true, allow_retry: true }
- if @ci_commit.retried.any?
.gray-content-block.second-block
@@ -60,8 +61,8 @@
%th Name
%th Duration
%th Finished at
- - if @ci_project && @ci_project.coverage_enabled?
+ - if @ci_commit.project.build_coverage_enabled?
%th Coverage
%th
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried,
- locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true }
+ locals: { coverage: @ci_commit.project.build_coverage_enabled?, stage: true }
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 132cdc35c94..634924db247 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -40,7 +40,7 @@
- @commit.parents.each do |parent|
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace"
-- if @ci_commit
+- if @ci_commit && @ci_commit.show_build_status?
.pull-right
= link_to ci_status_path(@ci_commit), class: "ci-status ci-#{@ci_commit.status}" do
= ci_status_icon(@ci_commit)
diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml
index a527bb2f84a..45a00e4d259 100644
--- a/app/views/projects/commit_statuses/_commit_status.html.haml
+++ b/app/views/projects/commit_statuses/_commit_status.html.haml
@@ -69,7 +69,7 @@
- if current_user && can?(current_user, :download_build_artifacts, @project) && commit_status.download_url
= link_to commit_status.download_url, title: 'Download artifacts' do
%i.fa.fa-download
- - if current_user && can?(current_user, :manage_builds, commit_status.gl_project)
+ - if current_user && can?(current_user, :manage_builds, commit_status.project)
- if commit_status.active?
- if commit_status.cancel_url
= link_to commit_status.cancel_url, method: :post, title: 'Cancel' do
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 0d64486164e..1303b27c4f3 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -9,7 +9,7 @@
- cache_key.push(ci_commit.status) if ci_commit
= cache(cache_key) do
- %li.commit.js-toggle-container
+ %li.commit.js-toggle-container{ id: "commit-#{commit.short_id}" }
.commit-row-title
%strong.str-truncated
= link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
@@ -17,7 +17,7 @@
%a.text-expander.js-toggle-button ...
.pull-right
- - if ci_commit
+ - if ci_commit && ci_commit.show_build_status?
= render_ci_status(ci_commit)
&nbsp;
= clipboard_button(clipboard_text: commit.id)
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index d865d299135..650629ef1b9 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -112,6 +112,62 @@
%hr
= link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
+ %fieldset.features
+ %legend
+ Continuous Integration
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ %p Get recent application code using the following command:
+ .radio
+ = f.label :build_allow_git_fetch do
+ = f.radio_button :build_allow_git_fetch, 'false'
+ %strong git clone
+ %br
+ %span.descr Slower but makes sure you have a clean dir before every build
+ .radio
+ = f.label :build_allow_git_fetch do
+ = f.radio_button :build_allow_git_fetch, 'true'
+ %strong git fetch
+ %br
+ %span.descr Faster
+ .form-group
+ = f.label :build_timeout_in_minutes, 'Timeout', class: 'control-label'
+ .col-sm-10
+ = f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
+ %p.help-block per build in minutes
+ .form-group
+ = f.label :build_coverage_regex, "Test coverage parsing", class: 'control-label'
+ .col-sm-10
+ .input-group
+ %span.input-group-addon /
+ = f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
+ %span.input-group-addon /
+ %p.help-block
+ We will use this regular expression to find test coverage output in build trace.
+ Leave blank if you want to disable this feature
+ .bs-callout.bs-callout-info
+ %p Below are examples of regex for existing tools:
+ %ul
+ %li
+ Simplecov (Ruby) -
+ %code \(\d+.\d+\%\) covered
+ %li
+ pytest-cov (Python) -
+ %code \d+\%\s*$
+ %li
+ phpunit --coverage-text --colors=never (PHP) -
+ %code ^\s*Lines:\s*\d+.\d+\%
+
+
+ %fieldset.features
+ %legend
+ Advanced settings
+ .form-group
+ = f.label :runners_token, "CI token", class: 'control-label'
+ .col-sm-10
+ = f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
+ %p.help-block The secure token used to checkout project.
+
.form-actions
= f.submit 'Save changes', class: "btn btn-save"
diff --git a/app/views/projects/graphs/ci/_overall.haml b/app/views/projects/graphs/ci/_overall.haml
index cf4285a2671..4b12e5f2da1 100644
--- a/app/views/projects/graphs/ci/_overall.haml
+++ b/app/views/projects/graphs/ci/_overall.haml
@@ -1,20 +1,19 @@
-- ci_project = @project.gitlab_ci_project
%h4 Overall stats
%ul
%li
Total:
- %strong= pluralize ci_project.builds.count(:all), 'build'
+ %strong= pluralize @project.builds.count(:all), 'build'
%li
Successful:
- %strong= pluralize ci_project.builds.success.count(:all), 'build'
+ %strong= pluralize @project.builds.success.count(:all), 'build'
%li
Failed:
- %strong= pluralize ci_project.builds.failed.count(:all), 'build'
+ %strong= pluralize @project.builds.failed.count(:all), 'build'
%li
Success ratio:
%strong
- #{success_ratio(ci_project.builds.success, ci_project.builds.failed)}%
+ #{success_ratio(@project.builds.success, @project.builds.failed)}%
%li
Commits covered:
%strong
- = ci_project.commits.count(:all)
+ = @project.ci_commits.count(:all)
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index 3702aeaecba..b18d9197d0b 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -55,6 +55,13 @@
%strong Merge Request events
%p.light
This url will be triggered when a merge request is created
+ %div
+ = f.check_box :build_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :build_events, class: 'list-label' do
+ %strong Build events
+ %p.light
+ This url will be triggered when the build status changes
.form-group
= f.label :enable_ssl_verification, "SSL verification", class: 'control-label checkbox'
.col-sm-10
@@ -78,7 +85,7 @@
.clearfix
%span.monospace= hook.url
%p
- - %w(push_events tag_push_events issues_events note_events merge_requests_events).each do |trigger|
+ - %w(push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger|
- if hook.send(trigger)
%span.label.label-gray= trigger.titleize
SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"}
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index f2011542ca7..405bae1bbb9 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -5,24 +5,8 @@
- else
= link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-grouped btn-close js-note-target-close', title: 'Close Issue'
-= render 'shared/show_aside'
-
.gray-content-block.second-block.oneline-block
- .row
- .col-md-9
- .votes-holder.pull-right
- #votes= render 'votes/votes_block', votable: @issue
- = render "shared/issuable/participants"
- .col-md-3
- .input-group.cross-project-reference
- %span#cross-project-reference.slead.has_tooltip{title: 'Cross-project reference'}
- = cross_project_reference(@project, @issue)
- = clipboard_button(clipboard_target: 'span#cross-project-reference')
+ = render 'votes/votes_block', votable: @issue
-.row
- %section.col-md-9
- .voting_notes#notes= render 'projects/notes/notes_with_form'
- %aside.col-md-3
- .issuable-affix
- .context
- = render 'shared/issuable/context', issuable: @issue
+#notes
+ = render 'projects/notes/notes_with_form'
diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml
new file mode 100644
index 00000000000..fe856ac991e
--- /dev/null
+++ b/app/views/projects/issues/_merge_requests.html.haml
@@ -0,0 +1,25 @@
+-if @merge_requests.any?
+ %h2.merge-requests-title
+ = pluralize(@merge_requests.count, 'Related Merge Request')
+ %ul.bordered-list
+ - has_any_ci = @merge_requests.any?(&:ci_commit)
+ - @merge_requests.each do |merge_request|
+ %li
+ %span.merge-request-ci-status
+ - if merge_request.ci_commit
+ = render_ci_status(merge_request.ci_commit)
+ - elsif has_any_ci
+ = icon('blank fw')
+ %span.merge-request-id
+ \##{merge_request.iid}
+ %span.merge-request-info
+ %strong
+ = link_to_gfm merge_request.title, merge_request_path(merge_request), class: "row_title"
+ in
+ - project = merge_request.target_project
+ = link_to project.name_with_namespace, namespace_project_path(project.namespace, project)
+ %span.merge-request-status.prepend-left-10
+ - if merge_request.merged?
+ MERGED
+ - elsif merge_request.closed?
+ CLOSED
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index a78d20cc07e..cc2cf8c8716 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -3,13 +3,13 @@
.issue
.issue-details.issuable-details
- .page-title
+ .issuable-title
.issue-box{ class: issue_box_class(@issue) }
- if @issue.closed?
Closed
- else
Open
- %span.issue-id Issue ##{@issue.iid}
+ %span.issuable-id Issue ##{@issue.iid}
%span.creator
&middot;
opened by #{link_to_member(@project, @issue.author, size: 24)}
@@ -36,18 +36,29 @@
= icon('pencil-square-o')
Edit
- .gray-content-block.middle-block
- %h2.issue-title
- = markdown escape_once(@issue.title), pipeline: :single_line
- %div
- - if @issue.description.present?
- .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
- .wiki
- = preserve do
- = markdown(@issue.description, cache_key: [@issue, "description"])
- %textarea.hidden.js-task-list-field
- = @issue.description
- - if @closed_by_merge_requests.present?
- = render 'projects/issues/closed_by_box'
- .issue-discussion
- = render 'projects/issues/discussion'
+ .row
+ %section.col-md-9
+ .gray-content-block
+ %h2.issue-title
+ = markdown escape_once(@issue.title), pipeline: :single_line
+ %div
+ - if @issue.description.present?
+ .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
+ .wiki
+ = preserve do
+ = markdown(@issue.description, cache_key: [@issue, "description"])
+ %textarea.hidden.js-task-list-field
+ = @issue.description
+
+ .merge-requests
+ = render 'merge_requests'
+
+ - if @closed_by_merge_requests.present?
+ = render 'projects/issues/closed_by_box'
+ .issue-discussion
+ = render 'projects/issues/discussion'
+
+ %aside.col-md-3
+ = render 'shared/issuable/sidebar', issuable: @issue
+
+ = render 'shared/show_aside'
diff --git a/app/views/projects/issues/update.js.haml b/app/views/projects/issues/update.js.haml
index b7735aaf3c1..2f0f3fcfb06 100644
--- a/app/views/projects/issues/update.js.haml
+++ b/app/views/projects/issues/update.js.haml
@@ -1,3 +1,3 @@
-$('.context').html("#{escape_javascript(render 'shared/issuable/context', issuable: @issue)}");
-$('.context').effect('highlight')
+$('.issuable-sidebar').html("#{escape_javascript(render 'shared/issuable/sidebar', issuable: @issue)}");
+$('.issuable-sidebar').parent().effect('highlight')
new Issue();
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index d64b19ae91a..7a7428d35cc 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -5,24 +5,7 @@
- if @merge_request.closed?
= link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
-= render 'shared/show_aside'
+.gray-content-block.second-block.oneline-block
+ = render 'votes/votes_block', votable: @merge_request
-.gray-content-block.middle-block.oneline-block
- .row
- .col-md-9
- .votes-holder.pull-right
- #votes= render 'votes/votes_block', votable: @merge_request
- = render "shared/issuable/participants"
- .col-md-3
- .input-group.cross-project-reference
- %span#cross-project-reference.slead.has_tooltip{title: 'Cross-project reference'}
- = cross_project_reference(@project, @merge_request)
- = clipboard_button(clipboard_target: 'span#cross-project-reference')
-
-.row
- %section.col-md-9
- .voting_notes#notes= render "projects/notes/notes_with_form"
- %aside.col-md-3
- .issuable-affix
- .context
- = render 'shared/issuable/context', issuable: @merge_request
+#notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 960d1561e73..04f8fd74422 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -7,71 +7,79 @@
.merge-request{'data-url' => merge_request_path(@merge_request)}
.merge-request-details.issuable-details
= render "projects/merge_requests/show/mr_title"
- = render "projects/merge_requests/show/mr_box"
- .append-bottom-default.mr-source-target.prepend-top-default
- - if @merge_request.open?
- .pull-right
- - if @merge_request.source_branch_exists?
- = link_to "#modal_merge_info", class: "btn btn-sm", "data-toggle" => "modal" do
- = icon('cloud-download fw')
- Check out branch
+ .row
+ %section.col-md-9
+ = render "projects/merge_requests/show/mr_box"
+ .append-bottom-default.mr-source-target.prepend-top-default
+ - if @merge_request.open?
+ .pull-right
+ - if @merge_request.source_branch_exists?
+ = link_to "#modal_merge_info", class: "btn btn-sm", "data-toggle" => "modal" do
+ = icon('cloud-download fw')
+ Check out branch
- %span.dropdown
- %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} }
- = icon('download')
- Download as
- %span.caret
- %ul.dropdown-menu
- %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
- %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
- .normal
- %span Request to merge
- %span.label-branch= source_branch_with_namespace(@merge_request)
- %span into
- = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do
- = @merge_request.target_branch
+ %span.dropdown
+ %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} }
+ = icon('download')
+ Download as
+ %span.caret
+ %ul.dropdown-menu
+ %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
+ %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
+ .normal
+ %span Request to merge
+ %span.label-branch= source_branch_with_namespace(@merge_request)
+ %span into
+ = link_to namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch), class: "label-branch" do
+ = @merge_request.target_branch
- = render "projects/merge_requests/show/how_to_merge"
- = render "projects/merge_requests/widget/show.html.haml"
+ = render "projects/merge_requests/show/how_to_merge"
+ = render "projects/merge_requests/widget/show.html.haml"
- - if @merge_request.open? && @merge_request.source_branch_exists? && @merge_request.can_be_merged? && @merge_request.can_be_merged_by?(current_user)
- .light.prepend-top-default
- You can also accept this merge request manually using the
- = succeed '.' do
- = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
+ - if @merge_request.open? && @merge_request.source_branch_exists? && @merge_request.can_be_merged? && @merge_request.can_be_merged_by?(current_user)
+ .light.prepend-top-default
+ You can also accept this merge request manually using the
+ = succeed '.' do
+ = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
- - if @commits.present?
- %ul.merge-request-tabs.center-top-menu.no-top.no-bottom
- %li.notes-tab
- = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do
- Discussion
- %span.badge= @merge_request.mr_and_commit_notes.user.count
- %li.commits-tab
- = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
- Commits
- %span.badge= @commits.size
- %li.diffs-tab
- = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do
- Changes
- %span.badge= @merge_request.diffs.size
- - if @ci_commit
- %li.builds-tab
- = link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do
- Builds
- %span.badge= @statuses.size
+ - if @commits.present?
+ %ul.merge-request-tabs.center-top-menu.no-top.no-bottom
+ %li.notes-tab
+ = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do
+ Discussion
+ %span.badge= @merge_request.mr_and_commit_notes.user.count
+ %li.commits-tab
+ = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
+ Commits
+ %span.badge= @commits.size
+ %li.diffs-tab
+ = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do
+ Changes
+ %span.badge= @merge_request.diffs.size
+ - if @ci_commit
+ %li.builds-tab
+ = link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do
+ Builds
+ %span.badge= @statuses.size
- .tab-content
- #notes.notes.tab-pane.voting_notes
- = render "projects/merge_requests/discussion"
- #commits.commits.tab-pane
- - # This tab is always loaded via AJAX
- #diffs.diffs.tab-pane
- - # This tab is always loaded via AJAX
- #builds.builds.tab-pane
- - # This tab is always loaded via AJAX
+ .tab-content
+ #notes.notes.tab-pane.voting_notes
+ = render "projects/merge_requests/discussion"
+ #commits.commits.tab-pane
+ - # This tab is always loaded via AJAX
+ #diffs.diffs.tab-pane
+ - # This tab is always loaded via AJAX
+ #builds.builds.tab-pane
+ - # This tab is always loaded via AJAX
+
+ .mr-loading-status
+ = spinner
+
+ %aside.col-md-3
+ = render 'shared/issuable/sidebar', issuable: @merge_request
+
+ = render 'shared/show_aside'
- .mr-loading-status
- = spinner
:javascript
var merge_request;
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index 4dfe46e2b86..d65c3b16618 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -1,7 +1,7 @@
-.page-title
+.issuable-title
.issue-box{ class: issue_box_class(@merge_request) }
= @merge_request.state_human_name
- %span.issue-id Merge Request ##{@merge_request.iid}
+ %span.issuable-id Merge Request ##{@merge_request.iid}
%span.creator
&middot;
opened by #{link_to_member(@project, @merge_request.author, size: 24)}
diff --git a/app/views/projects/merge_requests/update.js.haml b/app/views/projects/merge_requests/update.js.haml
index 25583b2cc6f..93db65ddf79 100644
--- a/app/views/projects/merge_requests/update.js.haml
+++ b/app/views/projects/merge_requests/update.js.haml
@@ -1,3 +1,3 @@
-$('.context').html("#{escape_javascript(render 'shared/issuable/context', issuable: @merge_request)}");
-$('.context').effect('highlight')
+$('.issuable-sidebar').html("#{escape_javascript(render 'shared/issuable/sidebar', issuable: @merge_request)}");
+$('.issuable-sidebar').parent().effect('highlight')
merge_request = new MergeRequest();
diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml
index 8c2b5366a06..6f52c963a53 100644
--- a/app/views/projects/merge_requests/widget/_merged.html.haml
+++ b/app/views/projects/merge_requests/widget/_merged.html.haml
@@ -33,7 +33,7 @@
.remove_source_branch_in_progress.hide
%p
= icon('spinner spin')
- Removing source branch '#{@merge_request.source_branch}'. Please wait. This page will be automatically reload.
+ Removing source branch '#{@merge_request.source_branch}'. Please wait, this page will be automatically reloaded.
:javascript
$('.remove_source_branch').on('click', function() {
diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml
index 08af124274b..2168294c683 100644
--- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml
@@ -12,7 +12,7 @@
- else
The source branch will not be removed.
- - remove_source_branch_button = @merge_request.can_remove_source_branch?(current_user) && !should_remove_source_branch
+ - remove_source_branch_button = @merge_request.can_remove_source_branch?(current_user) && !should_remove_source_branch && @merge_request.merge_user == current_user
- user_can_cancel_automatic_merge = @merge_request.can_cancel_merge_when_build_succeeds?(current_user)
- if remove_source_branch_button || user_can_cancel_automatic_merge
.clearfix.prepend-top-10
diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml
index 99c1b0fa43e..eb378b42603 100644
--- a/app/views/projects/notes/_notes_with_form.html.haml
+++ b/app/views/projects/notes/_notes_with_form.html.haml
@@ -7,4 +7,4 @@
= render "projects/notes/form", view: diff_view
:javascript
- new Notes("#{namespace_project_notes_path(namespace_id: @project.namespace, target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}, "#{diff_view}")
+ var notes = new Notes("#{namespace_project_notes_path(namespace_id: @project.namespace, target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}, "#{diff_view}")
diff --git a/app/views/projects/runners/_runner.html.haml b/app/views/projects/runners/_runner.html.haml
index e6b8a2e6fe7..47ec420189d 100644
--- a/app/views/projects/runners/_runner.html.haml
+++ b/app/views/projects/runners/_runner.html.haml
@@ -15,10 +15,10 @@
- if runner.belongs_to_one_project?
= link_to 'Remove runner', runner_path(runner), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
- else
- - runner_project = @ci_project.runner_projects.find_by(runner_id: runner)
- = link_to 'Disable for this project', [:ci, @ci_project, runner_project], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
+ - runner_project = @project.runner_projects.find_by(runner_id: runner)
+ = link_to 'Disable for this project', namespace_project_runner_project_path(@project.namespace, @project, runner_project), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
- elsif runner.specific?
- = form_for [:ci, @ci_project, @ci_project.runner_projects.new] do |f|
+ = form_for [@project.namespace.becomes(Namespace), @project, @project.runner_projects.new] do |f|
= f.hidden_field :runner_id, value: runner.id
= f.submit 'Enable for this project', class: 'btn btn-sm'
.pull-right
diff --git a/app/views/projects/runners/_shared_runners.html.haml b/app/views/projects/runners/_shared_runners.html.haml
index 316ea747b14..6a37f444bb7 100644
--- a/app/views/projects/runners/_shared_runners.html.haml
+++ b/app/views/projects/runners/_shared_runners.html.haml
@@ -3,17 +3,17 @@
.bs-callout.bs-callout-warning
GitLab Runners do not offer secure isolation between projects that they do builds for. You are TRUSTING all GitLab users who can push code to project A, B or C to run shell scripts on the machine hosting runner X.
%hr
- - if @ci_project.shared_runners_enabled
- = link_to toggle_shared_runners_ci_project_path(@ci_project), class: 'btn btn-warning', method: :post do
+ - if @project.shared_runners_enabled?
+ = link_to toggle_shared_runners_namespace_project_runners_path(@project.namespace, @project), class: 'btn btn-warning', method: :post do
Disable shared runners
- else
- = link_to toggle_shared_runners_ci_project_path(@ci_project), class: 'btn btn-success', method: :post do
+ = link_to toggle_shared_runners_namespace_project_runners_path(@project.namespace, @project), class: 'btn btn-success', method: :post do
Enable shared runners
&nbsp; for this project
- if @shared_runners_count.zero?
- This application has no shared runners yet.
- Please use specific runners or ask administrator to create one
+ This GitLab server does not provide any shared runners yet.
+ Please use specific runners or ask the administrator to create one.
- else
%h4.underlined-title Available shared runners - #{@shared_runners_count}
%ul.bordered-list.available-shared-runners
diff --git a/app/views/projects/runners/_specific_runners.html.haml b/app/views/projects/runners/_specific_runners.html.haml
index c13625c7e49..30cd1263a12 100644
--- a/app/views/projects/runners/_specific_runners.html.haml
+++ b/app/views/projects/runners/_specific_runners.html.haml
@@ -12,7 +12,7 @@
%code #{ci_root_url(only_path: false)}
%li
Use the following registration token during setup:
- %code #{@ci_project.token}
+ %code #{@project.runners_token}
%li
Start runner!
diff --git a/app/views/projects/triggers/index.html.haml b/app/views/projects/triggers/index.html.haml
index b3ad79a200e..bd346c4b8e6 100644
--- a/app/views/projects/triggers/index.html.haml
+++ b/app/views/projects/triggers/index.html.haml
@@ -36,7 +36,8 @@
:plain
curl -X POST \
-F token=TOKEN \
- #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}
+ -F ref=REF_NAME \
+ #{builds_trigger_url(@project.id)}
%h3
Use .gitlab-ci.yml
@@ -51,7 +52,7 @@
trigger:
type: deploy
script:
- - "curl -X POST -F token=TOKEN #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}"
+ - "curl -X POST -F token=TOKEN -F ref=REF_NAME #{builds_trigger_url(@project.id)}"
%h3
Pass build variables
@@ -65,5 +66,6 @@
:plain
curl -X POST \
-F token=TOKEN \
+ -F "ref=REF_NAME" \
-F "variables[RUN_NIGHTLY_BUILD]=true" \
- #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}
+ #{builds_trigger_url(@project.id)}
diff --git a/app/views/projects/variables/show.html.haml b/app/views/projects/variables/show.html.haml
index e052da1ac43..e80dffc1ced 100644
--- a/app/views/projects/variables/show.html.haml
+++ b/app/views/projects/variables/show.html.haml
@@ -10,13 +10,13 @@
%hr
-= nested_form_for @ci_project, url: url_for(controller: 'projects/variables', action: 'update'), html: { class: 'form-horizontal' } do |f|
+= nested_form_for @project, url: url_for(controller: 'projects/variables', action: 'update'), html: { class: 'form-horizontal' } do |f|
- if @project.errors.any?
#error_explanation
- %p.lead= "#{pluralize(@ci_project.errors.count, "error")} prohibited this project from being saved:"
+ %p.lead= "#{pluralize(@project.errors.count, "error")} prohibited this project from being saved:"
.alert.alert-error
%ul
- - @ci_project.errors.full_messages.each do |msg|
+ - @project.errors.full_messages.each do |msg|
%li= msg
= f.fields_for :variables do |variable_form|
diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml
index 16a98a7233c..28d6f421fea 100644
--- a/app/views/shared/_service_settings.html.haml
+++ b/app/views/shared/_service_settings.html.haml
@@ -59,6 +59,15 @@
%strong Merge Request events
%p.light
This url will be triggered when a merge request is created
+ - if @service.supported_events.include?("build")
+ %div
+ = form.check_box :build_events, class: 'pull-left'
+ .prepend-left-20
+ = form.label :build_events, class: 'list-label' do
+ %strong Build events
+ %p.light
+ This url will be triggered when a build status changes
+
- @service.fields.each do |field|
- type = field[:type]
diff --git a/app/views/shared/issuable/_context.html.haml b/app/views/shared/issuable/_context.html.haml
deleted file mode 100644
index 2aa46662613..00000000000
--- a/app/views/shared/issuable/_context.html.haml
+++ /dev/null
@@ -1,57 +0,0 @@
-= form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
- %div.prepend-top-default
- .issuable-context-title
- %label
- Assignee:
- - if issuable.assignee
- %strong= link_to_member(@project, issuable.assignee, size: 24)
- - else
- none
- .issuable-context-selectbox
- - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
- = users_select_tag("#{issuable.class.table_name.singularize}[assignee_id]", placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: issuable.assignee_id, project: @target_project, null_user: true, current_user: true, first_user: true)
-
- %div.prepend-top-default.clearfix
- .issuable-context-title
- %label
- Milestone:
- - if issuable.milestone
- %span.back-to-milestone
- = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do
- %strong
- = icon('clock-o')
- = issuable.milestone.title
- - else
- none
- .issuable-context-selectbox
- - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
- = f.select(:milestone_id, milestone_options(issuable), { include_blank: true }, { class: 'select2 select2-compact js-select2 js-milestone', data: { placeholder: 'Select milestone' }})
- = hidden_field_tag :issuable_context
- = f.submit class: 'btn hide'
-
- - if issuable.labels.any?
- %div.prepend-top-default.clearfix
- .issuable-context-title
- %label Labels
- .issuable-show-labels
- - issuable.labels.each do |label|
- = link_to_label(label)
-
- - if current_user
- - subscribed = issuable.subscribed?(current_user)
- %div.prepend-top-default.clearfix
- .issuable-context-title
- %label Subscription
- - subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed'
- .subscription-status{data: {status: subscribtion_status}}
- .description-block.unsubscribed{class: ( 'hidden' if subscribed )}
- You're not receiving notifications from this thread.
- .description-block.subscribed{class: ( 'hidden' unless subscribed )}
- You're receiving notifications because you're subscribed to this thread.
- %button.btn.btn-block.subscribe-button{:type => 'button'}
- = icon('eye')
- %span= subscribed ? 'Unsubscribe' : 'Subscribe'
-
-:javascript
- new Subscription("#{toggle_subscription_path(issuable)}");
- new IssuableContext();
diff --git a/app/views/shared/issuable/_participants.html.haml b/app/views/shared/issuable/_participants.html.haml
index b4e0def48b6..da6bacbb74a 100644
--- a/app/views/shared/issuable/_participants.html.haml
+++ b/app/views/shared/issuable/_participants.html.haml
@@ -1,5 +1,5 @@
-.participants
- %span
- = pluralize @participants.count, "participant"
- - @participants.each do |participant|
+.block.participants
+ .title
+ = pluralize participants.count, "participant"
+ - participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
new file mode 100644
index 00000000000..0019f739b89
--- /dev/null
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -0,0 +1,83 @@
+.issuable-sidebar.issuable-affix
+ = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
+ .block
+ .title
+ Cross-project reference
+ .cross-project-reference
+ %span#cross-project-reference
+ = cross_project_reference(@project, issuable)
+ = clipboard_button(clipboard_target: 'span#cross-project-reference')
+
+ .block.assignee
+ .title
+ %label
+ Assignee
+ - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
+ .pull-right
+ = link_to 'Edit', '#', class: 'edit-link'
+ .value
+ - if issuable.assignee
+ %strong= link_to_member(@project, issuable.assignee, size: 24)
+ - else
+ .light None
+
+ .selectbox
+ = users_select_tag("#{issuable.class.table_name.singularize}[assignee_id]", placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: issuable.assignee_id, project: @target_project, null_user: true, current_user: true, first_user: true)
+
+ .block.milestone
+ .title
+ %label
+ Milestone
+ - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
+ .pull-right
+ = link_to 'Edit', '#', class: 'edit-link'
+ .value
+ - if issuable.milestone
+ %span.back-to-milestone
+ = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do
+ %strong
+ = icon('clock-o')
+ = issuable.milestone.title
+ - else
+ .light None
+ .selectbox
+ = f.select(:milestone_id, milestone_options(issuable), { include_blank: true }, { class: 'select2 select2-compact js-select2 js-milestone', data: { placeholder: 'Select milestone' }})
+ = hidden_field_tag :issuable_context
+ = f.submit class: 'btn hide'
+
+ - if issuable.project.labels.any?
+ .block
+ .title
+ %label Labels
+ - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
+ .pull-right
+ = link_to 'Edit', '#', class: 'edit-link'
+ .value.issuable-show-labels
+ - if issuable.labels.any?
+ - issuable.labels.each do |label|
+ = link_to_label(label)
+ - else
+ .light None
+ .selectbox
+ = f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
+ { selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" }
+
+ = render "shared/issuable/participants", participants: issuable.participants(current_user)
+
+ - if current_user
+ - subscribed = issuable.subscribed?(current_user)
+ .block.light
+ .title
+ %label.light Notifications
+ - subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed'
+ %button.btn.btn-block.btn-gray.subscribe-button{:type => 'button'}
+ %span= subscribed ? 'Unsubscribe' : 'Subscribe'
+ .subscription-status{data: {status: subscribtion_status}}
+ .unsubscribed{class: ( 'hidden' if subscribed )}
+ You're not receiving notifications from this thread.
+ .subscribed{class: ( 'hidden' unless subscribed )}
+ You're receiving notifications because you're subscribed to this thread.
+
+ :javascript
+ new Subscription("#{toggle_subscription_path(issuable)}");
+ new IssuableContext();
diff --git a/app/workers/build_email_worker.rb b/app/workers/build_email_worker.rb
new file mode 100644
index 00000000000..1c7a04a66a8
--- /dev/null
+++ b/app/workers/build_email_worker.rb
@@ -0,0 +1,19 @@
+class BuildEmailWorker
+ include Sidekiq::Worker
+
+ def perform(build_id, recipients, push_data)
+ recipients.each do |recipient|
+ begin
+ case push_data['build_status']
+ when 'success'
+ Notify.build_success_email(build_id, recipient).deliver_now
+ when 'failed'
+ Notify.build_fail_email(build_id, recipient).deliver_now
+ end
+ # These are input errors and won't be corrected even if Sidekiq retries
+ rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e
+ logger.info("Failed to send e-mail for project '#{push_data['project_name']}' to #{recipient}: #{e}")
+ end
+ end
+ end
+end
diff --git a/app/workers/ci/hip_chat_notifier_worker.rb b/app/workers/ci/hip_chat_notifier_worker.rb
deleted file mode 100644
index ebb43570e2a..00000000000
--- a/app/workers/ci/hip_chat_notifier_worker.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module Ci
- class HipChatNotifierWorker
- include Sidekiq::Worker
-
- def perform(message, options={})
- room = options.delete('room')
- token = options.delete('token')
- server = options.delete('server')
- name = options.delete('service_name')
- client_opts = {
- api_version: 'v2',
- server_url: server
- }
-
- client = HipChat::Client.new(token, client_opts)
- client[room].send(name, message, options.symbolize_keys)
- end
- end
-end
diff --git a/app/workers/ci/slack_notifier_worker.rb b/app/workers/ci/slack_notifier_worker.rb
deleted file mode 100644
index 3bbb9b4bec7..00000000000
--- a/app/workers/ci/slack_notifier_worker.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-module Ci
- class SlackNotifierWorker
- include Sidekiq::Worker
-
- def perform(webhook_url, message, options={})
- notifier = Slack::Notifier.new(webhook_url)
- notifier.ping(message, options)
- end
- end
-end
diff --git a/app/workers/ci/web_hook_worker.rb b/app/workers/ci/web_hook_worker.rb
deleted file mode 100644
index 0bb83845572..00000000000
--- a/app/workers/ci/web_hook_worker.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module Ci
- class WebHookWorker
- include Sidekiq::Worker
-
- def perform(hook_id, data)
- Ci::WebHook.find(hook_id).execute data
- end
- end
-end
diff --git a/config/initializers/4_ci_app.rb b/config/initializers/4_ci_app.rb
index cac8edb32bf..d252e403102 100644
--- a/config/initializers/4_ci_app.rb
+++ b/config/initializers/4_ci_app.rb
@@ -1,8 +1,6 @@
module GitlabCi
VERSION = Gitlab::VERSION
REVISION = Gitlab::REVISION
-
- REGISTRATION_TOKEN = SecureRandom.hex(10)
def self.config
Settings
diff --git a/config/routes.rb b/config/routes.rb
index 061a8fd5da4..e2d4fcb65a8 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -24,43 +24,10 @@ Rails.application.routes.draw do
resource :lint, only: [:show, :create]
resources :projects do
- collection do
- post :add
- get :disabled
- end
-
member do
get :status, to: 'projects#badge'
get :integration
- post :toggle_shared_runners
end
-
- resources :runner_projects, only: [:create, :destroy]
- end
-
- resource :user_sessions do
- get :auth
- get :callback
- end
-
- namespace :admin do
- resources :runners, only: [:index, :show, :update, :destroy] do
- member do
- put :assign_all
- get :resume
- get :pause
- end
- end
-
- resources :events, only: [:index]
-
- resources :projects do
- resources :runner_projects
- end
-
- resources :builds, only: :index
-
- resource :application_settings, only: [:show, :update]
end
root to: 'projects#index'
@@ -271,15 +238,31 @@ Rails.application.routes.draw do
member do
put :transfer
end
+
+ resources :runner_projects
end
end
resource :application_settings, only: [:show, :update] do
resources :services
+ put :reset_runners_token
end
resources :labels
+ resources :runners, only: [:index, :show, :update, :destroy] do
+ member do
+ get :resume
+ get :pause
+ end
+ end
+
+ resources :builds, only: :index do
+ collection do
+ post :cancel_all
+ end
+ end
+
root to: 'dashboard#index'
end
@@ -595,18 +578,6 @@ Rails.application.routes.draw do
resources :protected_branches, only: [:index, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
resource :variables, only: [:show, :update]
resources :triggers, only: [:index, :create, :destroy]
- resource :ci_settings, only: [:edit, :update, :destroy]
- resources :ci_web_hooks, only: [:index, :create, :destroy] do
- member do
- get :test
- end
- end
-
- resources :ci_services, constraints: { id: /[^\/]+/ }, only: [:index, :edit, :update] do
- member do
- get :test
- end
- end
resources :builds, only: [:index, :show] do
collection do
@@ -685,7 +656,13 @@ Rails.application.routes.draw do
get :resume
get :pause
end
+
+ collection do
+ post :toggle_shared_runners
+ end
end
+
+ resources :runner_projects, only: [:create, :destroy]
end
end
end
diff --git a/db/migrate/20151203162134_add_build_events_to_services.rb b/db/migrate/20151203162134_add_build_events_to_services.rb
new file mode 100644
index 00000000000..a84be7db3f1
--- /dev/null
+++ b/db/migrate/20151203162134_add_build_events_to_services.rb
@@ -0,0 +1,6 @@
+class AddBuildEventsToServices < ActiveRecord::Migration
+ def up
+ add_column :services, :build_events, :boolean, default: false, null: false
+ add_column :web_hooks, :build_events, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20151209144329_migrate_ci_web_hooks.rb b/db/migrate/20151209144329_migrate_ci_web_hooks.rb
new file mode 100644
index 00000000000..825ba1973ff
--- /dev/null
+++ b/db/migrate/20151209144329_migrate_ci_web_hooks.rb
@@ -0,0 +1,13 @@
+class MigrateCiWebHooks < ActiveRecord::Migration
+ include Gitlab::Database
+
+ def up
+ execute(
+ 'INSERT INTO web_hooks (url, project_id, type, created_at, updated_at, push_events, issues_events, merge_requests_events, tag_push_events, note_events, build_events) ' \
+ "SELECT ci_web_hooks.url, projects.id, 'ProjectHook', ci_web_hooks.created_at, ci_web_hooks.updated_at, " \
+ "#{false_value}, #{false_value}, #{false_value}, #{false_value}, #{false_value}, #{true_value} FROM ci_web_hooks " \
+ 'JOIN ci_projects ON ci_web_hooks.project_id = ci_projects.id ' \
+ 'JOIN projects ON ci_projects.gitlab_id = projects.id'
+ )
+ end
+end
diff --git a/db/migrate/20151209145909_migrate_ci_emails.rb b/db/migrate/20151209145909_migrate_ci_emails.rb
new file mode 100644
index 00000000000..7f330a2cf0a
--- /dev/null
+++ b/db/migrate/20151209145909_migrate_ci_emails.rb
@@ -0,0 +1,45 @@
+class MigrateCiEmails < ActiveRecord::Migration
+ include Gitlab::Database
+
+ def up
+ # This inserts a new service: BuildsEmailService
+ # It "manually" constructs the properties (JSON-encoded)
+ # Migrating all ci_projects e-mail related columns
+ execute(
+ 'INSERT INTO services (project_id, type, created_at, updated_at, active, push_events, issues_events, merge_requests_events, tag_push_events, note_events, build_events, properties) ' \
+ "SELECT projects.id, 'BuildsEmailService', ci_services.created_at, ci_services.updated_at, " \
+ "#{true_value}, #{false_value}, #{false_value}, #{false_value}, #{false_value}, #{false_value}, #{true_value}, " \
+ "CONCAT('{\"notify_only_broken_builds\":\"', #{convert_bool('ci_projects.email_only_broken_builds')}, " \
+ "'\",\"add_pusher\":\"', #{convert_bool('ci_projects.email_add_pusher')}, " \
+ "'\",\"recipients\":\"', #{escape_text('ci_projects.email_recipients')}, " \
+ "'\"}') " \
+ 'FROM ci_services ' \
+ 'JOIN ci_projects ON ci_services.project_id = ci_projects.id ' \
+ 'JOIN projects ON ci_projects.gitlab_id = projects.id ' \
+ "WHERE ci_services.type = 'Ci::MailService' AND ci_services.active"
+ )
+ end
+
+ def down
+ end
+
+ # This function escapes double-quotes and slash
+ def escape_text(name)
+ if Gitlab::Database.postgresql?
+ "REPLACE(REPLACE(#{name}, '\\', '\\\\'), '\"', '\\\"')"
+ else
+ "REPLACE(REPLACE(#{name}, '\\\\', '\\\\\\\\'), '\\\"', '\\\\\\\"')"
+ end
+ end
+
+ # This function returns 0 or 1 for column
+ def convert_bool(name)
+ if Gitlab::Database.postgresql?
+ # PostgreSQL uses BOOLEAN type
+ "CASE WHEN #{name} IS TRUE THEN '1' ELSE '0' END"
+ else
+ # MySQL uses TINYINT
+ "#{name}"
+ end
+ end
+end
diff --git a/db/migrate/20151210072243_add_runners_registration_token_to_application_settings.rb b/db/migrate/20151210072243_add_runners_registration_token_to_application_settings.rb
new file mode 100644
index 00000000000..00f88180e46
--- /dev/null
+++ b/db/migrate/20151210072243_add_runners_registration_token_to_application_settings.rb
@@ -0,0 +1,5 @@
+class AddRunnersRegistrationTokenToApplicationSettings < ActiveRecord::Migration
+ def change
+ add_column :application_settings, :runners_registration_token, :string
+ end
+end
diff --git a/db/migrate/20151210125232_migrate_ci_slack_service.rb b/db/migrate/20151210125232_migrate_ci_slack_service.rb
new file mode 100644
index 00000000000..f14efa3e95d
--- /dev/null
+++ b/db/migrate/20151210125232_migrate_ci_slack_service.rb
@@ -0,0 +1,33 @@
+class MigrateCiSlackService < ActiveRecord::Migration
+ include Gitlab::Database
+
+ def up
+ properties_query = 'SELECT properties FROM ci_services ' \
+ 'JOIN ci_projects ON ci_services.project_id=ci_projects.id ' \
+ "WHERE ci_projects.gitlab_id=services.project_id AND ci_services.type='Ci::SlackService' AND ci_services.active " \
+ 'LIMIT 1'
+
+ active_query = 'SELECT 1 FROM ci_services ' \
+ 'JOIN ci_projects ON ci_services.project_id=ci_projects.id ' \
+ "WHERE ci_projects.gitlab_id=services.project_id AND ci_services.type='Ci::SlackService' AND ci_services.active " \
+ 'LIMIT 1'
+
+ # We update the service since services are always generated for project, even if they are inactive
+ # Activate service and migrate properties if currently the service is not active
+ execute(
+ "UPDATE services SET properties=(#{properties_query}), active=#{true_value}, " \
+ "push_events=#{false_value}, issues_events=#{false_value}, merge_requests_events=#{false_value}, " \
+ "tag_push_events=#{false_value}, note_events=#{false_value}, build_events=#{true_value} " \
+ "WHERE NOT services.active AND services.type='SlackService' AND (#{active_query}) IS NOT NULL"
+ )
+
+ # Tick only build_events if the service is already active
+ execute(
+ "UPDATE services SET build_events=#{true_value} " \
+ "WHERE services.active AND services.type='SlackService' AND (#{active_query}) IS NOT NULL"
+ )
+ end
+
+ def down
+ end
+end
diff --git a/db/migrate/20151210125927_migrate_ci_hip_chat_service.rb b/db/migrate/20151210125927_migrate_ci_hip_chat_service.rb
new file mode 100644
index 00000000000..b9e04323576
--- /dev/null
+++ b/db/migrate/20151210125927_migrate_ci_hip_chat_service.rb
@@ -0,0 +1,34 @@
+class MigrateCiHipChatService < ActiveRecord::Migration
+ include Gitlab::Database
+
+ def up
+ # From properties strip `hipchat_` key
+ properties_query = "SELECT REPLACE(properties, '\"hipchat_', '\"') FROM ci_services " \
+ 'JOIN ci_projects ON ci_services.project_id=ci_projects.id ' \
+ "WHERE ci_projects.gitlab_id=services.project_id AND ci_services.type='Ci::HipChatService' AND ci_services.active " \
+ 'LIMIT 1'
+
+ active_query = 'SELECT 1 FROM ci_services ' \
+ 'JOIN ci_projects ON ci_services.project_id=ci_projects.id ' \
+ "WHERE ci_projects.gitlab_id=services.project_id AND ci_services.type='Ci::HipChatService' AND ci_services.active " \
+ 'LIMIT 1'
+
+ # We update the service since services are always generated for project, even if they are inactive
+ # Activate service and migrate properties if currently the service is not active
+ execute(
+ "UPDATE services SET properties=(#{properties_query}), active=#{true_value}, " \
+ "push_events=#{false_value}, issues_events=#{false_value}, merge_requests_events=#{false_value}, " \
+ "tag_push_events=#{false_value}, note_events=#{false_value}, build_events=#{true_value} " \
+ "WHERE NOT services.active AND services.type='HipchatService' AND (#{active_query}) IS NOT NULL"
+ )
+
+ # Tick only build_events if the service is already active
+ execute(
+ "UPDATE services SET build_events=#{true_value} " \
+ "WHERE services.active AND services.type='HipchatService' AND (#{active_query}) IS NOT NULL"
+ )
+ end
+
+ def down
+ end
+end
diff --git a/db/migrate/20151210125928_add_ci_to_project.rb b/db/migrate/20151210125928_add_ci_to_project.rb
new file mode 100644
index 00000000000..8a65abab636
--- /dev/null
+++ b/db/migrate/20151210125928_add_ci_to_project.rb
@@ -0,0 +1,11 @@
+class AddCiToProject < ActiveRecord::Migration
+ def up
+ add_column :projects, :ci_id, :integer
+ add_column :projects, :builds_enabled, :boolean, default: true, null: false
+ add_column :projects, :shared_runners_enabled, :boolean, default: true, null: false
+ add_column :projects, :runners_token, :string
+ add_column :projects, :build_coverage_regex, :string
+ add_column :projects, :build_allow_git_fetch, :boolean, default: true, null: false
+ add_column :projects, :build_timeout, :integer, default: 3600, null: false
+ end
+end
diff --git a/db/migrate/20151210125929_add_project_id_to_ci.rb b/db/migrate/20151210125929_add_project_id_to_ci.rb
new file mode 100644
index 00000000000..5d1cf543576
--- /dev/null
+++ b/db/migrate/20151210125929_add_project_id_to_ci.rb
@@ -0,0 +1,8 @@
+class AddProjectIdToCi < ActiveRecord::Migration
+ def up
+ add_column :ci_builds, :gl_project_id, :integer
+ add_column :ci_runner_projects, :gl_project_id, :integer
+ add_column :ci_triggers, :gl_project_id, :integer
+ add_column :ci_variables, :gl_project_id, :integer
+ end
+end
diff --git a/db/migrate/20151210125930_migrate_ci_to_project.rb b/db/migrate/20151210125930_migrate_ci_to_project.rb
new file mode 100644
index 00000000000..7dfe05174ee
--- /dev/null
+++ b/db/migrate/20151210125930_migrate_ci_to_project.rb
@@ -0,0 +1,37 @@
+class MigrateCiToProject < ActiveRecord::Migration
+ def up
+ migrate_project_id_for_table('ci_runner_projects')
+ migrate_project_id_for_table('ci_triggers')
+ migrate_project_id_for_table('ci_variables')
+ migrate_project_id_for_builds
+
+ migrate_project_column('id', 'ci_id')
+ migrate_project_column('shared_runners_enabled', 'shared_runners_enabled')
+ migrate_project_column('token', 'runners_token')
+ migrate_project_column('coverage_regex', 'build_coverage_regex')
+ migrate_project_column('allow_git_fetch', 'build_allow_git_fetch')
+ migrate_project_column('timeout', 'build_timeout')
+ migrate_ci_service
+ end
+
+ def migrate_project_id_for_table(table)
+ subquery = "SELECT gitlab_id FROM ci_projects WHERE ci_projects.id = #{table}.project_id"
+ execute("UPDATE #{table} SET gl_project_id=(#{subquery}) WHERE gl_project_id IS NULL")
+ end
+
+ def migrate_project_id_for_builds
+ subquery = 'SELECT gl_project_id FROM ci_commits WHERE ci_commits.id = ci_builds.commit_id'
+ execute("UPDATE ci_builds SET gl_project_id=(#{subquery}) WHERE gl_project_id IS NULL")
+ end
+
+ def migrate_project_column(column, new_column = nil)
+ new_column ||= column
+ subquery = "SELECT ci_projects.#{column} FROM ci_projects WHERE projects.id = ci_projects.gitlab_id"
+ execute("UPDATE projects SET #{new_column}=(#{subquery}) WHERE (#{subquery}) IS NOT NULL")
+ end
+
+ def migrate_ci_service
+ subquery = "SELECT active FROM services WHERE projects.id = services.project_id AND type='GitlabCiService' LIMIT 1"
+ execute("UPDATE projects SET builds_enabled=(#{subquery}) WHERE (#{subquery}) IS NOT NULL")
+ end
+end
diff --git a/db/migrate/20151210125931_add_index_to_ci_tables.rb b/db/migrate/20151210125931_add_index_to_ci_tables.rb
new file mode 100644
index 00000000000..9fedb5d612c
--- /dev/null
+++ b/db/migrate/20151210125931_add_index_to_ci_tables.rb
@@ -0,0 +1,12 @@
+class AddIndexToCiTables < ActiveRecord::Migration
+ def up
+ add_index :ci_builds, :gl_project_id
+ add_index :ci_runner_projects, :gl_project_id
+ add_index :ci_triggers, :gl_project_id
+ add_index :ci_variables, :gl_project_id
+ add_index :projects, :runners_token
+ add_index :projects, :builds_enabled
+ add_index :projects, [:builds_enabled, :shared_runners_enabled]
+ add_index :projects, [:ci_id]
+ end
+end
diff --git a/db/migrate/20151210125932_drop_null_for_ci_tables.rb b/db/migrate/20151210125932_drop_null_for_ci_tables.rb
new file mode 100644
index 00000000000..0b007430b0c
--- /dev/null
+++ b/db/migrate/20151210125932_drop_null_for_ci_tables.rb
@@ -0,0 +1,9 @@
+class DropNullForCiTables < ActiveRecord::Migration
+ def up
+ remove_index :ci_variables, :project_id
+ remove_index :ci_runner_projects, :project_id
+ change_column_null :ci_triggers, :project_id, true
+ change_column_null :ci_variables, :project_id, true
+ change_column_null :ci_runner_projects, :project_id, true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 94b87040d88..0167e30ff8b 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20151203162133) do
+ActiveRecord::Schema.define(version: 20151210125932) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -49,6 +49,7 @@ ActiveRecord::Schema.define(version: 20151203162133) do
t.string "admin_notification_email"
t.boolean "shared_runners_enabled", default: true, null: false
t.integer "max_artifacts_size", default: 100, null: false
+ t.string "runners_registration_token"
end
create_table "audit_events", force: :cascade do |t|
@@ -110,6 +111,7 @@ ActiveRecord::Schema.define(version: 20151203162133) do
t.string "target_url"
t.string "description"
t.text "artifacts_file"
+ t.integer "gl_project_id"
end
add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree
@@ -117,6 +119,7 @@ ActiveRecord::Schema.define(version: 20151203162133) do
add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree
add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree
add_index "ci_builds", ["commit_id"], name: "index_ci_builds_on_commit_id", using: :btree
+ add_index "ci_builds", ["gl_project_id"], name: "index_ci_builds_on_gl_project_id", using: :btree
add_index "ci_builds", ["project_id", "commit_id"], name: "index_ci_builds_on_project_id_and_commit_id", using: :btree
add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree
add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree
@@ -201,13 +204,14 @@ ActiveRecord::Schema.define(version: 20151203162133) do
add_index "ci_projects", ["shared_runners_enabled"], name: "index_ci_projects_on_shared_runners_enabled", using: :btree
create_table "ci_runner_projects", force: :cascade do |t|
- t.integer "runner_id", null: false
- t.integer "project_id", null: false
+ t.integer "runner_id", null: false
+ t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
+ t.integer "gl_project_id"
end
- add_index "ci_runner_projects", ["project_id"], name: "index_ci_runner_projects_on_project_id", using: :btree
+ add_index "ci_runner_projects", ["gl_project_id"], name: "index_ci_runner_projects_on_gl_project_id", using: :btree
add_index "ci_runner_projects", ["runner_id"], name: "index_ci_runner_projects_on_runner_id", using: :btree
create_table "ci_runners", force: :cascade do |t|
@@ -277,24 +281,27 @@ ActiveRecord::Schema.define(version: 20151203162133) do
create_table "ci_triggers", force: :cascade do |t|
t.string "token"
- t.integer "project_id", null: false
+ t.integer "project_id"
t.datetime "deleted_at"
t.datetime "created_at"
t.datetime "updated_at"
+ t.integer "gl_project_id"
end
add_index "ci_triggers", ["deleted_at"], name: "index_ci_triggers_on_deleted_at", using: :btree
+ add_index "ci_triggers", ["gl_project_id"], name: "index_ci_triggers_on_gl_project_id", using: :btree
create_table "ci_variables", force: :cascade do |t|
- t.integer "project_id", null: false
+ t.integer "project_id"
t.string "key"
t.text "value"
t.text "encrypted_value"
t.string "encrypted_value_salt"
t.string "encrypted_value_iv"
+ t.integer "gl_project_id"
end
- add_index "ci_variables", ["project_id"], name: "index_ci_variables_on_project_id", using: :btree
+ add_index "ci_variables", ["gl_project_id"], name: "index_ci_variables_on_gl_project_id", using: :btree
create_table "ci_web_hooks", force: :cascade do |t|
t.string "url", null: false
@@ -649,13 +656,24 @@ ActiveRecord::Schema.define(version: 20151203162133) do
t.string "import_source"
t.integer "commit_count", default: 0
t.text "import_error"
- end
-
+ t.integer "ci_id"
+ t.boolean "builds_enabled", default: true, null: false
+ t.boolean "shared_runners_enabled", default: true, null: false
+ t.string "runners_token"
+ t.string "build_coverage_regex"
+ t.boolean "build_allow_git_fetch", default: true, null: false
+ t.integer "build_timeout", default: 3600, null: false
+ end
+
+ add_index "projects", ["builds_enabled", "shared_runners_enabled"], name: "index_projects_on_builds_enabled_and_shared_runners_enabled", using: :btree
+ add_index "projects", ["builds_enabled"], name: "index_projects_on_builds_enabled", using: :btree
+ add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
add_index "projects", ["created_at", "id"], name: "index_projects_on_created_at_and_id", using: :btree
add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree
add_index "projects", ["last_activity_at"], name: "index_projects_on_last_activity_at", using: :btree
add_index "projects", ["namespace_id"], name: "index_projects_on_namespace_id", using: :btree
add_index "projects", ["path"], name: "index_projects_on_path", using: :btree
+ add_index "projects", ["runners_token"], name: "index_projects_on_runners_token", using: :btree
add_index "projects", ["star_count"], name: "index_projects_on_star_count", using: :btree
add_index "projects", ["visibility_level"], name: "index_projects_on_visibility_level", using: :btree
@@ -706,6 +724,7 @@ ActiveRecord::Schema.define(version: 20151203162133) do
t.boolean "merge_requests_events", default: true
t.boolean "tag_push_events", default: true
t.boolean "note_events", default: true, null: false
+ t.boolean "build_events", default: false, null: false
end
add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree
@@ -854,6 +873,7 @@ ActiveRecord::Schema.define(version: 20151203162133) do
t.boolean "tag_push_events", default: false
t.boolean "note_events", default: false, null: false
t.boolean "enable_ssl_verification", default: true
+ t.boolean "build_events", default: false, null: false
end
add_index "web_hooks", ["created_at", "id"], name: "index_web_hooks_on_created_at_and_id", using: :btree
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 43a50a9a810..1a524400627 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -32,7 +32,6 @@ Parameters:
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
-- `ci_enabled_first` - Return projects ordered by ci_enabled flag. Projects with enabled GitLab CI go first
```json
[
@@ -137,7 +136,6 @@ Parameters:
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
-- `ci_enabled_first` - Return projects ordered by ci_enabled flag. Projects with enabled GitLab CI go first
### List ALL projects
@@ -153,7 +151,6 @@ Parameters:
- `order_by` (optional) - Return requests ordered by `id`, `name`, `path`, `created_at`, `updated_at` or `last_activity_at` fields. Default is `created_at`
- `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- `search` (optional) - Return list of authorized projects according to a search criteria
-- `ci_enabled_first` - Return projects ordered by ci_enabled flag. Projects with enabled GitLab CI go first
### Get single project
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 3dbf1afc7a9..7e2edb945da 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -113,6 +113,9 @@ The YAML-defined variables are also set to all created service containers, thus
### cache
`cache` is used to specify list of files and directories which should be cached between builds.
+Caches are stored according to the branch/ref and the job name. Caches are not
+currently shared between different job names or between branches/refs. This means
+caching will benefit you if you push subsequent commits to an existing feature branch.
**The global setting allows to specify default cached files for all jobs.**
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 618391e16d2..f8116a8a31c 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -38,6 +38,7 @@ The GitLab installation consists of setting up the following components:
1. Packages / Dependencies
1. Ruby
+1. Go
1. System Users
1. Database
1. Redis
@@ -62,7 +63,7 @@ up-to-date and install it.
Install the required packages (needed to compile Ruby and native extensions to Ruby gems):
- sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake nodejs
+ sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake nodejs
If you want to use Kerberos for user authentication, then install libkrb5-dev:
@@ -174,33 +175,53 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
## 6. Redis
- sudo apt-get install redis-server
+As of this writing, most Debian/Ubuntu distributions ship with Redis 2.2 or
+2.4. GitLab requires at least Redis 2.8.
- # Configure redis to use sockets
- sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.orig
+Ubuntu users [can use a PPA](https://launchpad.net/~chris-lea/+archive/ubuntu/redis-server)
+to install a recent version of Redis.
- # Disable Redis listening on TCP by setting 'port' to 0
- sed 's/^port .*/port 0/' /etc/redis/redis.conf.orig | sudo tee /etc/redis/redis.conf
+The following instructions cover building and installing Redis from scratch:
- # Enable Redis socket for default Debian / Ubuntu path
- echo 'unixsocket /var/run/redis/redis.sock' | sudo tee -a /etc/redis/redis.conf
- # Grant permission to the socket to all members of the redis group
- echo 'unixsocketperm 770' | sudo tee -a /etc/redis/redis.conf
+```sh
+# Build Redis
+wget http://download.redis.io/releases/redis-2.8.23.tar.gz
+tar xzf redis-2.8.23.tar.gz
+cd redis-2.8.23
+make
- # Create the directory which contains the socket
- mkdir /var/run/redis
- chown redis:redis /var/run/redis
- chmod 755 /var/run/redis
- # Persist the directory which contains the socket, if applicable
- if [ -d /etc/tmpfiles.d ]; then
- echo 'd /var/run/redis 0755 redis redis 10d -' | sudo tee -a /etc/tmpfiles.d/redis.conf
- fi
+# Install Redis
+cd utils
+sudo ./install_server.sh
- # Activate the changes to redis.conf
- sudo service redis-server restart
+# Configure redis to use sockets
+sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.orig
- # Add git to the redis group
- sudo usermod -aG redis git
+# Disable Redis listening on TCP by setting 'port' to 0
+sed 's/^port .*/port 0/' /etc/redis/redis.conf.orig | sudo tee /etc/redis/redis.conf
+
+# Enable Redis socket for default Debian / Ubuntu path
+echo 'unixsocket /var/run/redis/redis.sock' | sudo tee -a /etc/redis/redis.conf
+
+# Grant permission to the socket to all members of the redis group
+echo 'unixsocketperm 770' | sudo tee -a /etc/redis/redis.conf
+
+# Create the directory which contains the socket
+mkdir /var/run/redis
+chown redis:redis /var/run/redis
+chmod 755 /var/run/redis
+
+# Persist the directory which contains the socket, if applicable
+if [ -d /etc/tmpfiles.d ]; then
+ echo 'd /var/run/redis 0755 redis redis 10d -' | sudo tee -a /etc/tmpfiles.d/redis.conf
+fi
+
+# Activate the changes to redis.conf
+sudo service redis_6379 start
+
+# Add git to the redis group
+sudo usermod -aG redis git
+```
## 7. GitLab
@@ -210,9 +231,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
### Clone the Source
# Clone GitLab repository
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-2-stable gitlab
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-3-stable gitlab
-**Note:** You can change `8-2-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `8-3-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
diff --git a/doc/integration/saml.md b/doc/integration/saml.md
index 1b8c28dd0f4..1632e42f701 100644
--- a/doc/integration/saml.md
+++ b/doc/integration/saml.md
@@ -38,7 +38,8 @@ First configure SAML 2.0 support in GitLab, then register the GitLab application
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
- }
+ },
+ "label" => "Company Login" # optional label for SAML login button, defaults to "Saml"
}
]
```
@@ -79,4 +80,4 @@ On the sign in page there should now be a SAML button below the regular sign in
If you see a "500 error" in GitLab when you are redirected back from the SAML sign in page, this likely indicates that GitLab could not get the email address for the SAML user.
-Make sure the IdP provides a claim containing the user's email address, using claim name 'email' or 'mail'. The email will be used to automatically generate the GitLab username.
+Make sure the IdP provides a claim containing the user's email address, using claim name 'email' or 'mail'. The email will be used to automatically generate the GitLab username. \ No newline at end of file
diff --git a/doc/update/8.1-to-8.2.md b/doc/update/8.1-to-8.2.md
index b08a79ca0aa..46dfa2232b4 100644
--- a/doc/update/8.1-to-8.2.md
+++ b/doc/update/8.1-to-8.2.md
@@ -142,7 +142,7 @@ git diff origin/8-1-stable:lib/support/nginx/gitlab origin/8-2-stable:lib/suppor
If you are using Apache instead of NGINX please see the updated [Apache templates].
Also note that because Apache does not support upstreams behind Unix sockets you
-will need to let gitlab-git-http-server listen on a TCP port. You can do this
+will need to let gitlab-workhorse listen on a TCP port. You can do this
via [/etc/default/gitlab].
[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
diff --git a/doc/update/8.2-to-8.3.md b/doc/update/8.2-to-8.3.md
new file mode 100644
index 00000000000..e69c4f7ed3c
--- /dev/null
+++ b/doc/update/8.2-to-8.3.md
@@ -0,0 +1,184 @@
+# From 8.2 to 8.3
+
+**NOTE:** GitLab 8.0 introduced several significant changes related to
+installation and configuration which *are not duplicated here*. Be sure you're
+already running a working version of at least 8.0 before proceeding with this
+guide.
+
+### 0. Double-check your Git version
+
+**This notice applies only to /usr/local/bin/git**
+
+If you compiled Git from source on your GitLab server then please double-check
+that you are using a version that protects against CVE-2014-9390. For six
+months after this vulnerability became known the GitLab installation guide
+still contained instructions that would install the outdated, 'vulnerable' Git
+version 2.1.2.
+
+Run the following command to get your current Git version:
+
+```sh
+/usr/local/bin/git --version
+```
+
+If you see 'No such file or directory' then you did not install Git according
+to the outdated instructions from the GitLab installation guide and you can go
+to the next step 'Stop server' below.
+
+If you see a version string then it should be v1.8.5.6, v1.9.5, v2.0.5, v2.1.4,
+v2.2.1 or newer. You can use the [instructions in the GitLab source installation
+guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
+to install a newer version of Git.
+
+### 1. Stop server
+
+ sudo service gitlab stop
+
+### 2. Backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 3. Get latest code
+
+```bash
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+```
+
+For GitLab Community Edition:
+
+```bash
+sudo -u git -H git checkout 8-3-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 8-3-stable-ee
+```
+
+### 4. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout v2.6.8
+```
+
+### 5. Update gitlab-workhorse
+
+Install and compile gitlab-workhorse. This requires [Go 1.5](https://golang.org/dl)
+which should already be on your system from GitLab 8.1.
+
+```bash
+cd /home/git/gitlab-workhorse
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout 0.4.2
+sudo -u git -H make
+```
+
+### 6. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without postgres')
+sudo -u git -H bundle install --without postgres development test --deployment
+
+# PostgreSQL installations (note: the line below states '--without mysql')
+sudo -u git -H bundle install --without mysql development test --deployment
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Clean up assets and cache
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+# Update init.d script
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+### 7. Update configuration files
+
+#### New configuration options for `gitlab.yml`
+
+There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them manually to your current `gitlab.yml`:
+
+```sh
+git diff origin/8-2-stable:config/gitlab.yml.example origin/8-3-stable:config/gitlab.yml.example
+```
+
+#### Nginx configuration
+
+View changes between the previous recommended Nginx configuration and the
+current one:
+
+```sh
+# For HTTPS configurations
+git diff origin/8-2-stable:lib/support/nginx/gitlab-ssl origin/8-3-stable:lib/support/nginx/gitlab-ssl
+
+# For HTTP configurations
+git diff origin/8-2-stable:lib/support/nginx/gitlab origin/8-3-stable:lib/support/nginx/gitlab
+```
+
+If you are using Apache instead of NGINX please see the updated [Apache templates].
+Also note that because Apache does not support upstreams behind Unix sockets you
+will need to let gitlab-workhorse listen on a TCP port. You can do this
+via [/etc/default/gitlab].
+
+[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
+[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-3-stable/lib/support/init.d/gitlab.default.example#L34
+
+### 8. Use Redis v2.8.0+
+
+Previous versions of GitLab allowed Redis versions >= 2.0 to be used, but
+GitLab 8.3 uses Sidekiq 4.0, which requires Redis 2.8. You can check your Redis version
+with the following command:
+
+ redis-cli info | grep redis_version
+
+If you need to upgrade, see the [installation guide for Redis](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-3-stable/doc/install/installation.md#6-redis).
+
+### 9. Start application
+
+ sudo service gitlab start
+ sudo service nginx restart
+
+### 10. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+ sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check:
+
+ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations, the upgrade is complete!
+
+## Things went south? Revert to previous version (8.2)
+
+### 1. Revert the code to the previous version
+
+Follow the [upgrade guide from 8.1 to 8.2](8.1-to-8.2.md), except for the
+database migration (the backup is already migrated to the previous version).
+
+### 2. Restore from the backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+
+If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above.
+
+## Troubleshooting
+
+### "You appear to have cloned an empty repository."
+
+See the [7.14 to 8.0 update guide](7.14-to-8.0.md#troubleshooting).
diff --git a/features/project/commits/commits.feature b/features/project/commits/commits.feature
index 21367fd76a0..5bb2d0e976b 100644
--- a/features/project/commits/commits.feature
+++ b/features/project/commits/commits.feature
@@ -19,7 +19,8 @@ Feature: Project Commits
Scenario: I browse commit with ci from list
Given commit has ci status
- And I click on commit link
+ And repository contains ".gitlab-ci.yml" file
+ When I click on commit link
Then I see commit ci info
And I click status link
Then I see builds list
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index f08b30e0b88..ab234bc7507 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -197,3 +197,9 @@ Feature: Project Issues
And I should not see labels field
And I submit new issue "500 error on profile"
Then I should see issue "500 error on profile"
+
+ @javascript
+ Scenario: Another user adds a comment to issue I'm currently viewing
+ Given I visit issue page "Release 0.4"
+ And another user adds a comment with text "Yay!" to issue "Release 0.4"
+ Then I should see a new comment with text "Yay!"
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 7490ad400b5..aa9078b878f 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -95,6 +95,16 @@ Feature: Project Merge Requests
And I should see a diff comment saying "Typo, please fix"
@javascript
+ Scenario: I delete a comment on a merge request diff
+ Given project "Shop" have "Bug NS-05" open merge request with diffs inside
+ And I visit merge request page "Bug NS-05"
+ And I click on the Changes tab
+ And I leave a comment like "Line is wrong" on diff
+ And I delete the comment "Line is wrong" on diff
+ And I click on the Discussion tab
+ Then I should not see any discussion
+
+ @javascript
Scenario: I comment on a line of a commit in merge request
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
diff --git a/features/project/service.feature b/features/project/service.feature
index 5014b52b9f6..ff3e7a0b38e 100644
--- a/features/project/service.feature
+++ b/features/project/service.feature
@@ -7,12 +7,6 @@ Feature: Project Services
When I visit project "Shop" services page
Then I should see list of available services
- Scenario: Activate gitlab-ci service
- When I visit project "Shop" services page
- And I click gitlab-ci service link
- And I fill gitlab-ci settings
- Then I should see service settings saved
-
Scenario: Activate hipchat service
When I visit project "Shop" services page
And I click hipchat service link
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index 439787f2641..02159ee3776 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -35,6 +35,17 @@ Feature: Project Source Browse Files
And I should see its new content
@javascript
+ Scenario: I can create and commit file with new lines at the end of file
+ Given I click on "New file" link in repo
+ And I edit code with new lines at end of file
+ And I fill the new file name
+ And I fill the commit message
+ And I click on "Commit Changes"
+ Then I am redirected to the new file
+ And I click button "Edit"
+ And I should see its content with new lines preserved at end of file
+
+ @javascript
Scenario: I can upload file and commit
Given I click on "Upload file" link in repo
And I upload a new text file
diff --git a/features/steps/admin/settings.rb b/features/steps/admin/settings.rb
index 6acbf46eb20..037f7494a77 100644
--- a/features/steps/admin/settings.rb
+++ b/features/steps/admin/settings.rb
@@ -32,6 +32,7 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps
page.check('Comments')
page.check('Issues events')
page.check('Merge Request events')
+ page.check('Build events')
click_on 'Save'
end
@@ -39,6 +40,7 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps
fill_in 'Webhook', with: 'http://localhost'
fill_in 'Username', with: 'test_user'
fill_in 'Channel', with: '#test_channel'
+ page.check('Notify only broken builds')
end
step 'I should see service template settings saved' do
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index 0d6a9a8fc66..a3141fe3be1 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -104,10 +104,14 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
step 'commit has ci status' do
@project.enable_ci
- ci_commit = create :ci_commit, gl_project: @project, sha: sample_commit.id
+ ci_commit = create :ci_commit, project: @project, sha: sample_commit.id
create :ci_build, commit: ci_commit
end
+ step 'repository contains ".gitlab-ci.yml" file' do
+ allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file).and_return(String.new)
+ end
+
step 'I see commit ci info' do
expect(page).to have_content "build: pending"
end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index a13044c3ae1..4a7ff21d385 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -284,6 +284,16 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
end
end
+ step 'another user adds a comment with text "Yay!" to issue "Release 0.4"' do
+ issue = Issue.find_by!(title: 'Release 0.4')
+ create(:note_on_issue, noteable: issue, note: 'Yay!')
+ end
+
+ step 'I should see a new comment with text "Yay!"' do
+ page.within '#notes' do
+ expect(page).to have_content('Yay!')
+ end
+ end
def filter_issue(text)
fill_in 'issue_search', with: text
end
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 13d9d180dd1..0d340d97ff9 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -211,6 +211,25 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
end
+ step 'I delete the comment "Line is wrong" on diff' do
+ page.within('.diff-file:nth-of-type(5) .note') do
+ find('.js-note-delete').click
+ end
+ end
+
+ step 'I click on the Discussion tab' do
+ page.within '.merge-request-tabs' do
+ click_link 'Discussion'
+ end
+
+ # Waits for load
+ expect(page).to have_css('.tab-content #notes.active')
+ end
+
+ step 'I should not see any discussion' do
+ expect(page).not_to have_css('.notes .discussion')
+ end
+
step 'I should see a discussion has started on diff' do
page.within(".notes .discussion") do
page.should have_content "#{current_user.name} started a discussion"
@@ -386,7 +405,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
step '"Bug NS-05" has CI status' do
project = merge_request.source_project
project.enable_ci
- ci_commit = create :ci_commit, gl_project: project, sha: merge_request.last_commit.id
+ ci_commit = create :ci_commit, project: project, sha: merge_request.last_commit.id
create :ci_build, commit: ci_commit
end
diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb
index 1c700df0c63..ed3957ca873 100644
--- a/features/steps/project/services.rb
+++ b/features/steps/project/services.rb
@@ -11,7 +11,6 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
expect(page).to have_content 'Project services'
expect(page).to have_content 'Campfire'
expect(page).to have_content 'HipChat'
- expect(page).to have_content 'GitLab CI'
expect(page).to have_content 'Assembla'
expect(page).to have_content 'Pushover'
expect(page).to have_content 'Atlassian Bamboo'
@@ -20,15 +19,6 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
expect(page).to have_content 'Irker (IRC gateway)'
end
- step 'I click gitlab-ci service link' do
- click_link 'GitLab CI'
- end
-
- step 'I fill gitlab-ci settings' do
- check 'Active'
- click_button 'Save'
- end
-
step 'I should see service settings saved' do
expect(find_field('Active').value).to eq '1'
end
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index f2b95764267..b88709620ab 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -37,6 +37,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
expect(page).to have_content new_gitignore_content
end
+ step 'I should see its content with new lines preserved at end of file' do
+ expect(evaluate_script('blob.editor.getValue()')).to eq "Sample\n\n\n"
+ end
+
step 'I click link "Raw"' do
click_link 'Raw'
end
@@ -62,6 +66,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
set_new_content
end
+ step 'I edit code with new lines at end of file' do
+ execute_script('blob.editor.setValue("Sample\n\n\n")')
+ end
+
step 'I fill the new file name' do
fill_in :file_name, with: new_file_name
end
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index 7021fac5fe4..da643bf3ba9 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -204,7 +204,7 @@ module SharedProject
step 'project "Shop" has CI build' do
project = Project.find_by(name: "Shop")
- create :ci_commit, gl_project: project, sha: project.commit.sha
+ create :ci_commit, project: project, sha: project.commit.sha
end
step 'I should see last commit with CI status' do
diff --git a/features/support/capybara.rb b/features/support/capybara.rb
index 31dbf0feb2f..4156c7ec484 100644
--- a/features/support/capybara.rb
+++ b/features/support/capybara.rb
@@ -2,7 +2,7 @@ require 'spinach/capybara'
require 'capybara/poltergeist'
# Give CI some extra time
-timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 90 : 10
+timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 90 : 15
Capybara.javascript_driver = :poltergeist
Capybara.register_driver :poltergeist do |app|
diff --git a/lib/api/api.rb b/lib/api/api.rb
index fe1bf8a4816..7834262d612 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -53,5 +53,6 @@ module API
mount Settings
mount Keys
mount Tags
+ mount Triggers
end
end
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 2c0596c9dfb..1162271f5fc 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -53,7 +53,7 @@ module API
name = params[:name] || params[:context]
status = GenericCommitStatus.running_or_pending.find_by(commit: ci_commit, name: name, ref: params[:ref])
- status ||= GenericCommitStatus.new(commit: ci_commit, user: current_user)
+ status ||= GenericCommitStatus.new(project: @project, commit: ci_commit, user: current_user)
status.update(attrs)
case params[:state].to_s
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 81bf7a8222b..b1cd80bdf65 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -45,7 +45,8 @@ module API
class ProjectHook < Hook
expose :project_id, :push_events
- expose :issues_events, :merge_requests_events, :tag_push_events, :note_events, :enable_ssl_verification
+ expose :issues_events, :merge_requests_events, :tag_push_events, :note_events, :build_events
+ expose :enable_ssl_verification
end
class ForkedFromProject < Grape::Entity
@@ -63,6 +64,7 @@ module API
expose :name, :name_with_namespace
expose :path, :path_with_namespace
expose :issues_enabled, :merge_requests_enabled, :wiki_enabled, :builds_enabled, :snippets_enabled, :created_at, :last_activity_at
+ expose :shared_runners_enabled
expose :creator_id
expose :namespace
expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? }
@@ -252,7 +254,7 @@ module API
class ProjectService < Grape::Entity
expose :id, :title, :created_at, :updated_at, :active
- expose :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events
+ expose :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events, :build_events
# Expose serialized properties
expose :properties do |service, options|
field_names = service.fields.
@@ -359,5 +361,9 @@ module API
end
end
end
+
+ class TriggerRequest < Grape::Entity
+ expose :id, :variables
+ end
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 92540ccf2b1..a4df810e755 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -266,12 +266,7 @@ module API
projects = projects.search(params[:search])
end
- if params[:ci_enabled_first].present?
- projects.includes(:gitlab_ci_service).
- reorder("services.active DESC, projects.#{project_order_by} #{project_sort}")
- else
- projects.reorder(project_order_by => project_sort)
- end
+ projects.reorder(project_order_by => project_sort)
end
def project_order_by
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 882d1a083ad..cf9938d25a7 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -45,6 +45,7 @@ module API
:merge_requests_events,
:tag_push_events,
:note_events,
+ :build_events,
:enable_ssl_verification
]
@hook = user_project.hooks.new(attrs)
@@ -77,6 +78,7 @@ module API
:merge_requests_events,
:tag_push_events,
:note_events,
+ :build_events,
:enable_ssl_verification
]
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 6928fe0eb9d..bdf4b77596e 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -82,6 +82,7 @@ module API
# builds_enabled (optional)
# wiki_enabled (optional)
# snippets_enabled (optional)
+ # shared_runners_enabled (optional)
# namespace_id (optional) - defaults to user namespace
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional) - 0 by default
@@ -98,6 +99,7 @@ module API
:builds_enabled,
:wiki_enabled,
:snippets_enabled,
+ :shared_runners_enabled,
:namespace_id,
:public,
:visibility_level,
@@ -126,6 +128,7 @@ module API
# builds_enabled (optional)
# wiki_enabled (optional)
# snippets_enabled (optional)
+ # shared_runners_enabled (optional)
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional)
# import_url (optional)
@@ -142,6 +145,7 @@ module API
:builds_enabled,
:wiki_enabled,
:snippets_enabled,
+ :shared_runners_enabled,
:public,
:visibility_level,
:import_url]
@@ -183,6 +187,7 @@ module API
# builds_enabled (optional)
# wiki_enabled (optional)
# snippets_enabled (optional)
+ # shared_runners_enabled (optional)
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional) - visibility level of a project
# Example Request
@@ -197,6 +202,7 @@ module API
:builds_enabled,
:wiki_enabled,
:snippets_enabled,
+ :shared_runners_enabled,
:public,
:visibility_level]
attrs = map_public_to_visibility_level(attrs)
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
new file mode 100644
index 00000000000..2781f1cf191
--- /dev/null
+++ b/lib/api/triggers.rb
@@ -0,0 +1,48 @@
+module API
+ # Triggers API
+ class Triggers < Grape::API
+ resource :projects do
+ # Trigger a GitLab project build
+ #
+ # Parameters:
+ # id (required) - The ID of a CI project
+ # ref (required) - The name of project's branch or tag
+ # token (required) - The uniq token of trigger
+ # variables (optional) - The list of variables to be injected into build
+ # Example Request:
+ # POST /projects/:id/trigger/builds
+ post ":id/trigger/builds" do
+ required_attributes! [:ref, :token]
+
+ project = Project.find_with_namespace(params[:id]) || Project.find_by(id: params[:id])
+ trigger = Ci::Trigger.find_by_token(params[:token].to_s)
+ not_found! unless project && trigger
+ unauthorized! unless trigger.project == project
+
+ # validate variables
+ variables = params[:variables]
+ if variables
+ unless variables.is_a?(Hash)
+ render_api_error!('variables needs to be a hash', 400)
+ end
+
+ unless variables.all? { |key, value| key.is_a?(String) && value.is_a?(String) }
+ render_api_error!('variables needs to be a map of key-valued strings', 400)
+ end
+
+ # convert variables from Mash to Hash
+ variables = variables.to_h
+ end
+
+ # create request and trigger builds
+ trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref].to_s, variables)
+ if trigger_request
+ present trigger_request, with: Entities::TriggerRequest
+ else
+ errors = 'No builds created'
+ render_api_error!(errors, 400)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/ci/api/api.rb b/lib/ci/api/api.rb
index 07e68216d7f..5c347e432b4 100644
--- a/lib/ci/api/api.rb
+++ b/lib/ci/api/api.rb
@@ -30,9 +30,7 @@ module Ci
helpers Gitlab::CurrentSettings
mount Builds
- mount Commits
mount Runners
- mount Projects
mount Triggers
end
end
diff --git a/lib/ci/api/commits.rb b/lib/ci/api/commits.rb
deleted file mode 100644
index a60769d8305..00000000000
--- a/lib/ci/api/commits.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-module Ci
- module API
- class Commits < Grape::API
- resource :commits do
- # Get list of commits per project
- #
- # Parameters:
- # project_id (required) - The ID of a project
- # project_token (requires) - Project token
- # page (optional)
- # per_page (optional) - items per request (default is 20)
- #
- get do
- required_attributes! [:project_id, :project_token]
- project = Ci::Project.find(params[:project_id])
- authenticate_project_token!(project)
-
- commits = project.commits.page(params[:page]).per(params[:per_page] || 20)
- present commits, with: Entities::CommitWithBuilds
- end
-
- # Create a commit
- #
- # Parameters:
- # project_id (required) - The ID of a project
- # project_token (requires) - Project token
- # data (required) - GitLab push data
- #
- # Sample GitLab push data:
- # {
- # "before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
- # "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
- # "ref": "refs/heads/master",
- # "commits": [
- # {
- # "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
- # "message": "Update Catalan translation to e38cb41.",
- # "timestamp": "2011-12-12T14:27:31+02:00",
- # "url": "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
- # "author": {
- # "name": "Jordi Mallach",
- # "email": "jordi@softcatala.org",
- # }
- # }, .... more commits
- # ]
- # }
- #
- # Example Request:
- # POST /commits
- post do
- required_attributes! [:project_id, :data, :project_token]
- project = Ci::Project.find(params[:project_id])
- authenticate_project_token!(project)
- commit = Ci::CreateCommitService.new.execute(project, current_user, params[:data])
-
- if commit.persisted?
- present commit, with: Entities::CommitWithBuilds
- else
- errors = commit.errors.full_messages.join(", ")
- render_api_error!(errors, 400)
- end
- end
- end
- end
- end
-end
diff --git a/lib/ci/api/entities.rb b/lib/ci/api/entities.rb
index 750f421872d..e4ac0545ea2 100644
--- a/lib/ci/api/entities.rb
+++ b/lib/ci/api/entities.rb
@@ -37,15 +37,6 @@ module Ci
expose :id, :token
end
- class Project < Grape::Entity
- expose :id, :name, :token, :default_ref, :gitlab_url, :path,
- :always_build, :polling_interval, :public, :ssh_url_to_repo, :gitlab_id
-
- expose :timeout do |model|
- model.timeout
- end
- end
-
class RunnerProject < Grape::Entity
expose :id, :project_id, :runner_id
end
diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb
index 02502333756..443563c2e4a 100644
--- a/lib/ci/api/helpers.rb
+++ b/lib/ci/api/helpers.rb
@@ -6,22 +6,22 @@ module Ci
UPDATE_RUNNER_EVERY = 60
def authenticate_runners!
- forbidden! unless params[:token] == GitlabCi::REGISTRATION_TOKEN
+ forbidden! unless runner_registration_token_valid?
end
def authenticate_runner!
forbidden! unless current_runner
end
- def authenticate_project_token!(project)
- forbidden! unless project.valid_token?(params[:project_token])
- end
-
def authenticate_build_token!(build)
token = (params[BUILD_TOKEN_PARAM] || env[BUILD_TOKEN_HEADER]).to_s
forbidden! unless token && build.valid_token?(token)
end
+ def runner_registration_token_valid?
+ params[:token] == current_application_settings.ensure_runners_registration_token
+ end
+
def update_runner_last_contact
# Use a random threshold to prevent beating DB updates
contacted_at_max_age = UPDATE_RUNNER_EVERY + Random.rand(UPDATE_RUNNER_EVERY)
diff --git a/lib/ci/api/projects.rb b/lib/ci/api/projects.rb
deleted file mode 100644
index d719ad9e8d5..00000000000
--- a/lib/ci/api/projects.rb
+++ /dev/null
@@ -1,195 +0,0 @@
-module Ci
- module API
- # Projects API
- class Projects < Grape::API
- before { authenticate! }
-
- resource :projects do
- # Register new webhook for project
- #
- # Parameters
- # project_id (required) - The ID of a project
- # web_hook (required) - WebHook URL
- # Example Request
- # POST /projects/:project_id/webhooks
- post ":project_id/webhooks" do
- required_attributes! [:web_hook]
-
- project = Ci::Project.find(params[:project_id])
-
- unauthorized! unless can?(current_user, :admin_project, project.gl_project)
-
- web_hook = project.web_hooks.new({ url: params[:web_hook] })
-
- if web_hook.save
- present web_hook, with: Entities::WebHook
- else
- errors = web_hook.errors.full_messages.join(", ")
- render_api_error!(errors, 400)
- end
- end
-
- # Retrieve all Gitlab CI projects that the user has access to
- #
- # Example Request:
- # GET /projects
- get do
- gitlab_projects = current_user.authorized_projects
- gitlab_projects = filter_projects(gitlab_projects)
- gitlab_projects = paginate gitlab_projects
-
- ids = gitlab_projects.map { |project| project.id }
-
- projects = Ci::Project.where("gitlab_id IN (?)", ids).load
- present projects, with: Entities::Project
- end
-
- # Retrieve all Gitlab CI projects that the user owns
- #
- # Example Request:
- # GET /projects/owned
- get "owned" do
- gitlab_projects = current_user.owned_projects
- gitlab_projects = filter_projects(gitlab_projects)
- gitlab_projects = paginate gitlab_projects
-
- ids = gitlab_projects.map { |project| project.id }
-
- projects = Ci::Project.where("gitlab_id IN (?)", ids).load
- present projects, with: Entities::Project
- end
-
- # Retrieve info for a Gitlab CI project
- #
- # Parameters:
- # id (required) - The ID of a project
- # Example Request:
- # GET /projects/:id
- get ":id" do
- project = Ci::Project.find(params[:id])
- unauthorized! unless can?(current_user, :read_project, project.gl_project)
-
- present project, with: Entities::Project
- end
-
- # Create Gitlab CI project using Gitlab project info
- #
- # Parameters:
- # gitlab_id (required) - The gitlab id of the project
- # default_ref - The branch to run against (defaults to `master`)
- # Example Request:
- # POST /projects
- post do
- required_attributes! [:gitlab_id]
-
- filtered_params = {
- gitlab_id: params[:gitlab_id],
- # we accept gitlab_url for backward compatibility for a while (added to 7.11)
- default_ref: params[:default_ref] || 'master'
- }
-
- project = Ci::Project.new(filtered_params)
- project.build_missing_services
-
- if project.save
- present project, with: Entities::Project
- else
- errors = project.errors.full_messages.join(", ")
- render_api_error!(errors, 400)
- end
- end
-
- # Update a Gitlab CI project
- #
- # Parameters:
- # id (required) - The ID of a project
- # default_ref - The branch to run against (defaults to `master`)
- # Example Request:
- # PUT /projects/:id
- put ":id" do
- project = Ci::Project.find(params[:id])
-
- unauthorized! unless can?(current_user, :admin_project, project.gl_project)
-
- attrs = attributes_for_keys [:default_ref]
-
- if project.update_attributes(attrs)
- present project, with: Entities::Project
- else
- errors = project.errors.full_messages.join(", ")
- render_api_error!(errors, 400)
- end
- end
-
- # Remove a Gitlab CI project
- #
- # Parameters:
- # id (required) - The ID of a project
- # Example Request:
- # DELETE /projects/:id
- delete ":id" do
- project = Ci::Project.find(params[:id])
-
- unauthorized! unless can?(current_user, :admin_project, project.gl_project)
-
- project.destroy
- end
-
- # Link a Gitlab CI project to a runner
- #
- # Parameters:
- # id (required) - The ID of a CI project
- # runner_id (required) - The ID of a runner
- # Example Request:
- # POST /projects/:id/runners/:runner_id
- post ":id/runners/:runner_id" do
- project = Ci::Project.find(params[:id])
- runner = Ci::Runner.find(params[:runner_id])
-
- unauthorized! unless can?(current_user, :admin_project, project.gl_project)
-
- options = {
- project_id: project.id,
- runner_id: runner.id
- }
-
- runner_project = Ci::RunnerProject.new(options)
-
- if runner_project.save
- present runner_project, with: Entities::RunnerProject
- else
- errors = project.errors.full_messages.join(", ")
- render_api_error!(errors, 400)
- end
- end
-
- # Remove a Gitlab CI project from a runner
- #
- # Parameters:
- # id (required) - The ID of a CI project
- # runner_id (required) - The ID of a runner
- # Example Request:
- # DELETE /projects/:id/runners/:runner_id
- delete ":id/runners/:runner_id" do
- project = Ci::Project.find(params[:id])
- runner = Ci::Runner.find(params[:runner_id])
-
- unauthorized! unless can?(current_user, :admin_project, project.gl_project)
-
- options = {
- project_id: project.id,
- runner_id: runner.id
- }
-
- runner_project = Ci::RunnerProject.find_by(options)
-
- if runner_project.present?
- runner_project.destroy
- else
- not_found!
- end
- end
- end
- end
- end
-end
diff --git a/lib/ci/api/runners.rb b/lib/ci/api/runners.rb
index 1466fe4356e..bfc14fe7a6b 100644
--- a/lib/ci/api/runners.rb
+++ b/lib/ci/api/runners.rb
@@ -3,17 +3,6 @@ module Ci
# Runners API
class Runners < Grape::API
resource :runners do
- # Get list of all available runners
- #
- # Example Request:
- # GET /runners
- get do
- authenticate!
- runners = Ci::Runner.all
-
- present runners, with: Entities::Runner
- end
-
# Delete runner
# Parameters:
# token (required) - The unique token of runner
@@ -40,14 +29,14 @@ module Ci
required_attributes! [:token]
runner =
- if params[:token] == GitlabCi::REGISTRATION_TOKEN
+ if runner_registration_token_valid?
# Create shared runner. Requires admin access
Ci::Runner.create(
description: params[:description],
tag_list: params[:tag_list],
is_shared: true
)
- elsif project = Ci::Project.find_by(token: params[:token])
+ elsif project = Project.find_by(runners_token: params[:token])
# Create a specific runner for project.
project.runners.create(
description: params[:description],
diff --git a/lib/ci/api/triggers.rb b/lib/ci/api/triggers.rb
index 40907d6db54..63b42113513 100644
--- a/lib/ci/api/triggers.rb
+++ b/lib/ci/api/triggers.rb
@@ -14,7 +14,7 @@ module Ci
post ":id/refs/:ref/trigger" do
required_attributes! [:token]
- project = Ci::Project.find(params[:id])
+ project = Project.find_by(ci_id: params[:id].to_i)
trigger = Ci::Trigger.find_by_token(params[:token].to_s)
not_found! unless project && trigger
unauthorized! unless trigger.project == project
diff --git a/lib/ci/charts.rb b/lib/ci/charts.rb
index 5ff7407c6fe..d53bdcbd0f2 100644
--- a/lib/ci/charts.rb
+++ b/lib/ci/charts.rb
@@ -60,7 +60,7 @@ module Ci
class BuildTime < Chart
def collect
- commits = project.commits.last(30)
+ commits = project.ci_commits.last(30)
commits.each do |commit|
@labels << commit.short_sha
diff --git a/lib/ci/current_settings.rb b/lib/ci/current_settings.rb
deleted file mode 100644
index fd78b024970..00000000000
--- a/lib/ci/current_settings.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-module Ci
- module CurrentSettings
- def current_application_settings
- key = :ci_current_application_settings
-
- RequestStore.store[key] ||= begin
- if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('ci_application_settings')
- Ci::ApplicationSetting.current || Ci::ApplicationSetting.create_from_defaults
- else
- fake_application_settings
- end
- end
- end
-
- def fake_application_settings
- OpenStruct.new(
- all_broken_builds: Ci::Settings.gitlab_ci['all_broken_builds'],
- add_pusher: Ci::Settings.gitlab_ci['add_pusher'],
- )
- end
- end
-end
diff --git a/lib/ci/git.rb b/lib/ci/git.rb
deleted file mode 100644
index 7acc3f38edb..00000000000
--- a/lib/ci/git.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module Ci
- module Git
- BLANK_SHA = '0' * 40
- end
-end
diff --git a/lib/ci/scheduler.rb b/lib/ci/scheduler.rb
deleted file mode 100644
index ee0958f4be1..00000000000
--- a/lib/ci/scheduler.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-module Ci
- class Scheduler
- def perform
- projects = Ci::Project.where(always_build: true).all
- projects.each do |project|
- last_commit = project.commits.last
- next unless last_commit && last_commit.last_build
-
- interval = project.polling_interval
- if (last_commit.last_build.created_at + interval.hours) < Time.now
- last_commit.retry
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 0d156047ff0..cdcaae8094c 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -77,7 +77,9 @@ module Grack
if project && matched_login.present? && git_cmd == 'git-upload-pack'
underscored_service = matched_login['s'].underscore
- if Service.available_services_names.include?(underscored_service)
+ if underscored_service == 'gitlab_ci'
+ return project && project.valid_build_token?(password)
+ elsif Service.available_services_names.include?(underscored_service)
service_method = "#{underscored_service}_service"
service = project.send(service_method)
diff --git a/lib/gitlab/build_data_builder.rb b/lib/gitlab/build_data_builder.rb
new file mode 100644
index 00000000000..86bfa0a4378
--- /dev/null
+++ b/lib/gitlab/build_data_builder.rb
@@ -0,0 +1,64 @@
+module Gitlab
+ class BuildDataBuilder
+ class << self
+ def build(build)
+ project = build.project
+ commit = build.commit
+ user = build.user
+
+ data = {
+ object_kind: 'build',
+
+ ref: build.ref,
+ tag: build.tag,
+ before_sha: build.before_sha,
+ sha: build.sha,
+
+ # TODO: should this be not prefixed with build_?
+ # Leaving this way to have backward compatibility
+ build_id: build.id,
+ build_name: build.name,
+ build_stage: build.stage,
+ build_status: build.status,
+ build_started_at: build.started_at,
+ build_finished_at: build.finished_at,
+ build_duration: build.duration,
+
+ # TODO: do we still need it?
+ project_id: project.id,
+ project_name: project.name_with_namespace,
+
+ user: {
+ id: user.try(:id),
+ name: user.try(:name),
+ email: user.try(:email),
+ },
+
+ commit: {
+ id: commit.id,
+ sha: commit.sha,
+ message: commit.git_commit_message,
+ author_name: commit.git_author_name,
+ author_email: commit.git_author_email,
+ status: commit.status,
+ duration: commit.duration,
+ started_at: commit.started_at,
+ finished_at: commit.finished_at,
+ },
+
+ repository: {
+ name: project.name,
+ url: project.url_to_repo,
+ description: project.description,
+ homepage: project.web_url,
+ git_http_url: project.http_url_to_repo,
+ git_ssh_url: project.ssh_url_to_repo,
+ visibility_level: project.visibility_level
+ },
+ }
+
+ data
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index 71f37f1fef8..de77a6fbff1 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -7,5 +7,23 @@ module Gitlab
def self.postgresql?
ActiveRecord::Base.connection.adapter_name.downcase == 'postgresql'
end
+
+ def true_value
+ case ActiveRecord::Base.connection.adapter_name.downcase
+ when 'postgresql'
+ "'t'"
+ else
+ 1
+ end
+ end
+
+ def false_value
+ case ActiveRecord::Base.connection.adapter_name.downcase
+ when 'postgresql'
+ "'f'"
+ else
+ 0
+ end
+ end
end
end
diff --git a/lib/tasks/ci/schedule_builds.rake b/lib/tasks/ci/schedule_builds.rake
deleted file mode 100644
index 49435504c67..00000000000
--- a/lib/tasks/ci/schedule_builds.rake
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace :ci do
- desc "GitLab CI | Clean running builds"
- task schedule_builds: :environment do
- Ci::Scheduler.new.perform
- end
-end
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index a25fac62cfc..b5af3d88b4c 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -331,7 +331,7 @@ namespace :gitlab do
end
def check_redis_version
- min_redis_version = "2.4.0"
+ min_redis_version = "2.8.0"
print "Redis version >= #{min_redis_version}? ... "
redis_version = run(%W(redis-cli --version))
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 2fcd70182b9..f76e826f138 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -42,6 +42,10 @@ FactoryGirl.define do
commit factory: :ci_commit
+ after(:build) do |build, evaluator|
+ build.project = build.commit.project
+ end
+
factory :ci_not_started_build do
started_at nil
finished_at nil
diff --git a/spec/factories/ci/commits.rb b/spec/factories/ci/commits.rb
index 70e3fa319c6..b42cafa518a 100644
--- a/spec/factories/ci/commits.rb
+++ b/spec/factories/ci/commits.rb
@@ -21,7 +21,7 @@ FactoryGirl.define do
factory :ci_empty_commit, class: Ci::Commit do
sha '97de212e80737a608d939f648d959671fb0a0142'
- gl_project factory: :empty_project
+ project factory: :empty_project
factory :ci_commit_without_jobs do
after(:build) do |commit|
diff --git a/spec/factories/ci/events.rb b/spec/factories/ci/events.rb
deleted file mode 100644
index 9638618a400..00000000000
--- a/spec/factories/ci/events.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# == Schema Information
-#
-# Table name: events
-#
-# id :integer not null, primary key
-# project_id :integer
-# user_id :integer
-# is_admin :integer
-# description :text
-# created_at :datetime
-# updated_at :datetime
-#
-
-FactoryGirl.define do
- factory :ci_event, class: Ci::Event do
- sequence :description do |n|
- "updated project settings#{n}"
- end
-
- factory :ci_admin_event do
- is_admin true
- end
- end
-end
diff --git a/spec/factories/ci/projects.rb b/spec/factories/ci/projects.rb
deleted file mode 100644
index 11cb8c9eeaa..00000000000
--- a/spec/factories/ci/projects.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# == Schema Information
-#
-# Table name: projects
-#
-# id :integer not null, primary key
-# name :string(255) not null
-# timeout :integer default(3600), not null
-# created_at :datetime
-# updated_at :datetime
-# token :string(255)
-# default_ref :string(255)
-# path :string(255)
-# always_build :boolean default(FALSE), not null
-# polling_interval :integer
-# public :boolean default(FALSE), not null
-# ssh_url_to_repo :string(255)
-# gitlab_id :integer
-# allow_git_fetch :boolean default(TRUE), not null
-# email_recipients :string(255) default(""), not null
-# email_add_pusher :boolean default(TRUE), not null
-# email_only_broken_builds :boolean default(TRUE), not null
-# skip_refs :string(255)
-# coverage_regex :string(255)
-# shared_runners_enabled :boolean default(FALSE)
-# generated_yaml_config :text
-#
-
-# Read about factories at https://github.com/thoughtbot/factory_girl
-
-FactoryGirl.define do
- factory :ci_project_without_token, class: Ci::Project do
- default_ref 'master'
-
- shared_runners_enabled false
-
- factory :ci_project do
- token 'iPWx6WM4lhHNedGfBpPJNP'
- end
-
- initialize_with do
- # TODO:
- # this is required, because builds_enabled is initialized when Project is created
- # and this create gitlab_ci_project if builds is set to true
- # here we take created gitlab_ci_project and update it's attributes
- ci_project = create(:empty_project).ensure_gitlab_ci_project
- ci_project.update_attributes(attributes)
- ci_project
- end
- end
-end
diff --git a/spec/factories/ci/runner_projects.rb b/spec/factories/ci/runner_projects.rb
index 3aa14ca434d..008d1c5d961 100644
--- a/spec/factories/ci/runner_projects.rb
+++ b/spec/factories/ci/runner_projects.rb
@@ -14,6 +14,6 @@
FactoryGirl.define do
factory :ci_runner_project, class: Ci::RunnerProject do
runner_id 1
- project_id 1
+ gl_project_id 1
end
end
diff --git a/spec/factories/ci/web_hook.rb b/spec/factories/ci/web_hook.rb
deleted file mode 100644
index 40d878ecb3c..00000000000
--- a/spec/factories/ci/web_hook.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-FactoryGirl.define do
- factory :ci_web_hook, class: Ci::WebHook do
- sequence(:url) { FFaker::Internet.uri('http') }
- project factory: :ci_project
- end
-end
diff --git a/spec/features/ci/admin/builds_spec.rb b/spec/features/admin/admin_builds_spec.rb
index 623d466c67b..72764b1629d 100644
--- a/spec/features/ci/admin/builds_spec.rb
+++ b/spec/features/admin/admin_builds_spec.rb
@@ -5,17 +5,16 @@ describe "Admin Builds" do
let(:build) { FactoryGirl.create :ci_build, commit: commit }
before do
- skip_ci_admin_auth
- login_as :user
+ login_as :admin
end
describe "GET /admin/builds" do
before do
build
- visit ci_admin_builds_path
+ visit admin_builds_path
end
- it { expect(page).to have_content "All builds" }
+ it { expect(page).to have_content "Running" }
it { expect(page).to have_content build.short_sha }
end
@@ -26,43 +25,43 @@ describe "Admin Builds" do
FactoryGirl.create :ci_build, commit: commit, status: "success"
FactoryGirl.create :ci_build, commit: commit, status: "failed"
- visit ci_admin_builds_path
+ visit admin_builds_path
+
+ within ".center-top-menu" do
+ click_on "All"
+ end
expect(page.all(".build-link").size).to eq(4)
end
- it "shows pending builds" do
+ it "shows finished builds" do
build = FactoryGirl.create :ci_build, commit: commit, status: "pending"
build1 = FactoryGirl.create :ci_build, commit: commit, status: "running"
build2 = FactoryGirl.create :ci_build, commit: commit, status: "success"
- build3 = FactoryGirl.create :ci_build, commit: commit, status: "failed"
- visit ci_admin_builds_path
+ visit admin_builds_path
- within ".nav.nav-tabs" do
- click_on "Pending"
+ within ".center-top-menu" do
+ click_on "Finished"
end
- expect(page.find(".build-link")).to have_content(build.id)
+ expect(page.find(".build-link")).not_to have_content(build.id)
expect(page.find(".build-link")).not_to have_content(build1.id)
- expect(page.find(".build-link")).not_to have_content(build2.id)
- expect(page.find(".build-link")).not_to have_content(build3.id)
+ expect(page.find(".build-link")).to have_content(build2.id)
end
it "shows running builds" do
build = FactoryGirl.create :ci_build, commit: commit, status: "pending"
- build1 = FactoryGirl.create :ci_build, commit: commit, status: "running"
build2 = FactoryGirl.create :ci_build, commit: commit, status: "success"
build3 = FactoryGirl.create :ci_build, commit: commit, status: "failed"
- visit ci_admin_builds_path
+ visit admin_builds_path
- within ".nav.nav-tabs" do
+ within ".center-top-menu" do
click_on "Running"
end
- expect(page.find(".build-link")).to have_content(build1.id)
- expect(page.find(".build-link")).not_to have_content(build.id)
+ expect(page.find(".build-link")).to have_content(build.id)
expect(page.find(".build-link")).not_to have_content(build2.id)
expect(page.find(".build-link")).not_to have_content(build3.id)
end
diff --git a/spec/features/ci/admin/runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index b83744f53a8..66a2cc0c157 100644
--- a/spec/features/ci/admin/runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -10,7 +10,7 @@ describe "Admin Runners" do
runner = FactoryGirl.create(:ci_runner)
commit = FactoryGirl.create(:ci_commit)
FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id)
- visit ci_admin_runners_path
+ visit admin_runners_path
end
it { page.has_text? "Manage Runners" }
@@ -36,9 +36,9 @@ describe "Admin Runners" do
let(:runner) { FactoryGirl.create :ci_runner }
before do
- @project1 = FactoryGirl.create(:ci_project)
- @project2 = FactoryGirl.create(:ci_project)
- visit ci_admin_runner_path(runner)
+ @project1 = FactoryGirl.create(:empty_project)
+ @project2 = FactoryGirl.create(:empty_project)
+ visit admin_runner_path(runner)
end
describe 'runner info' do
@@ -53,7 +53,7 @@ describe "Admin Runners" do
describe 'search' do
before do
search_form = find('#runner-projects-search')
- search_form.fill_in 'search', with: @project1.gl_project.name
+ search_form.fill_in 'search', with: @project1.name
search_form.click_button 'Search'
end
@@ -61,4 +61,26 @@ describe "Admin Runners" do
it { expect(page).not_to have_content(@project2.name_with_namespace) }
end
end
+
+ describe 'runners registration token' do
+ let!(:token) { current_application_settings.ensure_runners_registration_token }
+ before { visit admin_runners_path }
+
+ it 'has a registration token' do
+ expect(page).to have_content("Registration token is #{token}")
+ expect(page).to have_selector('#runners-token', text: token)
+ end
+
+ describe 'reload registration token' do
+ let(:page_token) { find('#runners-token').text }
+
+ before do
+ click_button 'Reset runners registration token'
+ end
+
+ it 'changes registration token' do
+ expect(page_token).to_not eq token
+ end
+ end
+ end
end
diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb
index 52134556339..dc41be8246f 100644
--- a/spec/features/atom/users_spec.rb
+++ b/spec/features/atom/users_spec.rb
@@ -79,6 +79,6 @@ describe "User Feed", feature: true do
end
def safe_name
- CGI.escapeHTML(user.name)
+ html_escape(user.name)
end
end
diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb
index 1f99a808f87..f0031a0a247 100644
--- a/spec/features/builds_spec.rb
+++ b/spec/features/builds_spec.rb
@@ -7,15 +7,15 @@ describe "Builds" do
login_as(:user)
@commit = FactoryGirl.create :ci_commit
@build = FactoryGirl.create :ci_build, commit: @commit
- @gl_project = @commit.project.gl_project
- @gl_project.team << [@user, :master]
+ @project = @commit.project
+ @project.team << [@user, :master]
end
describe "GET /:project/builds" do
context "Running scope" do
before do
@build.run!
- visit namespace_project_builds_path(@gl_project.namespace, @gl_project)
+ visit namespace_project_builds_path(@project.namespace, @project)
end
it { expect(page).to have_content 'Running' }
@@ -28,7 +28,7 @@ describe "Builds" do
context "Finished scope" do
before do
@build.run!
- visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :finished)
+ visit namespace_project_builds_path(@project.namespace, @project, scope: :finished)
end
it { expect(page).to have_content 'No builds to show' }
@@ -37,8 +37,8 @@ describe "Builds" do
context "All builds" do
before do
- @gl_project.ci_builds.running_or_pending.each(&:success)
- visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :all)
+ @project.builds.running_or_pending.each(&:success)
+ visit namespace_project_builds_path(@project.namespace, @project, scope: :all)
end
it { expect(page).to have_content 'All' }
@@ -52,7 +52,7 @@ describe "Builds" do
describe "POST /:project/builds/:id/cancel_all" do
before do
@build.run!
- visit namespace_project_builds_path(@gl_project.namespace, @gl_project)
+ visit namespace_project_builds_path(@project.namespace, @project)
click_link "Cancel running"
end
@@ -62,7 +62,7 @@ describe "Builds" do
describe "GET /:project/builds/:id" do
before do
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
end
it { expect(page).to have_content @commit.sha[0..7] }
@@ -72,7 +72,7 @@ describe "Builds" do
context "Download artifacts" do
before do
@build.update_attributes(artifacts_file: artifacts_file)
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
end
it { expect(page).to have_content 'Download artifacts' }
@@ -82,7 +82,7 @@ describe "Builds" do
describe "POST /:project/builds/:id/cancel" do
before do
@build.run!
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
click_link "Cancel"
end
@@ -93,7 +93,7 @@ describe "Builds" do
describe "POST /:project/builds/:id/retry" do
before do
@build.run!
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
click_link "Cancel"
click_link 'Retry'
end
@@ -105,7 +105,7 @@ describe "Builds" do
describe "GET /:project/builds/:id/download" do
before do
@build.update_attributes(artifacts_file: artifacts_file)
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
click_link 'Download artifacts'
end
diff --git a/spec/features/ci/admin/events_spec.rb b/spec/features/ci/admin/events_spec.rb
deleted file mode 100644
index a7e75cc4f6b..00000000000
--- a/spec/features/ci/admin/events_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require 'spec_helper'
-
-describe "Admin Events" do
- let(:event) { FactoryGirl.create :ci_admin_event }
-
- before do
- skip_ci_admin_auth
- login_as :user
- end
-
- describe "GET /admin/events" do
- before do
- event
- visit ci_admin_events_path
- end
-
- it { expect(page).to have_content "Events" }
- it { expect(page).to have_content event.description }
- end
-end
diff --git a/spec/features/ci/admin/projects_spec.rb b/spec/features/ci/admin/projects_spec.rb
deleted file mode 100644
index b88f55a6807..00000000000
--- a/spec/features/ci/admin/projects_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'spec_helper'
-
-describe "Admin Projects" do
- let(:project) { FactoryGirl.create :ci_project }
-
- before do
- skip_ci_admin_auth
- login_as :user
- end
-
- describe "GET /admin/projects" do
- before do
- project
- visit ci_admin_projects_path
- end
-
- it { expect(page).to have_content "Projects" }
- end
-end
diff --git a/spec/features/ci_settings_spec.rb b/spec/features/ci_settings_spec.rb
deleted file mode 100644
index 7e25e883018..00000000000
--- a/spec/features/ci_settings_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'spec_helper'
-
-describe "CI settings" do
- let(:user) { create(:user) }
- before { login_as(user) }
-
- before do
- @project = FactoryGirl.create :ci_project
- @gl_project = @project.gl_project
- @gl_project.team << [user, :master]
- visit edit_namespace_project_ci_settings_path(@gl_project.namespace, @gl_project)
- end
-
- it { expect(page).to have_content 'Build Schedule' }
-
- it "updates configuration" do
- fill_in 'Timeout', with: '70'
- click_button 'Save changes'
- expect(page).to have_content 'was successfully updated'
- expect(find_field('Timeout').value).to eq '70'
- end
-end
diff --git a/spec/features/ci_web_hooks_spec.rb b/spec/features/ci_web_hooks_spec.rb
deleted file mode 100644
index efae0a42c1e..00000000000
--- a/spec/features/ci_web_hooks_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require 'spec_helper'
-
-describe 'CI web hooks' do
- let(:user) { create(:user) }
- before { login_as(user) }
-
- before do
- @project = FactoryGirl.create :ci_project
- @gl_project = @project.gl_project
- @gl_project.team << [user, :master]
- visit namespace_project_ci_web_hooks_path(@gl_project.namespace, @gl_project)
- end
-
- context 'create a trigger' do
- before do
- fill_in 'web_hook_url', with: 'http://example.com'
- click_on 'Add Web Hook'
- end
-
- it { expect(@project.web_hooks.count).to eq(1) }
-
- it 'revokes the trigger' do
- click_on 'Remove'
- expect(@project.web_hooks.count).to eq(0)
- end
- end
-end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index 90739cd6a28..ecc85376ffc 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -1,74 +1,116 @@
require 'spec_helper'
-describe "Commits" do
+describe 'Commits' do
include CiStatusHelper
let(:project) { create(:project) }
- describe "CI" do
+ describe 'CI' do
before do
login_as :user
project.team << [@user, :master]
- @ci_project = project.ensure_gitlab_ci_project
- @commit = FactoryGirl.create :ci_commit, gl_project: project, sha: project.commit.sha
- @build = FactoryGirl.create :ci_build, commit: @commit
- @generic_status = FactoryGirl.create :generic_commit_status, commit: @commit
+ stub_ci_commit_to_return_yaml_file
end
- before do
- stub_ci_commit_to_return_yaml_file
+ let!(:commit) do
+ FactoryGirl.create :ci_commit, project: project, sha: project.commit.sha
+ end
+
+ let!(:build) { FactoryGirl.create :ci_build, commit: commit }
+
+ describe 'Project commits' do
+ context 'builds enabled' do
+ context '.gitlab-ci.yml found' do
+ before do
+ visit namespace_project_commits_path(project.namespace, project, :master)
+ end
+
+ it 'should show build status' do
+ page.within("//li[@id='commit-#{commit.short_sha}']") do
+ expect(page).to have_css(".ci-status-link")
+ end
+ end
+ end
+
+ context 'no .gitlab-ci.yml found' do
+ before do
+ stub_ci_commit_yaml_file(nil)
+ visit namespace_project_commits_path(project.namespace, project, :master)
+ end
+
+ it 'should not show build status' do
+ page.within("//li[@id='commit-#{commit.short_sha}']") do
+ expect(page).to have_no_css(".ci-status-link")
+ end
+ end
+ end
+ end
end
- describe "GET /:project/commits/:sha/ci" do
+ describe 'Commit builds' do
before do
- visit ci_status_path(@commit)
+ visit ci_status_path(commit)
end
- it { expect(page).to have_content @commit.sha[0..7] }
- it { expect(page).to have_content @commit.git_commit_message }
- it { expect(page).to have_content @commit.git_author_name }
+ it { expect(page).to have_content commit.sha[0..7] }
+ it { expect(page).to have_content commit.git_commit_message }
+ it { expect(page).to have_content commit.git_author_name }
end
- context "Download artifacts" do
+ context 'Download artifacts' do
let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
before do
- @build.update_attributes(artifacts_file: artifacts_file)
+ build.update_attributes(artifacts_file: artifacts_file)
end
it do
- visit ci_status_path(@commit)
- click_on "Download artifacts"
+ visit ci_status_path(commit)
+ click_on 'Download artifacts'
expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type)
end
end
- describe "Cancel all builds" do
- it "cancels commit" do
- visit ci_status_path(@commit)
- click_on "Cancel running"
- expect(page).to have_content "canceled"
+ describe 'Cancel all builds' do
+ it 'cancels commit' do
+ visit ci_status_path(commit)
+ click_on 'Cancel running'
+ expect(page).to have_content 'canceled'
end
end
- describe "Cancel build" do
- it "cancels build" do
- visit ci_status_path(@commit)
- click_on "Cancel"
- expect(page).to have_content "canceled"
+ describe 'Cancel build' do
+ it 'cancels build' do
+ visit ci_status_path(commit)
+ click_on 'Cancel'
+ expect(page).to have_content 'canceled'
end
end
- describe ".gitlab-ci.yml not found warning" do
- it "does not show warning" do
- visit ci_status_path(@commit)
- expect(page).not_to have_content ".gitlab-ci.yml not found in this commit"
+ describe '.gitlab-ci.yml not found warning' do
+ context 'ci builds enabled' do
+ it "does not show warning" do
+ visit ci_status_path(commit)
+ expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
+ end
+
+ it 'shows warning' do
+ stub_ci_commit_yaml_file(nil)
+ visit ci_status_path(commit)
+ expect(page).to have_content '.gitlab-ci.yml not found in this commit'
+ end
end
- it "shows warning" do
- stub_ci_commit_yaml_file(nil)
- visit ci_status_path(@commit)
- expect(page).to have_content ".gitlab-ci.yml not found in this commit"
+ context 'ci builds disabled' do
+ before do
+ stub_ci_builds_disabled
+ stub_ci_commit_yaml_file(nil)
+ visit ci_status_path(commit)
+ end
+
+ it 'does not show warning' do
+ expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
+ end
end
end
end
diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb
new file mode 100644
index 00000000000..e4efdbe2421
--- /dev/null
+++ b/spec/features/issues/note_polling_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+
+feature 'Issue notes polling' do
+ let!(:project) { create(:project, :public) }
+ let!(:issue) { create(:issue, project: project) }
+
+ background do
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ scenario 'Another user adds a comment to an issue', js: true do
+ note = create(:note_on_issue, noteable: issue, note: 'Looks good!')
+ page.execute_script('notes.refresh();')
+ expect(page).to have_selector("#note_#{note.id}", text: 'Looks good!')
+ end
+end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 3d6d87e764a..a2fb3e4c75d 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -69,7 +69,10 @@ describe 'Issues', feature: true do
click_button 'Save changes'
- expect(page).to have_content 'Assignee: none'
+ page.within('.assignee') do
+ expect(page).to have_content 'None'
+ end
+
expect(issue.reload.assignee).to be_nil
end
end
@@ -202,11 +205,11 @@ describe 'Issues', feature: true do
it 'with dropdown menu' do
visit namespace_project_issue_path(project.namespace, project, issue)
- find('.context #issue_assignee_id').
+ find('.issuable-sidebar #issue_assignee_id').
set project.team.members.first.id
click_button 'Update Issue'
- expect(page).to have_content 'Assignee:'
+ expect(page).to have_content 'Assignee'
has_select?('issue_assignee_id',
selected: project.team.members.first.name)
end
@@ -241,12 +244,16 @@ describe 'Issues', feature: true do
it 'with dropdown menu' do
visit namespace_project_issue_path(project.namespace, project, issue)
- find('.context').
+ find('.issuable-sidebar').
select(milestone.title, from: 'issue_milestone_id')
click_button 'Update Issue'
expect(page).to have_content "Milestone changed to #{milestone.title}"
- expect(page).to have_content "Milestone: #{milestone.title}"
+
+ page.within('.milestone') do
+ expect(page).to have_content milestone.title
+ end
+
has_select?('issue_assignee_id', selected: milestone.title)
end
end
@@ -279,13 +286,19 @@ describe 'Issues', feature: true do
it 'allows user to remove assignee', js: true do
visit namespace_project_issue_path(project.namespace, project, issue)
- expect(page).to have_content "Assignee: #{user2.name}"
- first('#s2id_issue_assignee_id').click
+ page.within('.assignee') do
+ expect(page).to have_content user2.name
+ end
+
+ find('.assignee .edit-link').click
sleep 2 # wait for ajax stuff to complete
first('.user-result').click
- expect(page).to have_content 'Assignee: none'
+ page.within('.assignee') do
+ expect(page).to have_content 'None'
+ end
+
sleep 2 # wait for ajax stuff to complete
expect(issue.reload.assignee).to be_nil
end
diff --git a/spec/features/ci/lint_spec.rb b/spec/features/lint_spec.rb
index 5d8f56e2cfb..5d8f56e2cfb 100644
--- a/spec/features/ci/lint_spec.rb
+++ b/spec/features/lint_spec.rb
diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
index a674124aab7..28a46a0725d 100644
--- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
+++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
@@ -12,7 +12,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
end
context "Active build for Merge Request" do
- let!(:ci_commit) { create(:ci_commit, gl_project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
+ let!(:ci_commit) { create(:ci_commit, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
let!(:ci_build) { create(:ci_build, commit: ci_commit) }
before do
@@ -47,7 +47,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
merge_user: user, title: "MepMep", merge_when_build_succeeds: true)
end
- let!(:ci_commit) { create(:ci_commit, gl_project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
+ let!(:ci_commit) { create(:ci_commit, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
let!(:ci_build) { create(:ci_build, commit: ci_commit) }
before do
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index b0259026630..d97831aae14 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -8,14 +8,14 @@ describe "Runners" do
describe "specific runners" do
before do
- @project = FactoryGirl.create :ci_project
- @project.gl_project.team << [user, :master]
+ @project = FactoryGirl.create :empty_project, shared_runners_enabled: false
+ @project.team << [user, :master]
- @project2 = FactoryGirl.create :ci_project
- @project2.gl_project.team << [user, :master]
+ @project2 = FactoryGirl.create :empty_project
+ @project2.team << [user, :master]
- @project3 = FactoryGirl.create :ci_project
- @project3.gl_project.team << [user, :developer]
+ @project3 = FactoryGirl.create :empty_project
+ @project3.team << [user, :developer]
@shared_runner = FactoryGirl.create :ci_shared_runner
@specific_runner = FactoryGirl.create :ci_specific_runner
@@ -25,7 +25,7 @@ describe "Runners" do
@project2.runners << @specific_runner2
@project3.runners << @specific_runner3
- visit runners_path(@project.gl_project)
+ visit runners_path(@project)
end
before do
@@ -49,7 +49,7 @@ describe "Runners" do
it "disables specific runner for project" do
@project2.runners << @specific_runner
- visit runners_path(@project.gl_project)
+ visit runners_path(@project)
within ".activated-specific-runners" do
click_on "Disable for this project"
@@ -69,9 +69,9 @@ describe "Runners" do
describe "shared runners" do
before do
- @project = FactoryGirl.create :ci_project
- @project.gl_project.team << [user, :master]
- visit runners_path(@project.gl_project)
+ @project = FactoryGirl.create :empty_project, shared_runners_enabled: false
+ @project.team << [user, :master]
+ visit runners_path(@project)
end
it "enables shared runners" do
@@ -82,14 +82,14 @@ describe "Runners" do
describe "show page" do
before do
- @project = FactoryGirl.create :ci_project
- @project.gl_project.team << [user, :master]
+ @project = FactoryGirl.create :empty_project
+ @project.team << [user, :master]
@specific_runner = FactoryGirl.create :ci_specific_runner
@project.runners << @specific_runner
end
it "shows runner information" do
- visit runners_path(@project.gl_project)
+ visit runners_path(@project)
click_on @specific_runner.short_sha
expect(page).to have_content(@specific_runner.platform)
end
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 69492d58878..3cbc8253ad6 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -5,10 +5,9 @@ describe 'Triggers' do
before { login_as(user) }
before do
- @project = FactoryGirl.create :ci_project
- @gl_project = @project.gl_project
- @gl_project.team << [user, :master]
- visit namespace_project_triggers_path(@gl_project.namespace, @gl_project)
+ @project = FactoryGirl.create :empty_project
+ @project.team << [user, :master]
+ visit namespace_project_triggers_path(@project.namespace, @project)
end
context 'create a trigger' do
diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb
index adb602f3edd..afea1840cd7 100644
--- a/spec/features/variables_spec.rb
+++ b/spec/features/variables_spec.rb
@@ -6,13 +6,12 @@ describe "Variables" do
describe "specific runners" do
before do
- @project = FactoryGirl.create :ci_project
- @gl_project = @project.gl_project
- @gl_project.team << [user, :master]
+ @project = FactoryGirl.create :empty_project
+ @project.team << [user, :master]
end
it "creates variable", js: true do
- visit namespace_project_variables_path(@gl_project.namespace, @gl_project)
+ visit namespace_project_variables_path(@project.namespace, @project)
click_on "Add a variable"
fill_in "Key", with: "SECRET_KEY"
fill_in "Value", with: "SECRET_VALUE"
diff --git a/spec/lib/gitlab/backend/grack_auth_spec.rb b/spec/lib/gitlab/backend/grack_auth_spec.rb
index 73458735ad9..cd26dca0998 100644
--- a/spec/lib/gitlab/backend/grack_auth_spec.rb
+++ b/spec/lib/gitlab/backend/grack_auth_spec.rb
@@ -191,15 +191,10 @@ describe Grack::Auth, lib: true do
context "when a gitlab ci token is provided" do
let(:token) { "123" }
- let(:gitlab_ci_project) { FactoryGirl.create :ci_project, token: token }
+ let(:project) { FactoryGirl.create :empty_project }
before do
- project.gitlab_ci_project = gitlab_ci_project
- project.save
-
- gitlab_ci_service = project.build_gitlab_ci_service
- gitlab_ci_service.active = true
- gitlab_ci_service.save
+ project.update_attributes(runners_token: token, builds_enabled: true)
env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials("gitlab-ci-token", token)
end
diff --git a/spec/lib/gitlab/build_data_builder_spec.rb b/spec/lib/gitlab/build_data_builder_spec.rb
new file mode 100644
index 00000000000..839b30f1ff4
--- /dev/null
+++ b/spec/lib/gitlab/build_data_builder_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe 'Gitlab::BuildDataBuilder' do
+ let(:build) { create(:ci_build) }
+
+ describe :build do
+ let(:data) do
+ Gitlab::BuildDataBuilder.build(build)
+ end
+
+ it { expect(data).to be_a(Hash) }
+ it { expect(data[:ref]).to eq(build.ref) }
+ it { expect(data[:sha]).to eq(build.sha) }
+ it { expect(data[:tag]).to eq(build.tag) }
+ it { expect(data[:build_id]).to eq(build.id) }
+ it { expect(data[:build_status]).to eq(build.status) }
+ it { expect(data[:project_id]).to eq(build.project.id) }
+ it { expect(data[:project_name]).to eq(build.project.name_with_namespace) }
+ end
+end
diff --git a/spec/mailers/ci/notify_spec.rb b/spec/mailers/ci/notify_spec.rb
deleted file mode 100644
index b83fb41603b..00000000000
--- a/spec/mailers/ci/notify_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require 'spec_helper'
-
-describe Ci::Notify do
- include EmailSpec::Helpers
- include EmailSpec::Matchers
-
- before do
- @commit = FactoryGirl.create :ci_commit
- @build = FactoryGirl.create :ci_build, commit: @commit
- end
-
- describe 'build success' do
- subject { Ci::Notify.build_success_email(@build.id, 'wow@example.com') }
-
- it 'has the correct subject' do
- should have_subject /Build success for/
- end
-
- it 'contains name of project' do
- should have_body_text /build successful/
- end
- end
-
- describe 'build fail' do
- subject { Ci::Notify.build_fail_email(@build.id, 'wow@example.com') }
-
- it 'has the correct subject' do
- should have_subject /Build failed for/
- end
-
- it 'contains name of project' do
- should have_body_text /build failed/
- end
- end
-end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 27e509933b2..154901a2fbc 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -13,6 +13,7 @@ describe Notify do
let(:gitlab_sender_reply_to) { Gitlab.config.gitlab.email_reply_to }
let(:recipient) { create(:user, email: 'recipient@example.com') }
let(:project) { create(:project) }
+ let(:build) { create(:ci_build) }
before(:each) do
ActionMailer::Base.deliveries.clear
@@ -865,4 +866,32 @@ describe Notify do
is_expected.to have_body_text /#{diff_path}/
end
end
+
+ describe 'build success' do
+ before { build.success }
+
+ subject { Notify.build_success_email(build.id, 'wow@example.com') }
+
+ it 'has the correct subject' do
+ should have_subject /Build success for/
+ end
+
+ it 'contains name of project' do
+ should have_body_text build.project_name
+ end
+ end
+
+ describe 'build fail' do
+ before { build.drop }
+
+ subject { Notify.build_fail_email(build.id, 'wow@example.com') }
+
+ it 'has the correct subject' do
+ should have_subject /Build failed for/
+ end
+
+ it 'contains name of project' do
+ should have_body_text build.project_name
+ end
+ end
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index b67b84959d9..5f64453a35f 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -73,26 +73,4 @@ describe ApplicationSetting, models: true do
expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com'])
end
end
-
- context 'shared runners' do
- let(:gl_project) { create(:empty_project) }
-
- before do
- allow_any_instance_of(Project).to receive(:current_application_settings).and_return(setting)
- end
-
- subject { gl_project.ensure_gitlab_ci_project.shared_runners_enabled }
-
- context 'enabled' do
- before { setting.update_attributes(shared_runners_enabled: true) }
-
- it { is_expected.to be_truthy }
- end
-
- context 'disabled' do
- before { setting.update_attributes(shared_runners_enabled: false) }
-
- it { is_expected.to be_falsey }
- end
- end
end
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index 70c831b7cbe..96b6f1dbca6 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -26,9 +26,8 @@
require 'spec_helper'
describe Ci::Build, models: true do
- let(:project) { FactoryGirl.create :ci_project }
- let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
- let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+ let(:project) { FactoryGirl.create :empty_project }
+ let(:commit) { FactoryGirl.create :ci_commit, project: project }
let(:build) { FactoryGirl.create :ci_build, commit: commit }
it { is_expected.to validate_presence_of :ref }
@@ -112,7 +111,7 @@ describe Ci::Build, models: true do
let(:token) { 'my_secret_token' }
before do
- build.project.update_attributes(token: token)
+ build.project.update_attributes(runners_token: token)
build.update_attributes(trace: token)
end
@@ -120,11 +119,12 @@ describe Ci::Build, models: true do
end
end
- describe :timeout do
- subject { build.timeout }
-
- it { is_expected.to eq(commit.project.timeout) }
- end
+ # TODO: build timeout
+ # describe :timeout do
+ # subject { build.timeout }
+ #
+ # it { is_expected.to eq(commit.project.timeout) }
+ # end
describe :options do
let(:options) do
@@ -140,11 +140,12 @@ describe Ci::Build, models: true do
it { is_expected.to eq(options) }
end
- describe :allow_git_fetch do
- subject { build.allow_git_fetch }
-
- it { is_expected.to eq(project.allow_git_fetch) }
- end
+ # TODO: allow_git_fetch
+ # describe :allow_git_fetch do
+ # subject { build.allow_git_fetch }
+ #
+ # it { is_expected.to eq(project.allow_git_fetch) }
+ # end
describe :project do
subject { build.project }
@@ -164,12 +165,6 @@ describe Ci::Build, models: true do
it { is_expected.to eq(project.name) }
end
- describe :repo_url do
- subject { build.repo_url }
-
- it { is_expected.to eq(project.repo_url_with_auth) }
- end
-
describe :extract_coverage do
context 'valid content & regex' do
subject { build.extract_coverage('Coverage 1033 / 1051 LOC (98.29%) covered', '\(\d+.\d+\%\) covered') }
@@ -266,40 +261,6 @@ describe Ci::Build, models: true do
end
end
- describe :project_recipients do
- let(:pusher_email) { 'pusher@gitlab.test' }
- let(:user) { User.new(notification_email: pusher_email) }
- subject { build.project_recipients }
-
- before do
- build.update_attributes(user: user)
- end
-
- it 'should return pusher_email as only recipient when no additional recipients are given' do
- project.update_attributes(email_add_pusher: true,
- email_recipients: '')
- is_expected.to eq([pusher_email])
- end
-
- it 'should return pusher_email and additional recipients' do
- project.update_attributes(email_add_pusher: true,
- email_recipients: 'rec1 rec2')
- is_expected.to eq(['rec1', 'rec2', pusher_email])
- end
-
- it 'should return recipients' do
- project.update_attributes(email_add_pusher: false,
- email_recipients: 'rec1 rec2')
- is_expected.to eq(['rec1', 'rec2'])
- end
-
- it 'should return unique recipients only' do
- project.update_attributes(email_add_pusher: true,
- email_recipients: "rec1 rec1 #{pusher_email}")
- is_expected.to eq(['rec1', pusher_email])
- end
- end
-
describe :can_be_served? do
let(:runner) { FactoryGirl.create :ci_specific_runner }
@@ -415,4 +376,18 @@ describe Ci::Build, models: true do
is_expected.to_not be_nil
end
end
+
+ describe :repo_url do
+ let(:build) { FactoryGirl.create :ci_build }
+ let(:project) { build.project }
+
+ subject { build.repo_url }
+
+ it { is_expected.to be_a(String) }
+ it { is_expected.to end_with(".git") }
+ it { is_expected.to start_with(project.web_url[0..6]) }
+ it { is_expected.to include(build.token) }
+ it { is_expected.to include('gitlab-ci-token') }
+ it { is_expected.to include(project.web_url[7..-1]) }
+ end
end
diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb
index 89813cdf7fc..ac61c8fb525 100644
--- a/spec/models/ci/commit_spec.rb
+++ b/spec/models/ci/commit_spec.rb
@@ -13,17 +13,16 @@
# tag :boolean default(FALSE)
# yaml_errors :text
# committed_at :datetime
-# gl_project_id :integer
+# project_id :integer
#
require 'spec_helper'
describe Ci::Commit, models: true do
- let(:project) { FactoryGirl.create :ci_project }
- let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
- let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+ let(:project) { FactoryGirl.create :empty_project }
+ let(:commit) { FactoryGirl.create :ci_commit, project: project }
- it { is_expected.to belong_to(:gl_project) }
+ it { is_expected.to belong_to(:project) }
it { is_expected.to have_many(:statuses) }
it { is_expected.to have_many(:trigger_requests) }
it { is_expected.to have_many(:builds) }
@@ -37,16 +36,16 @@ describe Ci::Commit, models: true do
let(:project) { FactoryGirl.create :empty_project }
it 'returns ordered list of commits' do
- commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
- commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
+ commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
+ commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit1])
end
it 'returns commits ordered by committed_at and id, with nulls last' do
- commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
- commit2 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
- commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
- commit4 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
+ commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
+ commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
+ commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project
+ commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1])
end
end
@@ -162,7 +161,7 @@ describe Ci::Commit, models: true do
end
describe :create_builds do
- let!(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+ let!(:commit) { FactoryGirl.create :ci_commit, project: project }
def create_builds(trigger_request = nil)
commit.create_builds('master', false, nil, trigger_request)
@@ -390,9 +389,8 @@ describe Ci::Commit, models: true do
end
describe "coverage" do
- let(:project) { FactoryGirl.create :ci_project, coverage_regex: "/.*/" }
- let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
- let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+ let(:project) { FactoryGirl.create :empty_project, build_coverage_regex: "/.*/" }
+ let(:commit) { FactoryGirl.create :ci_commit, project: project }
it "calculates average when there are two builds with coverage" do
FactoryGirl.create :ci_build, name: "rspec", coverage: 30, commit: commit
diff --git a/spec/models/ci/project_services/hip_chat_message_spec.rb b/spec/models/ci/project_services/hip_chat_message_spec.rb
deleted file mode 100644
index 7d54b6cf84c..00000000000
--- a/spec/models/ci/project_services/hip_chat_message_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require 'spec_helper'
-
-describe Ci::HipChatMessage, models: true do
- subject { Ci::HipChatMessage.new(build) }
-
- let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
-
- let(:build) do
- commit.builds.first
- end
-
- context 'when all matrix builds succeed' do
- it 'returns a successful message' do
- commit.create_builds('master', false, nil)
- commit.builds.update_all(status: "success")
- commit.reload
-
- expect(subject.status_color).to eq 'green'
- expect(subject.notify?).to be_falsey
- expect(subject.to_s).to match(/Commit #\d+/)
- expect(subject.to_s).to match(/Successful in \d+ second\(s\)\./)
- end
- end
-
- context 'when at least one matrix build fails' do
- it 'returns a failure message' do
- commit.create_builds('master', false, nil)
- first_build = commit.builds.first
- second_build = commit.builds.last
- first_build.update(status: "success")
- second_build.update(status: "failed")
-
- expect(subject.status_color).to eq 'red'
- expect(subject.notify?).to be_truthy
- expect(subject.to_s).to match(/Commit #\d+/)
- expect(subject.to_s).to match(/Failed in \d+ second\(s\)\./)
- end
- end
-end
diff --git a/spec/models/ci/project_services/hip_chat_service_spec.rb b/spec/models/ci/project_services/hip_chat_service_spec.rb
deleted file mode 100644
index 714f1e17e0b..00000000000
--- a/spec/models/ci/project_services/hip_chat_service_spec.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-
-require 'spec_helper'
-
-describe Ci::HipChatService, models: true do
-
- describe "Validations" do
-
- context "active" do
- before do
- subject.active = true
- end
-
- it { is_expected.to validate_presence_of :hipchat_room }
- it { is_expected.to validate_presence_of :hipchat_token }
-
- end
- end
-
- describe "Execute" do
-
- let(:service) { Ci::HipChatService.new }
- let(:commit) { FactoryGirl.create :ci_commit }
- let(:build) { FactoryGirl.create :ci_build, commit: commit, status: 'failed' }
- let(:api_url) { 'https://api.hipchat.com/v2/room/123/notification?auth_token=a1b2c3d4e5f6' }
-
- before do
- allow(service).to receive_messages(
- project: commit.project,
- project_id: commit.project_id,
- notify_only_broken_builds: false,
- hipchat_room: 123,
- hipchat_token: 'a1b2c3d4e5f6'
- )
-
- WebMock.stub_request(:post, api_url)
- end
-
-
- it "should call the HipChat API" do
- service.execute(build)
- Ci::HipChatNotifierWorker.drain
-
- expect( WebMock ).to have_requested(:post, api_url).once
- end
-
- it "calls the worker with expected arguments" do
- expect( Ci::HipChatNotifierWorker ).to receive(:perform_async) \
- .with(an_instance_of(String), hash_including(
- token: 'a1b2c3d4e5f6',
- room: 123,
- server: 'https://api.hipchat.com',
- color: 'red',
- notify: true
- ))
-
- service.execute(build)
- end
- end
-end
diff --git a/spec/models/ci/project_services/mail_service_spec.rb b/spec/models/ci/project_services/mail_service_spec.rb
deleted file mode 100644
index 638d9a4a626..00000000000
--- a/spec/models/ci/project_services/mail_service_spec.rb
+++ /dev/null
@@ -1,177 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-require 'spec_helper'
-
-describe Ci::MailService, models: true do
- describe "Associations" do
- it { is_expected.to belong_to :project }
- end
-
- describe "Validations" do
- context "active" do
- before do
- subject.active = true
- end
- end
- end
-
- describe 'Sends email for' do
- let(:mail) { Ci::MailService.new }
- let(:user) { User.new(notification_email: 'git@example.com')}
-
- describe 'failed build' do
- let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true) }
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'failed', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- perform_enqueued_jobs do
- expect{ mail.execute(build) }.to change{ ActionMailer::Base.deliveries.size }.by(1)
- expect(ActionMailer::Base.deliveries.last.to).to eq(["git@example.com"])
- end
- end
- end
-
- describe 'successfull build' do
- let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true, email_only_broken_builds: false) }
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- perform_enqueued_jobs do
- expect{ mail.execute(build) }.to change{ ActionMailer::Base.deliveries.size }.by(1)
- expect(ActionMailer::Base.deliveries.last.to).to eq(["git@example.com"])
- end
- end
- end
-
- describe 'successfull build and project has email_recipients' do
- let(:project) do
- FactoryGirl.create(:ci_project,
- email_add_pusher: true,
- email_only_broken_builds: false,
- email_recipients: "jeroen@example.com")
- end
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- perform_enqueued_jobs do
- expect{ mail.execute(build) }.to change{ ActionMailer::Base.deliveries.size }.by(2)
- expect(
- ActionMailer::Base.deliveries.map(&:to).flatten
- ).to include("git@example.com", "jeroen@example.com")
- end
- end
- end
-
- describe 'successful build and notify only broken builds' do
- let(:project) do
- FactoryGirl.create(:ci_project,
- email_add_pusher: true,
- email_only_broken_builds: true,
- email_recipients: "jeroen@example.com")
- end
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- perform_enqueued_jobs do
- expect do
- mail.execute(build) if mail.can_execute?(build)
- end.to_not change{ ActionMailer::Base.deliveries.size }
- end
- end
- end
-
- describe 'successful build and can test service' do
- let(:project) do
- FactoryGirl.create(:ci_project,
- email_add_pusher: true,
- email_only_broken_builds: false,
- email_recipients: "jeroen@example.com")
- end
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- build
- end
-
- it do
- expect(mail.can_test?).to eq(true)
- end
- end
-
- describe 'retried build should not receive email' do
- let(:project) do
- FactoryGirl.create(:ci_project,
- email_add_pusher: true,
- email_only_broken_builds: true,
- email_recipients: "jeroen@example.com")
- end
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'failed', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- Ci::Build.retry(build)
- perform_enqueued_jobs do
- expect do
- mail.execute(build) if mail.can_execute?(build)
- end.to_not change{ ActionMailer::Base.deliveries.size }
- end
- end
- end
- end
-end
diff --git a/spec/models/ci/project_services/slack_message_spec.rb b/spec/models/ci/project_services/slack_message_spec.rb
deleted file mode 100644
index 226032b4cda..00000000000
--- a/spec/models/ci/project_services/slack_message_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'spec_helper'
-
-describe Ci::SlackMessage, models: true do
- subject { Ci::SlackMessage.new(commit) }
-
- let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
-
- context 'when all matrix builds succeeded' do
- let(:color) { 'good' }
-
- it 'returns a message with success' do
- commit.create_builds('master', false, nil)
- commit.builds.update_all(status: "success")
- commit.reload
-
- expect(subject.color).to eq(color)
- expect(subject.fallback).to include('Commit')
- expect(subject.fallback).to include("\##{commit.id}")
- expect(subject.fallback).to include('succeeded')
- expect(subject.attachments.first[:fields]).to be_empty
- end
- end
-
- context 'when one of matrix builds failed' do
- let(:color) { 'danger' }
-
- it 'returns a message with information about failed build' do
- commit.create_builds('master', false, nil)
- first_build = commit.builds.first
- second_build = commit.builds.last
- first_build.update(status: "success")
- second_build.update(status: "failed")
-
- expect(subject.color).to eq(color)
- expect(subject.fallback).to include('Commit')
- expect(subject.fallback).to include("\##{commit.id}")
- expect(subject.fallback).to include('failed')
- expect(subject.attachments.first[:fields].size).to eq(1)
- expect(subject.attachments.first[:fields].first[:title]).to eq(second_build.name)
- expect(subject.attachments.first[:fields].first[:value]).to include("\##{second_build.id}")
- end
- end
-end
diff --git a/spec/models/ci/project_services/slack_service_spec.rb b/spec/models/ci/project_services/slack_service_spec.rb
deleted file mode 100644
index e7d7d5d6f4c..00000000000
--- a/spec/models/ci/project_services/slack_service_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-require 'spec_helper'
-
-describe Ci::SlackService, models: true do
- describe "Associations" do
- it { is_expected.to belong_to :project }
- end
-
- describe "Validations" do
- context "active" do
- before do
- subject.active = true
- end
-
- it { is_expected.to validate_presence_of :webhook }
- end
- end
-
- describe "Execute" do
- let(:slack) { Ci::SlackService.new }
- let(:commit) { FactoryGirl.create :ci_commit }
- let(:build) { FactoryGirl.create :ci_build, commit: commit, status: 'failed' }
- let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' }
- let(:notify_only_broken_builds) { false }
-
- before do
- allow(slack).to receive_messages(
- project: commit.project,
- project_id: commit.project_id,
- webhook: webhook_url,
- notify_only_broken_builds: notify_only_broken_builds
- )
-
- WebMock.stub_request(:post, webhook_url)
- end
-
- it "should call Slack API" do
- slack.execute(build)
- Ci::SlackNotifierWorker.drain
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
- end
-end
diff --git a/spec/models/ci/project_spec.rb b/spec/models/ci/project_spec.rb
deleted file mode 100644
index 346471aa9b5..00000000000
--- a/spec/models/ci/project_spec.rb
+++ /dev/null
@@ -1,246 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_projects
-#
-# id :integer not null, primary key
-# name :string(255)
-# timeout :integer default(3600), not null
-# created_at :datetime
-# updated_at :datetime
-# token :string(255)
-# default_ref :string(255)
-# path :string(255)
-# always_build :boolean default(FALSE), not null
-# polling_interval :integer
-# public :boolean default(FALSE), not null
-# ssh_url_to_repo :string(255)
-# gitlab_id :integer
-# allow_git_fetch :boolean default(TRUE), not null
-# email_recipients :string(255) default(""), not null
-# email_add_pusher :boolean default(TRUE), not null
-# email_only_broken_builds :boolean default(TRUE), not null
-# skip_refs :string(255)
-# coverage_regex :string(255)
-# shared_runners_enabled :boolean default(FALSE)
-# generated_yaml_config :text
-#
-
-require 'spec_helper'
-
-describe Ci::Project, models: true do
- let(:project) { FactoryGirl.create :ci_project }
- let(:gl_project) { project.gl_project }
- subject { project }
-
- it { is_expected.to have_many(:runner_projects) }
- it { is_expected.to have_many(:runners) }
- it { is_expected.to have_many(:web_hooks) }
- it { is_expected.to have_many(:events) }
- it { is_expected.to have_many(:variables) }
- it { is_expected.to have_many(:triggers) }
- it { is_expected.to have_many(:services) }
-
- it { is_expected.to validate_presence_of :timeout }
- it { is_expected.to validate_presence_of :gitlab_id }
-
- describe 'before_validation' do
- it 'should set an random token if none provided' do
- project = FactoryGirl.create :ci_project_without_token
- expect(project.token).not_to eq("")
- end
-
- it 'should not set an random toke if one provided' do
- project = FactoryGirl.create :ci_project
- expect(project.token).to eq("iPWx6WM4lhHNedGfBpPJNP")
- end
- end
-
- describe :name_with_namespace do
- subject { project.name_with_namespace }
-
- it { is_expected.to eq(project.name) }
- it { is_expected.to eq(gl_project.name_with_namespace) }
- end
-
- describe :path_with_namespace do
- subject { project.path_with_namespace }
-
- it { is_expected.to eq(project.path) }
- it { is_expected.to eq(gl_project.path_with_namespace) }
- end
-
- describe :path_with_namespace do
- subject { project.web_url }
-
- it { is_expected.to eq(gl_project.web_url) }
- end
-
- describe :web_url do
- subject { project.web_url }
-
- it { is_expected.to eq(project.gitlab_url) }
- it { is_expected.to eq(gl_project.web_url) }
- end
-
- describe :http_url_to_repo do
- subject { project.http_url_to_repo }
-
- it { is_expected.to eq(gl_project.http_url_to_repo) }
- end
-
- describe :ssh_url_to_repo do
- subject { project.ssh_url_to_repo }
-
- it { is_expected.to eq(gl_project.ssh_url_to_repo) }
- end
-
- describe :commits do
- subject { project.commits }
-
- before do
- FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
- end
-
- it { is_expected.to eq(gl_project.ci_commits) }
- end
-
- describe :builds do
- subject { project.builds }
-
- before do
- commit = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
- FactoryGirl.create :ci_build, commit: commit
- end
-
- it { is_expected.to eq(gl_project.ci_builds) }
- end
-
- describe "ordered_by_last_commit_date" do
- it "returns ordered projects" do
- newest_project = FactoryGirl.create :empty_project
- newest_ci_project = newest_project.ensure_gitlab_ci_project
- oldest_project = FactoryGirl.create :empty_project
- oldest_ci_project = oldest_project.ensure_gitlab_ci_project
- project_without_commits = FactoryGirl.create :empty_project
- ci_project_without_commits = project_without_commits.ensure_gitlab_ci_project
-
- FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: newest_project
- FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: oldest_project
-
- expect(Ci::Project.ordered_by_last_commit_date).to eq([newest_ci_project, oldest_ci_project, ci_project_without_commits])
- end
- end
-
- context :valid_project do
- let(:commit) { FactoryGirl.create(:ci_commit) }
-
- context :project_with_commit_and_builds do
- let(:project) { commit.project }
-
- before do
- FactoryGirl.create(:ci_build, commit: commit)
- end
-
- it { expect(project.status).to eq('pending') }
- it { expect(project.last_commit).to be_kind_of(Ci::Commit) }
- it { expect(project.human_status).to eq('pending') }
- end
- end
-
- describe '#email_notification?' do
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- expect(project.email_notification?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: false, email_recipients: 'test tesft'
- expect(project.email_notification?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: false, email_recipients: ''
- expect(project.email_notification?).to eq(false)
- end
- end
-
- describe '#broken_or_success?' do
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- allow(project).to receive(:broken?).and_return(true)
- allow(project).to receive(:success?).and_return(true)
- expect(project.broken_or_success?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- allow(project).to receive(:broken?).and_return(true)
- allow(project).to receive(:success?).and_return(false)
- expect(project.broken_or_success?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- allow(project).to receive(:broken?).and_return(false)
- allow(project).to receive(:success?).and_return(true)
- expect(project.broken_or_success?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- allow(project).to receive(:broken?).and_return(false)
- allow(project).to receive(:success?).and_return(false)
- expect(project.broken_or_success?).to eq(false)
- end
- end
-
- describe :repo_url_with_auth do
- let(:project) { FactoryGirl.create :ci_project }
- subject { project.repo_url_with_auth }
-
- it { is_expected.to be_a(String) }
- it { is_expected.to end_with(".git") }
- it { is_expected.to start_with(project.gitlab_url[0..6]) }
- it { is_expected.to include(project.token) }
- it { is_expected.to include('gitlab-ci-token') }
- it { is_expected.to include(project.gitlab_url[7..-1]) }
- end
-
- describe :any_runners do
- it "there are no runners available" do
- project = FactoryGirl.create(:ci_project)
- expect(project.any_runners?).to be_falsey
- end
-
- it "there is a specific runner" do
- project = FactoryGirl.create(:ci_project)
- project.runners << FactoryGirl.create(:ci_specific_runner)
- expect(project.any_runners?).to be_truthy
- end
-
- it "there is a shared runner" do
- project = FactoryGirl.create(:ci_project, shared_runners_enabled: true)
- FactoryGirl.create(:ci_shared_runner)
- expect(project.any_runners?).to be_truthy
- end
-
- it "there is a shared runner, but they are prohibited to use" do
- project = FactoryGirl.create(:ci_project)
- FactoryGirl.create(:ci_shared_runner)
- expect(project.any_runners?).to be_falsey
- end
-
- it "checks the presence of specific runner" do
- project = FactoryGirl.create(:ci_project)
- specific_runner = FactoryGirl.create(:ci_specific_runner)
- project.runners << specific_runner
- expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
- end
-
- it "checks the presence of shared runner" do
- project = FactoryGirl.create(:ci_project, shared_runners_enabled: true)
- shared_runner = FactoryGirl.create(:ci_shared_runner)
- expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
- end
- end
-end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 6ebb5e86863..232760dfeba 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -38,7 +38,7 @@ describe Ci::Runner, models: true do
end
describe :assign_to do
- let!(:project) { FactoryGirl.create :ci_project }
+ let!(:project) { FactoryGirl.create :empty_project }
let!(:shared_runner) { FactoryGirl.create(:ci_shared_runner) }
before { shared_runner.assign_to(project) }
@@ -116,8 +116,8 @@ describe Ci::Runner, models: true do
describe "belongs_to_one_project?" do
it "returns false if there are two projects runner assigned to" do
runner = FactoryGirl.create(:ci_specific_runner)
- project = FactoryGirl.create(:ci_project)
- project1 = FactoryGirl.create(:ci_project)
+ project = FactoryGirl.create(:empty_project)
+ project1 = FactoryGirl.create(:empty_project)
project.runners << runner
project1.runners << runner
@@ -126,7 +126,7 @@ describe Ci::Runner, models: true do
it "returns true" do
runner = FactoryGirl.create(:ci_specific_runner)
- project = FactoryGirl.create(:ci_project)
+ project = FactoryGirl.create(:empty_project)
project.runners << runner
expect(runner.belongs_to_one_project?).to be_truthy
diff --git a/spec/models/ci/service_spec.rb b/spec/models/ci/service_spec.rb
deleted file mode 100644
index 34e3af7f810..00000000000
--- a/spec/models/ci/service_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-require 'spec_helper'
-
-describe Ci::Service, models: true do
-
- describe "Associations" do
- it { is_expected.to belong_to :project }
- end
-
- describe "Mass assignment" do
- end
-
- describe "Test Button" do
- before do
- @service = Ci::Service.new
- end
-
- describe "Testable" do
- let(:commit) { FactoryGirl.create :ci_commit }
- let(:build) { FactoryGirl.create :ci_build, commit: commit }
-
- before do
- allow(@service).to receive_messages(
- project: commit.project
- )
- build
- @testable = @service.can_test?
- end
-
- describe :can_test do
- it { expect(@testable).to eq(true) }
- end
- end
- end
-end
diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb
index 61eb3c08296..cb2f51e2011 100644
--- a/spec/models/ci/trigger_spec.rb
+++ b/spec/models/ci/trigger_spec.rb
@@ -13,7 +13,7 @@
require 'spec_helper'
describe Ci::Trigger, models: true do
- let(:project) { FactoryGirl.create :ci_project }
+ let(:project) { FactoryGirl.create :empty_project }
describe 'before_validation' do
it 'should set an random token if none provided' do
diff --git a/spec/models/ci/web_hook_spec.rb b/spec/models/ci/web_hook_spec.rb
deleted file mode 100644
index 1a4edec9d4f..00000000000
--- a/spec/models/ci/web_hook_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_web_hooks
-#
-# id :integer not null, primary key
-# url :string(255) not null
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-#
-
-require 'spec_helper'
-
-describe Ci::WebHook, models: true do
- describe "Associations" do
- it { is_expected.to belong_to :project }
- end
-
- describe "Validations" do
- it { is_expected.to validate_presence_of(:url) }
-
- context "url format" do
- it { is_expected.to allow_value("http://example.com").for(:url) }
- it { is_expected.to allow_value("https://excample.com").for(:url) }
- it { is_expected.to allow_value("http://test.com/api").for(:url) }
- it { is_expected.to allow_value("http://test.com/api?key=abc").for(:url) }
- it { is_expected.to allow_value("http://test.com/api?key=abc&type=def").for(:url) }
-
- it { is_expected.not_to allow_value("example.com").for(:url) }
- it { is_expected.not_to allow_value("ftp://example.com").for(:url) }
- it { is_expected.not_to allow_value("herp-and-derp").for(:url) }
- end
- end
-
- describe "execute" do
- before(:each) do
- @web_hook = FactoryGirl.create(:ci_web_hook)
- @project = @web_hook.project
- @data = { before: 'oldrev', after: 'newrev', ref: 'ref' }
-
- WebMock.stub_request(:post, @web_hook.url)
- end
-
- it "POSTs to the web hook URL" do
- @web_hook.execute(@data)
- expect(WebMock).to have_requested(:post, @web_hook.url).once
- end
-
- it "POSTs the data as JSON" do
- json = @data.to_json
-
- @web_hook.execute(@data)
- expect(WebMock).to have_requested(:post, @web_hook.url).with(body: json).once
- end
-
- it "catches exceptions" do
- expect(Ci::WebHook).to receive(:post).and_raise("Some HTTP Post error")
-
- expect{ @web_hook.execute(@data) }.
- to raise_error(RuntimeError, 'Some HTTP Post error')
- end
- end
-end
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 5e311ead28b..b8f901b3433 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -39,12 +39,13 @@ describe CommitStatus, models: true do
it { is_expected.to belong_to(:commit) }
it { is_expected.to belong_to(:user) }
+ it { is_expected.to belong_to(:project) }
+
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_inclusion_of(:status).in_array(%w(pending running failed success canceled)) }
it { is_expected.to delegate_method(:sha).to(:commit) }
it { is_expected.to delegate_method(:short_sha).to(:commit) }
- it { is_expected.to delegate_method(:gl_project).to(:commit) }
it { is_expected.to respond_to :success? }
it { is_expected.to respond_to :failed? }
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
new file mode 100644
index 00000000000..a9b0b64e5de
--- /dev/null
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -0,0 +1,57 @@
+require 'spec_helper'
+
+shared_examples 'TokenAuthenticatable' do
+ describe 'dynamically defined methods' do
+ it { expect(described_class).to be_private_method_defined(:generate_token_for) }
+ it { expect(described_class).to respond_to("find_by_#{token_field}") }
+ it { is_expected.to respond_to("ensure_#{token_field}") }
+ it { is_expected.to respond_to("reset_#{token_field}!") }
+ end
+end
+
+describe User, 'TokenAuthenticatable' do
+ let(:token_field) { :authentication_token }
+ it_behaves_like 'TokenAuthenticatable'
+
+ describe 'ensures authentication token' do
+ subject { create(:user).send(token_field) }
+ it { is_expected.to be_a String }
+ end
+end
+
+describe ApplicationSetting, 'TokenAuthenticatable' do
+ let(:token_field) { :runners_registration_token }
+ it_behaves_like 'TokenAuthenticatable'
+
+ describe 'generating new token' do
+ subject { described_class.new }
+ let(:token) { subject.send(token_field) }
+
+ context 'token is not generated yet' do
+ it { expect(token).to be nil }
+
+ describe 'ensured token' do
+ subject { described_class.new.send("ensure_#{token_field}") }
+
+ it { is_expected.to be_a String }
+ it { is_expected.to_not be_blank }
+ end
+ end
+
+ context 'token is generated' do
+ before { subject.send("reset_#{token_field}!") }
+ it { expect(token).to be_a String }
+ end
+ end
+
+ describe 'multiple token fields' do
+ before do
+ described_class.send(:add_authentication_token_field, :yet_another_token)
+ end
+
+ describe '.token_fields' do
+ subject { described_class.authentication_token_fields }
+ it { is_expected.to include(:runners_registration_token, :yet_another_token) }
+ end
+ end
+end
diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb
deleted file mode 100644
index 835bf364050..00000000000
--- a/spec/models/project_services/gitlab_ci_service_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-require 'spec_helper'
-
-describe GitlabCiService, models: true do
- describe 'associations' do
- it { is_expected.to belong_to(:project) }
- it { is_expected.to have_one(:service_hook) }
- end
-
- describe 'commits methods' do
- before do
- @ci_project = create(:ci_project)
- @service = GitlabCiService.new
- allow(@service).to receive_messages(
- service_hook: true,
- project_url: 'http://ci.gitlab.org/projects/2',
- token: 'verySecret',
- project: @ci_project.gl_project
- )
- end
-
- describe :build_page do
- it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/builds")}
- end
-
- describe "execute" do
- let(:user) { create(:user, username: 'username') }
- let(:project) { create(:project, name: 'project') }
- let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
-
- it "calls CreateCommitService" do
- expect_any_instance_of(Ci::CreateCommitService).to receive(:execute).with(@ci_project, user, push_sample_data)
-
- @service.execute(push_sample_data)
- end
- end
- end
-end
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index c96ab548149..a5662b08bda 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -247,6 +247,55 @@ describe HipchatService, models: true do
end
end
+ context 'build events' do
+ let(:build) { create(:ci_build) }
+ let(:data) { Gitlab::BuildDataBuilder.build(build) }
+
+ context 'for failed' do
+ before { build.drop }
+
+ it "should call Hipchat API" do
+ hipchat.execute(data)
+
+ expect(WebMock).to have_requested(:post, api_url).once
+ end
+
+ it "should create a build message" do
+ message = hipchat.send(:create_build_message, data)
+
+ project_url = project.web_url
+ project_name = project.name_with_namespace.gsub(/\s/, '')
+ sha = data[:sha]
+ ref = data[:ref]
+ ref_type = data[:tag] ? 'tag' : 'branch'
+ duration = data[:commit][:duration]
+
+ expect(message).to eq("<a href=\"#{project_url}\">#{project_name}</a>: " \
+ "Commit <a href=\"#{project_url}/commit/#{sha}/builds\">#{Commit.truncate_sha(sha)}</a> " \
+ "of <a href=\"#{project_url}/commits/#{ref}\">#{ref}</a> #{ref_type} " \
+ "by #{data[:commit][:author_name]} failed in #{duration} second(s)")
+ end
+ end
+
+ context 'for succeeded' do
+ before do
+ build.success
+ end
+
+ it "should call Hipchat API" do
+ hipchat.notify_only_broken_builds = false
+ hipchat.execute(data)
+ expect(WebMock).to have_requested(:post, api_url).once
+ end
+
+ it "should notify only broken" do
+ hipchat.notify_only_broken_builds = true
+ hipchat.execute(data)
+ expect(WebMock).to_not have_requested(:post, api_url).once
+ end
+ end
+ end
+
context "#message_options" do
it "should be set to the defaults" do
expect(hipchat.send(:message_options)).to eq({ notify: false, color: 'yellow' })
diff --git a/spec/models/project_services/slack_service/build_message_spec.rb b/spec/models/project_services/slack_service/build_message_spec.rb
new file mode 100644
index 00000000000..621c83c0cda
--- /dev/null
+++ b/spec/models/project_services/slack_service/build_message_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+describe SlackService::BuildMessage do
+ subject { SlackService::BuildMessage.new(args) }
+
+ let(:args) do
+ {
+ sha: '97de212e80737a608d939f648d959671fb0a0142',
+ ref: 'develop',
+ tag: false,
+
+ project_name: 'project_name',
+ project_url: 'somewhere.com',
+
+ commit: {
+ status: status,
+ author_name: 'hacker',
+ duration: 10,
+ },
+ }
+ end
+
+ context 'succeeded' do
+ let(:status) { 'success' }
+ let(:color) { 'good' }
+
+ it 'returns a message with information about succeeded build' do
+ message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker passed in 10 second(s)'
+ expect(subject.pretext).to be_empty
+ expect(subject.fallback).to eq(message)
+ expect(subject.attachments).to eq([text: message, color: color])
+ end
+ end
+
+ context 'failed' do
+ let(:status) { 'failed' }
+ let(:color) { 'danger' }
+
+ it 'returns a message with information about failed build' do
+ message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker failed in 10 second(s)'
+ expect(subject.pretext).to be_empty
+ expect(subject.fallback).to eq(message)
+ expect(subject.attachments).to eq([text: message, color: color])
+ end
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 6ddb0e2b8f7..87582e07494 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -54,6 +54,13 @@ describe Project, models: true do
it { is_expected.to have_one(:slack_service).dependent(:destroy) }
it { is_expected.to have_one(:pushover_service).dependent(:destroy) }
it { is_expected.to have_one(:asana_service).dependent(:destroy) }
+ it { is_expected.to have_many(:commit_statuses) }
+ it { is_expected.to have_many(:ci_commits) }
+ it { is_expected.to have_many(:builds) }
+ it { is_expected.to have_many(:runner_projects) }
+ it { is_expected.to have_many(:runners) }
+ it { is_expected.to have_many(:variables) }
+ it { is_expected.to have_many(:triggers) }
end
describe 'modules' do
@@ -88,6 +95,18 @@ describe Project, models: true do
expect(project2.errors[:limit_reached].first).to match(/Your project limit is 0/)
end
end
+
+ describe 'project token' do
+ it 'should set an random token if none provided' do
+ project = FactoryGirl.create :empty_project, runners_token: ''
+ expect(project.runners_token).not_to eq('')
+ end
+
+ it 'should not set an random toke if one provided' do
+ project = FactoryGirl.create :empty_project, runners_token: 'my-token'
+ expect(project.runners_token).to eq('my-token')
+ end
+ end
describe 'Respond to' do
it { is_expected.to respond_to(:url_to_repo) }
@@ -395,12 +414,7 @@ describe Project, models: true do
describe :ci_commit do
let(:project) { create :project }
- let(:commit) { create :ci_commit, gl_project: project }
-
- before do
- project.ensure_gitlab_ci_project
- project.create_gitlab_ci_service(active: true)
- end
+ let(:commit) { create :ci_commit, project: project }
it { expect(project.ci_commit(commit.sha)).to eq(commit) }
end
@@ -412,9 +426,7 @@ describe Project, models: true do
subject { project.builds_enabled }
- it { is_expected.to eq(project.gitlab_ci_service.active) }
it { expect(project.builds_enabled?).to be_truthy }
- it { expect(project.gitlab_ci_project).to be_a(Ci::Project) }
end
describe '.trending' do
@@ -475,4 +487,65 @@ describe Project, models: true do
it { is_expected.to eq([]) }
end
end
+
+ context 'shared runners by default' do
+ let(:project) { create(:empty_project) }
+
+ subject { project.shared_runners_enabled }
+
+ context 'are enabled' do
+ before { stub_application_setting(shared_runners_enabled: true) }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'are disabled' do
+ before { stub_application_setting(shared_runners_enabled: false) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe :any_runners do
+ let(:project) { create(:empty_project, shared_runners_enabled: shared_runners_enabled) }
+ let(:specific_runner) { create(:ci_specific_runner) }
+ let(:shared_runner) { create(:ci_shared_runner) }
+
+ context 'for shared runners disabled' do
+ let(:shared_runners_enabled) { false }
+
+ it 'there are no runners available' do
+ expect(project.any_runners?).to be_falsey
+ end
+
+ it 'there is a specific runner' do
+ project.runners << specific_runner
+ expect(project.any_runners?).to be_truthy
+ end
+
+ it 'there is a shared runner, but they are prohibited to use' do
+ shared_runner
+ expect(project.any_runners?).to be_falsey
+ end
+
+ it 'checks the presence of specific runner' do
+ project.runners << specific_runner
+ expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
+ end
+ end
+
+ context 'for shared runners enabled' do
+ let(:shared_runners_enabled) { true }
+
+ it 'there is a shared runner' do
+ shared_runner
+ expect(project.any_runners?).to be_truthy
+ end
+
+ it 'checks the presence of shared runner' do
+ shared_runner
+ expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
+ end
+ end
+ end
end
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index 606b226ad77..142b637d291 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -1,11 +1,17 @@
require 'spec_helper'
-describe API::API, 'ProjectHooks', api: true do
+describe API::API, 'ProjectHooks', api: true do
include ApiHelpers
let(:user) { create(:user) }
let(:user3) { create(:user) }
let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
- let!(:hook) { create(:project_hook, project: project, url: "http://example.com", push_events: true, merge_requests_events: true, tag_push_events: true, issues_events: true, note_events: true, enable_ssl_verification: true) }
+ let!(:hook) do
+ create(:project_hook,
+ project: project, url: "http://example.com",
+ push_events: true, merge_requests_events: true, tag_push_events: true,
+ issues_events: true, note_events: true, build_events: true,
+ enable_ssl_verification: true)
+ end
before do
project.team << [user, :master]
@@ -26,6 +32,7 @@ describe API::API, 'ProjectHooks', api: true do
expect(json_response.first['merge_requests_events']).to eq(true)
expect(json_response.first['tag_push_events']).to eq(true)
expect(json_response.first['note_events']).to eq(true)
+ expect(json_response.first['build_events']).to eq(true)
expect(json_response.first['enable_ssl_verification']).to eq(true)
end
end
@@ -83,6 +90,7 @@ describe API::API, 'ProjectHooks', api: true do
expect(json_response['merge_requests_events']).to eq(false)
expect(json_response['tag_push_events']).to eq(false)
expect(json_response['note_events']).to eq(false)
+ expect(json_response['build_events']).to eq(false)
expect(json_response['enable_ssl_verification']).to eq(true)
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 24b765f4979..e784b7d1f2d 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -86,18 +86,6 @@ describe API::API, api: true do
expect(json_response).to be_an Array
expect(json_response.first['id']).to eq(project3.id)
end
-
- it 'returns projects in the correct order when ci_enabled_first parameter is passed' do
- [project, project2, project3].each do |project|
- project.builds_enabled = false
- project.build_missing_services
- end
- project2.builds_enabled = true
- get api('/projects', user), { ci_enabled_first: 'true' }
- expect(response.status).to eq(200)
- expect(json_response).to be_an Array
- expect(json_response.first['id']).to eq(project2.id)
- end
end
end
end
diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb
new file mode 100644
index 00000000000..314bd7ddc59
--- /dev/null
+++ b/spec/requests/api/triggers_spec.rb
@@ -0,0 +1,80 @@
+require 'spec_helper'
+
+describe API::API do
+ include ApiHelpers
+
+ describe 'POST /projects/:project_id/trigger' do
+ let!(:trigger_token) { 'secure token' }
+ let!(:project) { FactoryGirl.create(:project) }
+ let!(:project2) { FactoryGirl.create(:empty_project) }
+ let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) }
+ let(:options) do
+ {
+ token: trigger_token
+ }
+ end
+
+ before do
+ stub_ci_commit_to_return_yaml_file
+ end
+
+ context 'Handles errors' do
+ it 'should return bad request if token is missing' do
+ post api("/projects/#{project.id}/trigger/builds"), ref: 'master'
+ expect(response.status).to eq(400)
+ end
+
+ it 'should return not found if project is not found' do
+ post api('/projects/0/trigger/builds'), options.merge(ref: 'master')
+ expect(response.status).to eq(404)
+ end
+
+ it 'should return unauthorized if token is for different project' do
+ post api("/projects/#{project2.id}/trigger/builds"), options.merge(ref: 'master')
+ expect(response.status).to eq(401)
+ end
+ end
+
+ context 'Have a commit' do
+ let(:commit) { project.ci_commits.last }
+
+ it 'should create builds' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(ref: 'master')
+ expect(response.status).to eq(201)
+ commit.builds.reload
+ expect(commit.builds.size).to eq(2)
+ end
+
+ it 'should return bad request with no builds created if there\'s no commit for that ref' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(ref: 'other-branch')
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('No builds created')
+ end
+
+ context 'Validates variables' do
+ let(:variables) do
+ { 'TRIGGER_KEY' => 'TRIGGER_VALUE' }
+ end
+
+ it 'should validate variables to be a hash' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(variables: 'value', ref: 'master')
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('variables needs to be a hash')
+ end
+
+ it 'should validate variables needs to be a map of key-valued strings' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(variables: { key: %w(1 2) }, ref: 'master')
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('variables needs to be a map of key-valued strings')
+ end
+
+ it 'create trigger request with variables' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(variables: variables, ref: 'master')
+ expect(response.status).to eq(201)
+ commit.builds.reload
+ expect(commit.builds.first.trigger_request.variables).to eq(variables)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index c2be045099d..c27e87c4acc 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -4,8 +4,7 @@ describe Ci::API::API do
include ApiHelpers
let(:runner) { FactoryGirl.create(:ci_runner, tag_list: ["mysql", "ruby"]) }
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:gl_project) { project.gl_project }
+ let(:project) { FactoryGirl.create(:empty_project) }
before do
stub_ci_commit_to_return_yaml_file
@@ -13,16 +12,15 @@ describe Ci::API::API do
describe "Builds API for runners" do
let(:shared_runner) { FactoryGirl.create(:ci_runner, token: "SharedRunner") }
- let(:shared_project) { FactoryGirl.create(:ci_project, name: "SharedProject") }
- let(:shared_gl_project) { shared_project.gl_project }
+ let(:shared_project) { FactoryGirl.create(:empty_project, name: "SharedProject") }
before do
- FactoryGirl.create :ci_runner_project, project_id: project.id, runner_id: runner.id
+ FactoryGirl.create :ci_runner_project, project: project, runner: runner
end
describe "POST /builds/register" do
it "should start a build" do
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
commit.create_builds('master', false, nil)
build = commit.builds.first
@@ -40,7 +38,7 @@ describe Ci::API::API do
end
it "should return 404 error if no builds for specific runner" do
- commit = FactoryGirl.create(:ci_commit, gl_project: shared_gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: shared_project)
FactoryGirl.create(:ci_build, commit: commit, status: 'pending')
post ci_api("/builds/register"), token: runner.token
@@ -49,7 +47,7 @@ describe Ci::API::API do
end
it "should return 404 error if no builds for shared runner" do
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
FactoryGirl.create(:ci_build, commit: commit, status: 'pending')
post ci_api("/builds/register"), token: shared_runner.token
@@ -58,7 +56,7 @@ describe Ci::API::API do
end
it "returns options" do
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
commit.create_builds('master', false, nil)
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
@@ -68,7 +66,7 @@ describe Ci::API::API do
end
it "returns variables" do
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
commit.create_builds('master', false, nil)
project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
@@ -85,7 +83,7 @@ describe Ci::API::API do
it "returns variables for triggers" do
trigger = FactoryGirl.create(:ci_trigger, project: project)
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, commit: commit, trigger: trigger)
commit.create_builds('master', false, nil, trigger_request)
@@ -106,7 +104,7 @@ describe Ci::API::API do
end
describe "PUT /builds/:id" do
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project)}
+ let(:commit) { FactoryGirl.create(:ci_commit, project: project)}
let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) }
it "should update a running build" do
@@ -126,14 +124,14 @@ describe Ci::API::API do
context "Artifacts" do
let(:file_upload) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
let(:file_upload2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/gif') }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
+ let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) }
let(:authorize_url) { ci_api("/builds/#{build.id}/artifacts/authorize") }
let(:post_url) { ci_api("/builds/#{build.id}/artifacts") }
let(:delete_url) { ci_api("/builds/#{build.id}/artifacts") }
let(:get_url) { ci_api("/builds/#{build.id}/artifacts") }
let(:headers) { { "GitLab-Workhorse" => "1.0" } }
- let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => build.project.token) }
+ let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => build.token) }
describe "POST /builds/:id/artifacts/authorize" do
context "should authorize posting artifact to running build" do
@@ -142,7 +140,7 @@ describe Ci::API::API do
end
it "using token as parameter" do
- post authorize_url, { token: build.project.token }, headers
+ post authorize_url, { token: build.token }, headers
expect(response.status).to eq(200)
expect(json_response["TempPath"]).to_not be_nil
end
@@ -161,7 +159,7 @@ describe Ci::API::API do
it "using token as parameter" do
stub_application_setting(max_artifacts_size: 0)
- post authorize_url, { token: build.project.token, filesize: 100 }, headers
+ post authorize_url, { token: build.token, filesize: 100 }, headers
expect(response.status).to eq(413)
end
@@ -241,7 +239,7 @@ describe Ci::API::API do
end
it do
- post post_url, { token: build.project.token }, {}
+ post post_url, { token: build.token }, {}
expect(response.status).to eq(403)
end
end
@@ -281,12 +279,12 @@ describe Ci::API::API do
describe "DELETE /builds/:id/artifacts" do
before do
build.run!
- post delete_url, token: build.project.token, file: file_upload
+ post delete_url, token: build.token, file: file_upload
end
it "should delete artifact build" do
build.success
- delete delete_url, token: build.project.token
+ delete delete_url, token: build.token
expect(response.status).to eq(200)
end
end
@@ -298,12 +296,12 @@ describe Ci::API::API do
it "should download artifact" do
build.update_attributes(artifacts_file: file_upload)
- get get_url, token: build.project.token
+ get get_url, token: build.token
expect(response.status).to eq(200)
end
it "should fail to download if no artifact uploaded" do
- get get_url, token: build.project.token
+ get get_url, token: build.token
expect(response.status).to eq(404)
end
end
diff --git a/spec/requests/ci/api/commits_spec.rb b/spec/requests/ci/api/commits_spec.rb
deleted file mode 100644
index aa51ba95bca..00000000000
--- a/spec/requests/ci/api/commits_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require 'spec_helper'
-
-describe Ci::API::API, 'Commits' do
- include ApiHelpers
-
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:gl_project) { project.gl_project }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
-
- let(:options) do
- {
- project_token: project.token,
- project_id: project.id
- }
- end
-
- describe "GET /commits" do
- before { commit }
-
- it "should return commits per project" do
- get ci_api("/commits"), options
-
- expect(response.status).to eq(200)
- expect(json_response.count).to eq(1)
- expect(json_response.first["project_id"]).to eq(project.id)
- expect(json_response.first["sha"]).to eq(commit.sha)
- end
- end
-
- describe "POST /commits" do
- let(:data) do
- {
- "before" => "95790bf891e76fee5e1747ab589903a6a1f80f22",
- "after" => "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
- "ref" => "refs/heads/master",
- "commits" => [
- {
- "id" => "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
- "message" => "Update Catalan translation to e38cb41.",
- "timestamp" => "2011-12-12T14:27:31+02:00",
- "url" => "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
- "author" => {
- "name" => "Jordi Mallach",
- "email" => "jordi@softcatala.org",
- }
- }
- ]
- }
- end
-
- it "should create a build" do
- post ci_api("/commits"), options.merge(data: data)
-
- expect(response.status).to eq(201)
- expect(json_response['sha']).to eq("da1560886d4f094c3e6c9ef40349f7d38b5d27d7")
- end
-
- it "should return 400 error if no data passed" do
- post ci_api("/commits"), options
-
- expect(response.status).to eq(400)
- expect(json_response['message']).to eq("400 (Bad request) \"data\" not given")
- end
- end
-end
diff --git a/spec/requests/ci/api/projects_spec.rb b/spec/requests/ci/api/projects_spec.rb
deleted file mode 100644
index 893fd168d3e..00000000000
--- a/spec/requests/ci/api/projects_spec.rb
+++ /dev/null
@@ -1,232 +0,0 @@
-require 'spec_helper'
-
-describe Ci::API::API do
- include ApiHelpers
-
- let(:gitlab_url) { GitlabCi.config.gitlab_ci.url }
- let(:user) { create(:user) }
- let(:private_token) { user.private_token }
-
- let(:options) do
- {
- private_token: private_token,
- url: gitlab_url
- }
- end
-
- before do
- stub_gitlab_calls
- end
-
- context "requests for scoped projects" do
- # NOTE: These ids are tied to the actual projects on demo.gitlab.com
- describe "GET /projects" do
- let!(:project1) { FactoryGirl.create(:ci_project) }
- let!(:project2) { FactoryGirl.create(:ci_project) }
-
- before do
- project1.gl_project.team << [user, :developer]
- project2.gl_project.team << [user, :developer]
- end
-
- it "should return all projects on the CI instance" do
- get ci_api("/projects"), options
- expect(response.status).to eq(200)
- expect(json_response.count).to eq(2)
- expect(json_response.first["id"]).to eq(project1.id)
- expect(json_response.last["id"]).to eq(project2.id)
- end
- end
-
- describe "GET /projects/owned" do
- let!(:gl_project1) {FactoryGirl.create(:empty_project, namespace: user.namespace)}
- let!(:gl_project2) {FactoryGirl.create(:empty_project, namespace: user.namespace)}
- let!(:project1) { gl_project1.ensure_gitlab_ci_project }
- let!(:project2) { gl_project2.ensure_gitlab_ci_project }
-
- before do
- project1.gl_project.team << [user, :developer]
- project2.gl_project.team << [user, :developer]
- end
-
- it "should return all projects on the CI instance" do
- get ci_api("/projects/owned"), options
-
- expect(response.status).to eq(200)
- expect(json_response.count).to eq(2)
- end
- end
- end
-
- describe "POST /projects/:project_id/webhooks" do
- let!(:project) { FactoryGirl.create(:ci_project) }
-
- context "Valid Webhook URL" do
- let!(:webhook) { { web_hook: "http://example.com/sth/1/ala_ma_kota" } }
-
- before do
- options.merge!(webhook)
- end
-
- it "should create webhook for specified project" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/webhooks"), options
- expect(response.status).to eq(201)
- expect(json_response["url"]).to eq(webhook[:web_hook])
- end
-
- it "fails to create webhook for non existsing project" do
- post ci_api("/projects/non-existant-id/webhooks"), options
- expect(response.status).to eq(404)
- end
-
- it "non-manager is not authorized" do
- post ci_api("/projects/#{project.id}/webhooks"), options
- expect(response.status).to eq(401)
- end
- end
-
- context "Invalid Webhook URL" do
- let!(:webhook) { { web_hook: "ala_ma_kota" } }
-
- before do
- options.merge!(webhook)
- end
-
- it "fails to create webhook for not valid url" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/webhooks"), options
- expect(response.status).to eq(400)
- end
- end
-
- context "Missed web_hook parameter" do
- it "fails to create webhook for not provided url" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/webhooks"), options
- expect(response.status).to eq(400)
- end
- end
- end
-
- describe "GET /projects/:id" do
- let!(:project) { FactoryGirl.create(:ci_project) }
-
- before do
- project.gl_project.team << [user, :developer]
- end
-
- context "with an existing project" do
- it "should retrieve the project info" do
- get ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(200)
- expect(json_response['id']).to eq(project.id)
- end
- end
-
- context "with a non-existing project" do
- it "should return 404 error if project not found" do
- get ci_api("/projects/non_existent_id"), options
- expect(response.status).to eq(404)
- end
- end
- end
-
- describe "PUT /projects/:id" do
- let!(:project) { FactoryGirl.create(:ci_project) }
- let!(:project_info) { { default_ref: "develop" } }
-
- before do
- options.merge!(project_info)
- end
-
- it "should update a specific project's information" do
- project.gl_project.team << [user, :master]
- put ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(200)
- expect(json_response["default_ref"]).to eq(project_info[:default_ref])
- end
-
- it "fails to update a non-existing project" do
- put ci_api("/projects/non-existant-id"), options
- expect(response.status).to eq(404)
- end
-
- it "non-manager is not authorized" do
- put ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(401)
- end
- end
-
- describe "DELETE /projects/:id" do
- let!(:project) { FactoryGirl.create(:ci_project) }
-
- it "should delete a specific project" do
- project.gl_project.team << [user, :master]
- delete ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(200)
- expect { project.reload }.
- to raise_error(ActiveRecord::RecordNotFound)
- end
-
- it "non-manager is not authorized" do
- delete ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(401)
- end
-
- it "is getting not found error" do
- delete ci_api("/projects/not-existing_id"), options
- expect(response.status).to eq(404)
- end
- end
-
- describe "POST /projects/:id/runners/:id" do
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:runner) { FactoryGirl.create(:ci_runner) }
-
- it "should add the project to the runner" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
- expect(response.status).to eq(201)
-
- project.reload
- expect(project.runners.first.id).to eq(runner.id)
- end
-
- it "should fail if it tries to link a non-existing project or runner" do
- post ci_api("/projects/#{project.id}/runners/non-existing"), options
- expect(response.status).to eq(404)
-
- post ci_api("/projects/non-existing/runners/#{runner.id}"), options
- expect(response.status).to eq(404)
- end
-
- it "non-manager is not authorized" do
- allow_any_instance_of(User).to receive(:can_manage_project?).and_return(false)
- post ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
- expect(response.status).to eq(401)
- end
- end
-
- describe "DELETE /projects/:id/runners/:id" do
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:runner) { FactoryGirl.create(:ci_runner) }
-
- it "should remove the project from the runner" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
-
- expect(project.runners).to be_present
- delete ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
- expect(response.status).to eq(200)
-
- project.reload
- expect(project.runners).to be_empty
- end
-
- it "non-manager is not authorized" do
- delete ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
- expect(response.status).to eq(401)
- end
- end
-end
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index 11dc089e1f5..567da013e6f 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -4,57 +4,38 @@ describe Ci::API::API do
include ApiHelpers
include StubGitlabCalls
+ let(:registration_token) { 'abcdefg123456' }
+
before do
stub_gitlab_calls
- end
-
- describe "GET /runners" do
- let(:gitlab_url) { GitlabCi.config.gitlab_ci.url }
- let(:private_token) { create(:user).private_token }
- let(:options) do
- {
- private_token: private_token,
- url: gitlab_url
- }
- end
-
- before do
- 5.times { FactoryGirl.create(:ci_runner) }
- end
-
- it "should retrieve a list of all runners" do
- get ci_api("/runners", nil), options
- expect(response.status).to eq(200)
- expect(json_response.count).to eq(5)
- expect(json_response.last).to have_key("id")
- expect(json_response.last).to have_key("token")
- end
+ stub_application_setting(ensure_runners_registration_token: registration_token)
+ stub_application_setting(runners_registration_token: registration_token)
end
describe "POST /runners/register" do
describe "should create a runner if token provided" do
- before { post ci_api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN }
+ before { post ci_api("/runners/register"), token: registration_token }
it { expect(response.status).to eq(201) }
end
describe "should create a runner with description" do
- before { post ci_api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN, description: "server.hostname" }
+ before { post ci_api("/runners/register"), token: registration_token, description: "server.hostname" }
it { expect(response.status).to eq(201) }
it { expect(Ci::Runner.first.description).to eq("server.hostname") }
end
describe "should create a runner with tags" do
- before { post ci_api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN, tag_list: "tag1, tag2" }
+ before { post ci_api("/runners/register"), token: registration_token, tag_list: "tag1, tag2" }
it { expect(response.status).to eq(201) }
it { expect(Ci::Runner.first.tag_list.sort).to eq(["tag1", "tag2"]) }
end
describe "should create a runner if project token provided" do
- let(:project) { FactoryGirl.create(:ci_project) }
- before { post ci_api("/runners/register"), token: project.token }
+ let(:project) { FactoryGirl.create(:empty_project) }
+ before { post ci_api("/runners/register"), token: project.runners_token }
it { expect(response.status).to eq(201) }
it { expect(project.runners.size).to eq(1) }
diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb
index a2b436d5811..0ef03f9371b 100644
--- a/spec/requests/ci/api/triggers_spec.rb
+++ b/spec/requests/ci/api/triggers_spec.rb
@@ -5,9 +5,8 @@ describe Ci::API::API do
describe 'POST /projects/:project_id/refs/:ref/trigger' do
let!(:trigger_token) { 'secure token' }
- let!(:gl_project) { FactoryGirl.create(:project) }
- let!(:project) { gl_project.ensure_gitlab_ci_project }
- let!(:project2) { FactoryGirl.create(:ci_project) }
+ let!(:project) { FactoryGirl.create(:project, ci_id: 10) }
+ let!(:project2) { FactoryGirl.create(:empty_project, ci_id: 11) }
let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) }
let(:options) do
{
@@ -21,7 +20,7 @@ describe Ci::API::API do
context 'Handles errors' do
it 'should return bad request if token is missing' do
- post ci_api("/projects/#{project.id}/refs/master/trigger")
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger")
expect(response.status).to eq(400)
end
@@ -31,23 +30,23 @@ describe Ci::API::API do
end
it 'should return unauthorized if token is for different project' do
- post ci_api("/projects/#{project2.id}/refs/master/trigger"), options
+ post ci_api("/projects/#{project2.ci_id}/refs/master/trigger"), options
expect(response.status).to eq(401)
end
end
context 'Have a commit' do
- let(:commit) { project.commits.last }
+ let(:commit) { project.ci_commits.last }
it 'should create builds' do
- post ci_api("/projects/#{project.id}/refs/master/trigger"), options
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options
expect(response.status).to eq(201)
commit.builds.reload
expect(commit.builds.size).to eq(2)
end
it 'should return bad request with no builds created if there\'s no commit for that ref' do
- post ci_api("/projects/#{project.id}/refs/other-branch/trigger"), options
+ post ci_api("/projects/#{project.ci_id}/refs/other-branch/trigger"), options
expect(response.status).to eq(400)
expect(json_response['message']).to eq('No builds created')
end
@@ -58,19 +57,19 @@ describe Ci::API::API do
end
it 'should validate variables to be a hash' do
- post ci_api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: 'value')
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options.merge(variables: 'value')
expect(response.status).to eq(400)
expect(json_response['message']).to eq('variables needs to be a hash')
end
it 'should validate variables needs to be a map of key-valued strings' do
- post ci_api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: { key: %w(1 2) })
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options.merge(variables: { key: %w(1 2) })
expect(response.status).to eq(400)
expect(json_response['message']).to eq('variables needs to be a map of key-valued strings')
end
it 'create trigger request with variables' do
- post ci_api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: variables)
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options.merge(variables: variables)
expect(response.status).to eq(201)
commit.builds.reload
expect(commit.builds.first.trigger_request.variables).to eq(variables)
diff --git a/spec/services/ci/create_commit_service_spec.rb b/spec/services/ci/create_commit_service_spec.rb
deleted file mode 100644
index c2fafca2ad2..00000000000
--- a/spec/services/ci/create_commit_service_spec.rb
+++ /dev/null
@@ -1,172 +0,0 @@
-require 'spec_helper'
-
-module Ci
- describe CreateCommitService, services: true do
- let(:service) { CreateCommitService.new }
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:user) { nil }
-
- before do
- stub_ci_commit_to_return_yaml_file
- end
-
- describe :execute do
- context 'valid params' do
- let(:commit) do
- service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: [ { message: "Message" } ]
- )
- end
-
- it { expect(commit).to be_kind_of(Commit) }
- it { expect(commit).to be_valid }
- it { expect(commit).to be_persisted }
- it { expect(commit).to eq(project.commits.last) }
- it { expect(commit.builds.first).to be_kind_of(Build) }
- end
-
- context "skip tag if there is no build for it" do
- it "creates commit if there is appropriate job" do
- result = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: [ { message: "Message" } ]
- )
- expect(result).to be_persisted
- end
-
- it "creates commit if there is no appropriate job but deploy job has right ref setting" do
- config = YAML.dump({ deploy: { deploy: "ls", only: ["0_1"] } })
- stub_ci_commit_yaml_file(config)
-
- result = service.execute(project, user,
- ref: 'refs/heads/0_1',
- before: '00000000',
- after: '31das312',
- commits: [ { message: "Message" } ]
- )
- expect(result).to be_persisted
- end
- end
-
- it 'skips commits without .gitlab-ci.yml' do
- stub_ci_commit_yaml_file(nil)
- result = service.execute(project, user,
- ref: 'refs/heads/0_1',
- before: '00000000',
- after: '31das312',
- commits: [ { message: 'Message' } ]
- )
- expect(result).to be_persisted
- expect(result.builds.any?).to be_falsey
- expect(result.status).to eq('skipped')
- expect(result.yaml_errors).to be_nil
- end
-
- it 'skips commits if yaml is invalid' do
- message = 'message'
- allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
- stub_ci_commit_yaml_file('invalid: file: file')
- commits = [{ message: message }]
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.any?).to be false
- expect(commit.status).to eq('failed')
- expect(commit.yaml_errors).to_not be_nil
- end
-
- describe :ci_skip? do
- let(:message) { "some message[ci skip]" }
-
- before do
- allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
- end
-
- it "skips builds creation if there is [ci skip] tag in commit message" do
- commits = [{ message: message }]
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.any?).to be false
- expect(commit.status).to eq("skipped")
- end
-
- it "does not skips builds creation if there is no [ci skip] tag in commit message" do
- allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { "some message" }
-
- commits = [{ message: "some message" }]
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(commit.builds.first.name).to eq("staging")
- end
-
- it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do
- stub_ci_commit_yaml_file('invalid: file: fiile')
- commits = [{ message: message }]
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.any?).to be false
- expect(commit.status).to eq("skipped")
- expect(commit.yaml_errors).to be_nil
- end
- end
-
- it "skips build creation if there are already builds" do
- allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { gitlab_ci_yaml }
-
- commits = [{ message: "message" }]
- commit = service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.count(:all)).to eq(2)
-
- commit = service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.count(:all)).to eq(2)
- end
-
- it "creates commit with failed status if yaml is invalid" do
- stub_ci_commit_yaml_file('invalid: file')
-
- commits = [{ message: "some message" }]
-
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(commit.status).to eq("failed")
- expect(commit.builds.any?).to be false
- end
- end
- end
-end
diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb
index c80cb58163a..dbdc5370bd8 100644
--- a/spec/services/ci/create_trigger_request_service_spec.rb
+++ b/spec/services/ci/create_trigger_request_service_spec.rb
@@ -2,8 +2,7 @@ require 'spec_helper'
describe Ci::CreateTriggerRequestService, services: true do
let(:service) { Ci::CreateTriggerRequestService.new }
- let(:gl_project) { create(:project) }
- let(:project) { gl_project.ensure_gitlab_ci_project }
+ let(:project) { create(:project) }
let(:trigger) { create(:ci_trigger, project: project) }
before do
@@ -29,7 +28,7 @@ describe Ci::CreateTriggerRequestService, services: true do
before do
stub_ci_commit_yaml_file('{}')
- FactoryGirl.create :ci_commit, gl_project: gl_project
+ FactoryGirl.create :ci_commit, project: project
end
it { expect(subject).to be_nil }
diff --git a/spec/services/ci/event_service_spec.rb b/spec/services/ci/event_service_spec.rb
deleted file mode 100644
index 32516c75cf3..00000000000
--- a/spec/services/ci/event_service_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'spec_helper'
-
-describe Ci::EventService, services: true do
- let(:project) { FactoryGirl.create :ci_project }
- let(:user) { double(username: "root", id: 1) }
-
- before do
- Event.destroy_all
- end
-
- describe :remove_project do
- it "creates event" do
- Ci::EventService.new.remove_project(user, project)
-
- expect(Ci::Event.admin.last.description).to eq("Project \"#{project.name_with_namespace}\" has been removed by root")
- end
- end
-
- describe :create_project do
- it "creates event" do
- Ci::EventService.new.create_project(user, project)
-
- expect(Ci::Event.admin.last.description).to eq("Project \"#{project.name_with_namespace}\" has been created by root")
- end
- end
-
- describe :change_project_settings do
- it "creates event" do
- Ci::EventService.new.change_project_settings(user, project)
-
- expect(Ci::Event.last.description).to eq("User \"root\" updated projects settings")
- end
- end
-end
diff --git a/spec/services/ci/image_for_build_service_spec.rb b/spec/services/ci/image_for_build_service_spec.rb
index b43cabb4ee4..870861ad20a 100644
--- a/spec/services/ci/image_for_build_service_spec.rb
+++ b/spec/services/ci/image_for_build_service_spec.rb
@@ -3,16 +3,16 @@ require 'spec_helper'
module Ci
describe ImageForBuildService, services: true do
let(:service) { ImageForBuildService.new }
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:gl_project) { FactoryGirl.create(:project, gitlab_ci_project: project) }
- let(:commit_sha) { gl_project.commit('master').sha }
- let(:commit) { gl_project.ensure_ci_commit(commit_sha) }
+ let(:project) { FactoryGirl.create(:empty_project) }
+ let(:commit_sha) { '01234567890123456789' }
+ let(:commit) { project.ensure_ci_commit(commit_sha) }
let(:build) { FactoryGirl.create(:ci_build, commit: commit) }
describe :execute do
before { build }
context 'branch name' do
+ before { allow(project).to receive(:commit).and_return(OpenStruct.new(sha: commit_sha)) }
before { build.run! }
let(:image) { service.execute(project, ref: 'master') }
diff --git a/spec/services/ci/register_build_service_spec.rb b/spec/services/ci/register_build_service_spec.rb
index 379e07982fb..e81f9e757ac 100644
--- a/spec/services/ci/register_build_service_spec.rb
+++ b/spec/services/ci/register_build_service_spec.rb
@@ -3,14 +3,14 @@ require 'spec_helper'
module Ci
describe RegisterBuildService, services: true do
let!(:service) { RegisterBuildService.new }
- let!(:gl_project) { FactoryGirl.create :empty_project }
- let!(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+ let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false }
+ let!(:commit) { FactoryGirl.create :ci_commit, project: project }
let!(:pending_build) { FactoryGirl.create :ci_build, commit: commit }
let!(:shared_runner) { FactoryGirl.create(:ci_runner, is_shared: true) }
let!(:specific_runner) { FactoryGirl.create(:ci_runner, is_shared: false) }
before do
- specific_runner.assign_to(gl_project.ensure_gitlab_ci_project)
+ specific_runner.assign_to(project)
end
describe :execute do
@@ -47,7 +47,7 @@ module Ci
context 'allow shared runners' do
before do
- gl_project.gitlab_ci_project.update(shared_runners_enabled: true)
+ project.update(shared_runners_enabled: true)
end
context 'shared runner' do
@@ -71,7 +71,7 @@ module Ci
context 'disallow shared runners' do
before do
- gl_project.gitlab_ci_project.update(shared_runners_enabled: false)
+ project.update(shared_runners_enabled: false)
end
context 'shared runner' do
diff --git a/spec/services/ci/web_hook_service_spec.rb b/spec/services/ci/web_hook_service_spec.rb
deleted file mode 100644
index e7d8ab30652..00000000000
--- a/spec/services/ci/web_hook_service_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'spec_helper'
-
-describe Ci::WebHookService, services: true do
- let(:project) { FactoryGirl.create :ci_project }
- let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
- let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
- let(:build) { FactoryGirl.create :ci_build, commit: commit }
- let(:hook) { FactoryGirl.create :ci_web_hook, project: project }
-
- describe :execute do
- it "should execute successfully" do
- stub_request(:post, hook.url).to_return(status: 200)
- expect(Ci::WebHookService.new.build_end(build)).to be_truthy
- end
- end
-
- context 'build_data' do
- it "contains all needed fields" do
- expect(build_data(build)).to include(
- :build_id,
- :project_id,
- :ref,
- :build_status,
- :build_started_at,
- :build_finished_at,
- :before_sha,
- :project_name,
- :gitlab_url,
- :build_name
- )
- end
- end
-
- def build_data(build)
- Ci::WebHookService.new.send :build_data, build
- end
-end
diff --git a/spec/services/create_commit_builds_service_spec.rb b/spec/services/create_commit_builds_service_spec.rb
new file mode 100644
index 00000000000..798c480b81a
--- /dev/null
+++ b/spec/services/create_commit_builds_service_spec.rb
@@ -0,0 +1,170 @@
+require 'spec_helper'
+
+describe CreateCommitBuildsService, services: true do
+ let(:service) { CreateCommitBuildsService.new }
+ let(:project) { FactoryGirl.create(:empty_project) }
+ let(:user) { nil }
+
+ before do
+ stub_ci_commit_to_return_yaml_file
+ end
+
+ describe :execute do
+ context 'valid params' do
+ let(:commit) do
+ service.execute(project, user,
+ ref: 'refs/heads/master',
+ before: '00000000',
+ after: '31das312',
+ commits: [{ message: "Message" }]
+ )
+ end
+
+ it { expect(commit).to be_kind_of(Ci::Commit) }
+ it { expect(commit).to be_valid }
+ it { expect(commit).to be_persisted }
+ it { expect(commit).to eq(project.ci_commits.last) }
+ it { expect(commit.builds.first).to be_kind_of(Ci::Build) }
+ end
+
+ context "skip tag if there is no build for it" do
+ it "creates commit if there is appropriate job" do
+ result = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: [{ message: "Message" }]
+ )
+ expect(result).to be_persisted
+ end
+
+ it "creates commit if there is no appropriate job but deploy job has right ref setting" do
+ config = YAML.dump({ deploy: { deploy: "ls", only: ["0_1"] } })
+ stub_ci_commit_yaml_file(config)
+
+ result = service.execute(project, user,
+ ref: 'refs/heads/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: [{ message: "Message" }]
+ )
+ expect(result).to be_persisted
+ end
+ end
+
+ it 'skips commits without .gitlab-ci.yml' do
+ stub_ci_commit_yaml_file(nil)
+ result = service.execute(project, user,
+ ref: 'refs/heads/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: [{ message: 'Message' }]
+ )
+ expect(result).to be_persisted
+ expect(result.builds.any?).to be_falsey
+ expect(result.status).to eq('skipped')
+ expect(result.yaml_errors).to be_nil
+ end
+
+ it 'skips commits if yaml is invalid' do
+ message = 'message'
+ allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
+ stub_ci_commit_yaml_file('invalid: file: file')
+ commits = [{ message: message }]
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit.builds.any?).to be false
+ expect(commit.status).to eq('failed')
+ expect(commit.yaml_errors).to_not be_nil
+ end
+
+ describe :ci_skip? do
+ let(:message) { "some message[ci skip]" }
+
+ before do
+ allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
+ end
+
+ it "skips builds creation if there is [ci skip] tag in commit message" do
+ commits = [{ message: message }]
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit.builds.any?).to be false
+ expect(commit.status).to eq("skipped")
+ end
+
+ it "does not skips builds creation if there is no [ci skip] tag in commit message" do
+ allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { "some message" }
+
+ commits = [{ message: "some message" }]
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+
+ expect(commit.builds.first.name).to eq("staging")
+ end
+
+ it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do
+ stub_ci_commit_yaml_file('invalid: file: fiile')
+ commits = [{ message: message }]
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit.builds.any?).to be false
+ expect(commit.status).to eq("skipped")
+ expect(commit.yaml_errors).to be_nil
+ end
+ end
+
+ it "skips build creation if there are already builds" do
+ allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { gitlab_ci_yaml }
+
+ commits = [{ message: "message" }]
+ commit = service.execute(project, user,
+ ref: 'refs/heads/master',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit.builds.count(:all)).to eq(2)
+
+ commit = service.execute(project, user,
+ ref: 'refs/heads/master',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit.builds.count(:all)).to eq(2)
+ end
+
+ it "creates commit with failed status if yaml is invalid" do
+ stub_ci_commit_yaml_file('invalid: file')
+
+ commits = [{ message: "some message" }]
+
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+
+ expect(commit.status).to eq("failed")
+ expect(commit.builds.any?).to be false
+ end
+ end
+end
diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
index 188fda6211f..449cecaa789 100644
--- a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
+++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
@@ -11,7 +11,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
end
let(:project) { create(:project) }
- let(:ci_commit) { create(:ci_commit_with_one_job, ref: mr_merge_if_green_enabled.source_branch, gl_project: project) }
+ let(:ci_commit) { create(:ci_commit_with_one_job, ref: mr_merge_if_green_enabled.source_branch, project: project) }
let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, commit_message: 'Awesome message') }
describe "#execute" do
diff --git a/spec/support/stub_gitlab_calls.rb b/spec/support/stub_gitlab_calls.rb
index 5b3eb1bfc5f..eec2e681117 100644
--- a/spec/support/stub_gitlab_calls.rb
+++ b/spec/support/stub_gitlab_calls.rb
@@ -21,6 +21,10 @@ module StubGitlabCalls
allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { ci_yaml }
end
+ def stub_ci_builds_disabled
+ allow_any_instance_of(Project).to receive(:builds_enabled?).and_return(false)
+ end
+
private
def gitlab_url
diff --git a/spec/workers/build_email_worker_spec.rb b/spec/workers/build_email_worker_spec.rb
new file mode 100644
index 00000000000..98deae0a588
--- /dev/null
+++ b/spec/workers/build_email_worker_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe BuildEmailWorker do
+ include RepoHelpers
+
+ let(:build) { create(:ci_build) }
+ let(:user) { create(:user) }
+ let(:data) { Gitlab::BuildDataBuilder.build(build) }
+
+ subject { BuildEmailWorker.new }
+
+ before do
+ allow(build).to receive(:execute_hooks).and_return(false)
+ build.success
+ end
+
+ describe "#perform" do
+ it "sends mail" do
+ subject.perform(build.id, [user.email], data.stringify_keys)
+
+ email = ActionMailer::Base.deliveries.last
+ expect(email.subject).to include('Build success for')
+ expect(email.to).to eq([user.email])
+ end
+
+ it "gracefully handles an input SMTP error" do
+ ActionMailer::Base.deliveries.clear
+ allow(Notify).to receive(:build_success_email).and_raise(Net::SMTPFatalError)
+
+ subject.perform(build.id, [user.email], data.stringify_keys)
+
+ expect(ActionMailer::Base.deliveries.count).to eq(0)
+ end
+ end
+end