mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-09 12:46:07 +10:00
Merge branch 'master' into notification-levels
This commit is contained in:
+3
-1
@@ -20,12 +20,13 @@ backups/*
|
||||
config/aws.yml
|
||||
config/database.yml
|
||||
config/gitlab.yml
|
||||
config/initializers/omniauth.rb
|
||||
config/gitlab_ci.yml
|
||||
config/initializers/rack_attack.rb
|
||||
config/initializers/smtp_settings.rb
|
||||
config/resque.yml
|
||||
config/unicorn.rb
|
||||
config/mail_room.yml
|
||||
config/secrets.yml
|
||||
coverage/*
|
||||
db/*.sqlite3
|
||||
db/*.sqlite3-journal
|
||||
@@ -41,3 +42,4 @@ rails_best_practices_output.html
|
||||
/tags
|
||||
tmp/
|
||||
vendor/bundle/*
|
||||
builds/*
|
||||
|
||||
@@ -998,7 +998,9 @@ AllCops:
|
||||
- 'tmp/**/*'
|
||||
- 'bin/**/*'
|
||||
- 'lib/backup/**/*'
|
||||
- 'lib/ci/backup/**/*'
|
||||
- 'lib/tasks/**/*'
|
||||
- 'lib/ci/migrate/**/*'
|
||||
- 'lib/email_validator.rb'
|
||||
- 'lib/gitlab/upgrader.rb'
|
||||
- 'lib/gitlab/seeder.rb'
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.0.0 (unreleased)
|
||||
- Fix broken sort in merge request API (Stan Hu)
|
||||
- Bump rouge to 1.10.1 to remove warning noise and fix other syntax highlighting bugs (Stan Hu)
|
||||
- Gracefully handle errors in syntax highlighting by leaving the block unformatted (Stan Hu)
|
||||
- Add "replace" and "upload" functionalities to allow user replace existing file and upload new file into current repository
|
||||
- Fix URL construction for merge requests, issues, notes, and commits for relative URL config (Stan Hu)
|
||||
- Fix emoji URLs in Markdown when relative_url_root is used (Stan Hu)
|
||||
- Omit filename in Content-Disposition header in raw file download to avoid RFC 6266 encoding issues (Stan HU)
|
||||
@@ -48,12 +50,14 @@ v 8.0.0 (unreleased)
|
||||
- Project notification level can be set on the project page itself
|
||||
- Added service API endpoint to retrieve service parameters (Petheő Bence)
|
||||
- Add FogBugz project import (Jared Szechy)
|
||||
- Sort users autocomplete lists by user (Allister Antosik)
|
||||
|
||||
v 7.14.3
|
||||
- No changes
|
||||
|
||||
v 7.14.2
|
||||
- Upgrade gitlab_git to 7.2.15 to fix `git blame` errors with ISO-encoded files (Stan Hu)
|
||||
- Allow configuration of LDAP attributes GitLab will use for the new user account.
|
||||
|
||||
v 7.14.1
|
||||
- Improve abuse reports management from admin area
|
||||
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
v7.14.0 (unreleased)
|
||||
- Truncate commit messages after subject line in table
|
||||
- Adjust CI config to support Docker executors
|
||||
- Added Application Settings
|
||||
- Randomize test database for CI tests
|
||||
- Make YAML validation stricter
|
||||
- Use avatars received from GitLab
|
||||
- Refactor GitLab API usage to use either access_token or private_token depending on what was specified during login
|
||||
- Allow to use access_token for API requests
|
||||
- Fix project API listing returning empty list when first projects are not added to CI
|
||||
- Allow to define variables from YAML
|
||||
- Added support for CI skipped status
|
||||
- Fix broken yaml error saving
|
||||
- Add committed_at to commits to properly order last commit (the force push issue)
|
||||
- Rename type(s) to stage(s)
|
||||
- Fix navigation icons
|
||||
- Add missing stage when doing retry
|
||||
- Require variable keys to be not-empty and unique
|
||||
- Fix variable saving issue
|
||||
- Display variable saving errors in variables page not the project's
|
||||
- Added Build Triggers API
|
||||
|
||||
v7.13.1
|
||||
- Fix: user could steal specific runner
|
||||
- Fix: don't send notifications for jobs with allow_failure set
|
||||
- Fix invalid link to doc.gitlab.com
|
||||
|
||||
v7.13.0
|
||||
- Fix inline edit runner-description
|
||||
- Allow to specify image and services in yml that can be used with docker
|
||||
- Fix: No runner notification can see managers only
|
||||
- Fix service testing for slack
|
||||
- Ability to cancel all builds in commit at once
|
||||
- Disable colors in rake tasks automatically (if IO is not a TTY)
|
||||
- Implemented "rake env:info". Rake task to receive system information
|
||||
- Fix coverage calculation on commit page
|
||||
- Enhance YAML validation
|
||||
- Redirect back after authorization
|
||||
- Change favicon
|
||||
- Refactoring: Get rid of private_token usage in the frontend.
|
||||
- Allow to specify allow_failure for job
|
||||
- Build traces is stored in the file instead of database
|
||||
- Make the builds path configurable
|
||||
- Disable link to runner if it's not assigned to specific project
|
||||
- Store all secrets in config/secrets.yml
|
||||
- Encrypt variables
|
||||
- Allow to specify flexible list of types in yaml
|
||||
|
||||
v7.12.2
|
||||
- Revert: Runner without tag should pick builds without tag only
|
||||
|
||||
v7.12.1
|
||||
- Runner without tag should pick builds without tag only
|
||||
- Explicit error in the GitLab when commit not found.
|
||||
- Fix: lint with relative subpath
|
||||
- Update webhook example
|
||||
- Improved Lint stability
|
||||
- Add warning when .gitlab-ci.yml not found
|
||||
- Improved validation for .gitlab-ci.yml
|
||||
- Fix list of branches in only section
|
||||
- Fix "Status Badge" button
|
||||
|
||||
v7.12.0
|
||||
- Endless scroll on the dashboard
|
||||
- Add notification if there are no runners
|
||||
- Fix pagination on dashboard
|
||||
- Remove ID column from runners list in the admin area
|
||||
- Increase default timeout for builds to 60 minutes
|
||||
- Using .gitlab-ci.yml file instead of jobs
|
||||
- Link to the runner from the build page for admin user
|
||||
- Ability to set secret variables for runner
|
||||
- Dont retry build when push same commit in same ref twice
|
||||
- Admin area: show amount of runners with last contact less than a minute ago
|
||||
- Fix re-adding project with the same name but different gitlab_id
|
||||
- Implementation of Lint (.gitlab-ci.yml validation tool)
|
||||
- Updated rails to 4.1.11
|
||||
- API fix: project create call
|
||||
- Link to web-editor with .gitlab-ci.yml
|
||||
- Updated examples in the documentation
|
||||
|
||||
v7.11.0
|
||||
- Deploy Jobs API calls
|
||||
- Projects search on dashboard page
|
||||
- Improved runners page
|
||||
- Running and Pending tabs on admin builds page
|
||||
- Fix [ci skip] tag, so you can skip CI triggering now
|
||||
- Add HipChat notifications
|
||||
- Clean up project advanced settings.
|
||||
- Add a GitLab project path parameter to the project API
|
||||
- Remove projects IDs from dashboard
|
||||
- UI fix: Remove page headers from the admin area
|
||||
- Improve Email templates
|
||||
- Add backup/restore utility
|
||||
- Coordinator stores information(version, platform, revision, etc.) about runners.
|
||||
- Fixed pagination on dashboard
|
||||
- Public accessible build and commit pages of public projects
|
||||
- Fix vulnerability in the API when MySQL is used
|
||||
|
||||
v7.10.1
|
||||
- Fix failing migration when update to 7.10 from 7.8 and older versions
|
||||
|
||||
sidekiq_wirker_fix
|
||||
- added sidekiq.yml
|
||||
- integrated in script/background_jobs
|
||||
v7.10.0
|
||||
- Projects sorting by last commit date
|
||||
- Add project search at runner page
|
||||
- Fix GitLab and CI projects collision
|
||||
- Events for admin
|
||||
- Events per projects
|
||||
- Search for runners in admin area
|
||||
- UI improvements: created separated admin section, removed useless project show page
|
||||
- Runners sorting in admin area (by id)
|
||||
- Remove protected_attributes gem
|
||||
- Skip commit creation if there is no appropriate job
|
||||
|
||||
v7.9.3
|
||||
- Contains no changes
|
||||
- Developers can cancel and retry jobs
|
||||
|
||||
v7.9.2
|
||||
- [Security] Already existing projects should not be served by shared runners
|
||||
- Ability to run deploy job without test jobs (every push will trigger deploy job)
|
||||
|
||||
v7.9.1
|
||||
- [Security] Adding explicit is_shared parameter to runner
|
||||
- [Security] By default new projects are not served by shared runners
|
||||
|
||||
v7.9.0
|
||||
- Reset user session if token is invalid
|
||||
- Runner delete api endpoint
|
||||
- Fix bug about showing edit button on commit page if user does not have permissions
|
||||
- Allow to pass description and tag list during Runner's registration
|
||||
- Added api for project jobs
|
||||
- Implementation of deploy jobs after all parallel jobs(tests).
|
||||
- Add scroll up/down buttons for better mobile experience with large build traces
|
||||
- Add runner last contact (Kamil Trzciński)
|
||||
- Allow to pause runners - when paused runner will not receive any new build (Kamil Trzciński)
|
||||
- Add brakeman (security scanner for Ruby on Rails)
|
||||
- Changed a color of the canceled builds
|
||||
- Fix of show the same commits in different branches
|
||||
|
||||
v7.8.2
|
||||
- Fix the broken build failed email
|
||||
- Notify only pusher instead of commiter
|
||||
|
||||
v7.8.0
|
||||
- Fix OAuth login with GitLab installed in relative URL
|
||||
- GitLab CI has same version as GitLab since now
|
||||
- Allow to pass description and tag list during Runner's registration (Kamil Trzciński)
|
||||
- Update documentation (API, Install, Update)
|
||||
- Skip refs field supports for wildcard branch name (ex. feature/*)
|
||||
- Migrate E-mail notification to Services menu (Kamil Trzciński)
|
||||
- Added Slack notifications (Kamil Trzciński)
|
||||
- Disable turbolink on links pointing out to GitLab server
|
||||
- Add test coverage parsing example for pytest-cov
|
||||
- Upgrade raindrops gem
|
||||
|
||||
v5.4.2
|
||||
- Fix exposure of project token via build data
|
||||
|
||||
v5.4.1
|
||||
- Fix 500 if on builds page if build has no job
|
||||
- Truncate project token from build trace
|
||||
- Allow users with access to project see build trace
|
||||
|
||||
v5.4.0 (Requires GitLab 7.7)
|
||||
- Fixed 500 error for badge if build is pending
|
||||
- Non-admin users can now register specific runners for their projects
|
||||
- Project specific runners page which users can access
|
||||
- Remove progress output from schedule_builds cron job
|
||||
- Fix schedule_builds rake task
|
||||
- Fix test webhook button
|
||||
- Job can be branch specific or tag specific or both
|
||||
- Shared runners builds projects which are not assigned to specific ones
|
||||
- Job can be runner specific through tags
|
||||
- Runner have tags
|
||||
- Move job settings to separate page
|
||||
- Add authorization level managing projects
|
||||
- OAuth authentication via GitLab.
|
||||
|
||||
v5.3
|
||||
- Remove annoying 'Done' message from schedule_builds cron job
|
||||
- Fix a style issue with the navbar
|
||||
- Skip CSRF check on the project's build page
|
||||
- Fix showing wrong build script on admin projects page
|
||||
- Add branch and commit message to build result emails
|
||||
|
||||
v5.2
|
||||
- Improve performance by adding new indicies
|
||||
- Separate Commit logic from Build logic in prep for Parallel Builds
|
||||
- Parallel builds
|
||||
- You can have multiple build scripts per project
|
||||
|
||||
v5.1
|
||||
- Registration token and runner token are named differently
|
||||
- Redirect to previous page after sign-in
|
||||
- Dont show archived projects
|
||||
- Add support for skip branches from build
|
||||
- Add coverage parsing feature
|
||||
- Update rails to 4.0.10
|
||||
- Look for a REVISION file before running `git log`
|
||||
- All builds page for admin
|
||||
|
||||
v5.0.1
|
||||
- Update rails to 4.0.5
|
||||
|
||||
v5.0.0
|
||||
- Set build timeout in minutes
|
||||
- Web Hooks for builds
|
||||
- Nprogress bar
|
||||
- Remove extra spaces in build script
|
||||
- Requires runner v5
|
||||
* All script commands executed as one file
|
||||
* Cancel button works correctly now
|
||||
* Runner stability increased
|
||||
* Timeout applies to build now instead of line of script
|
||||
|
||||
v4.3.0
|
||||
- Refactor build js
|
||||
- Redirect to build page with sha + bid if build id is not provided
|
||||
- Update rails to 4.0.3
|
||||
- Restyle project settings page
|
||||
- Improve help page
|
||||
- Replaced puma with unicorn
|
||||
- Improved init.d script
|
||||
- Add submodule init to default build script for new projects
|
||||
|
||||
v4.2.0
|
||||
- Build duration chart
|
||||
- Bootstrap 3 with responsive UI
|
||||
- Improved init.d script
|
||||
- Refactoring
|
||||
- Changed http codes for POST /projects/:id/build action
|
||||
- Turbolinks
|
||||
|
||||
v4.1.0
|
||||
- Rails 4
|
||||
- Click on build branch to see other builds for this branch
|
||||
- Email notifications (Jeroen Knoops)
|
||||
|
||||
v4.0.0
|
||||
- Shared runners (no need to add runner to every project)
|
||||
- Admin area (only available for GitLab admins)
|
||||
- Hide all runners management into admin area
|
||||
- Use http cloning for builds instead of deploy keys
|
||||
- Allow choose between git clone and git fetch when get code for build
|
||||
- Make build timeout actually works
|
||||
- Requires GitLab 6.3 or higher
|
||||
- GitLab CI settings go to GitLab project via api on creation
|
||||
|
||||
v3.2.0
|
||||
- Limit visibility of projects by gitlab authorized projects
|
||||
- Use one page for both gitlab and gitlab-ci projects
|
||||
|
||||
v3.1.0
|
||||
- Login with both username, email or LDAP credentials (if GitLab 6.0+)
|
||||
- Retry build button functionality
|
||||
- UI fixes for resolution 1366px and lower
|
||||
- Fix gravatar ssl warning
|
||||
|
||||
v3.0.0
|
||||
- Build running functionality extracted in gitlab-ci-runner
|
||||
- Added API for runners and builds
|
||||
- Redesigned application
|
||||
- Added charts
|
||||
- Use GitLab auth
|
||||
- Add projects via UI with few clicks
|
||||
|
||||
v2.2.0
|
||||
- replaced unicorn with puma
|
||||
- replaced grit with rugged
|
||||
- Runner.rb more transactional safe now
|
||||
- updated rails to 3.2.13
|
||||
- updated devise to 2.2
|
||||
- fixed issue when build left in running status if exception triggered
|
||||
- rescue build timeout correctly
|
||||
- badge helper with markdown & html
|
||||
- increased test coverage to 85%
|
||||
|
||||
v2.1.0
|
||||
- Removed horizontal scroll for build trace
|
||||
- new status badges
|
||||
- better encode
|
||||
- added several CI_* env variables
|
||||
|
||||
v2.0.0
|
||||
- Replace resque with sidekiq
|
||||
- Run only one build at time per project
|
||||
- Added whenever for schedule jobs
|
||||
|
||||
v1.2.0
|
||||
- Added Github web hook support
|
||||
- Added build schedule
|
||||
|
||||
v1.1.0
|
||||
- Added JSON response for builds status
|
||||
- Compatible with GitLab v4.0.0
|
||||
@@ -1,6 +1,14 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem 'rails', '4.1.11'
|
||||
def darwin_only(require_as)
|
||||
RUBY_PLATFORM.include?('darwin') && require_as
|
||||
end
|
||||
|
||||
def linux_only(require_as)
|
||||
RUBY_PLATFORM.include?('linux') && require_as
|
||||
end
|
||||
|
||||
gem 'rails', '4.1.12'
|
||||
|
||||
# Specify a sprockets version due to security issue
|
||||
# See https://groups.google.com/forum/#!topic/rubyonrails-security/doAVp0YaTqY
|
||||
@@ -10,29 +18,29 @@ gem 'sprockets', '~> 2.12.3'
|
||||
gem "default_value_for", "~> 3.0.0"
|
||||
|
||||
# Supported DBs
|
||||
gem "mysql2", group: :mysql
|
||||
gem "pg", group: :postgres
|
||||
gem "mysql2", '~> 0.3.16', group: :mysql
|
||||
gem "pg", '~> 0.18.2', group: :postgres
|
||||
|
||||
# Authentication libraries
|
||||
gem "devise", '3.2.4'
|
||||
gem "devise-async", '0.9.0'
|
||||
gem "devise", '~> 3.2.4'
|
||||
gem "devise-async", '~> 0.9.0'
|
||||
gem 'omniauth', "~> 1.2.2"
|
||||
gem 'omniauth-google-oauth2'
|
||||
gem 'omniauth-twitter'
|
||||
gem 'omniauth-github'
|
||||
gem 'omniauth-shibboleth'
|
||||
gem 'omniauth-kerberos', group: :kerberos
|
||||
gem 'omniauth-gitlab'
|
||||
gem 'omniauth-bitbucket'
|
||||
gem 'omniauth-google-oauth2', '~> 0.2.5'
|
||||
gem 'omniauth-twitter', '~> 1.0.1'
|
||||
gem 'omniauth-github', '~> 1.1.1'
|
||||
gem 'omniauth-shibboleth', '~> 1.1.1'
|
||||
gem 'omniauth-kerberos', '~> 0.2.0', group: :kerberos
|
||||
gem 'omniauth-gitlab', '~> 1.0.0'
|
||||
gem 'omniauth-bitbucket', '~> 0.0.2'
|
||||
gem 'omniauth-saml', '~> 1.4.0'
|
||||
gem 'doorkeeper', '~> 2.1.3'
|
||||
gem 'omniauth_crowd'
|
||||
gem 'doorkeeper', '2.1.3'
|
||||
gem "rack-oauth2", "~> 1.0.5"
|
||||
|
||||
# Two-factor authentication
|
||||
gem 'devise-two-factor'
|
||||
gem 'rqrcode-rails3'
|
||||
gem 'attr_encrypted', '1.3.4'
|
||||
gem 'devise-two-factor', '~> 1.0.1'
|
||||
gem 'rqrcode-rails3', '~> 0.1.7'
|
||||
gem 'attr_encrypted', '~> 1.3.4'
|
||||
|
||||
# Browser detection
|
||||
gem "browser", '~> 1.0.0'
|
||||
@@ -44,7 +52,7 @@ gem "gitlab_git", '~> 7.2.15'
|
||||
# LDAP Auth
|
||||
# GitLab fork with several improvements to original library. For full list of changes
|
||||
# see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master
|
||||
gem 'gitlab_omniauth-ldap', '1.2.1', require: "omniauth-ldap"
|
||||
gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap"
|
||||
|
||||
# Git Wiki
|
||||
gem 'gollum-lib', '~> 4.0.2'
|
||||
@@ -59,47 +67,47 @@ gem "gitlab-linguist", "~> 3.0.1", require: "linguist"
|
||||
# API
|
||||
gem "grape", "~> 0.6.1"
|
||||
gem "grape-entity", "~> 0.4.2"
|
||||
gem 'rack-cors', require: 'rack/cors'
|
||||
gem 'rack-cors', '~> 0.2.9', require: 'rack/cors'
|
||||
|
||||
# Format dates and times
|
||||
# based on human-friendly examples
|
||||
gem "stamp"
|
||||
gem "stamp", '~> 0.5.0'
|
||||
|
||||
# Enumeration fields
|
||||
gem 'enumerize'
|
||||
gem 'enumerize', '~> 0.7.0'
|
||||
|
||||
# Pagination
|
||||
gem "kaminari", "~> 0.15.1"
|
||||
|
||||
# HAML
|
||||
gem "haml-rails"
|
||||
gem "haml-rails", '~> 0.5.3'
|
||||
|
||||
# Files attachments
|
||||
gem "carrierwave"
|
||||
gem "carrierwave", '~> 0.9.0'
|
||||
|
||||
# Drag and Drop UI
|
||||
gem 'dropzonejs-rails'
|
||||
gem 'dropzonejs-rails', '~> 0.7.1'
|
||||
|
||||
# for aws storage
|
||||
gem "fog", "~> 1.25.0"
|
||||
gem "unf"
|
||||
gem "unf", '~> 0.1.4'
|
||||
|
||||
# Authorization
|
||||
gem "six"
|
||||
gem "six", '~> 0.2.0'
|
||||
|
||||
# Seed data
|
||||
gem "seed-fu"
|
||||
gem "seed-fu", '~> 2.3.5'
|
||||
|
||||
# Markdown and HTML processing
|
||||
gem 'html-pipeline', '~> 1.11.0'
|
||||
gem 'task_list', '1.0.2', require: 'task_list/railtie'
|
||||
gem 'github-markup'
|
||||
gem 'task_list', '~> 1.0.2', require: 'task_list/railtie'
|
||||
gem 'github-markup', '~> 1.3.1'
|
||||
gem 'redcarpet', '~> 3.3.2'
|
||||
gem 'RedCloth'
|
||||
gem 'RedCloth', '~> 4.2.9'
|
||||
gem 'rdoc', '~>3.6'
|
||||
gem 'org-ruby', '= 0.9.12'
|
||||
gem 'org-ruby', '~> 0.9.12'
|
||||
gem 'creole', '~>0.3.6'
|
||||
gem 'wikicloth', '=0.8.1'
|
||||
gem 'wikicloth', '0.8.1'
|
||||
gem 'asciidoctor', '~> 1.5.2'
|
||||
|
||||
# Diffs
|
||||
@@ -107,37 +115,38 @@ gem 'diffy', '~> 3.0.3'
|
||||
|
||||
# Application server
|
||||
group :unicorn do
|
||||
gem "unicorn", '~> 4.6.3'
|
||||
gem 'unicorn-worker-killer'
|
||||
gem "unicorn", '~> 4.8.2'
|
||||
gem 'unicorn-worker-killer', '~> 0.4.2'
|
||||
end
|
||||
|
||||
# State machine
|
||||
gem "state_machine"
|
||||
gem "state_machine", '~> 1.2.0'
|
||||
|
||||
# Issue tags
|
||||
gem 'acts-as-taggable-on', '~> 3.4'
|
||||
|
||||
# Background jobs
|
||||
gem 'slim'
|
||||
gem 'sinatra', require: nil
|
||||
gem 'sidekiq', '~> 3.3'
|
||||
gem 'sidetiq', '0.6.3'
|
||||
gem 'slim', '~> 2.0.2'
|
||||
gem 'sinatra', '~> 1.4.4', require: nil
|
||||
gem 'sidekiq', '3.3.0'
|
||||
gem 'sidetiq', '~> 0.6.3'
|
||||
|
||||
# HTTP requests
|
||||
gem "httparty"
|
||||
gem "httparty", '~> 0.13.3'
|
||||
|
||||
# Colored output to console
|
||||
gem "colored"
|
||||
gem "colored", '~> 1.2'
|
||||
gem "colorize", '~> 0.5.8'
|
||||
|
||||
# GitLab settings
|
||||
gem 'settingslogic'
|
||||
gem 'settingslogic', '~> 2.0.9'
|
||||
|
||||
# Misc
|
||||
gem "foreman"
|
||||
gem 'version_sorter'
|
||||
|
||||
gem 'version_sorter', '~> 2.0.0'
|
||||
|
||||
# Cache
|
||||
gem "redis-rails"
|
||||
gem "redis-rails", '~> 4.0.0'
|
||||
|
||||
# Campfire integration
|
||||
gem 'tinder', '~> 1.9.2'
|
||||
@@ -158,7 +167,7 @@ gem "slack-notifier", "~> 1.0.0"
|
||||
gem 'asana', '~> 0.0.6'
|
||||
|
||||
# FogBugz integration
|
||||
gem 'ruby-fogbugz'
|
||||
gem 'ruby-fogbugz', '~> 0.2.1'
|
||||
|
||||
# d3
|
||||
gem 'd3_rails', '~> 3.5.5'
|
||||
@@ -176,69 +185,70 @@ gem "sanitize", '~> 2.0'
|
||||
gem "rack-attack", '~> 4.3.0'
|
||||
|
||||
# Ace editor
|
||||
gem 'ace-rails-ap'
|
||||
gem 'ace-rails-ap', '~> 2.0.1'
|
||||
|
||||
# Keyboard shortcuts
|
||||
gem 'mousetrap-rails'
|
||||
gem 'mousetrap-rails', '~> 1.4.6'
|
||||
|
||||
# Detect and convert string character encoding
|
||||
gem 'charlock_holmes'
|
||||
gem 'charlock_holmes', '~> 0.6.9.4'
|
||||
|
||||
gem "sass-rails", '~> 4.0.5'
|
||||
gem "coffee-rails"
|
||||
gem "uglifier"
|
||||
gem "coffee-rails", '~> 4.1.0'
|
||||
gem "uglifier", '~> 2.3.2'
|
||||
gem 'turbolinks', '~> 2.5.0'
|
||||
gem 'jquery-turbolinks'
|
||||
gem 'jquery-turbolinks', '~> 2.0.1'
|
||||
|
||||
gem 'addressable'
|
||||
gem 'addressable', '~> 2.3.8'
|
||||
gem 'bootstrap-sass', '~> 3.0'
|
||||
gem 'font-awesome-rails', '~> 4.2'
|
||||
gem 'gitlab_emoji', '~> 0.1'
|
||||
gem 'gon', '~> 5.0.0'
|
||||
gem 'jquery-atwho-rails', '~> 1.0.0'
|
||||
gem 'jquery-rails', '3.1.3'
|
||||
gem 'jquery-scrollto-rails'
|
||||
gem 'jquery-ui-rails'
|
||||
gem 'nprogress-rails'
|
||||
gem 'jquery-rails', '~> 3.1.3'
|
||||
gem 'jquery-scrollto-rails', '~> 1.4.3'
|
||||
gem 'jquery-ui-rails', '~> 4.2.1'
|
||||
gem 'nprogress-rails', '~> 0.1.2.3'
|
||||
gem 'raphael-rails', '~> 2.1.2'
|
||||
gem 'request_store'
|
||||
gem 'request_store', '~> 1.2.0'
|
||||
gem 'select2-rails', '~> 3.5.9'
|
||||
gem 'virtus'
|
||||
gem 'virtus', '~> 1.0.1'
|
||||
|
||||
group :development do
|
||||
gem 'brakeman', require: false
|
||||
gem "annotate", "~> 2.6.0.beta2"
|
||||
gem "letter_opener"
|
||||
gem 'quiet_assets', '~> 1.0.1'
|
||||
gem 'rack-mini-profiler', require: false
|
||||
gem "foreman"
|
||||
gem 'brakeman', '3.0.1', require: false
|
||||
|
||||
gem "annotate", "~> 2.6.0"
|
||||
gem "letter_opener", '~> 1.1.2'
|
||||
gem 'quiet_assets', '~> 1.0.2'
|
||||
gem 'rack-mini-profiler', '~> 0.9.0', require: false
|
||||
gem 'rerun', '~> 0.10.0'
|
||||
|
||||
# Better errors handler
|
||||
gem 'better_errors'
|
||||
gem 'binding_of_caller'
|
||||
gem 'better_errors', '~> 1.0.1'
|
||||
gem 'binding_of_caller', '~> 0.7.2'
|
||||
|
||||
# Docs generator
|
||||
gem "sdoc"
|
||||
gem "sdoc", '~> 0.3.20'
|
||||
|
||||
# thin instead webrick
|
||||
gem 'thin'
|
||||
gem 'thin', '~> 1.6.1'
|
||||
end
|
||||
|
||||
group :development, :test do
|
||||
gem 'awesome_print'
|
||||
gem 'byebug', platform: :mri
|
||||
gem 'fuubar', '~> 2.0.0'
|
||||
gem 'pry-rails'
|
||||
|
||||
gem 'coveralls', '~> 0.8.2', require: false
|
||||
gem 'awesome_print', '~> 1.2.0'
|
||||
gem 'fuubar', '~> 2.0.0'
|
||||
|
||||
gem 'database_cleaner', '~> 1.4.0'
|
||||
gem 'factory_girl_rails'
|
||||
gem 'factory_girl_rails', '~> 4.3.0'
|
||||
gem 'rspec-rails', '~> 3.3.0'
|
||||
gem 'rubocop', '0.28.0', require: false
|
||||
gem 'spinach-rails'
|
||||
gem 'spinach-rails', '~> 0.2.1'
|
||||
|
||||
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
|
||||
gem 'minitest', '~> 5.3.0'
|
||||
gem 'minitest', '~> 5.7.0'
|
||||
|
||||
# Generate Fake data
|
||||
gem 'ffaker', '~> 2.0.0'
|
||||
@@ -248,20 +258,23 @@ group :development, :test do
|
||||
gem 'poltergeist', '~> 1.6.0'
|
||||
|
||||
gem 'teaspoon', '~> 1.0.0'
|
||||
gem 'teaspoon-jasmine'
|
||||
gem 'teaspoon-jasmine', '~> 2.2.0'
|
||||
|
||||
gem 'spring', '~> 1.3.1'
|
||||
gem 'spring-commands-rspec', '~> 1.0.0'
|
||||
gem 'spring', '~> 1.3.6'
|
||||
gem 'spring-commands-rspec', '~> 1.0.4'
|
||||
gem 'spring-commands-spinach', '~> 1.0.0'
|
||||
gem 'spring-commands-teaspoon', '~> 0.0.2'
|
||||
|
||||
gem 'rubocop', '~> 0.28.0', require: false
|
||||
gem 'coveralls', '~> 0.8.2', require: false
|
||||
gem 'simplecov', '~> 0.10.0', require: false
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'simplecov', require: false
|
||||
gem 'shoulda-matchers', '~> 2.8.0', require: false
|
||||
gem 'email_spec', '~> 1.6.0'
|
||||
gem 'webmock', '~> 1.21.0'
|
||||
gem 'test_after_commit'
|
||||
gem 'test_after_commit', '~> 0.2.2'
|
||||
gem 'sham_rack'
|
||||
end
|
||||
|
||||
@@ -269,10 +282,32 @@ group :production do
|
||||
gem "gitlab_meta", '7.0'
|
||||
end
|
||||
|
||||
gem "newrelic_rpm"
|
||||
gem "newrelic_rpm", '~> 3.9.4.245'
|
||||
|
||||
gem 'octokit', '3.7.0'
|
||||
gem 'octokit', '~> 3.7.0'
|
||||
|
||||
gem "mail_room", "~> 0.4.2"
|
||||
|
||||
gem 'email_reply_parser'
|
||||
gem 'email_reply_parser', '~> 0.5.8'
|
||||
|
||||
## CI
|
||||
gem 'activerecord-deprecated_finders', '~> 1.0.3'
|
||||
gem 'activerecord-session_store', '~> 0.1.0'
|
||||
gem "nested_form", '~> 0.3.2'
|
||||
|
||||
# Scheduled
|
||||
gem 'whenever', '~> 0.8.4', require: false
|
||||
|
||||
# OAuth
|
||||
gem 'oauth2', '~> 1.0.0'
|
||||
|
||||
# Soft deletion
|
||||
gem "paranoia", "~> 2.0"
|
||||
|
||||
group :development, :test do
|
||||
gem 'guard-rspec', '~> 4.2.0'
|
||||
|
||||
gem 'rb-fsevent', require: darwin_only('rb-fsevent')
|
||||
gem 'growl', require: darwin_only('growl')
|
||||
gem 'rb-inotify', require: linux_only('rb-inotify')
|
||||
end
|
||||
|
||||
+282
-243
@@ -4,31 +4,36 @@ GEM
|
||||
CFPropertyList (2.3.1)
|
||||
RedCloth (4.2.9)
|
||||
ace-rails-ap (2.0.1)
|
||||
actionmailer (4.1.11)
|
||||
actionpack (= 4.1.11)
|
||||
actionview (= 4.1.11)
|
||||
actionmailer (4.1.12)
|
||||
actionpack (= 4.1.12)
|
||||
actionview (= 4.1.12)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
actionpack (4.1.11)
|
||||
actionview (= 4.1.11)
|
||||
activesupport (= 4.1.11)
|
||||
actionpack (4.1.12)
|
||||
actionview (= 4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
rack (~> 1.5.2)
|
||||
rack-test (~> 0.6.2)
|
||||
actionview (4.1.11)
|
||||
activesupport (= 4.1.11)
|
||||
actionview (4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
activemodel (4.1.11)
|
||||
activesupport (= 4.1.11)
|
||||
activemodel (4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
builder (~> 3.1)
|
||||
activerecord (4.1.11)
|
||||
activemodel (= 4.1.11)
|
||||
activesupport (= 4.1.11)
|
||||
activerecord (4.1.12)
|
||||
activemodel (= 4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
arel (~> 5.0.0)
|
||||
activerecord-deprecated_finders (1.0.4)
|
||||
activerecord-session_store (0.1.1)
|
||||
actionpack (>= 4.0.0, < 5)
|
||||
activerecord (>= 4.0.0, < 5)
|
||||
railties (>= 4.0.0, < 5)
|
||||
activeresource (4.0.0)
|
||||
activemodel (~> 4.0)
|
||||
activesupport (~> 4.0)
|
||||
rails-observers (~> 0.1.1)
|
||||
activesupport (4.1.11)
|
||||
activesupport (4.1.12)
|
||||
i18n (~> 0.6, >= 0.6.9)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
@@ -37,33 +42,34 @@ GEM
|
||||
acts-as-taggable-on (3.5.0)
|
||||
activerecord (>= 3.2, < 5)
|
||||
addressable (2.3.8)
|
||||
annotate (2.6.0)
|
||||
activerecord (>= 2.3.0)
|
||||
rake (>= 0.8.7)
|
||||
annotate (2.6.10)
|
||||
activerecord (>= 3.2, <= 4.3)
|
||||
rake (~> 10.4)
|
||||
arel (5.0.1.20140414130214)
|
||||
asana (0.0.6)
|
||||
activeresource (>= 3.2.3)
|
||||
asciidoctor (1.5.2)
|
||||
ast (2.0.0)
|
||||
astrolabe (1.3.0)
|
||||
parser (>= 2.2.0.pre.3, < 3.0)
|
||||
ast (2.1.0)
|
||||
astrolabe (1.3.1)
|
||||
parser (~> 2.2)
|
||||
attr_encrypted (1.3.4)
|
||||
encryptor (>= 1.3.0)
|
||||
attr_required (1.0.0)
|
||||
autoprefixer-rails (5.1.11)
|
||||
autoprefixer-rails (5.2.1.2)
|
||||
execjs
|
||||
json
|
||||
awesome_print (1.2.0)
|
||||
axiom-types (0.0.5)
|
||||
descendants_tracker (~> 0.0.1)
|
||||
ice_nine (~> 0.9)
|
||||
bcrypt (3.1.7)
|
||||
axiom-types (0.1.1)
|
||||
descendants_tracker (~> 0.0.4)
|
||||
ice_nine (~> 0.11.0)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
bcrypt (3.1.10)
|
||||
better_errors (1.0.1)
|
||||
coderay (>= 1.0.0)
|
||||
erubis (>= 2.6.6)
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bootstrap-sass (3.3.4.1)
|
||||
bootstrap-sass (3.3.5)
|
||||
autoprefixer-rails (>= 5.0.0.1)
|
||||
sass (>= 3.2.19)
|
||||
brakeman (3.0.1)
|
||||
@@ -78,9 +84,7 @@ GEM
|
||||
terminal-table (~> 1.4)
|
||||
browser (1.0.0)
|
||||
builder (3.2.2)
|
||||
byebug (3.2.0)
|
||||
columnize (~> 0.8)
|
||||
debugger-linecache (~> 1.2)
|
||||
byebug (6.0.2)
|
||||
cal-heatmap-rails (0.0.1)
|
||||
capybara (2.4.4)
|
||||
mime-types (>= 1.16)
|
||||
@@ -88,7 +92,7 @@ GEM
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (~> 2.0)
|
||||
capybara-screenshot (1.0.9)
|
||||
capybara-screenshot (1.0.11)
|
||||
capybara (>= 1.0, < 3)
|
||||
launchy
|
||||
carrierwave (0.9.0)
|
||||
@@ -98,6 +102,8 @@ GEM
|
||||
celluloid (0.16.0)
|
||||
timers (~> 4.0.0)
|
||||
charlock_holmes (0.6.9.4)
|
||||
chronic (0.10.2)
|
||||
chunky_png (1.3.4)
|
||||
cliver (0.3.2)
|
||||
coderay (1.1.0)
|
||||
coercible (1.0.0)
|
||||
@@ -111,8 +117,7 @@ GEM
|
||||
coffee-script-source (1.9.1.1)
|
||||
colored (1.2)
|
||||
colorize (0.5.8)
|
||||
columnize (0.9.0)
|
||||
connection_pool (2.1.0)
|
||||
connection_pool (2.2.0)
|
||||
coveralls (0.8.2)
|
||||
json (~> 1.8)
|
||||
rest-client (>= 1.6.8, < 2)
|
||||
@@ -122,15 +127,15 @@ GEM
|
||||
crack (0.4.2)
|
||||
safe_yaml (~> 1.0.0)
|
||||
creole (0.3.8)
|
||||
d3_rails (3.5.5)
|
||||
d3_rails (3.5.6)
|
||||
railties (>= 3.1.0)
|
||||
daemons (1.1.9)
|
||||
daemons (1.2.3)
|
||||
database_cleaner (1.4.1)
|
||||
debug_inspector (0.0.2)
|
||||
debugger-linecache (1.2.0)
|
||||
default_value_for (3.0.0)
|
||||
default_value_for (3.0.1)
|
||||
activerecord (>= 3.2.0, < 5.0)
|
||||
descendants_tracker (0.0.3)
|
||||
descendants_tracker (0.0.4)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
devise (3.2.4)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
@@ -139,21 +144,20 @@ GEM
|
||||
warden (~> 1.2.3)
|
||||
devise-async (0.9.0)
|
||||
devise (~> 3.2)
|
||||
devise-two-factor (1.0.1)
|
||||
devise-two-factor (1.0.2)
|
||||
activemodel
|
||||
activesupport
|
||||
attr_encrypted (~> 1.3.2)
|
||||
devise (~> 3.2.4)
|
||||
rails
|
||||
rotp (~> 1.6.1)
|
||||
devise (>= 3.2.4, < 3.5)
|
||||
railties
|
||||
rotp (< 2)
|
||||
diff-lcs (1.2.5)
|
||||
diffy (3.0.3)
|
||||
diffy (3.0.7)
|
||||
docile (1.1.5)
|
||||
domain_name (0.5.24)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
doorkeeper (2.1.3)
|
||||
doorkeeper (2.1.4)
|
||||
railties (>= 3.2)
|
||||
dotenv (0.9.0)
|
||||
dropzonejs-rails (0.7.1)
|
||||
rails (> 3.1)
|
||||
email_reply_parser (0.5.8)
|
||||
@@ -163,25 +167,25 @@ GEM
|
||||
encryptor (1.3.0)
|
||||
enumerize (0.7.0)
|
||||
activesupport (>= 3.2)
|
||||
equalizer (0.0.8)
|
||||
equalizer (0.0.11)
|
||||
erubis (2.7.0)
|
||||
escape_utils (0.2.4)
|
||||
eventmachine (1.0.4)
|
||||
excon (0.45.3)
|
||||
execjs (2.5.2)
|
||||
eventmachine (1.0.8)
|
||||
excon (0.45.4)
|
||||
execjs (2.6.0)
|
||||
expression_parser (0.9.0)
|
||||
factory_girl (4.3.0)
|
||||
activesupport (>= 3.0.0)
|
||||
factory_girl_rails (4.3.0)
|
||||
factory_girl (~> 4.3.0)
|
||||
railties (>= 3.0.0)
|
||||
faraday (0.8.9)
|
||||
faraday (0.8.10)
|
||||
multipart-post (~> 1.2.0)
|
||||
faraday_middleware (0.9.0)
|
||||
faraday (>= 0.7.4, < 0.9)
|
||||
faraday_middleware (0.10.0)
|
||||
faraday (>= 0.7.4, < 0.10)
|
||||
fastercsv (1.5.5)
|
||||
ffaker (2.0.0)
|
||||
ffi (1.9.8)
|
||||
ffi (1.9.10)
|
||||
fission (0.5.0)
|
||||
CFPropertyList (~> 2.2)
|
||||
flowdock (0.7.0)
|
||||
@@ -202,11 +206,11 @@ GEM
|
||||
ipaddress (~> 0.5)
|
||||
nokogiri (~> 1.5, >= 1.5.11)
|
||||
opennebula
|
||||
fog-brightbox (0.7.1)
|
||||
fog-brightbox (0.9.0)
|
||||
fog-core (~> 1.22)
|
||||
fog-json
|
||||
inflecto (~> 0.0.2)
|
||||
fog-core (1.30.0)
|
||||
fog-core (1.32.1)
|
||||
builder
|
||||
excon (~> 0.45)
|
||||
formatador (~> 0.2)
|
||||
@@ -216,7 +220,7 @@ GEM
|
||||
fog-json (1.0.2)
|
||||
fog-core (~> 1.0)
|
||||
multi_json (~> 1.10)
|
||||
fog-profitbricks (0.0.3)
|
||||
fog-profitbricks (0.0.5)
|
||||
fog-core
|
||||
fog-xml
|
||||
nokogiri
|
||||
@@ -227,7 +231,7 @@ GEM
|
||||
fog-sakuracloud (1.0.1)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-softlayer (0.4.6)
|
||||
fog-softlayer (0.4.7)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-terremark (0.1.0)
|
||||
@@ -242,28 +246,26 @@ GEM
|
||||
fog-xml (0.1.2)
|
||||
fog-core
|
||||
nokogiri (~> 1.5, >= 1.5.11)
|
||||
font-awesome-rails (4.2.0.0)
|
||||
font-awesome-rails (4.4.0.0)
|
||||
railties (>= 3.2, < 5.0)
|
||||
foreman (0.63.0)
|
||||
dotenv (>= 0.7)
|
||||
thor (>= 0.13.6)
|
||||
foreman (0.78.0)
|
||||
thor (~> 0.19.1)
|
||||
formatador (0.2.5)
|
||||
fuubar (2.0.0)
|
||||
rspec (~> 3.0)
|
||||
ruby-progressbar (~> 1.4)
|
||||
gemnasium-gitlab-service (0.2.6)
|
||||
rugged (~> 0.21)
|
||||
gemojione (2.0.0)
|
||||
gemojione (2.0.1)
|
||||
json
|
||||
gherkin-ruby (0.3.1)
|
||||
racc
|
||||
github-markup (1.3.1)
|
||||
posix-spawn (~> 0.3.8)
|
||||
get_process_mem (0.2.0)
|
||||
gherkin-ruby (0.3.2)
|
||||
github-markup (1.3.3)
|
||||
gitlab-flowdock-git-hook (1.0.1)
|
||||
flowdock (~> 0.7)
|
||||
gitlab-grit (>= 2.4.1)
|
||||
multi_json
|
||||
gitlab-grit (2.7.2)
|
||||
gitlab-grit (2.7.3)
|
||||
charlock_holmes (~> 0.6)
|
||||
diff-lcs (~> 1.1)
|
||||
mime-types (~> 1.15)
|
||||
@@ -272,7 +274,7 @@ GEM
|
||||
charlock_holmes (~> 0.6.6)
|
||||
escape_utils (~> 0.2.4)
|
||||
mime-types (~> 1.19)
|
||||
gitlab_emoji (0.1.0)
|
||||
gitlab_emoji (0.1.1)
|
||||
gemojione (~> 2.0)
|
||||
gitlab_git (7.2.15)
|
||||
activesupport (~> 4.0)
|
||||
@@ -285,16 +287,16 @@ GEM
|
||||
omniauth (~> 1.0)
|
||||
pyu-ruby-sasl (~> 0.0.3.1)
|
||||
rubyntlm (~> 0.3)
|
||||
gollum-grit_adapter (0.1.3)
|
||||
gollum-grit_adapter (1.0.0)
|
||||
gitlab-grit (~> 2.7, >= 2.7.1)
|
||||
gollum-lib (4.0.2)
|
||||
github-markup (~> 1.3.1)
|
||||
gollum-grit_adapter (~> 0.1, >= 0.1.1)
|
||||
gollum-lib (4.0.3)
|
||||
github-markup (~> 1.3.3)
|
||||
gollum-grit_adapter (~> 1.0)
|
||||
nokogiri (~> 1.6.4)
|
||||
rouge (~> 1.10.1)
|
||||
sanitize (~> 2.1.0)
|
||||
stringex (~> 2.5.1)
|
||||
gon (5.0.1)
|
||||
gon (5.0.4)
|
||||
actionpack (>= 2.3.0)
|
||||
json
|
||||
grape (0.6.1)
|
||||
@@ -307,9 +309,22 @@ GEM
|
||||
rack-accept
|
||||
rack-mount
|
||||
virtus (>= 1.0.0)
|
||||
grape-entity (0.4.2)
|
||||
grape-entity (0.4.8)
|
||||
activesupport
|
||||
multi_json (>= 1.3.2)
|
||||
growl (1.0.3)
|
||||
guard (2.13.0)
|
||||
formatador (>= 0.2.4)
|
||||
listen (>= 2.7, <= 4.0)
|
||||
lumberjack (~> 1.0)
|
||||
nenv (~> 0.1)
|
||||
notiffany (~> 0.0)
|
||||
pry (>= 0.9.12)
|
||||
shellany (~> 0.0)
|
||||
thor (>= 0.18.1)
|
||||
guard-rspec (4.2.10)
|
||||
guard (~> 2.1)
|
||||
rspec (>= 2.14, < 4.0)
|
||||
haml (4.0.7)
|
||||
tilt
|
||||
haml-rails (0.5.3)
|
||||
@@ -320,24 +335,23 @@ GEM
|
||||
hashie (2.1.2)
|
||||
highline (1.6.21)
|
||||
hike (1.2.3)
|
||||
hipchat (1.5.0)
|
||||
hipchat (1.5.2)
|
||||
httparty
|
||||
mimemagic
|
||||
hitimes (1.2.2)
|
||||
hitimes (1.2.3)
|
||||
html-pipeline (1.11.0)
|
||||
activesupport (>= 2)
|
||||
nokogiri (~> 1.4)
|
||||
http-cookie (1.0.2)
|
||||
domain_name (~> 0.5)
|
||||
http_parser.rb (0.5.3)
|
||||
httparty (0.13.3)
|
||||
httparty (0.13.5)
|
||||
json (~> 1.8)
|
||||
multi_xml (>= 0.5.2)
|
||||
httpauth (0.2.1)
|
||||
httpclient (2.5.3.3)
|
||||
httpclient (2.6.0.1)
|
||||
i18n (0.7.0)
|
||||
ice_cube (0.11.1)
|
||||
ice_nine (0.10.0)
|
||||
ice_nine (0.11.1)
|
||||
inflecto (0.0.2)
|
||||
ipaddress (0.8.0)
|
||||
jquery-atwho-rails (1.0.1)
|
||||
@@ -346,26 +360,26 @@ GEM
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-scrollto-rails (1.4.3)
|
||||
railties (> 3.1, < 5.0)
|
||||
jquery-turbolinks (2.0.1)
|
||||
jquery-turbolinks (2.0.2)
|
||||
railties (>= 3.1.0)
|
||||
turbolinks
|
||||
jquery-ui-rails (4.2.1)
|
||||
railties (>= 3.2.16)
|
||||
json (1.8.3)
|
||||
jwt (0.1.13)
|
||||
multi_json (>= 1.5)
|
||||
jwt (1.5.1)
|
||||
kaminari (0.15.1)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
kgio (2.9.2)
|
||||
kgio (2.9.3)
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
letter_opener (1.1.2)
|
||||
launchy (~> 2.2)
|
||||
listen (2.10.0)
|
||||
listen (2.10.1)
|
||||
celluloid (~> 0.16.0)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
lumberjack (1.0.9)
|
||||
macaddr (1.7.1)
|
||||
systemu (~> 2.6.2)
|
||||
mail (2.6.3)
|
||||
@@ -375,12 +389,14 @@ GEM
|
||||
mime-types (1.25.1)
|
||||
mimemagic (0.3.0)
|
||||
mini_portile (0.6.2)
|
||||
minitest (5.3.5)
|
||||
minitest (5.7.0)
|
||||
mousetrap-rails (1.4.6)
|
||||
multi_json (1.11.2)
|
||||
multi_xml (0.5.5)
|
||||
multipart-post (1.2.0)
|
||||
mysql2 (0.3.16)
|
||||
mysql2 (0.3.20)
|
||||
nenv (0.2.0)
|
||||
nested_form (0.3.2)
|
||||
net-ldap (0.11)
|
||||
net-scp (1.2.1)
|
||||
net-ssh (>= 2.6.5)
|
||||
@@ -389,15 +405,18 @@ GEM
|
||||
newrelic_rpm (3.9.4.245)
|
||||
nokogiri (1.6.6.2)
|
||||
mini_portile (~> 0.6.0)
|
||||
notiffany (0.0.7)
|
||||
nenv (~> 0.1)
|
||||
shellany (~> 0.0)
|
||||
nprogress-rails (0.1.2.3)
|
||||
oauth (0.4.7)
|
||||
oauth2 (0.8.1)
|
||||
faraday (~> 0.8)
|
||||
httpauth (~> 0.1)
|
||||
jwt (~> 0.1.4)
|
||||
multi_json (~> 1.0)
|
||||
oauth2 (1.0.0)
|
||||
faraday (>= 0.8, < 0.10)
|
||||
jwt (~> 1.0)
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (~> 1.2)
|
||||
octokit (3.7.0)
|
||||
octokit (3.7.1)
|
||||
sawyer (~> 0.6.0, >= 0.5.3)
|
||||
omniauth (1.2.2)
|
||||
hashie (>= 1.2, < 4)
|
||||
@@ -406,30 +425,30 @@ GEM
|
||||
multi_json (~> 1.7)
|
||||
omniauth (~> 1.1)
|
||||
omniauth-oauth (~> 1.0)
|
||||
omniauth-github (1.1.1)
|
||||
omniauth-github (1.1.2)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.1)
|
||||
omniauth-gitlab (1.0.0)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.0)
|
||||
omniauth-google-oauth2 (0.2.5)
|
||||
omniauth-google-oauth2 (0.2.6)
|
||||
omniauth (> 1.0)
|
||||
omniauth-oauth2 (~> 1.1)
|
||||
omniauth-kerberos (0.2.0)
|
||||
omniauth-multipassword
|
||||
timfel-krb5-auth (~> 0.8)
|
||||
omniauth-multipassword (0.4.1)
|
||||
omniauth-multipassword (0.4.2)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth (1.0.1)
|
||||
omniauth-oauth (1.1.0)
|
||||
oauth
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (1.1.1)
|
||||
oauth2 (~> 0.8.0)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (1.3.1)
|
||||
oauth2 (~> 1.0)
|
||||
omniauth (~> 1.2)
|
||||
omniauth-saml (1.4.1)
|
||||
omniauth (~> 1.1)
|
||||
ruby-saml (~> 1.0.0)
|
||||
omniauth-shibboleth (1.1.1)
|
||||
omniauth-shibboleth (1.1.2)
|
||||
omniauth (>= 1.0.0)
|
||||
omniauth-twitter (1.0.1)
|
||||
multi_json (~> 1.3)
|
||||
@@ -445,7 +464,9 @@ GEM
|
||||
org-ruby (0.9.12)
|
||||
rubypants (~> 0.2)
|
||||
orm_adapter (0.5.0)
|
||||
parser (2.2.0.2)
|
||||
paranoia (2.1.3)
|
||||
activerecord (~> 4.0)
|
||||
parser (2.2.2.6)
|
||||
ast (>= 1.1, < 3.0)
|
||||
pg (0.18.2)
|
||||
poltergeist (1.6.0)
|
||||
@@ -453,60 +474,59 @@ GEM
|
||||
cliver (~> 0.3.1)
|
||||
multi_json (~> 1.0)
|
||||
websocket-driver (>= 0.2.0)
|
||||
posix-spawn (0.3.9)
|
||||
posix-spawn (0.3.11)
|
||||
powerpack (0.0.9)
|
||||
pry (0.9.12.4)
|
||||
coderay (~> 1.0)
|
||||
method_source (~> 0.8)
|
||||
pry (0.10.1)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
pry-rails (0.3.2)
|
||||
pry-rails (0.3.4)
|
||||
pry (>= 0.9.10)
|
||||
pyu-ruby-sasl (0.0.3.3)
|
||||
quiet_assets (1.0.2)
|
||||
quiet_assets (1.0.3)
|
||||
railties (>= 3.1, < 5.0)
|
||||
racc (1.4.12)
|
||||
rack (1.5.5)
|
||||
rack-accept (0.4.5)
|
||||
rack (>= 0.4)
|
||||
rack-attack (4.3.0)
|
||||
rack
|
||||
rack-cors (0.2.9)
|
||||
rack-mini-profiler (0.9.0)
|
||||
rack-mini-profiler (0.9.7)
|
||||
rack (>= 1.1.3)
|
||||
rack-mount (0.8.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-oauth2 (1.0.8)
|
||||
rack-oauth2 (1.0.10)
|
||||
activesupport (>= 2.3)
|
||||
attr_required (>= 0.0.5)
|
||||
httpclient (>= 2.2.0.2)
|
||||
httpclient (>= 2.4)
|
||||
multi_json (>= 1.3.6)
|
||||
rack (>= 1.1)
|
||||
rack-protection (1.5.1)
|
||||
rack-protection (1.5.3)
|
||||
rack
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (4.1.11)
|
||||
actionmailer (= 4.1.11)
|
||||
actionpack (= 4.1.11)
|
||||
actionview (= 4.1.11)
|
||||
activemodel (= 4.1.11)
|
||||
activerecord (= 4.1.11)
|
||||
activesupport (= 4.1.11)
|
||||
rails (4.1.12)
|
||||
actionmailer (= 4.1.12)
|
||||
actionpack (= 4.1.12)
|
||||
actionview (= 4.1.12)
|
||||
activemodel (= 4.1.12)
|
||||
activerecord (= 4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 4.1.11)
|
||||
railties (= 4.1.12)
|
||||
sprockets-rails (~> 2.0)
|
||||
rails-observers (0.1.2)
|
||||
activemodel (~> 4.0)
|
||||
railties (4.1.11)
|
||||
actionpack (= 4.1.11)
|
||||
activesupport (= 4.1.11)
|
||||
railties (4.1.12)
|
||||
actionpack (= 4.1.12)
|
||||
activesupport (= 4.1.12)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (2.0.0)
|
||||
raindrops (0.13.0)
|
||||
raindrops (0.15.0)
|
||||
rake (10.4.2)
|
||||
raphael-rails (2.1.2)
|
||||
rb-fsevent (0.9.4)
|
||||
rb-fsevent (0.9.5)
|
||||
rb-inotify (0.9.5)
|
||||
ffi (>= 0.5.0)
|
||||
rbvmomi (1.8.2)
|
||||
@@ -521,10 +541,10 @@ GEM
|
||||
actionpack (~> 4)
|
||||
redis-rack (~> 1.5.0)
|
||||
redis-store (~> 1.1.0)
|
||||
redis-activesupport (4.0.0)
|
||||
redis-activesupport (4.1.1)
|
||||
activesupport (~> 4)
|
||||
redis-store (~> 1.1.0)
|
||||
redis-namespace (1.5.1)
|
||||
redis-namespace (1.5.2)
|
||||
redis (~> 3.0, >= 3.0.4)
|
||||
redis-rack (1.5.0)
|
||||
rack (~> 1.5)
|
||||
@@ -535,7 +555,7 @@ GEM
|
||||
redis-store (~> 1.1.0)
|
||||
redis-store (1.1.6)
|
||||
redis (>= 2.2)
|
||||
request_store (1.0.5)
|
||||
request_store (1.2.0)
|
||||
rerun (0.10.0)
|
||||
listen (~> 2.7, >= 2.7.3)
|
||||
rest-client (1.8.0)
|
||||
@@ -545,22 +565,23 @@ GEM
|
||||
rinku (1.7.3)
|
||||
rotp (1.6.1)
|
||||
rouge (1.10.1)
|
||||
rqrcode (0.4.2)
|
||||
rqrcode (0.7.0)
|
||||
chunky_png
|
||||
rqrcode-rails3 (0.1.7)
|
||||
rqrcode (>= 0.4.2)
|
||||
rspec (3.3.0)
|
||||
rspec-core (~> 3.3.0)
|
||||
rspec-expectations (~> 3.3.0)
|
||||
rspec-mocks (~> 3.3.0)
|
||||
rspec-core (3.3.1)
|
||||
rspec-core (3.3.2)
|
||||
rspec-support (~> 3.3.0)
|
||||
rspec-expectations (3.3.0)
|
||||
rspec-expectations (3.3.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.3.0)
|
||||
rspec-mocks (3.3.0)
|
||||
rspec-mocks (3.3.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.3.0)
|
||||
rspec-rails (3.3.2)
|
||||
rspec-rails (3.3.3)
|
||||
actionpack (>= 3.0, < 4.3)
|
||||
activesupport (>= 3.0, < 4.3)
|
||||
railties (>= 3.0, < 4.3)
|
||||
@@ -575,18 +596,18 @@ GEM
|
||||
powerpack (~> 0.0.6)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.4)
|
||||
ruby-fogbugz (0.1.1)
|
||||
crack
|
||||
ruby-progressbar (1.7.1)
|
||||
ruby-fogbugz (0.2.1)
|
||||
crack (~> 0.4)
|
||||
ruby-progressbar (1.7.5)
|
||||
ruby-saml (1.0.0)
|
||||
nokogiri (>= 1.5.10)
|
||||
uuid (~> 2.3)
|
||||
ruby2ruby (2.1.3)
|
||||
ruby2ruby (2.1.4)
|
||||
ruby_parser (~> 3.1)
|
||||
sexp_processor (~> 4.0)
|
||||
ruby_parser (3.5.0)
|
||||
sexp_processor (~> 4.1)
|
||||
rubyntlm (0.5.0)
|
||||
rubyntlm (0.5.2)
|
||||
rubypants (0.2.0)
|
||||
rugged (0.22.2)
|
||||
safe_yaml (1.0.4)
|
||||
@@ -610,9 +631,10 @@ GEM
|
||||
select2-rails (3.5.9.3)
|
||||
thor (~> 0.14)
|
||||
settingslogic (2.0.9)
|
||||
sexp_processor (4.4.5)
|
||||
sexp_processor (4.6.0)
|
||||
sham_rack (1.3.6)
|
||||
rack
|
||||
shellany (0.0.1)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
sidekiq (3.3.0)
|
||||
@@ -631,19 +653,20 @@ GEM
|
||||
json (~> 1.8)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.0)
|
||||
sinatra (1.4.4)
|
||||
sinatra (1.4.6)
|
||||
rack (~> 1.4)
|
||||
rack-protection (~> 1.4)
|
||||
tilt (~> 1.3, >= 1.3.4)
|
||||
tilt (>= 1.3, < 3)
|
||||
six (0.2.0)
|
||||
slack-notifier (1.0.0)
|
||||
slim (2.0.2)
|
||||
slim (2.0.3)
|
||||
temple (~> 0.6.6)
|
||||
tilt (>= 1.3.3, < 2.1)
|
||||
slop (3.6.0)
|
||||
spinach (0.8.7)
|
||||
colorize (= 0.5.8)
|
||||
gherkin-ruby (>= 0.3.1)
|
||||
spinach (0.8.10)
|
||||
colorize
|
||||
gherkin-ruby (>= 0.3.2)
|
||||
json
|
||||
spinach-rails (0.2.1)
|
||||
capybara (>= 2.0.0)
|
||||
railties (>= 3)
|
||||
@@ -674,31 +697,32 @@ GEM
|
||||
railties (>= 3.2.5, < 5)
|
||||
teaspoon-jasmine (2.2.0)
|
||||
teaspoon (>= 1.0.0)
|
||||
temple (0.6.7)
|
||||
temple (0.6.10)
|
||||
term-ansicolor (1.3.2)
|
||||
tins (~> 1.0)
|
||||
terminal-table (1.4.5)
|
||||
test_after_commit (0.2.2)
|
||||
thin (1.6.1)
|
||||
daemons (>= 1.0.9)
|
||||
eventmachine (>= 1.0.0)
|
||||
rack (>= 1.0.0)
|
||||
terminal-table (1.5.2)
|
||||
test_after_commit (0.2.7)
|
||||
activerecord (>= 3.2)
|
||||
thin (1.6.3)
|
||||
daemons (~> 1.0, >= 1.0.9)
|
||||
eventmachine (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.5)
|
||||
tilt (1.4.1)
|
||||
timers (4.0.1)
|
||||
timers (4.0.4)
|
||||
hitimes
|
||||
timfel-krb5-auth (0.8.3)
|
||||
tinder (1.9.3)
|
||||
tinder (1.9.4)
|
||||
eventmachine (~> 1.0)
|
||||
faraday (~> 0.8)
|
||||
faraday (~> 0.8.9)
|
||||
faraday_middleware (~> 0.9)
|
||||
hashie (>= 1.0, < 3)
|
||||
json (~> 1.8.0)
|
||||
mime-types (~> 1.19)
|
||||
multi_json (~> 1.7)
|
||||
twitter-stream (~> 0.1)
|
||||
tins (1.5.4)
|
||||
tins (1.6.0)
|
||||
trollop (2.1.2)
|
||||
turbolinks (2.5.3)
|
||||
coffee-rails
|
||||
@@ -708,35 +732,39 @@ GEM
|
||||
simple_oauth (~> 0.1.4)
|
||||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (2.3.2)
|
||||
uglifier (2.3.3)
|
||||
execjs (>= 0.3.0)
|
||||
json (>= 1.8.0)
|
||||
underscore-rails (1.4.4)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.1)
|
||||
unicorn (4.6.3)
|
||||
unicorn (4.8.3)
|
||||
kgio (~> 2.6)
|
||||
rack
|
||||
raindrops (~> 0.7)
|
||||
unicorn-worker-killer (0.4.2)
|
||||
unicorn-worker-killer (0.4.3)
|
||||
get_process_mem (~> 0)
|
||||
unicorn (~> 4)
|
||||
uuid (2.3.8)
|
||||
macaddr (~> 1.0)
|
||||
version_sorter (2.0.0)
|
||||
virtus (1.0.1)
|
||||
axiom-types (~> 0.0.5)
|
||||
virtus (1.0.5)
|
||||
axiom-types (~> 0.1)
|
||||
coercible (~> 1.0)
|
||||
descendants_tracker (~> 0.0.1)
|
||||
equalizer (~> 0.0.7)
|
||||
descendants_tracker (~> 0.0, >= 0.0.3)
|
||||
equalizer (~> 0.0, >= 0.0.9)
|
||||
warden (1.2.3)
|
||||
rack (>= 1.0)
|
||||
webmock (1.21.0)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
websocket-driver (0.5.4)
|
||||
websocket-driver (0.6.2)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.2)
|
||||
whenever (0.8.4)
|
||||
activesupport (>= 2.3.4)
|
||||
chronic (>= 0.6.3)
|
||||
wikicloth (0.8.1)
|
||||
builder
|
||||
expression_parser
|
||||
@@ -748,147 +776,158 @@ PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
RedCloth
|
||||
ace-rails-ap
|
||||
RedCloth (~> 4.2.9)
|
||||
ace-rails-ap (~> 2.0.1)
|
||||
activerecord-deprecated_finders (~> 1.0.3)
|
||||
activerecord-session_store (~> 0.1.0)
|
||||
acts-as-taggable-on (~> 3.4)
|
||||
addressable
|
||||
annotate (~> 2.6.0.beta2)
|
||||
addressable (~> 2.3.8)
|
||||
annotate (~> 2.6.0)
|
||||
asana (~> 0.0.6)
|
||||
asciidoctor (~> 1.5.2)
|
||||
attr_encrypted (= 1.3.4)
|
||||
awesome_print
|
||||
better_errors
|
||||
binding_of_caller
|
||||
attr_encrypted (~> 1.3.4)
|
||||
awesome_print (~> 1.2.0)
|
||||
better_errors (~> 1.0.1)
|
||||
binding_of_caller (~> 0.7.2)
|
||||
bootstrap-sass (~> 3.0)
|
||||
brakeman
|
||||
brakeman (= 3.0.1)
|
||||
browser (~> 1.0.0)
|
||||
byebug
|
||||
cal-heatmap-rails (~> 0.0.1)
|
||||
capybara (~> 2.4.0)
|
||||
capybara-screenshot (~> 1.0.0)
|
||||
carrierwave
|
||||
charlock_holmes
|
||||
coffee-rails
|
||||
colored
|
||||
carrierwave (~> 0.9.0)
|
||||
charlock_holmes (~> 0.6.9.4)
|
||||
coffee-rails (~> 4.1.0)
|
||||
colored (~> 1.2)
|
||||
colorize (~> 0.5.8)
|
||||
coveralls (~> 0.8.2)
|
||||
creole (~> 0.3.6)
|
||||
d3_rails (~> 3.5.5)
|
||||
database_cleaner (~> 1.4.0)
|
||||
default_value_for (~> 3.0.0)
|
||||
devise (= 3.2.4)
|
||||
devise-async (= 0.9.0)
|
||||
devise-two-factor
|
||||
devise (~> 3.2.4)
|
||||
devise-async (~> 0.9.0)
|
||||
devise-two-factor (~> 1.0.1)
|
||||
diffy (~> 3.0.3)
|
||||
doorkeeper (= 2.1.3)
|
||||
dropzonejs-rails
|
||||
email_reply_parser
|
||||
doorkeeper (~> 2.1.3)
|
||||
dropzonejs-rails (~> 0.7.1)
|
||||
email_reply_parser (~> 0.5.8)
|
||||
email_spec (~> 1.6.0)
|
||||
enumerize
|
||||
factory_girl_rails
|
||||
enumerize (~> 0.7.0)
|
||||
factory_girl_rails (~> 4.3.0)
|
||||
ffaker (~> 2.0.0)
|
||||
fog (~> 1.25.0)
|
||||
font-awesome-rails (~> 4.2)
|
||||
foreman
|
||||
fuubar (~> 2.0.0)
|
||||
gemnasium-gitlab-service (~> 0.2)
|
||||
github-markup
|
||||
github-markup (~> 1.3.1)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab-linguist (~> 3.0.1)
|
||||
gitlab_emoji (~> 0.1)
|
||||
gitlab_git (~> 7.2.15)
|
||||
gitlab_meta (= 7.0)
|
||||
gitlab_omniauth-ldap (= 1.2.1)
|
||||
gitlab_omniauth-ldap (~> 1.2.1)
|
||||
gollum-lib (~> 4.0.2)
|
||||
gon (~> 5.0.0)
|
||||
grape (~> 0.6.1)
|
||||
grape-entity (~> 0.4.2)
|
||||
haml-rails
|
||||
growl
|
||||
guard-rspec (~> 4.2.0)
|
||||
haml-rails (~> 0.5.3)
|
||||
hipchat (~> 1.5.0)
|
||||
html-pipeline (~> 1.11.0)
|
||||
httparty
|
||||
httparty (~> 0.13.3)
|
||||
jquery-atwho-rails (~> 1.0.0)
|
||||
jquery-rails (= 3.1.3)
|
||||
jquery-scrollto-rails
|
||||
jquery-turbolinks
|
||||
jquery-ui-rails
|
||||
jquery-rails (~> 3.1.3)
|
||||
jquery-scrollto-rails (~> 1.4.3)
|
||||
jquery-turbolinks (~> 2.0.1)
|
||||
jquery-ui-rails (~> 4.2.1)
|
||||
kaminari (~> 0.15.1)
|
||||
letter_opener
|
||||
letter_opener (~> 1.1.2)
|
||||
mail_room (~> 0.4.2)
|
||||
minitest (~> 5.3.0)
|
||||
mousetrap-rails
|
||||
mysql2
|
||||
newrelic_rpm
|
||||
nprogress-rails
|
||||
octokit (= 3.7.0)
|
||||
minitest (~> 5.7.0)
|
||||
mousetrap-rails (~> 1.4.6)
|
||||
mysql2 (~> 0.3.16)
|
||||
nested_form (~> 0.3.2)
|
||||
newrelic_rpm (~> 3.9.4.245)
|
||||
nprogress-rails (~> 0.1.2.3)
|
||||
oauth2 (~> 1.0.0)
|
||||
octokit (~> 3.7.0)
|
||||
omniauth (~> 1.2.2)
|
||||
omniauth-bitbucket
|
||||
omniauth-github
|
||||
omniauth-gitlab
|
||||
omniauth-google-oauth2
|
||||
omniauth-kerberos
|
||||
omniauth-bitbucket (~> 0.0.2)
|
||||
omniauth-github (~> 1.1.1)
|
||||
omniauth-gitlab (~> 1.0.0)
|
||||
omniauth-google-oauth2 (~> 0.2.5)
|
||||
omniauth-kerberos (~> 0.2.0)
|
||||
omniauth-saml (~> 1.4.0)
|
||||
omniauth-shibboleth
|
||||
omniauth-twitter
|
||||
omniauth-shibboleth (~> 1.1.1)
|
||||
omniauth-twitter (~> 1.0.1)
|
||||
omniauth_crowd
|
||||
org-ruby (= 0.9.12)
|
||||
pg
|
||||
org-ruby (~> 0.9.12)
|
||||
paranoia (~> 2.0)
|
||||
pg (~> 0.18.2)
|
||||
poltergeist (~> 1.6.0)
|
||||
pry-rails
|
||||
quiet_assets (~> 1.0.1)
|
||||
quiet_assets (~> 1.0.2)
|
||||
rack-attack (~> 4.3.0)
|
||||
rack-cors
|
||||
rack-mini-profiler
|
||||
rack-cors (~> 0.2.9)
|
||||
rack-mini-profiler (~> 0.9.0)
|
||||
rack-oauth2 (~> 1.0.5)
|
||||
rails (= 4.1.11)
|
||||
rails (= 4.1.12)
|
||||
raphael-rails (~> 2.1.2)
|
||||
rb-fsevent
|
||||
rb-inotify
|
||||
rdoc (~> 3.6)
|
||||
redcarpet (~> 3.3.2)
|
||||
redis-rails
|
||||
request_store
|
||||
redis-rails (~> 4.0.0)
|
||||
request_store (~> 1.2.0)
|
||||
rerun (~> 0.10.0)
|
||||
rqrcode-rails3
|
||||
rqrcode-rails3 (~> 0.1.7)
|
||||
rspec-rails (~> 3.3.0)
|
||||
rubocop (= 0.28.0)
|
||||
ruby-fogbugz
|
||||
rubocop (~> 0.28.0)
|
||||
ruby-fogbugz (~> 0.2.1)
|
||||
sanitize (~> 2.0)
|
||||
sass-rails (~> 4.0.5)
|
||||
sdoc
|
||||
seed-fu
|
||||
sdoc (~> 0.3.20)
|
||||
seed-fu (~> 2.3.5)
|
||||
select2-rails (~> 3.5.9)
|
||||
settingslogic
|
||||
settingslogic (~> 2.0.9)
|
||||
sham_rack
|
||||
shoulda-matchers (~> 2.8.0)
|
||||
sidekiq (~> 3.3)
|
||||
sidetiq (= 0.6.3)
|
||||
simplecov
|
||||
sinatra
|
||||
six
|
||||
sidekiq (= 3.3.0)
|
||||
sidetiq (~> 0.6.3)
|
||||
simplecov (~> 0.10.0)
|
||||
sinatra (~> 1.4.4)
|
||||
six (~> 0.2.0)
|
||||
slack-notifier (~> 1.0.0)
|
||||
slim
|
||||
spinach-rails
|
||||
spring (~> 1.3.1)
|
||||
spring-commands-rspec (~> 1.0.0)
|
||||
slim (~> 2.0.2)
|
||||
spinach-rails (~> 0.2.1)
|
||||
spring (~> 1.3.6)
|
||||
spring-commands-rspec (~> 1.0.4)
|
||||
spring-commands-spinach (~> 1.0.0)
|
||||
spring-commands-teaspoon (~> 0.0.2)
|
||||
sprockets (~> 2.12.3)
|
||||
stamp
|
||||
state_machine
|
||||
task_list (= 1.0.2)
|
||||
stamp (~> 0.5.0)
|
||||
state_machine (~> 1.2.0)
|
||||
task_list (~> 1.0.2)
|
||||
teaspoon (~> 1.0.0)
|
||||
teaspoon-jasmine
|
||||
test_after_commit
|
||||
thin
|
||||
teaspoon-jasmine (~> 2.2.0)
|
||||
test_after_commit (~> 0.2.2)
|
||||
thin (~> 1.6.1)
|
||||
tinder (~> 1.9.2)
|
||||
turbolinks (~> 2.5.0)
|
||||
uglifier
|
||||
uglifier (~> 2.3.2)
|
||||
underscore-rails (~> 1.4.4)
|
||||
unf
|
||||
unicorn (~> 4.6.3)
|
||||
unicorn-worker-killer
|
||||
version_sorter
|
||||
virtus
|
||||
unf (~> 0.1.4)
|
||||
unicorn (~> 4.8.2)
|
||||
unicorn-worker-killer (~> 0.4.2)
|
||||
version_sorter (~> 2.0.0)
|
||||
virtus (~> 1.0.1)
|
||||
webmock (~> 1.21.0)
|
||||
whenever (~> 0.8.4)
|
||||
wikicloth (= 0.8.1)
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.5
|
||||
1.10.6
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"}
|
||||
worker: bundle exec sidekiq -q post_receive -q mailer -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q common -q default
|
||||
worker: bundle exec sidekiq -q post_receive -q mailer -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default
|
||||
# mail_room: bundle exec mail_room -q -c config/mail_room.yml
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[](https://ci.gitlab.com/projects/1?ref=master)
|
||||
[](https://semaphoreci.com/gitlabhq/gitlabhq)
|
||||
[](https://codeclimate.com/github/gitlabhq/gitlabhq)
|
||||
[](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
|
||||
[](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
|
||||
|
||||
## Canonical source
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,67 @@
|
||||
class @BlobFileDropzone
|
||||
constructor: (form, method) ->
|
||||
form_dropzone = form.find('.dropzone')
|
||||
Dropzone.autoDiscover = false
|
||||
dropzone = form_dropzone.dropzone(
|
||||
autoDiscover: false
|
||||
autoProcessQueue: false
|
||||
url: form.attr('action')
|
||||
# Rails uses a hidden input field for PUT
|
||||
# http://stackoverflow.com/questions/21056482/how-to-set-method-put-in-form-tag-in-rails
|
||||
method: method
|
||||
clickable: true
|
||||
uploadMultiple: false
|
||||
paramName: "file"
|
||||
maxFilesize: gon.max_file_size or 10
|
||||
parallelUploads: 1
|
||||
maxFiles: 1
|
||||
addRemoveLinks: true
|
||||
previewsContainer: '.dropzone-previews'
|
||||
headers:
|
||||
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
|
||||
|
||||
init: ->
|
||||
this.on 'addedfile', (file) ->
|
||||
$('.dropzone-alerts').html('').hide()
|
||||
commit_message = form.find('#commit_message')[0]
|
||||
|
||||
if /^Upload/.test(commit_message.placeholder)
|
||||
commit_message.placeholder = 'Upload ' + file.name
|
||||
|
||||
return
|
||||
|
||||
this.on 'removedfile', (file) ->
|
||||
commit_message = form.find('#commit_message')[0]
|
||||
|
||||
if /^Upload/.test(commit_message.placeholder)
|
||||
commit_message.placeholder = 'Upload new file'
|
||||
|
||||
return
|
||||
|
||||
this.on 'success', (header, response) ->
|
||||
window.location.href = response.filePath
|
||||
return
|
||||
|
||||
this.on 'maxfilesexceeded', (file) ->
|
||||
@removeFile file
|
||||
return
|
||||
|
||||
this.on 'sending', (file, xhr, formData) ->
|
||||
formData.append('commit_message', form.find('#commit_message').val())
|
||||
return
|
||||
|
||||
# Override behavior of adding error underneath preview
|
||||
error: (file, errorMessage) ->
|
||||
stripped = $("<div/>").html(errorMessage).text();
|
||||
$('.dropzone-alerts').html('Error uploading file: \"' + stripped + '\"').show()
|
||||
@removeFile file
|
||||
return
|
||||
)
|
||||
|
||||
submitButton = form.find('#submit-all')[0]
|
||||
submitButton.addEventListener 'click', (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
alert "Please select a file" if dropzone[0].dropzone.getQueuedFiles().length == 0
|
||||
dropzone[0].dropzone.processQueue()
|
||||
return false
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
var Chart=function(s){function v(a,c,b){a=A((a-c.graphMin)/(c.steps*c.stepValue),1,0);return b*c.steps*a}function x(a,c,b,e){function h(){g+=f;var k=a.animation?A(d(g),null,0):1;e.clearRect(0,0,q,u);a.scaleOverlay?(b(k),c()):(c(),b(k));if(1>=g)D(h);else if("function"==typeof a.onAnimationComplete)a.onAnimationComplete()}var f=a.animation?1/A(a.animationSteps,Number.MAX_VALUE,1):1,d=B[a.animationEasing],g=a.animation?0:1;"function"!==typeof c&&(c=function(){});D(h)}function C(a,c,b,e,h,f){var d;a=
|
||||
Math.floor(Math.log(e-h)/Math.LN10);h=Math.floor(h/(1*Math.pow(10,a)))*Math.pow(10,a);e=Math.ceil(e/(1*Math.pow(10,a)))*Math.pow(10,a)-h;a=Math.pow(10,a);for(d=Math.round(e/a);d<b||d>c;)a=d<b?a/2:2*a,d=Math.round(e/a);c=[];z(f,c,d,h,a);return{steps:d,stepValue:a,graphMin:h,labels:c}}function z(a,c,b,e,h){if(a)for(var f=1;f<b+1;f++)c.push(E(a,{value:(e+h*f).toFixed(0!=h%1?h.toString().split(".")[1].length:0)}))}function A(a,c,b){return!isNaN(parseFloat(c))&&isFinite(c)&&a>c?c:!isNaN(parseFloat(b))&&
|
||||
isFinite(b)&&a<b?b:a}function y(a,c){var b={},e;for(e in a)b[e]=a[e];for(e in c)b[e]=c[e];return b}function E(a,c){var b=!/\W/.test(a)?F[a]=F[a]||E(document.getElementById(a).innerHTML):new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?
|
||||
b(c):b}var r=this,B={linear:function(a){return a},easeInQuad:function(a){return a*a},easeOutQuad:function(a){return-1*a*(a-2)},easeInOutQuad:function(a){return 1>(a/=0.5)?0.5*a*a:-0.5*(--a*(a-2)-1)},easeInCubic:function(a){return a*a*a},easeOutCubic:function(a){return 1*((a=a/1-1)*a*a+1)},easeInOutCubic:function(a){return 1>(a/=0.5)?0.5*a*a*a:0.5*((a-=2)*a*a+2)},easeInQuart:function(a){return a*a*a*a},easeOutQuart:function(a){return-1*((a=a/1-1)*a*a*a-1)},easeInOutQuart:function(a){return 1>(a/=0.5)?
|
||||
0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)},easeInQuint:function(a){return 1*(a/=1)*a*a*a*a},easeOutQuint:function(a){return 1*((a=a/1-1)*a*a*a*a+1)},easeInOutQuint:function(a){return 1>(a/=0.5)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)},easeInSine:function(a){return-1*Math.cos(a/1*(Math.PI/2))+1},easeOutSine:function(a){return 1*Math.sin(a/1*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a/1)-1)},easeInExpo:function(a){return 0==a?1:1*Math.pow(2,10*(a/1-1))},easeOutExpo:function(a){return 1==
|
||||
a?1:1*(-Math.pow(2,-10*a/1)+1)},easeInOutExpo:function(a){return 0==a?0:1==a?1:1>(a/=0.5)?0.5*Math.pow(2,10*(a-1)):0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return 1<=a?a:-1*(Math.sqrt(1-(a/=1)*a)-1)},easeOutCirc:function(a){return 1*Math.sqrt(1-(a=a/1-1)*a)},easeInOutCirc:function(a){return 1>(a/=0.5)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeInElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*
|
||||
Math.PI)*Math.asin(1/e);return-(e*Math.pow(2,10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b))},easeOutElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/e);return e*Math.pow(2,-10*a)*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInOutElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(2==(a/=0.5))return 1;b||(b=1*0.3*1.5);e<Math.abs(1)?(e=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/e);return 1>a?-0.5*e*Math.pow(2,10*
|
||||
(a-=1))*Math.sin((1*a-c)*2*Math.PI/b):0.5*e*Math.pow(2,-10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInBack:function(a){return 1*(a/=1)*a*(2.70158*a-1.70158)},easeOutBack:function(a){return 1*((a=a/1-1)*a*(2.70158*a+1.70158)+1)},easeInOutBack:function(a){var c=1.70158;return 1>(a/=0.5)?0.5*a*a*(((c*=1.525)+1)*a-c):0.5*((a-=2)*a*(((c*=1.525)+1)*a+c)+2)},easeInBounce:function(a){return 1-B.easeOutBounce(1-a)},easeOutBounce:function(a){return(a/=1)<1/2.75?1*7.5625*a*a:a<2/2.75?1*(7.5625*(a-=1.5/2.75)*
|
||||
a+0.75):a<2.5/2.75?1*(7.5625*(a-=2.25/2.75)*a+0.9375):1*(7.5625*(a-=2.625/2.75)*a+0.984375)},easeInOutBounce:function(a){return 0.5>a?0.5*B.easeInBounce(2*a):0.5*B.easeOutBounce(2*a-1)+0.5}},q=s.canvas.width,u=s.canvas.height;window.devicePixelRatio&&(s.canvas.style.width=q+"px",s.canvas.style.height=u+"px",s.canvas.height=u*window.devicePixelRatio,s.canvas.width=q*window.devicePixelRatio,s.scale(window.devicePixelRatio,window.devicePixelRatio));this.PolarArea=function(a,c){r.PolarArea.defaults={scaleOverlay:!0,
|
||||
scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",
|
||||
animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.PolarArea.defaults,c):r.PolarArea.defaults;return new G(a,b,s)};this.Radar=function(a,c){r.Radar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!1,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",
|
||||
scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,angleShowLineOut:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:12,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Radar.defaults,c):r.Radar.defaults;return new H(a,b,s)};this.Pie=function(a,
|
||||
c){r.Pie.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.Pie.defaults,c):r.Pie.defaults;return new I(a,b,s)};this.Doughnut=function(a,c){r.Doughnut.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,
|
||||
onAnimationComplete:null};var b=c?y(r.Doughnut.defaults,c):r.Doughnut.defaults;return new J(a,b,s)};this.Line=function(a,c){r.Line.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,bezierCurve:!0,
|
||||
pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:2,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Line.defaults,c):r.Line.defaults;return new K(a,b,s)};this.Bar=function(a,c){r.Bar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",
|
||||
scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Bar.defaults,c):r.Bar.defaults;return new L(a,b,s)};var G=function(a,c,b){var e,h,f,d,g,k,j,l,m;g=Math.min.apply(Math,[q,u])/2;g-=Math.max.apply(Math,[0.5*c.scaleFontSize,0.5*c.scaleLineWidth]);
|
||||
d=2*c.scaleFontSize;c.scaleShowLabelBackdrop&&(d+=2*c.scaleBackdropPaddingY,g-=1.5*c.scaleBackdropPaddingY);l=g;d=d?d:5;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.length;f++)a[f].value>e&&(e=a[f].value),a[f].value<h&&(h=a[f].value);f=Math.floor(l/(0.66*d));d=Math.floor(0.5*(l/d));m=c.scaleShowLabels?c.scaleLabel:null;c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(m,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(l,f,d,e,h,
|
||||
m);k=g/j.steps;x(c,function(){for(var a=0;a<j.steps;a++)if(c.scaleShowLine&&(b.beginPath(),b.arc(q/2,u/2,k*(a+1),0,2*Math.PI,!0),b.strokeStyle=c.scaleLineColor,b.lineWidth=c.scaleLineWidth,b.stroke()),c.scaleShowLabels){b.textAlign="center";b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;var e=j.labels[a];if(c.scaleShowLabelBackdrop){var d=b.measureText(e).width;b.fillStyle=c.scaleBackdropColor;b.beginPath();b.rect(Math.round(q/2-d/2-c.scaleBackdropPaddingX),Math.round(u/2-k*(a+
|
||||
1)-0.5*c.scaleFontSize-c.scaleBackdropPaddingY),Math.round(d+2*c.scaleBackdropPaddingX),Math.round(c.scaleFontSize+2*c.scaleBackdropPaddingY));b.fill()}b.textBaseline="middle";b.fillStyle=c.scaleFontColor;b.fillText(e,q/2,u/2-k*(a+1))}},function(e){var d=-Math.PI/2,g=2*Math.PI/a.length,f=1,h=1;c.animation&&(c.animateScale&&(f=e),c.animateRotate&&(h=e));for(e=0;e<a.length;e++)b.beginPath(),b.arc(q/2,u/2,f*v(a[e].value,j,k),d,d+h*g,!1),b.lineTo(q/2,u/2),b.closePath(),b.fillStyle=a[e].color,b.fill(),
|
||||
c.segmentShowStroke&&(b.strokeStyle=c.segmentStrokeColor,b.lineWidth=c.segmentStrokeWidth,b.stroke()),d+=h*g},b)},H=function(a,c,b){var e,h,f,d,g,k,j,l,m;a.labels||(a.labels=[]);g=Math.min.apply(Math,[q,u])/2;d=2*c.scaleFontSize;for(e=l=0;e<a.labels.length;e++)b.font=c.pointLabelFontStyle+" "+c.pointLabelFontSize+"px "+c.pointLabelFontFamily,h=b.measureText(a.labels[e]).width,h>l&&(l=h);g-=Math.max.apply(Math,[l,1.5*(c.pointLabelFontSize/2)]);g-=c.pointLabelFontSize;l=g=A(g,null,0);d=d?d:5;e=Number.MIN_VALUE;
|
||||
h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(m=0;m<a.datasets[f].data.length;m++)a.datasets[f].data[m]>e&&(e=a.datasets[f].data[m]),a.datasets[f].data[m]<h&&(h=a.datasets[f].data[m]);f=Math.floor(l/(0.66*d));d=Math.floor(0.5*(l/d));m=c.scaleShowLabels?c.scaleLabel:null;c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(m,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(l,f,d,e,h,m);k=g/j.steps;x(c,function(){var e=2*Math.PI/
|
||||
a.datasets[0].data.length;b.save();b.translate(q/2,u/2);if(c.angleShowLineOut){b.strokeStyle=c.angleLineColor;b.lineWidth=c.angleLineWidth;for(var d=0;d<a.datasets[0].data.length;d++)b.rotate(e),b.beginPath(),b.moveTo(0,0),b.lineTo(0,-g),b.stroke()}for(d=0;d<j.steps;d++){b.beginPath();if(c.scaleShowLine){b.strokeStyle=c.scaleLineColor;b.lineWidth=c.scaleLineWidth;b.moveTo(0,-k*(d+1));for(var f=0;f<a.datasets[0].data.length;f++)b.rotate(e),b.lineTo(0,-k*(d+1));b.closePath();b.stroke()}c.scaleShowLabels&&
|
||||
(b.textAlign="center",b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily,b.textBaseline="middle",c.scaleShowLabelBackdrop&&(f=b.measureText(j.labels[d]).width,b.fillStyle=c.scaleBackdropColor,b.beginPath(),b.rect(Math.round(-f/2-c.scaleBackdropPaddingX),Math.round(-k*(d+1)-0.5*c.scaleFontSize-c.scaleBackdropPaddingY),Math.round(f+2*c.scaleBackdropPaddingX),Math.round(c.scaleFontSize+2*c.scaleBackdropPaddingY)),b.fill()),b.fillStyle=c.scaleFontColor,b.fillText(j.labels[d],0,-k*(d+
|
||||
1)))}for(d=0;d<a.labels.length;d++){b.font=c.pointLabelFontStyle+" "+c.pointLabelFontSize+"px "+c.pointLabelFontFamily;b.fillStyle=c.pointLabelFontColor;var f=Math.sin(e*d)*(g+c.pointLabelFontSize),h=Math.cos(e*d)*(g+c.pointLabelFontSize);b.textAlign=e*d==Math.PI||0==e*d?"center":e*d>Math.PI?"right":"left";b.textBaseline="middle";b.fillText(a.labels[d],f,-h)}b.restore()},function(d){var e=2*Math.PI/a.datasets[0].data.length;b.save();b.translate(q/2,u/2);for(var g=0;g<a.datasets.length;g++){b.beginPath();
|
||||
b.moveTo(0,d*-1*v(a.datasets[g].data[0],j,k));for(var f=1;f<a.datasets[g].data.length;f++)b.rotate(e),b.lineTo(0,d*-1*v(a.datasets[g].data[f],j,k));b.closePath();b.fillStyle=a.datasets[g].fillColor;b.strokeStyle=a.datasets[g].strokeColor;b.lineWidth=c.datasetStrokeWidth;b.fill();b.stroke();if(c.pointDot){b.fillStyle=a.datasets[g].pointColor;b.strokeStyle=a.datasets[g].pointStrokeColor;b.lineWidth=c.pointDotStrokeWidth;for(f=0;f<a.datasets[g].data.length;f++)b.rotate(e),b.beginPath(),b.arc(0,d*-1*
|
||||
v(a.datasets[g].data[f],j,k),c.pointDotRadius,2*Math.PI,!1),b.fill(),b.stroke()}b.rotate(e)}b.restore()},b)},I=function(a,c,b){for(var e=0,h=Math.min.apply(Math,[u/2,q/2])-5,f=0;f<a.length;f++)e+=a[f].value;x(c,null,function(d){var g=-Math.PI/2,f=1,j=1;c.animation&&(c.animateScale&&(f=d),c.animateRotate&&(j=d));for(d=0;d<a.length;d++){var l=j*a[d].value/e*2*Math.PI;b.beginPath();b.arc(q/2,u/2,f*h,g,g+l);b.lineTo(q/2,u/2);b.closePath();b.fillStyle=a[d].color;b.fill();c.segmentShowStroke&&(b.lineWidth=
|
||||
c.segmentStrokeWidth,b.strokeStyle=c.segmentStrokeColor,b.stroke());g+=l}},b)},J=function(a,c,b){for(var e=0,h=Math.min.apply(Math,[u/2,q/2])-5,f=h*(c.percentageInnerCutout/100),d=0;d<a.length;d++)e+=a[d].value;x(c,null,function(d){var k=-Math.PI/2,j=1,l=1;c.animation&&(c.animateScale&&(j=d),c.animateRotate&&(l=d));for(d=0;d<a.length;d++){var m=l*a[d].value/e*2*Math.PI;b.beginPath();b.arc(q/2,u/2,j*h,k,k+m,!1);b.arc(q/2,u/2,j*f,k+m,k,!0);b.closePath();b.fillStyle=a[d].color;b.fill();c.segmentShowStroke&&
|
||||
(b.lineWidth=c.segmentStrokeWidth,b.strokeStyle=c.segmentStrokeColor,b.stroke());k+=m}},b)},K=function(a,c,b){var e,h,f,d,g,k,j,l,m,t,r,n,p,s=0;g=u;b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;t=1;for(d=0;d<a.labels.length;d++)e=b.measureText(a.labels[d]).width,t=e>t?e:t;q/a.labels.length<t?(s=45,q/a.labels.length<Math.cos(s)*t?(s=90,g-=t):g-=Math.sin(s)*t):g-=c.scaleFontSize;d=c.scaleFontSize;g=g-5-d;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(l=
|
||||
0;l<a.datasets[f].data.length;l++)a.datasets[f].data[l]>e&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]<h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;
|
||||
for(e=0;e<j.labels.length;e++)h=b.measureText(j.labels[e]).width,d=h>d?h:d;d+=10}r=q-d-t;m=Math.floor(r/(a.labels.length-1));n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0<s?(b.save(),b.textAlign="right"):b.textAlign="center";b.fillStyle=c.scaleFontColor;for(var d=0;d<a.labels.length;d++)b.save(),0<s?(b.translate(n+d*m,p+c.scaleFontSize),b.rotate(-(s*(Math.PI/180))),b.fillText(a.labels[d],
|
||||
0,0),b.restore()):b.fillText(a.labels[d],n+d*m,p+c.scaleFontSize+3),b.beginPath(),b.moveTo(n+d*m,p+3),c.scaleShowGridLines&&0<d?(b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+d*m,5)):b.lineTo(n+d*m,p+3),b.stroke();b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(n,p+5);b.lineTo(n,5);b.stroke();b.textAlign="right";b.textBaseline="middle";for(d=0;d<j.steps;d++)b.beginPath(),b.moveTo(n-3,p-(d+1)*k),c.scaleShowGridLines?(b.lineWidth=c.scaleGridLineWidth,
|
||||
b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+r+5,p-(d+1)*k)):b.lineTo(n-0.5,p-(d+1)*k),b.stroke(),c.scaleShowLabels&&b.fillText(j.labels[d],n-8,p-(d+1)*k)},function(d){function e(b,c){return p-d*v(a.datasets[b].data[c],j,k)}for(var f=0;f<a.datasets.length;f++){b.strokeStyle=a.datasets[f].strokeColor;b.lineWidth=c.datasetStrokeWidth;b.beginPath();b.moveTo(n,p-d*v(a.datasets[f].data[0],j,k));for(var g=1;g<a.datasets[f].data.length;g++)c.bezierCurve?b.bezierCurveTo(n+m*(g-0.5),e(f,g-1),n+m*(g-0.5),
|
||||
e(f,g),n+m*g,e(f,g)):b.lineTo(n+m*g,e(f,g));b.stroke();c.datasetFill?(b.lineTo(n+m*(a.datasets[f].data.length-1),p),b.lineTo(n,p),b.closePath(),b.fillStyle=a.datasets[f].fillColor,b.fill()):b.closePath();if(c.pointDot){b.fillStyle=a.datasets[f].pointColor;b.strokeStyle=a.datasets[f].pointStrokeColor;b.lineWidth=c.pointDotStrokeWidth;for(g=0;g<a.datasets[f].data.length;g++)b.beginPath(),b.arc(n+m*g,p-d*v(a.datasets[f].data[g],j,k),c.pointDotRadius,0,2*Math.PI,!0),b.fill(),b.stroke()}}},b)},L=function(a,
|
||||
c,b){var e,h,f,d,g,k,j,l,m,t,r,n,p,s,w=0;g=u;b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;t=1;for(d=0;d<a.labels.length;d++)e=b.measureText(a.labels[d]).width,t=e>t?e:t;q/a.labels.length<t?(w=45,q/a.labels.length<Math.cos(w)*t?(w=90,g-=t):g-=Math.sin(w)*t):g-=c.scaleFontSize;d=c.scaleFontSize;g=g-5-d;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;f<a.datasets.length;f++)for(l=0;l<a.datasets[f].data.length;l++)a.datasets[f].data[l]>e&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]<
|
||||
h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;for(e=0;e<j.labels.length;e++)h=b.measureText(j.labels[e]).width,d=h>d?h:d;d+=10}r=q-d-t;m=
|
||||
Math.floor(r/a.labels.length);s=(m-2*c.scaleGridLineWidth-2*c.barValueSpacing-(c.barDatasetSpacing*a.datasets.length-1)-(c.barStrokeWidth/2*a.datasets.length-1))/a.datasets.length;n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0<w?(b.save(),b.textAlign="right"):b.textAlign="center";b.fillStyle=c.scaleFontColor;for(var d=0;d<a.labels.length;d++)b.save(),0<w?(b.translate(n+
|
||||
d*m,p+c.scaleFontSize),b.rotate(-(w*(Math.PI/180))),b.fillText(a.labels[d],0,0),b.restore()):b.fillText(a.labels[d],n+d*m+m/2,p+c.scaleFontSize+3),b.beginPath(),b.moveTo(n+(d+1)*m,p+3),b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+(d+1)*m,5),b.stroke();b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(n,p+5);b.lineTo(n,5);b.stroke();b.textAlign="right";b.textBaseline="middle";for(d=0;d<j.steps;d++)b.beginPath(),b.moveTo(n-3,p-(d+1)*
|
||||
k),c.scaleShowGridLines?(b.lineWidth=c.scaleGridLineWidth,b.strokeStyle=c.scaleGridLineColor,b.lineTo(n+r+5,p-(d+1)*k)):b.lineTo(n-0.5,p-(d+1)*k),b.stroke(),c.scaleShowLabels&&b.fillText(j.labels[d],n-8,p-(d+1)*k)},function(d){b.lineWidth=c.barStrokeWidth;for(var e=0;e<a.datasets.length;e++){b.fillStyle=a.datasets[e].fillColor;b.strokeStyle=a.datasets[e].strokeColor;for(var f=0;f<a.datasets[e].data.length;f++){var g=n+c.barValueSpacing+m*f+s*e+c.barDatasetSpacing*e+c.barStrokeWidth*e;b.beginPath();
|
||||
b.moveTo(g,p);b.lineTo(g,p-d*v(a.datasets[e].data[f],j,k)+c.barStrokeWidth/2);b.lineTo(g+s,p-d*v(a.datasets[e].data[f],j,k)+c.barStrokeWidth/2);b.lineTo(g+s,p);c.barShowStroke&&b.stroke();b.closePath();b.fill()}}},b)},D=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)},F={}};
|
||||
@@ -0,0 +1,40 @@
|
||||
# This is a manifest file that'll be compiled into application.js, which will include all the files
|
||||
# listed below.
|
||||
#
|
||||
# Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
||||
# or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
||||
#
|
||||
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
# the compiled file.
|
||||
#
|
||||
# WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
||||
# GO AFTER THE REQUIRES BELOW.
|
||||
#
|
||||
#= require pager
|
||||
#= require jquery_nested_form
|
||||
#= require_tree .
|
||||
#
|
||||
$(document).on 'click', '.edit-runner-link', (event) ->
|
||||
event.preventDefault()
|
||||
|
||||
descr = $(this).closest('.runner-description').first()
|
||||
descr.addClass('hide')
|
||||
form = descr.next('.runner-description-form')
|
||||
descrInput = form.find('input.description')
|
||||
originalValue = descrInput.val()
|
||||
form.removeClass('hide')
|
||||
form.find('.cancel').on 'click', (event) ->
|
||||
event.preventDefault()
|
||||
|
||||
form.addClass('hide')
|
||||
descrInput.val(originalValue)
|
||||
descr.removeClass('hide')
|
||||
|
||||
$(document).on 'click', '.assign-all-runner', ->
|
||||
$(this).replaceWith('<i class="fa fa-refresh fa-spin"></i> Assign in progress..')
|
||||
|
||||
window.unbindEvents = ->
|
||||
$(document).unbind('scroll')
|
||||
$(document).off('scroll')
|
||||
|
||||
document.addEventListener("page:fetch", unbindEvents)
|
||||
@@ -0,0 +1,41 @@
|
||||
class CiBuild
|
||||
@interval: null
|
||||
|
||||
constructor: (build_url, build_status) ->
|
||||
clearInterval(CiBuild.interval)
|
||||
|
||||
if build_status == "running" || build_status == "pending"
|
||||
#
|
||||
# Bind autoscroll button to follow build output
|
||||
#
|
||||
$("#autoscroll-button").bind "click", ->
|
||||
state = $(this).data("state")
|
||||
if "enabled" is state
|
||||
$(this).data "state", "disabled"
|
||||
$(this).text "enable autoscroll"
|
||||
else
|
||||
$(this).data "state", "enabled"
|
||||
$(this).text "disable autoscroll"
|
||||
|
||||
#
|
||||
# Check for new build output if user still watching build page
|
||||
# Only valid for runnig build when output changes during time
|
||||
#
|
||||
CiBuild.interval = setInterval =>
|
||||
if window.location.href is build_url
|
||||
$.ajax
|
||||
url: build_url
|
||||
dataType: "json"
|
||||
success: (build) =>
|
||||
if build.status == "running"
|
||||
$('#build-trace code').html build.trace_html
|
||||
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
|
||||
@checkAutoscroll()
|
||||
else
|
||||
Turbolinks.visit build_url
|
||||
, 4000
|
||||
|
||||
checkAutoscroll: ->
|
||||
$("html,body").scrollTop $("#build-trace").height() if "enabled" is $("#autoscroll-button").data("state")
|
||||
|
||||
@CiBuild = CiBuild
|
||||
@@ -0,0 +1,42 @@
|
||||
@CiPager =
|
||||
init: (@url, @limit = 0, preload, @disable = false) ->
|
||||
if preload
|
||||
@offset = 0
|
||||
@getItems()
|
||||
else
|
||||
@offset = @limit
|
||||
@initLoadMore()
|
||||
|
||||
getItems: ->
|
||||
$(".loading").show()
|
||||
$.ajax
|
||||
type: "GET"
|
||||
url: @url
|
||||
data: "limit=" + @limit + "&offset=" + @offset
|
||||
complete: =>
|
||||
$(".loading").hide()
|
||||
success: (data) =>
|
||||
CiPager.append(data.count, data.html)
|
||||
dataType: "json"
|
||||
|
||||
append: (count, html) ->
|
||||
if count > 1
|
||||
$(".content-list").append html
|
||||
if count == @limit
|
||||
@offset += count
|
||||
else
|
||||
@disable = true
|
||||
|
||||
initLoadMore: ->
|
||||
$(document).unbind('scroll')
|
||||
$(document).endlessScroll
|
||||
bottomPixels: 400
|
||||
fireDelay: 1000
|
||||
fireOnce: true
|
||||
ceaseFire: ->
|
||||
CiPager.disable
|
||||
|
||||
callback: (i) =>
|
||||
unless $(".loading").is(':visible')
|
||||
$(".loading").show()
|
||||
CiPager.getItems()
|
||||
@@ -0,0 +1,6 @@
|
||||
$(document).on 'click', '.badge-codes-toggle', ->
|
||||
$('.badge-codes-block').toggleClass("hide")
|
||||
return false
|
||||
|
||||
$(document).on 'click', '.sync-now', ->
|
||||
$(this).find('i').addClass('fa-spin')
|
||||
@@ -61,3 +61,9 @@
|
||||
* Styles for JS behaviors.
|
||||
*/
|
||||
@import "behaviors.scss";
|
||||
|
||||
/**
|
||||
* CI specific styles:
|
||||
*/
|
||||
@import "ci/**/*";
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
.ci-body {
|
||||
pre.trace {
|
||||
background: #111111;
|
||||
color: #fff;
|
||||
font-family: $monospace_font;
|
||||
white-space: pre;
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
overflow: auto;
|
||||
overflow-y: hidden;
|
||||
font-size: 12px;
|
||||
|
||||
.fa-refresh {
|
||||
font-size: 24px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.autoscroll-container {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
right: 20px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.scroll-controls {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
left: 250px;
|
||||
z-index: 100;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-sidebar-collapsed {
|
||||
.scroll-controls {
|
||||
left: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
.build-widget {
|
||||
padding: 10px;
|
||||
background: $background-color;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
|
||||
.title {
|
||||
margin-top: 0;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.attr-name {
|
||||
color: #777;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-disabled {
|
||||
background: $background-color;
|
||||
|
||||
a {
|
||||
color: #3084bb !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
.ci-body {
|
||||
.incorrect-syntax{
|
||||
font-size: 19px;
|
||||
color: red;
|
||||
}
|
||||
.correct-syntax{
|
||||
font-size: 19px;
|
||||
color: #47a447;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
.ci-body {
|
||||
.project-title {
|
||||
margin: 0;
|
||||
color: #444;
|
||||
font-size: 20px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.wide-table-holder {
|
||||
margin-left: -$gl-padding;
|
||||
margin-right: -$gl-padding;
|
||||
}
|
||||
|
||||
.builds,
|
||||
.projects-table {
|
||||
.alert-success {
|
||||
background-color: #6fc995;
|
||||
border-color: #5bba83;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background-color: #eb897f;
|
||||
border-color: #d4776e;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background-color: #3498db;
|
||||
border-color: #2e8ece;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background-color: #EB974E;
|
||||
border-color: #E87E04;
|
||||
}
|
||||
|
||||
.alert-disabled {
|
||||
background: $background-color;
|
||||
border-color: $border-color;
|
||||
}
|
||||
|
||||
.light {
|
||||
border-color: $border-color;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 10px $gl-padding;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: middle !important;
|
||||
border-color: inherit !important;
|
||||
|
||||
a {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.commit-info {
|
||||
font-size: 14px;
|
||||
|
||||
.attr-name {
|
||||
font-weight: 300;
|
||||
color: #666;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
pre.commit-message {
|
||||
font-size: 14px;
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
margin: 20px 0;
|
||||
border-bottom: 1px solid #EEE;
|
||||
padding-bottom: 20px;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.loading{
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.ci-charts {
|
||||
fieldset {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
.ci-body {
|
||||
.runner-state {
|
||||
padding: 6px 12px;
|
||||
margin-right: 10px;
|
||||
color: #FFF;
|
||||
|
||||
&.runner-state-shared {
|
||||
background: #32b186;
|
||||
}
|
||||
&.runner-state-specific {
|
||||
background: #3498db;
|
||||
}
|
||||
}
|
||||
|
||||
.runner-status-online {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.runner-status-offline {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.runner-status-paused {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.runner {
|
||||
.btn {
|
||||
padding: 1px 6px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,906 @@
|
||||
.ci-body {
|
||||
// color codes are based on http://en.wikipedia.org/wiki/File:Xterm_256color_chart.svg
|
||||
// see also: https://gist.github.com/jasonm23/2868981
|
||||
|
||||
$black: #000000;
|
||||
$red: #cd0000;
|
||||
$green: #00cd00;
|
||||
$yellow: #cdcd00;
|
||||
$blue: #0000ee; // according to wikipedia, this is the xterm standard
|
||||
//$blue: #1e90ff; // this is used by all the terminals I tried (when configured with the xterm color profile)
|
||||
$magenta: #cd00cd;
|
||||
$cyan: #00cdcd;
|
||||
$white: #e5e5e5;
|
||||
$l-black: #7f7f7f;
|
||||
$l-red: #ff0000;
|
||||
$l-green: #00ff00;
|
||||
$l-yellow: #ffff00;
|
||||
$l-blue: #5c5cff;
|
||||
$l-magenta: #ff00ff;
|
||||
$l-cyan: #00ffff;
|
||||
$l-white: #ffffff;
|
||||
|
||||
.term-bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.term-italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.term-conceal {
|
||||
visibility: hidden;
|
||||
}
|
||||
.term-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.term-cross {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.term-fg-black {
|
||||
color: $black;
|
||||
}
|
||||
.term-fg-red {
|
||||
color: $red;
|
||||
}
|
||||
.term-fg-green {
|
||||
color: $green;
|
||||
}
|
||||
.term-fg-yellow {
|
||||
color: $yellow;
|
||||
}
|
||||
.term-fg-blue {
|
||||
color: $blue;
|
||||
}
|
||||
.term-fg-magenta {
|
||||
color: $magenta;
|
||||
}
|
||||
.term-fg-cyan {
|
||||
color: $cyan;
|
||||
}
|
||||
.term-fg-white {
|
||||
color: $white;
|
||||
}
|
||||
.term-fg-l-black {
|
||||
color: $l-black;
|
||||
}
|
||||
.term-fg-l-red {
|
||||
color: $l-red;
|
||||
}
|
||||
.term-fg-l-green {
|
||||
color: $l-green;
|
||||
}
|
||||
.term-fg-l-yellow {
|
||||
color: $l-yellow;
|
||||
}
|
||||
.term-fg-l-blue {
|
||||
color: $l-blue;
|
||||
}
|
||||
.term-fg-l-magenta {
|
||||
color: $l-magenta;
|
||||
}
|
||||
.term-fg-l-cyan {
|
||||
color: $l-cyan;
|
||||
}
|
||||
.term-fg-l-white {
|
||||
color: $l-white;
|
||||
}
|
||||
|
||||
.term-bg-black {
|
||||
background-color: $black;
|
||||
}
|
||||
.term-bg-red {
|
||||
background-color: $red;
|
||||
}
|
||||
.term-bg-green {
|
||||
background-color: $green;
|
||||
}
|
||||
.term-bg-yellow {
|
||||
background-color: $yellow;
|
||||
}
|
||||
.term-bg-blue {
|
||||
background-color: $blue;
|
||||
}
|
||||
.term-bg-magenta {
|
||||
background-color: $magenta;
|
||||
}
|
||||
.term-bg-cyan {
|
||||
background-color: $cyan;
|
||||
}
|
||||
.term-bg-white {
|
||||
background-color: $white;
|
||||
}
|
||||
.term-bg-l-black {
|
||||
background-color: $l-black;
|
||||
}
|
||||
.term-bg-l-red {
|
||||
background-color: $l-red;
|
||||
}
|
||||
.term-bg-l-green {
|
||||
background-color: $l-green;
|
||||
}
|
||||
.term-bg-l-yellow {
|
||||
background-color: $l-yellow;
|
||||
}
|
||||
.term-bg-l-blue {
|
||||
background-color: $l-blue;
|
||||
}
|
||||
.term-bg-l-magenta {
|
||||
background-color: $l-magenta;
|
||||
}
|
||||
.term-bg-l-cyan {
|
||||
background-color: $l-cyan;
|
||||
}
|
||||
.term-bg-l-white {
|
||||
background-color: $l-white;
|
||||
}
|
||||
|
||||
|
||||
.xterm-fg-0 {
|
||||
color: #000000;
|
||||
}
|
||||
.xterm-fg-1 {
|
||||
color: #800000;
|
||||
}
|
||||
.xterm-fg-2 {
|
||||
color: #008000;
|
||||
}
|
||||
.xterm-fg-3 {
|
||||
color: #808000;
|
||||
}
|
||||
.xterm-fg-4 {
|
||||
color: #000080;
|
||||
}
|
||||
.xterm-fg-5 {
|
||||
color: #800080;
|
||||
}
|
||||
.xterm-fg-6 {
|
||||
color: #008080;
|
||||
}
|
||||
.xterm-fg-7 {
|
||||
color: #c0c0c0;
|
||||
}
|
||||
.xterm-fg-8 {
|
||||
color: #808080;
|
||||
}
|
||||
.xterm-fg-9 {
|
||||
color: #ff0000;
|
||||
}
|
||||
.xterm-fg-10 {
|
||||
color: #00ff00;
|
||||
}
|
||||
.xterm-fg-11 {
|
||||
color: #ffff00;
|
||||
}
|
||||
.xterm-fg-12 {
|
||||
color: #0000ff;
|
||||
}
|
||||
.xterm-fg-13 {
|
||||
color: #ff00ff;
|
||||
}
|
||||
.xterm-fg-14 {
|
||||
color: #00ffff;
|
||||
}
|
||||
.xterm-fg-15 {
|
||||
color: #ffffff;
|
||||
}
|
||||
.xterm-fg-16 {
|
||||
color: #000000;
|
||||
}
|
||||
.xterm-fg-17 {
|
||||
color: #00005f;
|
||||
}
|
||||
.xterm-fg-18 {
|
||||
color: #000087;
|
||||
}
|
||||
.xterm-fg-19 {
|
||||
color: #0000af;
|
||||
}
|
||||
.xterm-fg-20 {
|
||||
color: #0000d7;
|
||||
}
|
||||
.xterm-fg-21 {
|
||||
color: #0000ff;
|
||||
}
|
||||
.xterm-fg-22 {
|
||||
color: #005f00;
|
||||
}
|
||||
.xterm-fg-23 {
|
||||
color: #005f5f;
|
||||
}
|
||||
.xterm-fg-24 {
|
||||
color: #005f87;
|
||||
}
|
||||
.xterm-fg-25 {
|
||||
color: #005faf;
|
||||
}
|
||||
.xterm-fg-26 {
|
||||
color: #005fd7;
|
||||
}
|
||||
.xterm-fg-27 {
|
||||
color: #005fff;
|
||||
}
|
||||
.xterm-fg-28 {
|
||||
color: #008700;
|
||||
}
|
||||
.xterm-fg-29 {
|
||||
color: #00875f;
|
||||
}
|
||||
.xterm-fg-30 {
|
||||
color: #008787;
|
||||
}
|
||||
.xterm-fg-31 {
|
||||
color: #0087af;
|
||||
}
|
||||
.xterm-fg-32 {
|
||||
color: #0087d7;
|
||||
}
|
||||
.xterm-fg-33 {
|
||||
color: #0087ff;
|
||||
}
|
||||
.xterm-fg-34 {
|
||||
color: #00af00;
|
||||
}
|
||||
.xterm-fg-35 {
|
||||
color: #00af5f;
|
||||
}
|
||||
.xterm-fg-36 {
|
||||
color: #00af87;
|
||||
}
|
||||
.xterm-fg-37 {
|
||||
color: #00afaf;
|
||||
}
|
||||
.xterm-fg-38 {
|
||||
color: #00afd7;
|
||||
}
|
||||
.xterm-fg-39 {
|
||||
color: #00afff;
|
||||
}
|
||||
.xterm-fg-40 {
|
||||
color: #00d700;
|
||||
}
|
||||
.xterm-fg-41 {
|
||||
color: #00d75f;
|
||||
}
|
||||
.xterm-fg-42 {
|
||||
color: #00d787;
|
||||
}
|
||||
.xterm-fg-43 {
|
||||
color: #00d7af;
|
||||
}
|
||||
.xterm-fg-44 {
|
||||
color: #00d7d7;
|
||||
}
|
||||
.xterm-fg-45 {
|
||||
color: #00d7ff;
|
||||
}
|
||||
.xterm-fg-46 {
|
||||
color: #00ff00;
|
||||
}
|
||||
.xterm-fg-47 {
|
||||
color: #00ff5f;
|
||||
}
|
||||
.xterm-fg-48 {
|
||||
color: #00ff87;
|
||||
}
|
||||
.xterm-fg-49 {
|
||||
color: #00ffaf;
|
||||
}
|
||||
.xterm-fg-50 {
|
||||
color: #00ffd7;
|
||||
}
|
||||
.xterm-fg-51 {
|
||||
color: #00ffff;
|
||||
}
|
||||
.xterm-fg-52 {
|
||||
color: #5f0000;
|
||||
}
|
||||
.xterm-fg-53 {
|
||||
color: #5f005f;
|
||||
}
|
||||
.xterm-fg-54 {
|
||||
color: #5f0087;
|
||||
}
|
||||
.xterm-fg-55 {
|
||||
color: #5f00af;
|
||||
}
|
||||
.xterm-fg-56 {
|
||||
color: #5f00d7;
|
||||
}
|
||||
.xterm-fg-57 {
|
||||
color: #5f00ff;
|
||||
}
|
||||
.xterm-fg-58 {
|
||||
color: #5f5f00;
|
||||
}
|
||||
.xterm-fg-59 {
|
||||
color: #5f5f5f;
|
||||
}
|
||||
.xterm-fg-60 {
|
||||
color: #5f5f87;
|
||||
}
|
||||
.xterm-fg-61 {
|
||||
color: #5f5faf;
|
||||
}
|
||||
.xterm-fg-62 {
|
||||
color: #5f5fd7;
|
||||
}
|
||||
.xterm-fg-63 {
|
||||
color: #5f5fff;
|
||||
}
|
||||
.xterm-fg-64 {
|
||||
color: #5f8700;
|
||||
}
|
||||
.xterm-fg-65 {
|
||||
color: #5f875f;
|
||||
}
|
||||
.xterm-fg-66 {
|
||||
color: #5f8787;
|
||||
}
|
||||
.xterm-fg-67 {
|
||||
color: #5f87af;
|
||||
}
|
||||
.xterm-fg-68 {
|
||||
color: #5f87d7;
|
||||
}
|
||||
.xterm-fg-69 {
|
||||
color: #5f87ff;
|
||||
}
|
||||
.xterm-fg-70 {
|
||||
color: #5faf00;
|
||||
}
|
||||
.xterm-fg-71 {
|
||||
color: #5faf5f;
|
||||
}
|
||||
.xterm-fg-72 {
|
||||
color: #5faf87;
|
||||
}
|
||||
.xterm-fg-73 {
|
||||
color: #5fafaf;
|
||||
}
|
||||
.xterm-fg-74 {
|
||||
color: #5fafd7;
|
||||
}
|
||||
.xterm-fg-75 {
|
||||
color: #5fafff;
|
||||
}
|
||||
.xterm-fg-76 {
|
||||
color: #5fd700;
|
||||
}
|
||||
.xterm-fg-77 {
|
||||
color: #5fd75f;
|
||||
}
|
||||
.xterm-fg-78 {
|
||||
color: #5fd787;
|
||||
}
|
||||
.xterm-fg-79 {
|
||||
color: #5fd7af;
|
||||
}
|
||||
.xterm-fg-80 {
|
||||
color: #5fd7d7;
|
||||
}
|
||||
.xterm-fg-81 {
|
||||
color: #5fd7ff;
|
||||
}
|
||||
.xterm-fg-82 {
|
||||
color: #5fff00;
|
||||
}
|
||||
.xterm-fg-83 {
|
||||
color: #5fff5f;
|
||||
}
|
||||
.xterm-fg-84 {
|
||||
color: #5fff87;
|
||||
}
|
||||
.xterm-fg-85 {
|
||||
color: #5fffaf;
|
||||
}
|
||||
.xterm-fg-86 {
|
||||
color: #5fffd7;
|
||||
}
|
||||
.xterm-fg-87 {
|
||||
color: #5fffff;
|
||||
}
|
||||
.xterm-fg-88 {
|
||||
color: #870000;
|
||||
}
|
||||
.xterm-fg-89 {
|
||||
color: #87005f;
|
||||
}
|
||||
.xterm-fg-90 {
|
||||
color: #870087;
|
||||
}
|
||||
.xterm-fg-91 {
|
||||
color: #8700af;
|
||||
}
|
||||
.xterm-fg-92 {
|
||||
color: #8700d7;
|
||||
}
|
||||
.xterm-fg-93 {
|
||||
color: #8700ff;
|
||||
}
|
||||
.xterm-fg-94 {
|
||||
color: #875f00;
|
||||
}
|
||||
.xterm-fg-95 {
|
||||
color: #875f5f;
|
||||
}
|
||||
.xterm-fg-96 {
|
||||
color: #875f87;
|
||||
}
|
||||
.xterm-fg-97 {
|
||||
color: #875faf;
|
||||
}
|
||||
.xterm-fg-98 {
|
||||
color: #875fd7;
|
||||
}
|
||||
.xterm-fg-99 {
|
||||
color: #875fff;
|
||||
}
|
||||
.xterm-fg-100 {
|
||||
color: #878700;
|
||||
}
|
||||
.xterm-fg-101 {
|
||||
color: #87875f;
|
||||
}
|
||||
.xterm-fg-102 {
|
||||
color: #878787;
|
||||
}
|
||||
.xterm-fg-103 {
|
||||
color: #8787af;
|
||||
}
|
||||
.xterm-fg-104 {
|
||||
color: #8787d7;
|
||||
}
|
||||
.xterm-fg-105 {
|
||||
color: #8787ff;
|
||||
}
|
||||
.xterm-fg-106 {
|
||||
color: #87af00;
|
||||
}
|
||||
.xterm-fg-107 {
|
||||
color: #87af5f;
|
||||
}
|
||||
.xterm-fg-108 {
|
||||
color: #87af87;
|
||||
}
|
||||
.xterm-fg-109 {
|
||||
color: #87afaf;
|
||||
}
|
||||
.xterm-fg-110 {
|
||||
color: #87afd7;
|
||||
}
|
||||
.xterm-fg-111 {
|
||||
color: #87afff;
|
||||
}
|
||||
.xterm-fg-112 {
|
||||
color: #87d700;
|
||||
}
|
||||
.xterm-fg-113 {
|
||||
color: #87d75f;
|
||||
}
|
||||
.xterm-fg-114 {
|
||||
color: #87d787;
|
||||
}
|
||||
.xterm-fg-115 {
|
||||
color: #87d7af;
|
||||
}
|
||||
.xterm-fg-116 {
|
||||
color: #87d7d7;
|
||||
}
|
||||
.xterm-fg-117 {
|
||||
color: #87d7ff;
|
||||
}
|
||||
.xterm-fg-118 {
|
||||
color: #87ff00;
|
||||
}
|
||||
.xterm-fg-119 {
|
||||
color: #87ff5f;
|
||||
}
|
||||
.xterm-fg-120 {
|
||||
color: #87ff87;
|
||||
}
|
||||
.xterm-fg-121 {
|
||||
color: #87ffaf;
|
||||
}
|
||||
.xterm-fg-122 {
|
||||
color: #87ffd7;
|
||||
}
|
||||
.xterm-fg-123 {
|
||||
color: #87ffff;
|
||||
}
|
||||
.xterm-fg-124 {
|
||||
color: #af0000;
|
||||
}
|
||||
.xterm-fg-125 {
|
||||
color: #af005f;
|
||||
}
|
||||
.xterm-fg-126 {
|
||||
color: #af0087;
|
||||
}
|
||||
.xterm-fg-127 {
|
||||
color: #af00af;
|
||||
}
|
||||
.xterm-fg-128 {
|
||||
color: #af00d7;
|
||||
}
|
||||
.xterm-fg-129 {
|
||||
color: #af00ff;
|
||||
}
|
||||
.xterm-fg-130 {
|
||||
color: #af5f00;
|
||||
}
|
||||
.xterm-fg-131 {
|
||||
color: #af5f5f;
|
||||
}
|
||||
.xterm-fg-132 {
|
||||
color: #af5f87;
|
||||
}
|
||||
.xterm-fg-133 {
|
||||
color: #af5faf;
|
||||
}
|
||||
.xterm-fg-134 {
|
||||
color: #af5fd7;
|
||||
}
|
||||
.xterm-fg-135 {
|
||||
color: #af5fff;
|
||||
}
|
||||
.xterm-fg-136 {
|
||||
color: #af8700;
|
||||
}
|
||||
.xterm-fg-137 {
|
||||
color: #af875f;
|
||||
}
|
||||
.xterm-fg-138 {
|
||||
color: #af8787;
|
||||
}
|
||||
.xterm-fg-139 {
|
||||
color: #af87af;
|
||||
}
|
||||
.xterm-fg-140 {
|
||||
color: #af87d7;
|
||||
}
|
||||
.xterm-fg-141 {
|
||||
color: #af87ff;
|
||||
}
|
||||
.xterm-fg-142 {
|
||||
color: #afaf00;
|
||||
}
|
||||
.xterm-fg-143 {
|
||||
color: #afaf5f;
|
||||
}
|
||||
.xterm-fg-144 {
|
||||
color: #afaf87;
|
||||
}
|
||||
.xterm-fg-145 {
|
||||
color: #afafaf;
|
||||
}
|
||||
.xterm-fg-146 {
|
||||
color: #afafd7;
|
||||
}
|
||||
.xterm-fg-147 {
|
||||
color: #afafff;
|
||||
}
|
||||
.xterm-fg-148 {
|
||||
color: #afd700;
|
||||
}
|
||||
.xterm-fg-149 {
|
||||
color: #afd75f;
|
||||
}
|
||||
.xterm-fg-150 {
|
||||
color: #afd787;
|
||||
}
|
||||
.xterm-fg-151 {
|
||||
color: #afd7af;
|
||||
}
|
||||
.xterm-fg-152 {
|
||||
color: #afd7d7;
|
||||
}
|
||||
.xterm-fg-153 {
|
||||
color: #afd7ff;
|
||||
}
|
||||
.xterm-fg-154 {
|
||||
color: #afff00;
|
||||
}
|
||||
.xterm-fg-155 {
|
||||
color: #afff5f;
|
||||
}
|
||||
.xterm-fg-156 {
|
||||
color: #afff87;
|
||||
}
|
||||
.xterm-fg-157 {
|
||||
color: #afffaf;
|
||||
}
|
||||
.xterm-fg-158 {
|
||||
color: #afffd7;
|
||||
}
|
||||
.xterm-fg-159 {
|
||||
color: #afffff;
|
||||
}
|
||||
.xterm-fg-160 {
|
||||
color: #d70000;
|
||||
}
|
||||
.xterm-fg-161 {
|
||||
color: #d7005f;
|
||||
}
|
||||
.xterm-fg-162 {
|
||||
color: #d70087;
|
||||
}
|
||||
.xterm-fg-163 {
|
||||
color: #d700af;
|
||||
}
|
||||
.xterm-fg-164 {
|
||||
color: #d700d7;
|
||||
}
|
||||
.xterm-fg-165 {
|
||||
color: #d700ff;
|
||||
}
|
||||
.xterm-fg-166 {
|
||||
color: #d75f00;
|
||||
}
|
||||
.xterm-fg-167 {
|
||||
color: #d75f5f;
|
||||
}
|
||||
.xterm-fg-168 {
|
||||
color: #d75f87;
|
||||
}
|
||||
.xterm-fg-169 {
|
||||
color: #d75faf;
|
||||
}
|
||||
.xterm-fg-170 {
|
||||
color: #d75fd7;
|
||||
}
|
||||
.xterm-fg-171 {
|
||||
color: #d75fff;
|
||||
}
|
||||
.xterm-fg-172 {
|
||||
color: #d78700;
|
||||
}
|
||||
.xterm-fg-173 {
|
||||
color: #d7875f;
|
||||
}
|
||||
.xterm-fg-174 {
|
||||
color: #d78787;
|
||||
}
|
||||
.xterm-fg-175 {
|
||||
color: #d787af;
|
||||
}
|
||||
.xterm-fg-176 {
|
||||
color: #d787d7;
|
||||
}
|
||||
.xterm-fg-177 {
|
||||
color: #d787ff;
|
||||
}
|
||||
.xterm-fg-178 {
|
||||
color: #d7af00;
|
||||
}
|
||||
.xterm-fg-179 {
|
||||
color: #d7af5f;
|
||||
}
|
||||
.xterm-fg-180 {
|
||||
color: #d7af87;
|
||||
}
|
||||
.xterm-fg-181 {
|
||||
color: #d7afaf;
|
||||
}
|
||||
.xterm-fg-182 {
|
||||
color: #d7afd7;
|
||||
}
|
||||
.xterm-fg-183 {
|
||||
color: #d7afff;
|
||||
}
|
||||
.xterm-fg-184 {
|
||||
color: #d7d700;
|
||||
}
|
||||
.xterm-fg-185 {
|
||||
color: #d7d75f;
|
||||
}
|
||||
.xterm-fg-186 {
|
||||
color: #d7d787;
|
||||
}
|
||||
.xterm-fg-187 {
|
||||
color: #d7d7af;
|
||||
}
|
||||
.xterm-fg-188 {
|
||||
color: #d7d7d7;
|
||||
}
|
||||
.xterm-fg-189 {
|
||||
color: #d7d7ff;
|
||||
}
|
||||
.xterm-fg-190 {
|
||||
color: #d7ff00;
|
||||
}
|
||||
.xterm-fg-191 {
|
||||
color: #d7ff5f;
|
||||
}
|
||||
.xterm-fg-192 {
|
||||
color: #d7ff87;
|
||||
}
|
||||
.xterm-fg-193 {
|
||||
color: #d7ffaf;
|
||||
}
|
||||
.xterm-fg-194 {
|
||||
color: #d7ffd7;
|
||||
}
|
||||
.xterm-fg-195 {
|
||||
color: #d7ffff;
|
||||
}
|
||||
.xterm-fg-196 {
|
||||
color: #ff0000;
|
||||
}
|
||||
.xterm-fg-197 {
|
||||
color: #ff005f;
|
||||
}
|
||||
.xterm-fg-198 {
|
||||
color: #ff0087;
|
||||
}
|
||||
.xterm-fg-199 {
|
||||
color: #ff00af;
|
||||
}
|
||||
.xterm-fg-200 {
|
||||
color: #ff00d7;
|
||||
}
|
||||
.xterm-fg-201 {
|
||||
color: #ff00ff;
|
||||
}
|
||||
.xterm-fg-202 {
|
||||
color: #ff5f00;
|
||||
}
|
||||
.xterm-fg-203 {
|
||||
color: #ff5f5f;
|
||||
}
|
||||
.xterm-fg-204 {
|
||||
color: #ff5f87;
|
||||
}
|
||||
.xterm-fg-205 {
|
||||
color: #ff5faf;
|
||||
}
|
||||
.xterm-fg-206 {
|
||||
color: #ff5fd7;
|
||||
}
|
||||
.xterm-fg-207 {
|
||||
color: #ff5fff;
|
||||
}
|
||||
.xterm-fg-208 {
|
||||
color: #ff8700;
|
||||
}
|
||||
.xterm-fg-209 {
|
||||
color: #ff875f;
|
||||
}
|
||||
.xterm-fg-210 {
|
||||
color: #ff8787;
|
||||
}
|
||||
.xterm-fg-211 {
|
||||
color: #ff87af;
|
||||
}
|
||||
.xterm-fg-212 {
|
||||
color: #ff87d7;
|
||||
}
|
||||
.xterm-fg-213 {
|
||||
color: #ff87ff;
|
||||
}
|
||||
.xterm-fg-214 {
|
||||
color: #ffaf00;
|
||||
}
|
||||
.xterm-fg-215 {
|
||||
color: #ffaf5f;
|
||||
}
|
||||
.xterm-fg-216 {
|
||||
color: #ffaf87;
|
||||
}
|
||||
.xterm-fg-217 {
|
||||
color: #ffafaf;
|
||||
}
|
||||
.xterm-fg-218 {
|
||||
color: #ffafd7;
|
||||
}
|
||||
.xterm-fg-219 {
|
||||
color: #ffafff;
|
||||
}
|
||||
.xterm-fg-220 {
|
||||
color: #ffd700;
|
||||
}
|
||||
.xterm-fg-221 {
|
||||
color: #ffd75f;
|
||||
}
|
||||
.xterm-fg-222 {
|
||||
color: #ffd787;
|
||||
}
|
||||
.xterm-fg-223 {
|
||||
color: #ffd7af;
|
||||
}
|
||||
.xterm-fg-224 {
|
||||
color: #ffd7d7;
|
||||
}
|
||||
.xterm-fg-225 {
|
||||
color: #ffd7ff;
|
||||
}
|
||||
.xterm-fg-226 {
|
||||
color: #ffff00;
|
||||
}
|
||||
.xterm-fg-227 {
|
||||
color: #ffff5f;
|
||||
}
|
||||
.xterm-fg-228 {
|
||||
color: #ffff87;
|
||||
}
|
||||
.xterm-fg-229 {
|
||||
color: #ffffaf;
|
||||
}
|
||||
.xterm-fg-230 {
|
||||
color: #ffffd7;
|
||||
}
|
||||
.xterm-fg-231 {
|
||||
color: #ffffff;
|
||||
}
|
||||
.xterm-fg-232 {
|
||||
color: #080808;
|
||||
}
|
||||
.xterm-fg-233 {
|
||||
color: #121212;
|
||||
}
|
||||
.xterm-fg-234 {
|
||||
color: #1c1c1c;
|
||||
}
|
||||
.xterm-fg-235 {
|
||||
color: #262626;
|
||||
}
|
||||
.xterm-fg-236 {
|
||||
color: #303030;
|
||||
}
|
||||
.xterm-fg-237 {
|
||||
color: #3a3a3a;
|
||||
}
|
||||
.xterm-fg-238 {
|
||||
color: #444444;
|
||||
}
|
||||
.xterm-fg-239 {
|
||||
color: #4e4e4e;
|
||||
}
|
||||
.xterm-fg-240 {
|
||||
color: #585858;
|
||||
}
|
||||
.xterm-fg-241 {
|
||||
color: #626262;
|
||||
}
|
||||
.xterm-fg-242 {
|
||||
color: #6c6c6c;
|
||||
}
|
||||
.xterm-fg-243 {
|
||||
color: #767676;
|
||||
}
|
||||
.xterm-fg-244 {
|
||||
color: #808080;
|
||||
}
|
||||
.xterm-fg-245 {
|
||||
color: #8a8a8a;
|
||||
}
|
||||
.xterm-fg-246 {
|
||||
color: #949494;
|
||||
}
|
||||
.xterm-fg-247 {
|
||||
color: #9e9e9e;
|
||||
}
|
||||
.xterm-fg-248 {
|
||||
color: #a8a8a8;
|
||||
}
|
||||
.xterm-fg-249 {
|
||||
color: #b2b2b2;
|
||||
}
|
||||
.xterm-fg-250 {
|
||||
color: #bcbcbc;
|
||||
}
|
||||
.xterm-fg-251 {
|
||||
color: #c6c6c6;
|
||||
}
|
||||
.xterm-fg-252 {
|
||||
color: #d0d0d0;
|
||||
}
|
||||
.xterm-fg-253 {
|
||||
color: #dadada;
|
||||
}
|
||||
.xterm-fg-254 {
|
||||
color: #e4e4e4;
|
||||
}
|
||||
.xterm-fg-255 {
|
||||
color: #eeeeee;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,11 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.clear-block {
|
||||
margin-bottom: $gl-padding - 1px;
|
||||
padding-bottom: $gl-padding;
|
||||
}
|
||||
|
||||
&.second-block {
|
||||
margin-top: -1px;
|
||||
margin-bottom: 0;
|
||||
|
||||
@@ -377,4 +377,16 @@ table {
|
||||
height: 56px;
|
||||
margin-top: -$gl-padding;
|
||||
padding-top: $gl-padding;
|
||||
|
||||
&.no-bottom {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dropzone .dz-preview .dz-progress {
|
||||
border-color: $border-color !important;
|
||||
}
|
||||
|
||||
.dropzone .dz-preview .dz-progress .dz-upload {
|
||||
background: $gl-success !important;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ace_gutter-cell {
|
||||
background-color: $background-color;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
color: #B94A48;
|
||||
&:hover {
|
||||
@@ -32,14 +36,12 @@
|
||||
|
||||
.file-title {
|
||||
@extend .monospace;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.editor-ref {
|
||||
background: $background-color;
|
||||
padding: 11px 15px;
|
||||
border-right: 1px solid #CCC;
|
||||
border-right: 1px solid $border-color;
|
||||
display: inline-block;
|
||||
margin: -5px -5px;
|
||||
margin-right: 10px;
|
||||
@@ -50,5 +52,15 @@
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
margin-top: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin: -$gl-padding;
|
||||
margin-top: 0;
|
||||
padding: $gl-padding
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,3 +116,16 @@
|
||||
}
|
||||
|
||||
#modal-remove-blob > .modal-dialog { width: 850px; }
|
||||
|
||||
.blob-upload-dropzone-previews {
|
||||
text-align: center;
|
||||
border: 2px;
|
||||
border-style: dashed;
|
||||
border-color: $border-color;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.upload-link {
|
||||
font-weight: normal;
|
||||
color: $md-link-color;
|
||||
}
|
||||
|
||||
@@ -134,9 +134,6 @@ class ApplicationController < ActionController::Base
|
||||
|
||||
def repository
|
||||
@repository ||= project.repository
|
||||
rescue Grit::NoSuchPathError => e
|
||||
log_exception(e)
|
||||
nil
|
||||
end
|
||||
|
||||
def authorize_project!(action)
|
||||
|
||||
@@ -32,6 +32,7 @@ class AutocompleteController < ApplicationController
|
||||
@users ||= User.none
|
||||
@users = @users.search(params[:search]) if params[:search].present?
|
||||
@users = @users.active
|
||||
@users = @users.reorder(:name)
|
||||
@users = @users.page(params[:page]).per(PER_PAGE)
|
||||
|
||||
unless params[:search].present?
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
module Ci
|
||||
module Admin
|
||||
class ApplicationController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :authenticate_admin!
|
||||
|
||||
layout "ci/admin"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
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
|
||||
@@ -0,0 +1,18 @@
|
||||
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
|
||||
@@ -0,0 +1,9 @@
|
||||
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
|
||||
@@ -0,0 +1,19 @@
|
||||
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
|
||||
@@ -0,0 +1,34 @@
|
||||
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
|
||||
@@ -0,0 +1,69 @@
|
||||
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.where("contacted_at > ?", 1.minutes.ago).count
|
||||
end
|
||||
|
||||
def show
|
||||
@builds = @runner.builds.order('id DESC').first(30)
|
||||
@projects = Ci::Project.all
|
||||
@projects = @projects.search(params[:search]) if params[:search].present?
|
||||
@projects = @projects.where("ci_projects.id NOT IN (?)", @runner.projects.pluck(: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 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, :contacted_at, :active)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,76 @@
|
||||
module Ci
|
||||
class ApplicationController < ::ApplicationController
|
||||
def self.railtie_helpers_paths
|
||||
"app/helpers/ci"
|
||||
end
|
||||
|
||||
helper_method :gl_project
|
||||
|
||||
private
|
||||
|
||||
def authenticate_public_page!
|
||||
unless project.public
|
||||
unless current_user
|
||||
redirect_to(new_user_sessions_path) and return
|
||||
end
|
||||
|
||||
return access_denied! unless can?(current_user, :read_project, gl_project)
|
||||
end
|
||||
end
|
||||
|
||||
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)
|
||||
return page_404
|
||||
end
|
||||
end
|
||||
|
||||
def authorize_manage_builds!
|
||||
unless can?(current_user, :admin_project, gl_project)
|
||||
return page_404
|
||||
end
|
||||
end
|
||||
|
||||
def authenticate_admin!
|
||||
return render_404 unless current_user.is_admin?
|
||||
end
|
||||
|
||||
def authorize_manage_project!
|
||||
unless can?(current_user, :admin_project, gl_project)
|
||||
return page_404
|
||||
end
|
||||
end
|
||||
|
||||
def page_404
|
||||
render file: "#{Rails.root}/public/404.html", status: 404, layout: false
|
||||
end
|
||||
|
||||
def default_headers
|
||||
headers['X-Frame-Options'] = 'DENY'
|
||||
headers['X-XSS-Protection'] = '1; mode=block'
|
||||
end
|
||||
|
||||
# JSON for infinite scroll via Pager object
|
||||
def pager_json(partial, count)
|
||||
html = render_to_string(
|
||||
partial,
|
||||
layout: false,
|
||||
formats: [:html]
|
||||
)
|
||||
|
||||
render json: {
|
||||
html: html,
|
||||
count: count
|
||||
}
|
||||
end
|
||||
|
||||
def gl_project
|
||||
::Project.find(@project.gitlab_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,78 @@
|
||||
module Ci
|
||||
class BuildsController < Ci::ApplicationController
|
||||
before_action :authenticate_user!, except: [:status, :show]
|
||||
before_action :authenticate_public_page!, only: :show
|
||||
before_action :project
|
||||
before_action :authorize_access_project!, except: [:status, :show]
|
||||
before_action :authorize_manage_project!, except: [:status, :show, :retry, :cancel]
|
||||
before_action :authorize_manage_builds!, only: [:retry, :cancel]
|
||||
before_action :build, except: [:show]
|
||||
layout 'ci/build'
|
||||
|
||||
def show
|
||||
if params[:id] =~ /\A\d+\Z/
|
||||
@build = build
|
||||
else
|
||||
# try to find commit by sha
|
||||
commit = commit_by_sha
|
||||
|
||||
if commit
|
||||
# Redirect to commit page
|
||||
redirect_to ci_project_ref_commit_path(@project, @build.commit.ref, @build.commit.sha)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
raise ActiveRecord::RecordNotFound unless @build
|
||||
|
||||
@builds = @project.commits.find_by_sha(@build.sha).builds.order('id DESC')
|
||||
@builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20)
|
||||
@commit = @build.commit
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: @build.to_json(methods: :trace_html)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def retry
|
||||
if @build.commands.blank?
|
||||
return page_404
|
||||
end
|
||||
|
||||
build = Ci::Build.retry(@build)
|
||||
|
||||
if params[:return_to]
|
||||
redirect_to URI.parse(params[:return_to]).path
|
||||
else
|
||||
redirect_to ci_project_build_path(project, build)
|
||||
end
|
||||
end
|
||||
|
||||
def status
|
||||
render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
|
||||
end
|
||||
|
||||
def cancel
|
||||
@build.cancel
|
||||
|
||||
redirect_to ci_project_build_path(@project, @build)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def project
|
||||
@project = Ci::Project.find(params[:project_id])
|
||||
end
|
||||
|
||||
def build
|
||||
@build ||= project.builds.unscoped.find_by(id: params[:id])
|
||||
end
|
||||
|
||||
def commit_by_sha
|
||||
@project.commits.find_by(sha: params[:id])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
module Ci
|
||||
class ChartsController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :project
|
||||
before_action :authorize_access_project!
|
||||
before_action :authorize_manage_project!
|
||||
|
||||
layout 'ci/project'
|
||||
|
||||
def show
|
||||
@charts = {}
|
||||
@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
|
||||
|
||||
protected
|
||||
|
||||
def project
|
||||
@project = Ci::Project.find(params[:project_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,38 @@
|
||||
module Ci
|
||||
class CommitsController < Ci::ApplicationController
|
||||
before_action :authenticate_user!, except: [:status, :show]
|
||||
before_action :authenticate_public_page!, only: :show
|
||||
before_action :project
|
||||
before_action :authorize_access_project!, except: [:status, :show, :cancel]
|
||||
before_action :authorize_manage_builds!, only: [:cancel]
|
||||
before_action :commit, only: :show
|
||||
layout 'ci/commit'
|
||||
|
||||
def show
|
||||
@builds = @commit.builds
|
||||
end
|
||||
|
||||
def status
|
||||
commit = Ci::Project.find(params[:project_id]).commits.find_by_sha_and_ref!(params[:id], params[:ref_id])
|
||||
render json: commit.to_json(only: [:id, :sha], methods: [:status, :coverage])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render json: { status: "not_found" }
|
||||
end
|
||||
|
||||
def cancel
|
||||
commit.builds.running_or_pending.each(&:cancel)
|
||||
|
||||
redirect_to ci_project_ref_commits_path(project, commit.ref, commit.sha)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project
|
||||
@project ||= Ci::Project.find(params[:project_id])
|
||||
end
|
||||
|
||||
def commit
|
||||
@commit ||= Ci::Project.find(params[:project_id]).commits.find_by_sha_and_ref!(params[:id], params[:ref_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
module Ci
|
||||
class EventsController < Ci::ApplicationController
|
||||
EVENTS_PER_PAGE = 50
|
||||
|
||||
before_action :authenticate_user!
|
||||
before_action :project
|
||||
before_action :authorize_manage_project!
|
||||
|
||||
layout 'ci/project'
|
||||
|
||||
def index
|
||||
@events = project.events.order("created_at DESC").page(params[:page]).per(EVENTS_PER_PAGE)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project
|
||||
@project ||= Ci::Project.find(params[:project_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,16 @@
|
||||
module Ci
|
||||
class HelpsController < Ci::ApplicationController
|
||||
skip_filter :check_config
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def oauth2
|
||||
if valid_config?
|
||||
redirect_to ci_root_path
|
||||
else
|
||||
render layout: 'ci/empty'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
module Ci
|
||||
class LintsController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def create
|
||||
if params[:content].blank?
|
||||
@status = false
|
||||
@error = "Please provide content of .gitlab-ci.yml"
|
||||
else
|
||||
@config_processor = Ci::GitlabCiYamlProcessor.new params[:content]
|
||||
@stages = @config_processor.stages
|
||||
@builds = @config_processor.builds
|
||||
@status = true
|
||||
end
|
||||
rescue Ci::GitlabCiYamlProcessor::ValidationError => e
|
||||
@error = e.message
|
||||
@status = false
|
||||
rescue Exception => e
|
||||
@error = "Undefined error"
|
||||
@status = false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,137 @@
|
||||
module Ci
|
||||
class ProjectsController < Ci::ApplicationController
|
||||
PROJECTS_BATCH = 100
|
||||
|
||||
before_action :authenticate_user!, except: [:build, :badge, :index, :show]
|
||||
before_action :authenticate_public_page!, only: :show
|
||||
before_action :project, only: [:build, :integration, :show, :badge, :edit, :update, :destroy, :toggle_shared_runners, :dumped_yaml]
|
||||
before_action :authorize_access_project!, except: [:build, :gitlab, :badge, :index, :show, :new, :create]
|
||||
before_action :authorize_manage_project!, only: [:edit, :integration, :update, :destroy, :toggle_shared_runners, :dumped_yaml]
|
||||
before_action :authenticate_token!, only: [:build]
|
||||
before_action :no_cache, only: [:badge]
|
||||
protect_from_forgery except: :build
|
||||
|
||||
layout 'ci/project', except: [:index, :gitlab]
|
||||
|
||||
def index
|
||||
@projects = Ci::Project.ordered_by_last_commit_date.public_only.page(params[:page]) unless current_user
|
||||
end
|
||||
|
||||
def gitlab
|
||||
@limit, @offset = (params[:limit] || PROJECTS_BATCH).to_i, (params[:offset] || 0).to_i
|
||||
@page = @offset == 0 ? 1 : (@offset / @limit + 1)
|
||||
|
||||
@gl_projects = current_user.authorized_projects
|
||||
@gl_projects = @gl_projects.where("name LIKE ?", "%#{params[:search]}%") if params[:search]
|
||||
@gl_projects = @gl_projects.page(@page).per(@limit)
|
||||
|
||||
@projects = Ci::Project.where(gitlab_id: @gl_projects.map(&:id)).ordered_by_last_commit_date
|
||||
@total_count = @gl_projects.size
|
||||
|
||||
@gl_projects = @gl_projects.where.not(id: @projects.map(&:gitlab_id))
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
pager_json("ci/projects/gitlab", @total_count)
|
||||
end
|
||||
end
|
||||
rescue
|
||||
@error = 'Failed to fetch GitLab projects'
|
||||
end
|
||||
|
||||
def show
|
||||
@ref = params[:ref]
|
||||
|
||||
@commits = @project.commits.reverse_order
|
||||
@commits = @commits.where(ref: @ref) if @ref
|
||||
@commits = @commits.page(params[:page]).per(20)
|
||||
end
|
||||
|
||||
def integration
|
||||
end
|
||||
|
||||
def create
|
||||
project_data = OpenStruct.new(JSON.parse(params["project"]))
|
||||
|
||||
unless can?(current_user, :admin_project, ::Project.find(project_data.id))
|
||||
return redirect_to ci_root_path, alert: 'You have to have at least master role to enable CI for this project'
|
||||
end
|
||||
|
||||
@project = Ci::CreateProjectService.new.execute(current_user, project_data, ci_project_url(":project_id"))
|
||||
|
||||
if @project.persisted?
|
||||
redirect_to ci_project_path(@project, show_guide: true), notice: 'Project was successfully created.'
|
||||
else
|
||||
redirect_to :back, alert: 'Cannot save project'
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if project.update_attributes(project_params)
|
||||
Ci::EventService.new.change_project_settings(current_user, project)
|
||||
|
||||
redirect_to :back, notice: 'Project was successfully updated.'
|
||||
else
|
||||
render action: "edit"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
project.gl_project.gitlab_ci_service.update_attributes(active: false)
|
||||
project.destroy
|
||||
|
||||
Ci::EventService.new.remove_project(current_user, project)
|
||||
|
||||
redirect_to ci_projects_url
|
||||
end
|
||||
|
||||
def build
|
||||
@commit = Ci::CreateCommitService.new.execute(@project, params.dup)
|
||||
|
||||
if @commit && @commit.valid?
|
||||
head 201
|
||||
else
|
||||
head 400
|
||||
end
|
||||
end
|
||||
|
||||
# Project status badge
|
||||
# Image with build status for sha or ref
|
||||
def badge
|
||||
image = Ci::ImageForBuildService.new.execute(@project, params)
|
||||
|
||||
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 :back
|
||||
end
|
||||
|
||||
def dumped_yaml
|
||||
send_data @project.generated_yaml_config, filename: '.gitlab-ci.yml'
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def project
|
||||
@project ||= Ci::Project.find(params[:id])
|
||||
end
|
||||
|
||||
def no_cache
|
||||
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
|
||||
response.headers["Pragma"] = "no-cache"
|
||||
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
module Ci
|
||||
class RunnerProjectsController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :project
|
||||
before_action :authorize_manage_project!
|
||||
|
||||
layout 'ci/project'
|
||||
|
||||
def create
|
||||
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
|
||||
|
||||
return head(403) unless current_user.ci_authorized_runners.include?(@runner)
|
||||
|
||||
if @runner.assign_to(project, current_user)
|
||||
redirect_to ci_project_runners_path(project)
|
||||
else
|
||||
redirect_to ci_project_runners_path(project), alert: 'Failed adding runner to project'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
runner_project = project.runner_projects.find(params[:id])
|
||||
runner_project.destroy
|
||||
|
||||
redirect_to ci_project_runners_path(project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project
|
||||
@project ||= Ci::Project.find(params[:project_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,73 @@
|
||||
module Ci
|
||||
class RunnersController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :project
|
||||
before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
|
||||
before_action :authorize_access_project!
|
||||
before_action :authorize_manage_project!
|
||||
|
||||
layout 'ci/project'
|
||||
|
||||
def index
|
||||
@runners = @project.runners.order('id DESC')
|
||||
@specific_runners =
|
||||
Ci::Runner.specific.includes(:runner_projects).
|
||||
where(Ci::RunnerProject.table_name => { project_id: current_user.authorized_projects } ).
|
||||
where.not(id: @runners).order("#{Ci::Runner.table_name}.id DESC").page(params[:page]).per(20)
|
||||
@shared_runners = Ci::Runner.shared.active
|
||||
@shared_runners_count = @shared_runners.count(:all)
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @runner.update_attributes(runner_params)
|
||||
redirect_to edit_ci_project_runner_path(@project, @runner), notice: 'Runner was successfully updated.'
|
||||
else
|
||||
redirect_to edit_ci_project_runner_path(@project, @runner), alert: 'Runner was not updated.'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @runner.only_for?(@project)
|
||||
@runner.destroy
|
||||
end
|
||||
|
||||
redirect_to ci_project_runners_path(@project)
|
||||
end
|
||||
|
||||
def resume
|
||||
if @runner.update_attributes(active: true)
|
||||
redirect_to ci_project_runners_path(@project, @runner), notice: 'Runner was successfully updated.'
|
||||
else
|
||||
redirect_to ci_project_runners_path(@project, @runner), alert: 'Runner was not updated.'
|
||||
end
|
||||
end
|
||||
|
||||
def pause
|
||||
if @runner.update_attributes(active: false)
|
||||
redirect_to ci_project_runners_path(@project, @runner), notice: 'Runner was successfully updated.'
|
||||
else
|
||||
redirect_to ci_project_runners_path(@project, @runner), alert: 'Runner was not updated.'
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def project
|
||||
@project = Ci::Project.find(params[:project_id])
|
||||
end
|
||||
|
||||
def set_runner
|
||||
@runner ||= @project.runners.find(params[:id])
|
||||
end
|
||||
|
||||
def runner_params
|
||||
params.require(:runner).permit(:description, :tag_list, :contacted_at, :active)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,59 @@
|
||||
module Ci
|
||||
class ServicesController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :project
|
||||
before_action :authorize_access_project!
|
||||
before_action :authorize_manage_project!
|
||||
before_action :service, only: [:edit, :update, :test]
|
||||
|
||||
respond_to :html
|
||||
|
||||
layout 'ci/project'
|
||||
|
||||
def index
|
||||
@project.build_missing_services
|
||||
@services = @project.services.reload
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @service.update_attributes(service_params)
|
||||
redirect_to edit_ci_project_service_path(@project, @service.to_param)
|
||||
else
|
||||
render 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
def test
|
||||
last_build = @project.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_to :back, message
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project
|
||||
@project = Ci::Project.find(params[:project_id])
|
||||
end
|
||||
|
||||
def service
|
||||
@service ||= @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
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
module Ci
|
||||
class TriggersController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :project
|
||||
before_action :authorize_access_project!
|
||||
before_action :authorize_manage_project!
|
||||
|
||||
layout 'ci/project'
|
||||
|
||||
def index
|
||||
@triggers = @project.triggers
|
||||
@trigger = Ci::Trigger.new
|
||||
end
|
||||
|
||||
def create
|
||||
@trigger = @project.triggers.new
|
||||
@trigger.save
|
||||
|
||||
if @trigger.valid?
|
||||
redirect_to ci_project_triggers_path(@project)
|
||||
else
|
||||
@triggers = @project.triggers.select(&:persisted?)
|
||||
render :index
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
trigger.destroy
|
||||
|
||||
redirect_to ci_project_triggers_path(@project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def trigger
|
||||
@trigger ||= @project.triggers.find(params[:id])
|
||||
end
|
||||
|
||||
def project
|
||||
@project = Ci::Project.find(params[:project_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
module Ci
|
||||
class VariablesController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :project
|
||||
before_action :authorize_access_project!
|
||||
before_action :authorize_manage_project!
|
||||
|
||||
layout 'ci/project'
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def update
|
||||
if project.update_attributes(project_params)
|
||||
Ci::EventService.new.change_project_settings(current_user, project)
|
||||
|
||||
redirect_to ci_project_variables_path(project), notice: 'Variables were successfully updated.'
|
||||
else
|
||||
render action: 'show'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project
|
||||
@project ||= Ci::Project.find(params[:project_id])
|
||||
end
|
||||
|
||||
def project_params
|
||||
params.require(:project).permit({ variables_attributes: [:id, :key, :value, :_destroy] })
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,53 @@
|
||||
module Ci
|
||||
class WebHooksController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :project
|
||||
before_action :authorize_access_project!
|
||||
before_action :authorize_manage_project!
|
||||
|
||||
layout 'ci/project'
|
||||
|
||||
def index
|
||||
@web_hooks = @project.web_hooks
|
||||
@web_hook = Ci::WebHook.new
|
||||
end
|
||||
|
||||
def create
|
||||
@web_hook = @project.web_hooks.new(web_hook_params)
|
||||
@web_hook.save
|
||||
|
||||
if @web_hook.valid?
|
||||
redirect_to ci_project_web_hooks_path(@project)
|
||||
else
|
||||
@web_hooks = @project.web_hooks.select(&:persisted?)
|
||||
render :index
|
||||
end
|
||||
end
|
||||
|
||||
def test
|
||||
Ci::TestHookService.new.execute(hook, current_user)
|
||||
|
||||
redirect_to :back
|
||||
end
|
||||
|
||||
def destroy
|
||||
hook.destroy
|
||||
|
||||
redirect_to ci_project_web_hooks_path(@project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def hook
|
||||
@web_hook ||= @project.web_hooks.find(params[:id])
|
||||
end
|
||||
|
||||
def project
|
||||
@project = Ci::Project.find(params[:project_id])
|
||||
end
|
||||
|
||||
def web_hook_params
|
||||
params.require(:web_hook).permit(:url)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,6 @@ class Import::FogbugzController < Import::BaseController
|
||||
before_action :verify_fogbugz_import_enabled
|
||||
before_action :user_map, only: [:new_user_map, :create_user_map]
|
||||
|
||||
# Doesn't work yet due to bug in ruby-fogbugz, see below
|
||||
rescue_from Fogbugz::AuthenticationException, with: :fogbugz_unauthorized
|
||||
|
||||
def new
|
||||
@@ -13,8 +12,8 @@ class Import::FogbugzController < Import::BaseController
|
||||
begin
|
||||
res = Gitlab::FogbugzImport::Client.new(import_params.symbolize_keys)
|
||||
rescue
|
||||
# Needed until https://github.com/firmafon/ruby-fogbugz/pull/9 is merged
|
||||
return redirect_to :back, alert: 'Could not authenticate with FogBugz, check your URL, email, and password'
|
||||
# If the URI is invalid various errors can occur
|
||||
return redirect_to new_import_fogbugz_path, alert: 'Could not connect to FogBugz, check your URL'
|
||||
end
|
||||
session[:fogbugz_token] = res.get_token
|
||||
session[:fogbugz_uri] = params[:uri]
|
||||
@@ -92,8 +91,7 @@ class Import::FogbugzController < Import::BaseController
|
||||
end
|
||||
|
||||
def fogbugz_unauthorized(exception)
|
||||
flash[:alert] = exception.message
|
||||
redirect_to new_import_fogbugz_path
|
||||
redirect_to new_import_fogbugz_path, alert: exception.message
|
||||
end
|
||||
|
||||
def import_params
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
|
||||
include Gitlab::CurrentSettings
|
||||
include PageLayoutHelper
|
||||
|
||||
|
||||
before_action :verify_user_oauth_applications_enabled
|
||||
before_action :authenticate_user!
|
||||
|
||||
|
||||
@@ -18,6 +18,12 @@ class Projects::BlobController < Projects::ApplicationController
|
||||
before_action :after_edit_path, only: [:edit, :update]
|
||||
|
||||
def new
|
||||
@title = 'Upload'
|
||||
@placeholder = 'Upload new file'
|
||||
@button_title = 'Upload file'
|
||||
@form_path = namespace_project_create_blob_path(@project.namespace, @project, @id)
|
||||
@method = :post
|
||||
|
||||
commit unless @repository.empty?
|
||||
end
|
||||
|
||||
@@ -26,14 +32,25 @@ class Projects::BlobController < Projects::ApplicationController
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully committed"
|
||||
redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path))
|
||||
respond_to do |format|
|
||||
format.html { redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) }
|
||||
format.json { render json: { message: "success", filePath: namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) } }
|
||||
end
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
render :new
|
||||
respond_to do |format|
|
||||
format.html { render :new }
|
||||
format.json { render json: { message: "failed", filePath: namespace_project_new_blob_path(@project.namespace, @project, @id) } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@title = "Replace #{@blob.name}"
|
||||
@placeholder = @title
|
||||
@button_title = 'Replace file'
|
||||
@form_path = namespace_project_update_blob_path(@project.namespace, @project, @id)
|
||||
@method = :put
|
||||
end
|
||||
|
||||
def edit
|
||||
@@ -45,10 +62,16 @@ class Projects::BlobController < Projects::ApplicationController
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully committed"
|
||||
redirect_to after_edit_path
|
||||
respond_to do |format|
|
||||
format.html { redirect_to after_edit_path }
|
||||
format.json { render json: { message: "success", filePath: after_edit_path } }
|
||||
end
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
render :edit
|
||||
respond_to do |format|
|
||||
format.html { render :edit }
|
||||
format.json { render json: { message: "failed", filePath: namespace_project_new_blob_path(@project.namespace, @project, @id) } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -146,11 +169,19 @@ class Projects::BlobController < Projects::ApplicationController
|
||||
|
||||
@file_path =
|
||||
if action_name.to_s == 'create'
|
||||
if params[:file].present?
|
||||
params[:file_name] = params[:file].original_filename
|
||||
end
|
||||
File.join(@path, File.basename(params[:file_name]))
|
||||
else
|
||||
@path
|
||||
end
|
||||
|
||||
if params[:file].present?
|
||||
params[:content] = Base64.encode64(params[:file].read)
|
||||
params[:encoding] = 'base64'
|
||||
end
|
||||
|
||||
@commit_params = {
|
||||
file_path: @file_path,
|
||||
current_branch: @current_branch,
|
||||
|
||||
@@ -82,7 +82,7 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
def default_avatar
|
||||
image_path('no_avatar.png')
|
||||
'no_avatar.png'
|
||||
end
|
||||
|
||||
def last_commit(project)
|
||||
|
||||
@@ -40,7 +40,7 @@ module AuthHelper
|
||||
if provider_has_icon?(provider)
|
||||
file_name = "#{provider.to_s.split('_').first}_#{size}.png"
|
||||
|
||||
image_tag(image_path("auth_buttons/#{file_name}"), alt: label, title: "Sign in with #{label}")
|
||||
image_tag("auth_buttons/#{file_name}", alt: label, title: "Sign in with #{label}")
|
||||
else
|
||||
label
|
||||
end
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
module Ci
|
||||
module ApplicationHelper
|
||||
def loader_html
|
||||
image_tag 'ci/loader.gif', alt: 'Loading'
|
||||
end
|
||||
|
||||
# Navigation link helper
|
||||
#
|
||||
# Returns an `li` element with an 'active' class if the supplied
|
||||
# controller(s) and/or action(s) are currently active. The content of the
|
||||
# element is the value passed to the block.
|
||||
#
|
||||
# options - The options hash used to determine if the element is "active" (default: {})
|
||||
# :controller - One or more controller names to check (optional).
|
||||
# :action - One or more action names to check (optional).
|
||||
# :path - A shorthand path, such as 'dashboard#index', to check (optional).
|
||||
# :html_options - Extra options to be passed to the list element (optional).
|
||||
# block - An optional block that will become the contents of the returned
|
||||
# `li` element.
|
||||
#
|
||||
# When both :controller and :action are specified, BOTH must match in order
|
||||
# to be marked as active. When only one is given, either can match.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# # Assuming we're on TreeController#show
|
||||
#
|
||||
# # Controller matches, but action doesn't
|
||||
# nav_link(controller: [:tree, :refs], action: :edit) { "Hello" }
|
||||
# # => '<li>Hello</li>'
|
||||
#
|
||||
# # Controller matches
|
||||
# nav_link(controller: [:tree, :refs]) { "Hello" }
|
||||
# # => '<li class="active">Hello</li>'
|
||||
#
|
||||
# # Shorthand path
|
||||
# nav_link(path: 'tree#show') { "Hello" }
|
||||
# # => '<li class="active">Hello</li>'
|
||||
#
|
||||
# # Supplying custom options for the list element
|
||||
# nav_link(controller: :tree, html_options: {class: 'home'}) { "Hello" }
|
||||
# # => '<li class="home active">Hello</li>'
|
||||
#
|
||||
# Returns a list item element String
|
||||
def nav_link(options = {}, &block)
|
||||
if path = options.delete(:path)
|
||||
if path.respond_to?(:each)
|
||||
c = path.map { |p| p.split('#').first }
|
||||
a = path.map { |p| p.split('#').last }
|
||||
else
|
||||
c, a, _ = path.split('#')
|
||||
end
|
||||
else
|
||||
c = options.delete(:controller)
|
||||
a = options.delete(:action)
|
||||
end
|
||||
|
||||
if c && a
|
||||
# When given both options, make sure BOTH are active
|
||||
klass = current_controller?(*c) && current_action?(*a) ? 'active' : ''
|
||||
else
|
||||
# Otherwise check EITHER option
|
||||
klass = current_controller?(*c) || current_action?(*a) ? 'active' : ''
|
||||
end
|
||||
|
||||
# Add our custom class into the html_options, which may or may not exist
|
||||
# and which may or may not already have a :class key
|
||||
o = options.delete(:html_options) || {}
|
||||
o[:class] ||= ''
|
||||
o[:class] += ' ' + klass
|
||||
o[:class].strip!
|
||||
|
||||
if block_given?
|
||||
content_tag(:li, capture(&block), o)
|
||||
else
|
||||
content_tag(:li, nil, o)
|
||||
end
|
||||
end
|
||||
|
||||
# Check if a particular controller is the current one
|
||||
#
|
||||
# args - One or more controller names to check
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# # On TreeController
|
||||
# current_controller?(:tree) # => true
|
||||
# current_controller?(:commits) # => false
|
||||
# current_controller?(:commits, :tree) # => true
|
||||
def current_controller?(*args)
|
||||
args.any? { |v| v.to_s.downcase == controller.controller_name }
|
||||
end
|
||||
|
||||
# Check if a particular action is the current one
|
||||
#
|
||||
# args - One or more action names to check
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# # On Projects#new
|
||||
# current_action?(:new) # => true
|
||||
# current_action?(:create) # => false
|
||||
# current_action?(:new, :create) # => true
|
||||
def current_action?(*args)
|
||||
args.any? { |v| v.to_s.downcase == action_name }
|
||||
end
|
||||
|
||||
def date_from_to(from, to)
|
||||
"#{from.to_s(:short)} - #{to.to_s(:short)}"
|
||||
end
|
||||
|
||||
def body_data_page
|
||||
path = controller.controller_path.split('/')
|
||||
namespace = path.first if path.second
|
||||
|
||||
[namespace, controller.controller_name, controller.action_name].compact.join(":")
|
||||
end
|
||||
|
||||
def duration_in_words(finished_at, started_at)
|
||||
if finished_at && started_at
|
||||
interval_in_seconds = finished_at.to_i - started_at.to_i
|
||||
elsif started_at
|
||||
interval_in_seconds = Time.now.to_i - started_at.to_i
|
||||
end
|
||||
|
||||
time_interval_in_words(interval_in_seconds)
|
||||
end
|
||||
|
||||
def time_interval_in_words(interval_in_seconds)
|
||||
minutes = interval_in_seconds / 60
|
||||
seconds = interval_in_seconds - minutes * 60
|
||||
|
||||
if minutes >= 1
|
||||
"#{pluralize(minutes, "minute")} #{pluralize(seconds, "second")}"
|
||||
else
|
||||
"#{pluralize(seconds, "second")}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,41 @@
|
||||
module Ci
|
||||
module BuildsHelper
|
||||
def build_ref_link build
|
||||
gitlab_ref_link build.project, build.ref
|
||||
end
|
||||
|
||||
def build_compare_link build
|
||||
gitlab_compare_link build.project, build.commit.short_before_sha, build.short_sha
|
||||
end
|
||||
|
||||
def build_commit_link build
|
||||
gitlab_commit_link build.project, build.short_sha
|
||||
end
|
||||
|
||||
def build_url(build)
|
||||
ci_project_build_url(build.project, build)
|
||||
end
|
||||
|
||||
def build_status_alert_class(build)
|
||||
if build.success?
|
||||
'alert-success'
|
||||
elsif build.failed?
|
||||
'alert-danger'
|
||||
elsif build.canceled?
|
||||
'alert-disabled'
|
||||
else
|
||||
'alert-warning'
|
||||
end
|
||||
end
|
||||
|
||||
def build_icon_css_class(build)
|
||||
if build.success?
|
||||
'fa-circle cgreen'
|
||||
elsif build.failed?
|
||||
'fa-circle cred'
|
||||
else
|
||||
'fa-circle light'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
module Ci
|
||||
module CommitsHelper
|
||||
def commit_status_alert_class(commit)
|
||||
return 'alert-info' unless commit
|
||||
|
||||
case commit.status
|
||||
when 'success'
|
||||
'alert-success'
|
||||
when 'failed', 'canceled'
|
||||
'alert-danger'
|
||||
when 'skipped'
|
||||
'alert-disabled'
|
||||
else
|
||||
'alert-warning'
|
||||
end
|
||||
end
|
||||
|
||||
def ci_commit_path(commit)
|
||||
ci_project_ref_commits_path(commit.project, commit.ref, commit.sha)
|
||||
end
|
||||
|
||||
def commit_link(commit)
|
||||
link_to(commit.short_sha, ci_commit_path(commit))
|
||||
end
|
||||
|
||||
def truncate_first_line(message, length = 50)
|
||||
truncate(message.each_line.first.chomp, length: length) if message
|
||||
end
|
||||
|
||||
def ci_commit_title(commit)
|
||||
content_tag :span do
|
||||
link_to(
|
||||
simple_sanitize(commit.project.name), ci_project_path(commit.project)
|
||||
) + ' @ ' +
|
||||
gitlab_commit_link(@project, @commit.sha)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
module Ci
|
||||
module GitlabHelper
|
||||
def no_turbolink
|
||||
{ :"data-no-turbolink" => "data-no-turbolink" }
|
||||
end
|
||||
|
||||
def gitlab_ref_link project, ref
|
||||
gitlab_url = project.gitlab_url.dup
|
||||
gitlab_url << "/commits/#{ref}"
|
||||
link_to ref, gitlab_url, no_turbolink
|
||||
end
|
||||
|
||||
def gitlab_compare_link project, before, after
|
||||
gitlab_url = project.gitlab_url.dup
|
||||
gitlab_url << "/compare/#{before}...#{after}"
|
||||
|
||||
link_to "#{before}...#{after}", gitlab_url, no_turbolink
|
||||
end
|
||||
|
||||
def gitlab_commit_link project, sha
|
||||
gitlab_url = project.gitlab_url.dup
|
||||
gitlab_url << "/commit/#{sha}"
|
||||
link_to Ci::Commit.truncate_sha(sha), gitlab_url, no_turbolink
|
||||
end
|
||||
|
||||
def yaml_web_editor_link(project)
|
||||
commits = project.commits
|
||||
|
||||
if commits.any? && commits.last.push_data[:ci_yaml_file]
|
||||
"#{@project.gitlab_url}/edit/master/.gitlab-ci.yml"
|
||||
else
|
||||
"#{@project.gitlab_url}/new/master"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
module Ci
|
||||
module IconsHelper
|
||||
def boolean_to_icon(value)
|
||||
if value.to_s == "true"
|
||||
content_tag :i, nil, class: 'fa fa-circle cgreen'
|
||||
else
|
||||
content_tag :i, nil, class: 'fa fa-power-off clgray'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
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')
|
||||
"[](#{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
|
||||
@@ -0,0 +1,29 @@
|
||||
module Ci
|
||||
module RoutesHelper
|
||||
class Base
|
||||
include Gitlab::Application.routes.url_helpers
|
||||
|
||||
def default_url_options
|
||||
{
|
||||
host: Settings.gitlab['host'],
|
||||
protocol: Settings.gitlab['https'] ? "https" : "http",
|
||||
port: Settings.gitlab['port']
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def url_helpers
|
||||
@url_helpers ||= Base.new
|
||||
end
|
||||
|
||||
def self.method_missing(method, *args, &block)
|
||||
@url_helpers ||= Base.new
|
||||
|
||||
if @url_helpers.respond_to?(method)
|
||||
@url_helpers.send(method, *args, &block)
|
||||
else
|
||||
super method, *args, &block
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
module Ci
|
||||
module RunnersHelper
|
||||
def runner_status_icon(runner)
|
||||
unless runner.contacted_at
|
||||
return content_tag :i, nil,
|
||||
class: "fa fa-warning-sign",
|
||||
title: "New runner. Has not connected yet"
|
||||
end
|
||||
|
||||
status =
|
||||
if runner.active?
|
||||
runner.contacted_at > 3.hour.ago ? :online : :offline
|
||||
else
|
||||
:paused
|
||||
end
|
||||
|
||||
content_tag :i, nil,
|
||||
class: "fa fa-circle runner-status-#{status}",
|
||||
title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
module Ci
|
||||
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"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
module Ci
|
||||
module UserHelper
|
||||
def user_avatar_url(user = nil, size = nil, default = 'identicon')
|
||||
size = 40 if size.nil? || size <= 0
|
||||
|
||||
if user.blank? || user.avatar_url.blank?
|
||||
'ci/no_avatar.png'
|
||||
elsif /^(http(s?):\/\/(www|secure)\.gravatar\.com\/avatar\/(\w*))/ =~ user.avatar_url
|
||||
Regexp.last_match[0] + "?s=#{size}&d=#{default}"
|
||||
else
|
||||
user.avatar_url
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -27,7 +27,7 @@ module GroupsHelper
|
||||
if group && group.avatar.present?
|
||||
group.avatar.url
|
||||
else
|
||||
image_path('no_group_avatar.png')
|
||||
'no_group_avatar.png'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
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
|
||||
@@ -0,0 +1,47 @@
|
||||
module Ci
|
||||
class Notify < ActionMailer::Base
|
||||
include Ci::Emails::Builds
|
||||
|
||||
add_template_helper Ci::ApplicationHelper
|
||||
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
|
||||
@@ -100,7 +100,7 @@ class Notify < BaseMailer
|
||||
|
||||
def mail_thread(model, headers = {})
|
||||
if @project
|
||||
headers['X-GitLab-Project'] = @project.name
|
||||
headers['X-GitLab-Project'] = @project.name
|
||||
headers['X-GitLab-Project-Id'] = @project.id
|
||||
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
|
||||
end
|
||||
|
||||
@@ -149,6 +149,7 @@ class Ability
|
||||
:admin_merge_request,
|
||||
:create_merge_request,
|
||||
:create_wiki,
|
||||
:manage_builds,
|
||||
:push_code
|
||||
]
|
||||
end
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: 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
|
||||
|
||||
def self.current
|
||||
Ci::ApplicationSetting.last
|
||||
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
|
||||
@@ -0,0 +1,285 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: builds
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# project_id :integer
|
||||
# status :string(255)
|
||||
# finished_at :datetime
|
||||
# trace :text
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# started_at :datetime
|
||||
# runner_id :integer
|
||||
# commit_id :integer
|
||||
# coverage :float
|
||||
# commands :text
|
||||
# job_id :integer
|
||||
# name :string(255)
|
||||
# options :text
|
||||
# allow_failure :boolean default(FALSE), not null
|
||||
# stage :string(255)
|
||||
# deploy :boolean default(FALSE)
|
||||
# trigger_request_id :integer
|
||||
#
|
||||
|
||||
module Ci
|
||||
class Build < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
|
||||
LAZY_ATTRIBUTES = ['trace']
|
||||
|
||||
belongs_to :commit, class_name: 'Ci::Commit'
|
||||
belongs_to :project, class_name: 'Ci::Project'
|
||||
belongs_to :runner, class_name: 'Ci::Runner'
|
||||
belongs_to :trigger_request, class_name: 'Ci::TriggerRequest'
|
||||
|
||||
serialize :options
|
||||
|
||||
validates :commit, presence: true
|
||||
validates :status, presence: true
|
||||
validates :coverage, numericality: true, allow_blank: true
|
||||
|
||||
scope :running, ->() { where(status: "running") }
|
||||
scope :pending, ->() { where(status: "pending") }
|
||||
scope :success, ->() { where(status: "success") }
|
||||
scope :failed, ->() { where(status: "failed") }
|
||||
scope :unstarted, ->() { where(runner_id: nil) }
|
||||
scope :running_or_pending, ->() { where(status:[:running, :pending]) }
|
||||
|
||||
acts_as_taggable
|
||||
|
||||
# To prevent db load megabytes of data from trace
|
||||
default_scope -> { select(Ci::Build.columns_without_lazy) }
|
||||
|
||||
class << self
|
||||
def columns_without_lazy
|
||||
(column_names - LAZY_ATTRIBUTES).map do |column_name|
|
||||
"#{table_name}.#{column_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def last_month
|
||||
where('created_at > ?', Date.today - 1.month)
|
||||
end
|
||||
|
||||
def first_pending
|
||||
pending.unstarted.order('created_at ASC').first
|
||||
end
|
||||
|
||||
def create_from(build)
|
||||
new_build = build.dup
|
||||
new_build.status = :pending
|
||||
new_build.runner_id = nil
|
||||
new_build.save
|
||||
end
|
||||
|
||||
def retry(build)
|
||||
new_build = Ci::Build.new(status: :pending)
|
||||
new_build.options = build.options
|
||||
new_build.commands = build.commands
|
||||
new_build.tag_list = build.tag_list
|
||||
new_build.commit_id = build.commit_id
|
||||
new_build.project_id = build.project_id
|
||||
new_build.name = build.name
|
||||
new_build.allow_failure = build.allow_failure
|
||||
new_build.stage = build.stage
|
||||
new_build.trigger_request = build.trigger_request
|
||||
new_build.save
|
||||
new_build
|
||||
end
|
||||
end
|
||||
|
||||
state_machine :status, initial: :pending do
|
||||
event :run do
|
||||
transition pending: :running
|
||||
end
|
||||
|
||||
event :drop do
|
||||
transition running: :failed
|
||||
end
|
||||
|
||||
event :success do
|
||||
transition running: :success
|
||||
end
|
||||
|
||||
event :cancel do
|
||||
transition [:pending, :running] => :canceled
|
||||
end
|
||||
|
||||
after_transition pending: :running do |build, transition|
|
||||
build.update_attributes started_at: Time.now
|
||||
end
|
||||
|
||||
after_transition any => [:success, :failed, :canceled] do |build, transition|
|
||||
build.update_attributes finished_at: Time.now
|
||||
project = build.project
|
||||
|
||||
if project.web_hooks?
|
||||
Ci::WebHookService.new.build_end(build)
|
||||
end
|
||||
|
||||
if build.commit.success?
|
||||
build.commit.create_next_builds(build.trigger_request)
|
||||
end
|
||||
|
||||
project.execute_services(build)
|
||||
|
||||
if project.coverage_enabled?
|
||||
build.update_coverage
|
||||
end
|
||||
end
|
||||
|
||||
state :pending, value: 'pending'
|
||||
state :running, value: 'running'
|
||||
state :failed, value: 'failed'
|
||||
state :success, value: 'success'
|
||||
state :canceled, value: 'canceled'
|
||||
end
|
||||
|
||||
delegate :sha, :short_sha, :before_sha, :ref,
|
||||
to: :commit, prefix: false
|
||||
|
||||
def trace_html
|
||||
html = Ci::Ansi2html::convert(trace) if trace.present?
|
||||
html ||= ''
|
||||
end
|
||||
|
||||
def trace
|
||||
if project && read_attribute(:trace).present?
|
||||
read_attribute(:trace).gsub(project.token, 'xxxxxx')
|
||||
end
|
||||
end
|
||||
|
||||
def started?
|
||||
!pending? && !canceled? && started_at
|
||||
end
|
||||
|
||||
def active?
|
||||
running? || pending?
|
||||
end
|
||||
|
||||
def complete?
|
||||
canceled? || success? || failed?
|
||||
end
|
||||
|
||||
def ignored?
|
||||
failed? && allow_failure?
|
||||
end
|
||||
|
||||
def timeout
|
||||
project.timeout
|
||||
end
|
||||
|
||||
def variables
|
||||
yaml_variables + project_variables + trigger_variables
|
||||
end
|
||||
|
||||
def duration
|
||||
if started_at && finished_at
|
||||
finished_at - started_at
|
||||
elsif started_at
|
||||
Time.now - started_at
|
||||
end
|
||||
end
|
||||
|
||||
def project
|
||||
commit.project
|
||||
end
|
||||
|
||||
def project_id
|
||||
commit.project_id
|
||||
end
|
||||
|
||||
def project_name
|
||||
project.name
|
||||
end
|
||||
|
||||
def repo_url
|
||||
project.repo_url_with_auth
|
||||
end
|
||||
|
||||
def allow_git_fetch
|
||||
project.allow_git_fetch
|
||||
end
|
||||
|
||||
def update_coverage
|
||||
coverage = extract_coverage(trace, project.coverage_regex)
|
||||
|
||||
if coverage.is_a? Numeric
|
||||
update_attributes(coverage: coverage)
|
||||
end
|
||||
end
|
||||
|
||||
def extract_coverage(text, regex)
|
||||
begin
|
||||
matches = text.gsub(Regexp.new(regex)).to_a.last
|
||||
coverage = matches.gsub(/\d+(\.\d+)?/).first
|
||||
|
||||
if coverage.present?
|
||||
coverage.to_f
|
||||
end
|
||||
rescue => ex
|
||||
# if bad regex or something goes wrong we dont want to interrupt transition
|
||||
# so we just silentrly ignore error for now
|
||||
end
|
||||
end
|
||||
|
||||
def trace
|
||||
if File.exist?(path_to_trace)
|
||||
File.read(path_to_trace)
|
||||
else
|
||||
# backward compatibility
|
||||
read_attribute :trace
|
||||
end
|
||||
end
|
||||
|
||||
def trace=(trace)
|
||||
unless Dir.exists? dir_to_trace
|
||||
FileUtils.mkdir_p dir_to_trace
|
||||
end
|
||||
|
||||
File.write(path_to_trace, trace)
|
||||
end
|
||||
|
||||
def dir_to_trace
|
||||
File.join(
|
||||
Settings.gitlab_ci.builds_path,
|
||||
created_at.utc.strftime("%Y_%m"),
|
||||
project.id.to_s
|
||||
)
|
||||
end
|
||||
|
||||
def path_to_trace
|
||||
"#{dir_to_trace}/#{id}.log"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def yaml_variables
|
||||
if commit.config_processor
|
||||
commit.config_processor.variables.map do |key, value|
|
||||
{ key: key, value: value, public: true }
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def project_variables
|
||||
project.variables.map do |variable|
|
||||
{ key: variable.key, value: variable.value, public: false }
|
||||
end
|
||||
end
|
||||
|
||||
def trigger_variables
|
||||
if trigger_request && trigger_request.variables
|
||||
trigger_request.variables.map do |key, value|
|
||||
{ key: key, value: value, public: false }
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,267 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: commits
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# project_id :integer
|
||||
# ref :string(255)
|
||||
# sha :string(255)
|
||||
# before_sha :string(255)
|
||||
# push_data :text
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# tag :boolean default(FALSE)
|
||||
# yaml_errors :text
|
||||
# committed_at :datetime
|
||||
#
|
||||
|
||||
module Ci
|
||||
class Commit < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
|
||||
belongs_to :project, class_name: 'Ci::Project'
|
||||
has_many :builds, dependent: :destroy, class_name: 'Ci::Build'
|
||||
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
|
||||
|
||||
serialize :push_data
|
||||
|
||||
validates_presence_of :ref, :sha, :before_sha, :push_data
|
||||
validate :valid_commit_sha
|
||||
|
||||
def self.truncate_sha(sha)
|
||||
sha[0...8]
|
||||
end
|
||||
|
||||
def to_param
|
||||
sha
|
||||
end
|
||||
|
||||
def last_build
|
||||
builds.order(:id).last
|
||||
end
|
||||
|
||||
def retry
|
||||
builds_without_retry.each do |build|
|
||||
Ci::Build.retry(build)
|
||||
end
|
||||
end
|
||||
|
||||
def valid_commit_sha
|
||||
if self.sha == Ci::Git::BLANK_SHA
|
||||
self.errors.add(:sha, " cant be 00000000 (branch removal)")
|
||||
end
|
||||
end
|
||||
|
||||
def new_branch?
|
||||
before_sha == Ci::Git::BLANK_SHA
|
||||
end
|
||||
|
||||
def compare?
|
||||
!new_branch?
|
||||
end
|
||||
|
||||
def git_author_name
|
||||
commit_data[:author][:name] if commit_data && commit_data[:author]
|
||||
end
|
||||
|
||||
def git_author_email
|
||||
commit_data[:author][:email] if commit_data && commit_data[:author]
|
||||
end
|
||||
|
||||
def git_commit_message
|
||||
commit_data[:message] if commit_data && commit_data[:message]
|
||||
end
|
||||
|
||||
def short_before_sha
|
||||
Ci::Commit.truncate_sha(before_sha)
|
||||
end
|
||||
|
||||
def short_sha
|
||||
Ci::Commit.truncate_sha(sha)
|
||||
end
|
||||
|
||||
def commit_data
|
||||
push_data[:commits].find do |commit|
|
||||
commit[:id] == sha
|
||||
end
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
def project_recipients
|
||||
recipients = project.email_recipients.split(' ')
|
||||
|
||||
if project.email_add_pusher? && push_data[:user_email].present?
|
||||
recipients << push_data[:user_email]
|
||||
end
|
||||
|
||||
recipients.uniq
|
||||
end
|
||||
|
||||
def stage
|
||||
return unless config_processor
|
||||
stages = builds_without_retry.select(&:active?).map(&:stage)
|
||||
config_processor.stages.find { |stage| stages.include? stage }
|
||||
end
|
||||
|
||||
def create_builds_for_stage(stage, trigger_request)
|
||||
return if skip_ci? && trigger_request.blank?
|
||||
return unless config_processor
|
||||
|
||||
builds_attrs = config_processor.builds_for_stage_and_ref(stage, ref, tag)
|
||||
builds_attrs.map do |build_attrs|
|
||||
builds.create!({
|
||||
project: project,
|
||||
name: build_attrs[:name],
|
||||
commands: build_attrs[:script],
|
||||
tag_list: build_attrs[:tags],
|
||||
options: build_attrs[:options],
|
||||
allow_failure: build_attrs[:allow_failure],
|
||||
stage: build_attrs[:stage],
|
||||
trigger_request: trigger_request,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
def create_next_builds(trigger_request)
|
||||
return if skip_ci? && trigger_request.blank?
|
||||
return unless config_processor
|
||||
|
||||
stages = builds.where(trigger_request: trigger_request).group_by(&:stage)
|
||||
|
||||
config_processor.stages.any? do |stage|
|
||||
!stages.include?(stage) && create_builds_for_stage(stage, trigger_request).present?
|
||||
end
|
||||
end
|
||||
|
||||
def create_builds(trigger_request = nil)
|
||||
return if skip_ci? && trigger_request.blank?
|
||||
return unless config_processor
|
||||
|
||||
config_processor.stages.any? do |stage|
|
||||
create_builds_for_stage(stage, trigger_request).present?
|
||||
end
|
||||
end
|
||||
|
||||
def builds_without_retry
|
||||
@builds_without_retry ||=
|
||||
begin
|
||||
grouped_builds = builds.group_by(&:name)
|
||||
grouped_builds.map do |name, builds|
|
||||
builds.sort_by(&:id).last
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def builds_without_retry_sorted
|
||||
return builds_without_retry unless config_processor
|
||||
|
||||
stages = config_processor.stages
|
||||
builds_without_retry.sort_by do |build|
|
||||
[stages.index(build.stage) || -1, build.name || ""]
|
||||
end
|
||||
end
|
||||
|
||||
def retried_builds
|
||||
@retried_builds ||= (builds.order(id: :desc) - builds_without_retry)
|
||||
end
|
||||
|
||||
def status
|
||||
if skip_ci?
|
||||
return 'skipped'
|
||||
elsif yaml_errors.present?
|
||||
return 'failed'
|
||||
elsif builds.none?
|
||||
return 'skipped'
|
||||
elsif success?
|
||||
'success'
|
||||
elsif pending?
|
||||
'pending'
|
||||
elsif running?
|
||||
'running'
|
||||
elsif canceled?
|
||||
'canceled'
|
||||
else
|
||||
'failed'
|
||||
end
|
||||
end
|
||||
|
||||
def pending?
|
||||
builds_without_retry.all? do |build|
|
||||
build.pending?
|
||||
end
|
||||
end
|
||||
|
||||
def running?
|
||||
builds_without_retry.any? do |build|
|
||||
build.running? || build.pending?
|
||||
end
|
||||
end
|
||||
|
||||
def success?
|
||||
builds_without_retry.all? do |build|
|
||||
build.success? || build.ignored?
|
||||
end
|
||||
end
|
||||
|
||||
def failed?
|
||||
status == 'failed'
|
||||
end
|
||||
|
||||
def canceled?
|
||||
builds_without_retry.all? do |build|
|
||||
build.canceled?
|
||||
end
|
||||
end
|
||||
|
||||
def duration
|
||||
@duration ||= builds_without_retry.select(&:duration).sum(&:duration).to_i
|
||||
end
|
||||
|
||||
def finished_at
|
||||
@finished_at ||= builds.order('finished_at DESC').first.try(:finished_at)
|
||||
end
|
||||
|
||||
def coverage
|
||||
if project.coverage_enabled?
|
||||
coverage_array = builds_without_retry.map(&:coverage).compact
|
||||
if coverage_array.size >= 1
|
||||
'%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def matrix?
|
||||
builds_without_retry.size > 1
|
||||
end
|
||||
|
||||
def config_processor
|
||||
@config_processor ||= Ci::GitlabCiYamlProcessor.new(push_data[:ci_yaml_file] || project.generated_yaml_config)
|
||||
rescue Ci::GitlabCiYamlProcessor::ValidationError => e
|
||||
save_yaml_error(e.message)
|
||||
nil
|
||||
rescue Exception => e
|
||||
logger.error e.message + "\n" + e.backtrace.join("\n")
|
||||
save_yaml_error("Undefined yaml error")
|
||||
nil
|
||||
end
|
||||
|
||||
def skip_ci?
|
||||
return false if builds.any?
|
||||
commits = push_data[:commits]
|
||||
commits.present? && commits.last[:message] =~ /(\[ci skip\])/
|
||||
end
|
||||
|
||||
def update_committed!
|
||||
update!(committed_at: DateTime.now)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def save_yaml_error(error)
|
||||
return if self.yaml_errors?
|
||||
self.yaml_errors = error
|
||||
save
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
# == 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
|
||||
#
|
||||
|
||||
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
|
||||
@@ -0,0 +1,225 @@
|
||||
# == 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
|
||||
#
|
||||
|
||||
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 :commits, ->() { order('CASE WHEN ci_commits.committed_at IS NULL THEN 0 ELSE 1 END', :committed_at, :id) }, dependent: :destroy, class_name: 'Ci::Commit'
|
||||
has_many :builds, through: :commits, dependent: :destroy, class_name: 'Ci::Build'
|
||||
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
|
||||
|
||||
#
|
||||
# Validations
|
||||
#
|
||||
validates_presence_of :name, :timeout, :token, :default_ref,
|
||||
:path, :ssh_url_to_repo, :gitlab_id
|
||||
|
||||
validates_uniqueness_of :gitlab_id
|
||||
|
||||
validates :polling_interval,
|
||||
presence: true,
|
||||
if: ->(project) { project.always_build.present? }
|
||||
|
||||
scope :public_only, ->() { where(public: true) }
|
||||
|
||||
before_validation :set_default_values
|
||||
|
||||
class << self
|
||||
include Ci::CurrentSettings
|
||||
|
||||
def base_build_script
|
||||
<<-eos
|
||||
git submodule update --init
|
||||
ls -la
|
||||
eos
|
||||
end
|
||||
|
||||
def parse(project)
|
||||
params = {
|
||||
name: project.name_with_namespace,
|
||||
gitlab_id: project.id,
|
||||
path: project.path_with_namespace,
|
||||
default_ref: project.default_branch || 'master',
|
||||
ssh_url_to_repo: project.ssh_url_to_repo,
|
||||
email_add_pusher: current_application_settings.add_pusher,
|
||||
email_only_broken_builds: current_application_settings.all_broken_builds,
|
||||
}
|
||||
|
||||
project = Ci::Project.new(params)
|
||||
project.build_missing_services
|
||||
project
|
||||
end
|
||||
|
||||
# TODO: remove
|
||||
def from_gitlab(user, scope = :owned, options)
|
||||
opts = user.authenticate_options
|
||||
opts.merge! options
|
||||
|
||||
raise 'Implement me of fix'
|
||||
#projects = Ci::Network.new.projects(opts.compact, scope)
|
||||
|
||||
if projects
|
||||
projects.map { |pr| OpenStruct.new(pr) }
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def already_added?(project)
|
||||
where(gitlab_id: project.id).any?
|
||||
end
|
||||
|
||||
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 project_id, MAX(committed_at) committed_at FROM #{Ci::Commit.table_name} GROUP BY project_id)"
|
||||
joins("LEFT JOIN #{last_commit_subquery} AS last_commit ON #{Ci::Project.table_name}.id = last_commit.project_id").
|
||||
order("CASE WHEN last_commit.committed_at IS NULL THEN 1 ELSE 0 END, last_commit.committed_at DESC")
|
||||
end
|
||||
|
||||
def search(query)
|
||||
where("LOWER(#{Ci::Project.table_name}.name) LIKE :query",
|
||||
query: "%#{query.try(:downcase)}%")
|
||||
end
|
||||
end
|
||||
|
||||
def any_runners?
|
||||
if runners.active.any?
|
||||
return true
|
||||
end
|
||||
|
||||
shared_runners_enabled && Ci::Runner.shared.active.any?
|
||||
end
|
||||
|
||||
def set_default_values
|
||||
self.token = SecureRandom.hex(15) if self.token.blank?
|
||||
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}@"
|
||||
url = gitlab_url + ".git"
|
||||
url.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`
|
||||
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 gitlab_url
|
||||
File.join(Gitlab.config.gitlab.url, path)
|
||||
end
|
||||
|
||||
def setup_finished?
|
||||
commits.any?
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,47 @@
|
||||
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
|
||||
|
||||
# only check for toggling build status within same ref.
|
||||
def last_commit_changed_status?
|
||||
ref = last_commit.ref
|
||||
last_commits = commits.where(ref: ref).last(2)
|
||||
|
||||
if last_commits.size < 2
|
||||
false
|
||||
else
|
||||
last_commits[0].status != last_commits[1].status
|
||||
end
|
||||
end
|
||||
|
||||
def last_commit_for_ref(ref)
|
||||
commits.where(ref: ref).last
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,80 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: runners
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# token :string(255)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# description :string(255)
|
||||
# contacted_at :datetime
|
||||
# active :boolean default(TRUE), not null
|
||||
# is_shared :boolean default(FALSE)
|
||||
# name :string(255)
|
||||
# version :string(255)
|
||||
# revision :string(255)
|
||||
# platform :string(255)
|
||||
# architecture :string(255)
|
||||
#
|
||||
|
||||
module Ci
|
||||
class Runner < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
|
||||
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_one :last_build, ->() { order('id DESC') }, class_name: 'Ci::Build'
|
||||
|
||||
before_validation :set_default_values
|
||||
|
||||
scope :specific, ->() { where(is_shared: false) }
|
||||
scope :shared, ->() { where(is_shared: true) }
|
||||
scope :active, ->() { where(active: true) }
|
||||
scope :paused, ->() { where(active: false) }
|
||||
|
||||
acts_as_taggable
|
||||
|
||||
def self.search(query)
|
||||
where('LOWER(ci_runners.token) LIKE :query OR LOWER(ci_runners.description) like :query',
|
||||
query: "%#{query.try(:downcase)}%")
|
||||
end
|
||||
|
||||
def set_default_values
|
||||
self.token = SecureRandom.hex(15) if self.token.blank?
|
||||
end
|
||||
|
||||
def assign_to(project, current_user = nil)
|
||||
self.is_shared = false if shared?
|
||||
self.save
|
||||
project.runner_projects.create!(runner_id: self.id)
|
||||
end
|
||||
|
||||
def display_name
|
||||
return token unless !description.blank?
|
||||
|
||||
description
|
||||
end
|
||||
|
||||
def shared?
|
||||
is_shared
|
||||
end
|
||||
|
||||
def belongs_to_one_project?
|
||||
runner_projects.count == 1
|
||||
end
|
||||
|
||||
def specific?
|
||||
!shared?
|
||||
end
|
||||
|
||||
def only_for?(project)
|
||||
projects == [project]
|
||||
end
|
||||
|
||||
def short_sha
|
||||
token[0...10]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: runner_projects
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# runner_id :integer not null
|
||||
# project_id :integer not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
module Ci
|
||||
class RunnerProject < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
|
||||
belongs_to :runner, class_name: 'Ci::Runner'
|
||||
belongs_to :project, class_name: 'Ci::Project'
|
||||
|
||||
validates_uniqueness_of :runner_id, scope: :project_id
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,105 @@
|
||||
# == 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
|
||||
#
|
||||
|
||||
# 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
|
||||
@@ -0,0 +1,39 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: triggers
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# token :string(255)
|
||||
# project_id :integer not null
|
||||
# deleted_at :datetime
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
module Ci
|
||||
class Trigger < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
|
||||
acts_as_paranoid
|
||||
|
||||
belongs_to :project, class_name: 'Ci::Project'
|
||||
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
|
||||
|
||||
validates_presence_of :token
|
||||
validates_uniqueness_of :token
|
||||
|
||||
before_validation :set_default_values
|
||||
|
||||
def set_default_values
|
||||
self.token = SecureRandom.hex(15) if self.token.blank?
|
||||
end
|
||||
|
||||
def last_trigger_request
|
||||
trigger_requests.last
|
||||
end
|
||||
|
||||
def short_token
|
||||
token[0...10]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: trigger_requests
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# trigger_id :integer not null
|
||||
# variables :text
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# commit_id :integer
|
||||
#
|
||||
|
||||
module Ci
|
||||
class TriggerRequest < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
|
||||
belongs_to :trigger, class_name: 'Ci::Trigger'
|
||||
belongs_to :commit, class_name: 'Ci::Commit'
|
||||
has_many :builds, class_name: 'Ci::Build'
|
||||
|
||||
serialize :variables
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: variables
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# project_id :integer not null
|
||||
# key :string(255)
|
||||
# value :text
|
||||
# encrypted_value :text
|
||||
# encrypted_value_salt :string(255)
|
||||
# encrypted_value_iv :string(255)
|
||||
#
|
||||
|
||||
module Ci
|
||||
class Variable < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
|
||||
belongs_to :project, class_name: 'Ci::Project'
|
||||
|
||||
validates_presence_of :key
|
||||
validates_uniqueness_of :key, scope: :project_id
|
||||
|
||||
attr_encrypted :value, mode: :per_attribute_iv_and_salt, key: Gitlab::Application.secrets.db_key_base
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,44 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: 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,
|
||||
format: { with: URI::regexp(%w(http https)), message: "should be a valid url" }
|
||||
|
||||
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
|
||||
@@ -119,6 +119,7 @@ class Project < ActiveRecord::Base
|
||||
has_many :starrers, through: :users_star_projects, source: :user
|
||||
|
||||
has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
|
||||
has_one :gitlab_ci_project, dependent: :destroy, class_name: "Ci::Project", foreign_key: :gitlab_id
|
||||
|
||||
delegate :name, to: :owner, allow_nil: true, prefix: true
|
||||
delegate :members, to: :team, prefix: true
|
||||
@@ -329,7 +330,7 @@ class Project < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def web_url
|
||||
Rails.application.routes.url_helpers.namespace_project_url(self.namespace, self)
|
||||
Gitlab::Application.routes.url_helpers.namespace_project_url(self.namespace, self)
|
||||
end
|
||||
|
||||
def web_url_without_protocol
|
||||
@@ -455,7 +456,7 @@ class Project < ActiveRecord::Base
|
||||
if avatar.present?
|
||||
[gitlab_config.url, avatar.url].join
|
||||
elsif avatar_in_git
|
||||
Rails.application.routes.url_helpers.namespace_project_avatar_url(namespace, self)
|
||||
Gitlab::Application.routes.url_helpers.namespace_project_avatar_url(namespace, self)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
module Ci
|
||||
class HipChatMessage
|
||||
attr_reader :build
|
||||
|
||||
def initialize(build)
|
||||
@build = build
|
||||
end
|
||||
|
||||
def to_s
|
||||
lines = Array.new
|
||||
lines.push("<a href=\"#{Ci::RoutesHelper.ci_project_url(project)}\">#{project.name}</a> - ")
|
||||
|
||||
if commit.matrix?
|
||||
lines.push("<a href=\"#{Ci::RoutesHelper.ci_project_ref_commits_url(project, commit.ref, commit.sha)}\">Commit ##{commit.id}</a></br>")
|
||||
else
|
||||
first_build = commit.builds_without_retry.first
|
||||
lines.push("<a href=\"#{Ci::RoutesHelper.ci_project_build_url(project, first_build)}\">Build '#{first_build.name}' ##{first_build.id}</a></br>")
|
||||
end
|
||||
|
||||
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
|
||||
@@ -0,0 +1,93 @@
|
||||
# == 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
|
||||
#
|
||||
|
||||
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.builds_without_retry.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
|
||||
@@ -0,0 +1,84 @@
|
||||
# == 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
|
||||
#
|
||||
|
||||
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.builds_without_retry.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.commit.project_recipients.each do |recipient|
|
||||
case build.status.to_sym
|
||||
when :success
|
||||
mailer.build_success_email(build.id, recipient)
|
||||
when :failed
|
||||
mailer.build_fail_email(build.id, recipient)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_project
|
||||
project.save!
|
||||
end
|
||||
|
||||
def mailer
|
||||
Ci::Notify.delay
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,97 @@
|
||||
require 'slack-notifier'
|
||||
|
||||
module Ci
|
||||
class SlackMessage
|
||||
def initialize(commit)
|
||||
@commit = commit
|
||||
end
|
||||
|
||||
def pretext
|
||||
''
|
||||
end
|
||||
|
||||
def color
|
||||
attachment_color
|
||||
end
|
||||
|
||||
def fallback
|
||||
format(attachment_message)
|
||||
end
|
||||
|
||||
def attachments
|
||||
fields = []
|
||||
|
||||
if commit.matrix?
|
||||
commit.builds_without_retry.each do |build|
|
||||
next if build.allow_failure?
|
||||
next unless build.failed?
|
||||
fields << {
|
||||
title: build.name,
|
||||
value: "Build <#{Ci::RoutesHelper.ci_project_build_url(project, build)}|\##{build.id}> failed in #{build.duration.to_i} second(s)."
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
[{
|
||||
text: attachment_message,
|
||||
color: attachment_color,
|
||||
fields: fields
|
||||
}]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :commit
|
||||
|
||||
def attachment_message
|
||||
out = "<#{Ci::RoutesHelper.ci_project_url(project)}|#{project_name}>: "
|
||||
if commit.matrix?
|
||||
out << "Commit <#{Ci::RoutesHelper.ci_project_ref_commits_url(project, commit.ref, commit.sha)}|\##{commit.id}> "
|
||||
else
|
||||
build = commit.builds_without_retry.first
|
||||
out << "Build <#{Ci::RoutesHelper.ci_project_build_path(project, build)}|\##{build.id}> "
|
||||
end
|
||||
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
|
||||
@@ -0,0 +1,81 @@
|
||||
# == 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
|
||||
#
|
||||
|
||||
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.builds_without_retry.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
|
||||
@@ -19,7 +19,7 @@
|
||||
#
|
||||
|
||||
class GitlabIssueTrackerService < IssueTrackerService
|
||||
include Rails.application.routes.url_helpers
|
||||
include Gitlab::Application.routes.url_helpers
|
||||
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#
|
||||
|
||||
class JiraService < IssueTrackerService
|
||||
include Rails.application.routes.url_helpers
|
||||
include Gitlab::Application.routes.url_helpers
|
||||
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
|
||||
@@ -34,6 +34,12 @@ class SlackService < Service
|
||||
'slack'
|
||||
end
|
||||
|
||||
def help
|
||||
'This service sends notifications to your Slack channel.<br/>
|
||||
To setup this Service you need to create a new <b>"Incoming webhook"</b> in your Slack integration panel,
|
||||
and enter the Webhook URL below.'
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{ type: 'text', name: 'webhook',
|
||||
|
||||
@@ -753,4 +753,13 @@ class User < ActiveRecord::Base
|
||||
def can_be_removed?
|
||||
!solo_owned_groups.present?
|
||||
end
|
||||
|
||||
def ci_authorized_projects
|
||||
@ci_authorized_projects ||= Ci::Project.where(gitlab_id: authorized_projects)
|
||||
end
|
||||
|
||||
def ci_authorized_runners
|
||||
Ci::Runner.specific.includes(:runner_projects).
|
||||
where(ci_runner_projects: { project_id: ci_authorized_projects } )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
module Ci
|
||||
class CreateCommitService
|
||||
def execute(project, params)
|
||||
before_sha = params[:before]
|
||||
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
|
||||
|
||||
commit = project.commits.find_by_sha_and_ref(sha, ref)
|
||||
|
||||
# Create commit if not exists yet
|
||||
unless commit
|
||||
data = {
|
||||
ref: ref,
|
||||
sha: sha,
|
||||
tag: origin_ref.start_with?('refs/tags/'),
|
||||
before_sha: before_sha,
|
||||
push_data: {
|
||||
before: before_sha,
|
||||
after: sha,
|
||||
ref: ref,
|
||||
user_name: params[:user_name],
|
||||
user_email: params[:user_email],
|
||||
repository: params[:repository],
|
||||
commits: params[:commits],
|
||||
total_commits_count: params[:total_commits_count],
|
||||
ci_yaml_file: params[:ci_yaml_file]
|
||||
}
|
||||
}
|
||||
|
||||
commit = project.commits.create(data)
|
||||
end
|
||||
|
||||
commit.update_committed!
|
||||
commit.create_builds unless commit.builds.any?
|
||||
|
||||
commit
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,35 @@
|
||||
module Ci
|
||||
class CreateProjectService
|
||||
include Gitlab::Application.routes.url_helpers
|
||||
|
||||
def execute(current_user, params, project_route, forked_project = nil)
|
||||
@project = Ci::Project.parse(params)
|
||||
|
||||
Ci::Project.transaction do
|
||||
@project.save!
|
||||
|
||||
data = {
|
||||
token: @project.token,
|
||||
project_url: project_route.gsub(":project_id", @project.id.to_s),
|
||||
}
|
||||
|
||||
gl_project = ::Project.find(@project.gitlab_id)
|
||||
gl_project.build_missing_services
|
||||
gl_project.gitlab_ci_service.update_attributes(data.merge(active: true))
|
||||
end
|
||||
|
||||
if forked_project
|
||||
# Copy settings
|
||||
settings = forked_project.attributes.select do |attr_name, value|
|
||||
["public", "shared_runners_enabled", "allow_git_fetch"].include? attr_name
|
||||
end
|
||||
|
||||
@project.update(settings)
|
||||
end
|
||||
|
||||
Ci::EventService.new.create_project(current_user, @project)
|
||||
|
||||
@project
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
module Ci
|
||||
class CreateTriggerRequestService
|
||||
def execute(project, trigger, ref, variables = nil)
|
||||
commit = project.commits.where(ref: ref).last
|
||||
return unless commit
|
||||
|
||||
trigger_request = trigger.trigger_requests.create!(
|
||||
commit: commit,
|
||||
variables: variables
|
||||
)
|
||||
|
||||
if commit.create_builds(trigger_request)
|
||||
trigger_request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user