Full Code of square/kochiku for AI

master d9a2dd8f1d6c cached
285 files
831.4 KB
221.6k tokens
726 symbols
1 requests
Download .txt
Showing preview only (908K chars total). Download the full file or copy to clipboard to get everything.
Repository: square/kochiku
Branch: master
Commit: d9a2dd8f1d6c
Files: 285
Total size: 831.4 KB

Directory structure:
gitextract_m1o94eo4/

├── .gitignore
├── .haml-lint.yml
├── .rspec
├── .rubocop.yml
├── .rubocop_todo.yml
├── .ruby-version
├── .travis.yml
├── CONTRIBUTING.md
├── Capfile
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── app/
│   ├── assets/
│   │   ├── javascripts/
│   │   │   └── application.js
│   │   └── stylesheets/
│   │       └── screen.sass
│   ├── controllers/
│   │   ├── application_controller.rb
│   │   ├── branches_controller.rb
│   │   ├── build_artifacts_controller.rb
│   │   ├── build_attempts_controller.rb
│   │   ├── build_parts_controller.rb
│   │   ├── builds_controller.rb
│   │   ├── concerns/
│   │   │   └── build_attempts_queue_position.rb
│   │   ├── dashboards_controller.rb
│   │   ├── pull_requests_controller.rb
│   │   ├── repositories_controller.rb
│   │   └── status_controller.rb
│   ├── decorators/
│   │   ├── branch_decorator.rb
│   │   └── build_part_decorator.rb
│   ├── helpers/
│   │   ├── application_helper.rb
│   │   ├── build_helper.rb
│   │   ├── mail_helper.rb
│   │   └── project_stats_helper.rb
│   ├── jobs/
│   │   ├── build_attempt_job.rb
│   │   ├── build_initiated_by_job.rb
│   │   ├── build_partitioning_job.rb
│   │   ├── build_state_update_job.rb
│   │   ├── enforce_timeouts_job.rb
│   │   ├── job_base.rb
│   │   ├── poll_repositories_job.rb
│   │   └── timeout_stuck_builds_job.rb
│   ├── mailers/
│   │   ├── build_mailer.rb
│   │   └── merge_mailer.rb
│   ├── models/
│   │   ├── branch.rb
│   │   ├── build.rb
│   │   ├── build_artifact.rb
│   │   ├── build_attempt.rb
│   │   ├── build_part.rb
│   │   ├── repository.rb
│   │   └── repository_observer.rb
│   ├── uploaders/
│   │   ├── base_log_file_uploader.rb
│   │   ├── log_file_uploader.rb
│   │   └── on_success_uploader.rb
│   └── views/
│       ├── branches/
│       │   ├── health.html.haml
│       │   ├── index.html.haml
│       │   ├── show.html.haml
│       │   ├── show.json.erb
│       │   ├── show.rss.builder
│       │   └── status_report.xml.builder
│       ├── build_attempts/
│       │   ├── _build_attempt.html.haml
│       │   └── stream_logs.html.haml
│       ├── build_mailer/
│       │   ├── build_break_email.html.haml
│       │   ├── build_break_email.text.erb
│       │   ├── build_success_email.html.haml
│       │   ├── build_success_email.text.erb
│       │   ├── error_email.html.haml
│       │   └── error_email.text.erb
│       ├── build_parts/
│       │   ├── _build_attempts.html.haml
│       │   ├── _build_part.html.haml
│       │   └── show.html.haml
│       ├── builds/
│       │   ├── _build.html.haml
│       │   ├── _build_parts.html.haml
│       │   └── show.html.haml
│       ├── dashboards/
│       │   └── build_history_by_worker.html.haml
│       ├── layouts/
│       │   └── application.html.haml
│       ├── merge_mailer/
│       │   ├── merge_failed.text.erb
│       │   └── merge_successful.html.erb
│       └── repositories/
│           ├── _form.html.haml
│           ├── dashboard.html.haml
│           ├── edit.html.haml
│           ├── index.html.haml
│           └── new.html.haml
├── bin/
│   ├── bundle
│   ├── rails
│   ├── rake
│   ├── setup
│   └── spring
├── config/
│   ├── application.dev.yml
│   ├── application.rb
│   ├── application.test.yml
│   ├── application.yml
│   ├── boot.rb
│   ├── compass.rb
│   ├── database.production.yml.sample
│   ├── database.yml
│   ├── deploy/
│   │   └── production.rb
│   ├── deploy.rb
│   ├── environment.rb
│   ├── environments/
│   │   ├── development.rb
│   │   ├── production.rb
│   │   ├── staging.rb
│   │   └── test.rb
│   ├── initializers/
│   │   ├── backtrace_silencers.rb
│   │   ├── cocaine.rb
│   │   ├── inflections.rb
│   │   ├── load_build_strategy.rb
│   │   ├── mime_types.rb
│   │   ├── readthis.rb
│   │   ├── redis.rb
│   │   ├── resque.rb
│   │   ├── secret_token.rb
│   │   ├── session_store.rb
│   │   └── wrap_parameters.rb
│   ├── kochiku.yml
│   ├── kochiku.yml.sample
│   ├── locales/
│   │   └── en.yml
│   ├── resque_schedule.yml
│   └── routes.rb
├── config.ru
├── db/
│   ├── migrate/
│   │   ├── 20110621212000_create_schema.rb
│   │   ├── 20110624003418_change_artifact_type_to_name.rb
│   │   ├── 20110624015709_rename_build_part_result_result_to_state.rb
│   │   ├── 20110708203120_change_build_artifacts_for_carrier_wave.rb
│   │   ├── 20110713175724_rename_build_part_result_to_build_part_run.rb
│   │   ├── 20110713191536_add_foreign_key_indexes.rb
│   │   ├── 20110719204508_create_projects.rb
│   │   ├── 20110719205413_add_project_id_to_builds.rb
│   │   ├── 20110721185201_rename_builds_sha_to_ref.rb
│   │   ├── 20110801215540_rename_error_state_to_errored.rb
│   │   ├── 20120803005242_add_merge_bool_to_build.rb
│   │   ├── 20120817225343_add_branch_to_build.rb
│   │   ├── 20121008211955_create_repositories.rb
│   │   ├── 20121017173936_add_github_repository_id_to_repository.rb
│   │   ├── 20121017182543_fix_repository_schema.rb
│   │   ├── 20121017184946_remove_options_from_repository.rb
│   │   ├── 20121017222538_add_target_name_to_builds.rb
│   │   ├── 20121017224003_add_command_flag_to_repositories.rb
│   │   ├── 20121018182435_add_options_to_build_part.rb
│   │   ├── 20121024005715_add_send_build_failure_email_to_repository.rb
│   │   ├── 20121024164929_record_build_failure_email_sent.rb
│   │   ├── 20121024210129_add_success_script_to_repositories.rb
│   │   ├── 20121024212949_add_on_success_log_file_to_build.rb
│   │   ├── 20121030213442_add_queue_to_repository.rb
│   │   ├── 20121101220831_add_timeout_to_repository.rb
│   │   ├── 20130226232844_add_index_to_build_ref.rb
│   │   ├── 20130409144945_add_on_success_note_to_repositories.rb
│   │   ├── 20130511012855_add_deployable_map_to_build.rb
│   │   ├── 20130626183046_add_maven_modules_to_build.rb
│   │   ├── 20130627194433_add_index_to_build_part_paths.rb
│   │   ├── 20130709123456_add_upload_artifacts_to_build_parts.rb
│   │   ├── 20130822191419_add_queue_to_build_part.rb
│   │   ├── 20130822231850_remove_upload_artifacts_from_build_parts.rb
│   │   ├── 20130823210844_add_retry_count_to_build_part.rb
│   │   ├── 20130823231854_remove_java_specific_stuff.rb
│   │   ├── 20130823234546_remove_queue_override_from_repositories.rb
│   │   ├── 20130910190203_add_repository_name_as_column.rb
│   │   ├── 20131217022000_add_error_text_to_build.rb
│   │   ├── 20140123234208_add_allows_kochiku_merges_to_repository.rb
│   │   ├── 20140128180258_rename_auto_merge_on_build.rb
│   │   ├── 20140415001051_remove_use_branches_on_green_from_repositories.rb
│   │   ├── 20140415011144_remove_command_flag_from_repositories.rb
│   │   ├── 20140506012721_unique_index_on_builds_ref.rb
│   │   ├── 20140507184819_add_host_and_namespace_to_repositories.rb
│   │   ├── 20140617214701_add_success_email.rb
│   │   ├── 20140715225910_remove_notes.rb
│   │   ├── 20141031234747_add_email_first_failure_to_repositories.rb
│   │   ├── 20150324001246_remove_on_success_script_from_repositories.rb
│   │   ├── 20150331160909_add_send_merge_successful_email.rb
│   │   ├── 20150714234635_add_log_port_to_build_attempt.rb
│   │   ├── 20150717214656_create_branches.rb
│   │   ├── 20150717220149_assign_builds_to_branches.rb
│   │   ├── 20150717231250_remove_branch_string_from_builds.rb
│   │   ├── 20150719130110_index_repositories_namespace_and_name.rb
│   │   ├── 20151111080255_remove_repo_cache_dir_from_repositories.rb
│   │   ├── 20151114185514_fix_convergence_index.rb
│   │   ├── 20160408214135_index_created_at_on_build_attempts.rb
│   │   ├── 20170804214538_add_enabled_bool_to_repositories.rb
│   │   ├── 20180208202524_add_test_command_to_builds.rb
│   │   ├── 20180220185338_add_assume_lost_after_to_repository.rb
│   │   ├── 20180227222254_add_initiated_by_to_builds.rb
│   │   ├── 20180301221320_add_instance_type_to_build_attempts.rb
│   │   └── 20180619210823_add_kochiku_yml_config_to_builds.rb
│   ├── schema.rb
│   └── seeds.rb
├── lib/
│   ├── build_strategies/
│   │   ├── no_op_build_strategy.rb
│   │   └── production_build_strategy.rb
│   ├── capistrano/
│   │   └── tasks/
│   │       ├── deploy.cap
│   │       └── kochiku.cap
│   ├── fileless_io.rb
│   ├── git_blame.rb
│   ├── git_merge_executor.rb
│   ├── git_repo.rb
│   ├── github_commit_status.rb
│   ├── github_post_receive_hook.rb
│   ├── github_request.rb
│   ├── partitioner/
│   │   ├── base.rb
│   │   ├── default.rb
│   │   ├── dependency_map.rb
│   │   ├── go.rb
│   │   ├── maven.rb
│   │   └── topological_sorter.rb
│   ├── partitioner.rb
│   ├── remote_server/
│   │   ├── github.rb
│   │   └── stash.rb
│   ├── remote_server.rb
│   ├── server_settings.rb
│   ├── settings_accessor.rb
│   ├── stash_merge_executor.rb
│   └── tasks/
│       ├── .gitkeep
│       ├── kochiku.rake
│       └── resque.rake
├── public/
│   ├── 404.html
│   ├── 422.html
│   ├── 500.html
│   ├── fonts/
│   │   └── SQMarket-Regular.otf
│   └── robots.txt
├── script/
│   ├── ci
│   └── kochiku-build.sh.sample
├── spec/
│   ├── controllers/
│   │   ├── branches_controller_spec.rb
│   │   ├── build_artifacts_controller_spec.rb
│   │   ├── build_attempts_controller_spec.rb
│   │   ├── build_parts_controller_spec.rb
│   │   ├── builds_controller_spec.rb
│   │   ├── dashboards_controller_spec.rb
│   │   ├── pull_requests_controller_spec.rb
│   │   ├── repositories_controller_spec.rb
│   │   └── status_controller_spec.rb
│   ├── decorators/
│   │   ├── branch_decorator_spec.rb
│   │   └── build_part_decorator_spec.rb
│   ├── features/
│   │   └── integration_spec.rb
│   ├── fixtures/
│   │   ├── build_artifact.log
│   │   ├── sample_github_webhook_payload.json
│   │   └── stdout.log
│   ├── helpers/
│   │   ├── application_helper_spec.rb
│   │   ├── build_helper_spec.rb
│   │   └── project_stats_helper_spec.rb
│   ├── jobs/
│   │   ├── build_partitioning_job_spec.rb
│   │   ├── build_state_update_job_spec.rb
│   │   ├── enforce_timeouts_job_spec.rb
│   │   ├── poll_repositories_job_spec.rb
│   │   └── timeout_stuck_builds_job_spec.rb
│   ├── lib/
│   │   ├── build_strategies/
│   │   │   └── production_build_strategy_spec.rb
│   │   ├── git_blame_spec.rb
│   │   ├── git_merge_executor_spec.rb
│   │   ├── git_repo_spec.rb
│   │   ├── github_commit_status_spec.rb
│   │   ├── github_post_receive_hook_spec.rb
│   │   ├── github_request_spec.rb
│   │   ├── partitioner/
│   │   │   ├── default_spec.rb
│   │   │   ├── dependency_map_spec.rb
│   │   │   ├── go_spec.rb
│   │   │   ├── maven_spec.rb
│   │   │   └── shared_default_behavior.rb
│   │   ├── partitioner_spec.rb
│   │   ├── remote_server/
│   │   │   ├── github_spec.rb
│   │   │   └── stash_spec.rb
│   │   ├── remote_server_spec.rb
│   │   ├── server_settings_spec.rb
│   │   ├── settings_accessor_spec.rb
│   │   └── stash_merge_executor_spec.rb
│   ├── mailers/
│   │   ├── build_mailer_spec.rb
│   │   ├── merge_mailer_spec.rb
│   │   └── previews/
│   │       └── build_mailer_preview.rb
│   ├── models/
│   │   ├── branch_spec.rb
│   │   ├── build_artifact_spec.rb
│   │   ├── build_attempt_spec.rb
│   │   ├── build_part_spec.rb
│   │   ├── build_spec.rb
│   │   ├── repository_observer_spec.rb
│   │   └── repository_spec.rb
│   ├── routes_spec.rb
│   ├── spec_helper.rb
│   └── support/
│       ├── command_stubber.rb
│       ├── custom_argument_matchers.rb
│       ├── factories.rb
│       ├── git_spec_helper.rb
│       └── sha_helper.rb
└── vendor/
    └── assets/
        ├── javascripts/
        │   ├── jquery.flot.categories.js
        │   ├── jquery.flot.errorbars.js
        │   ├── jquery.flot.js
        │   ├── jquery.tablesorter.js
        │   ├── jquery.timeago.js
        │   ├── jquery.tipTip.js
        │   └── moment.js
        └── stylesheets/
            ├── tablesorter.theme.kochiku.css
            └── tipTip.scss

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/.bundle
log/*.log
tmp/
public/uploads
public/log_files
vendor/ruby

# file with the real db config for production
/config/database.production.yml

# rspec
/spec/examples.txt


================================================
FILE: .haml-lint.yml
================================================
linters:
  ConsecutiveSilentScripts:
    enabled: false

  IdNames:
    enabled: false

  InlineStyles:
    enabled: false

  InstanceVariables:
    enabled: false

  ImplicitDiv:
    enabled: false

  LineLength:
    enabled: false

  RuboCop:
    enabled: false

  SpaceInsideHashAttributes:
    style: no_space

  ViewLength:
    enabled: false


================================================
FILE: .rspec
================================================
--color



================================================
FILE: .rubocop.yml
================================================
inherit_from: .rubocop_todo.yml
AllCops:
  TargetRubyVersion: 2.3
  TargetRailsVersion: 4.2
  DisplayCopNames: true
  Include:
    - 'Capfile'
    - 'Gemfile'
    - 'Rakefile'
    - 'config.ru'
  Exclude:
    - 'config/deploy.rb'
    - 'db/migrate/*'
    - 'db/schema.rb'
    - 'lib/ext/activerecord/persistence.rb'
    - 'vendor/**/*'

Layout/EmptyLinesAroundBlockBody:
  Enabled: false

Layout/EmptyLinesAroundClassBody:
  Enabled: false

Layout/ExtraSpacing:
  Enabled: false

Layout/MultilineBlockLayout:
  Exclude:
    - 'spec/lib/partitioner/maven_spec.rb'

Lint/HandleExceptions:
  Exclude:
    - 'lib/git_repo.rb'

Lint/NestedMethodDefinition:
  Exclude:
    - 'app/jobs/enforce_timeouts_job.rb'

Lint/UselessAssignment:
  Exclude:
    - 'config/compass.rb'
    - 'spec/models/build_spec.rb'

Metrics/MethodLength:
  Exclude:
    - 'lib/partitioner/pants.rb'

Metrics/ClassLength:
  Enabled: false

Rails:
  Enabled: true

Style/BlockDelimiters:
  Enabled: false

Style/DoubleNegation:
  Enabled: false

Style/FrozenStringLiteralComment:
  # will enable this after Ruby 3.0 is released
  Enabled: false

Style/GuardClause:
  # Personally disagree with this one. In certain situations not using a
  # GuardClause makes it more readable.
  Enabled: false

Style/IfUnlessModifier:
  Enabled: false

Style/MultilineBlockChain:
  Enabled: false

Style/TrailingCommaInLiteral:
  Enabled: false


================================================
FILE: .rubocop_todo.yml
================================================
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2017-12-08 16:49:35 -0800 using RuboCop version 0.51.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 3
# Cop supports --auto-correct.
Layout/EmptyLineAfterMagicComment:
  Exclude:
    - 'lib/github_post_receive_hook.rb'
    - 'lib/partitioner/maven.rb'
    - 'spec/features/integration_spec.rb'

# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces
Layout/IndentHash:
  Exclude:
    - 'app/views/branches/status_report.xml.builder'

# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
Layout/IndentHeredoc:
  Exclude:
    - 'spec/features/integration_spec.rb'
    - 'spec/lib/git_blame_spec.rb'
    - 'spec/lib/partitioner/maven_spec.rb'

# Offense count: 11
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: symmetrical, new_line, same_line
Layout/MultilineMethodCallBraceLayout:
  Exclude:
    - 'app/controllers/build_attempts_controller.rb'
    - 'spec/controllers/pull_requests_controller_spec.rb'
    - 'spec/jobs/build_partitioning_job_spec.rb'
    - 'spec/jobs/build_state_update_job_spec.rb'
    - 'spec/lib/github_commit_status_spec.rb'

# Offense count: 11
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: aligned, indented, indented_relative_to_receiver
Layout/MultilineMethodCallIndentation:
  Exclude:
    - 'spec/lib/build_strategies/production_build_strategy_spec.rb'
    - 'spec/lib/git_merge_executor_spec.rb'
    - 'spec/lib/partitioner/maven_spec.rb'

# Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, SupportedStylesForEmptyBraces.
# SupportedStyles: space, no_space
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceBeforeBlockBraces:
  Exclude:
    - 'config/application.rb'
    - 'spec/controllers/branches_controller_spec.rb'
    - 'spec/controllers/build_artifacts_controller_spec.rb'
    - 'spec/controllers/repositories_controller_spec.rb'
    - 'spec/jobs/poll_repositories_job_spec.rb'
    - 'spec/lib/remote_server_spec.rb'
    - 'spec/models/build_spec.rb'

# Offense count: 245
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces.
# SupportedStyles: space, no_space, compact
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceInsideHashLiteralBraces:
  Enabled: false

# Offense count: 2
# Cop supports --auto-correct.
Layout/SpaceInsidePercentLiteralDelimiters:
  Exclude:
    - 'spec/models/repository_spec.rb'

# Offense count: 5
Lint/AmbiguousBlockAssociation:
  Exclude:
    - 'spec/controllers/branches_controller_spec.rb'
    - 'spec/controllers/build_parts_controller_spec.rb'
    - 'spec/jobs/build_state_update_job_spec.rb'
    - 'spec/jobs/enforce_timeouts_job_spec.rb'
    - 'spec/jobs/poll_repositories_job_spec.rb'

# Offense count: 1
# Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition:
  Exclude:
    - 'app/decorators/branch_decorator.rb'

# Offense count: 3
Lint/RescueWithoutErrorClass:
  Exclude:
    - 'app/controllers/build_attempts_controller.rb'
    - 'app/jobs/job_base.rb'
    - 'lib/remote_server/stash.rb'

# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
Lint/UnusedBlockArgument:
  Exclude:
    - 'app/controllers/application_controller.rb'
    - 'spec/lib/git_blame_spec.rb'
    - 'spec/models/build_part_spec.rb'
    - 'spec/support/custom_argument_matchers.rb'
    - 'spec/support/factories.rb'

# Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
Lint/UnusedMethodArgument:
  Exclude:
    - 'app/decorators/branch_decorator.rb'
    - 'app/helpers/build_helper.rb'
    - 'app/jobs/build_attempt_job.rb'
    - 'lib/partitioner/default.rb'
    - 'lib/remote_server/stash.rb'
    - 'spec/mailers/previews/build_mailer_preview.rb'

# Offense count: 48
Metrics/AbcSize:
  Max: 58

# Offense count: 128
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
  Max: 550

# Offense count: 7
# Configuration parameters: CountComments.
Metrics/ClassLength:
  Max: 232

# Offense count: 8
Metrics/CyclomaticComplexity:
  Max: 17

# Offense count: 1110
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
  Max: 562

# Offense count: 58
# Configuration parameters: CountComments.
Metrics/MethodLength:
  Max: 46

# Offense count: 7
Metrics/PerceivedComplexity:
  Max: 19

# Offense count: 1
# Configuration parameters: Blacklist.
# Blacklist: END, (?-mix:EO[A-Z]{1})
Naming/HeredocDelimiterNaming:
  Exclude:
    - 'app/models/build.rb'

# Offense count: 2
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist, MethodDefinitionMacros.
# NamePrefix: is_, has_, have_
# NamePrefixBlacklist: is_, has_, have_
# NameWhitelist: is_a?
# MethodDefinitionMacros: define_method, define_singleton_method
Naming/PredicateName:
  Exclude:
    - 'spec/**/*'
    - 'app/helpers/build_helper.rb'
    - 'app/models/build.rb'

# Offense count: 10
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: snake_case, camelCase
Naming/VariableName:
  Exclude:
    - 'lib/remote_server/stash.rb'
    - 'spec/controllers/repositories_controller_spec.rb'
    - 'spec/models/repository_spec.rb'

# Offense count: 18
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: snake_case, normalcase, non_integer
Naming/VariableNumber:
  Exclude:
    - 'spec/controllers/builds_controller_spec.rb'
    - 'spec/models/build_spec.rb'

# Offense count: 3
# Cop supports --auto-correct.
Performance/RegexpMatch:
  Exclude:
    - 'lib/git_blame.rb'
    - 'lib/remote_server/github.rb'
    - 'lib/remote_server/stash.rb'

# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: NilOrEmpty, NotPresent, UnlessPresent.
Rails/Blank:
  Exclude:
    - 'app/jobs/build_state_update_job.rb'
    - 'app/models/repository.rb'
    - 'lib/git_blame.rb'

# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: Whitelist.
# Whitelist: find_by_sql
Rails/DynamicFindBy:
  Exclude:
    - 'spec/models/build_spec.rb'

# Offense count: 4
Rails/FilePath:
  Exclude:
    - 'app/controllers/status_controller.rb'
    - 'db/seeds.rb'
    - 'spec/lib/build_strategies/production_build_strategy_spec.rb'
    - 'spec/spec_helper.rb'

# Offense count: 2
Rails/OutputSafety:
  Exclude:
    - 'app/helpers/build_helper.rb'
    - 'app/helpers/mail_helper.rb'

# Offense count: 18
# Configuration parameters: Blacklist.
# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
Rails/SkipsModelValidations:
  Exclude:
    - 'app/models/build.rb'
    - 'app/models/build_attempt.rb'
    - 'app/models/build_part.rb'
    - 'spec/controllers/pull_requests_controller_spec.rb'
    - 'spec/features/integration_spec.rb'
    - 'spec/helpers/project_stats_helper_spec.rb'
    - 'spec/mailers/build_mailer_spec.rb'
    - 'spec/models/build_part_spec.rb'
    - 'spec/models/build_spec.rb'

# Offense count: 2
# Configuration parameters: Environments.
# Environments: development, test, production
Rails/UnknownEnv:
  Exclude:
    - 'app/models/repository_observer.rb'
    - 'config/initializers/readthis.rb'

# Offense count: 2
# Cop supports --auto-correct.
Security/YAMLLoad:
  Exclude:
    - 'lib/git_repo.rb'
    - 'lib/settings_accessor.rb'

# Offense count: 92
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: braces, no_braces, context_dependent
Style/BracesAroundHashParameters:
  Exclude:
    - 'app/views/branches/show.rss.builder'
    - 'app/views/branches/status_report.xml.builder'
    - 'db/seeds.rb'
    - 'lib/git_repo.rb'
    - 'lib/remote_server/stash.rb'
    - 'spec/controllers/pull_requests_controller_spec.rb'
    - 'spec/lib/git_blame_spec.rb'
    - 'spec/lib/partitioner/maven_spec.rb'
    - 'spec/lib/partitioner/shared_default_behavior.rb'
    - 'spec/mailers/build_mailer_spec.rb'
    - 'spec/models/build_part_spec.rb'
    - 'spec/models/build_spec.rb'

# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly, IncludeTernaryExpressions.
# SupportedStyles: assign_to_condition, assign_inside_condition
Style/ConditionalAssignment:
  Exclude:
    - 'app/helpers/build_helper.rb'

# Offense count: 52
Style/Documentation:
  Enabled: false

# Offense count: 1
# Cop supports --auto-correct.
Style/EmptyCaseCondition:
  Exclude:
    - 'app/models/build.rb'

# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, expanded
Style/EmptyMethod:
  Exclude:
    - 'app/jobs/build_attempt_job.rb'
    - 'lib/build_strategies/no_op_build_strategy.rb'

# Offense count: 1
# Cop supports --auto-correct.
Style/Encoding:
  Exclude:
    - 'spec/features/integration_spec.rb'

# Offense count: 1
# Configuration parameters: SupportedStyles.
# SupportedStyles: annotated, template
Style/FormatStringToken:
  EnforcedStyle: template

# Offense count: 738
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
Style/HashSyntax:
  Enabled: false

# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: keyword, braces
Style/MultilineMemoization:
  Exclude:
    - 'lib/partitioner/dependency_map.rb'

# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
# SupportedStyles: skip_modifier_ifs, always
Style/Next:
  Exclude:
    - 'app/jobs/enforce_timeouts_job.rb'
    - 'lib/tasks/kochiku.rake'

# Offense count: 16
# Cop supports --auto-correct.
# Configuration parameters: Strict.
Style/NumericLiterals:
  MinDigits: 11

# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
  Exclude:
    - 'spec/**/*'
    - 'app/models/build.rb'
    - 'lib/git_repo.rb'
    - 'lib/partitioner/dependency_map.rb'

# Offense count: 1
# Cop supports --auto-correct.
Style/ParallelAssignment:
  Exclude:
    - 'app/helpers/project_stats_helper.rb'

# Offense count: 68
# Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
  Exclude:
    - 'config/deploy/production.rb'
    - 'db/seeds.rb'
    - 'lib/partitioner/dependency_map.rb'
    - 'spec/controllers/branches_controller_spec.rb'
    - 'spec/helpers/application_helper_spec.rb'
    - 'spec/jobs/build_state_update_job_spec.rb'
    - 'spec/lib/github_commit_status_spec.rb'
    - 'spec/lib/partitioner/dependency_map_spec.rb'
    - 'spec/lib/partitioner/maven_spec.rb'
    - 'spec/lib/partitioner/shared_default_behavior.rb'
    - 'spec/lib/settings_accessor_spec.rb'
    - 'spec/models/build_spec.rb'
    - 'spec/models/repository_spec.rb'

# Offense count: 3
# Cop supports --auto-correct.
Style/Proc:
  Exclude:
    - 'app/mailers/build_mailer.rb'
    - 'app/mailers/merge_mailer.rb'
    - 'config/application.rb'

# Offense count: 2
# Cop supports --auto-correct.
Style/RedundantBegin:
  Exclude:
    - 'lib/git_merge_executor.rb'
    - 'lib/github_post_receive_hook.rb'

# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: AllowMultipleReturnValues.
Style/RedundantReturn:
  Exclude:
    - 'app/models/branch.rb'
    - 'lib/partitioner/default.rb'
    - 'lib/remote_server/stash.rb'

# Offense count: 12
# Cop supports --auto-correct.
Style/RedundantSelf:
  Exclude:
    - 'app/models/branch.rb'
    - 'app/models/build.rb'
    - 'app/models/repository.rb'

# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral:
  Exclude:
    - 'app/controllers/repositories_controller.rb'
    - 'app/helpers/build_helper.rb'
    - 'config/routes.rb'
    - 'spec/models/build_spec.rb'

# Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: ConvertCodeThatCanStartToReturnNil.
Style/SafeNavigation:
  Exclude:
    - 'app/models/build.rb'
    - 'app/models/build_attempt.rb'
    - 'app/models/build_part.rb'
    - 'lib/settings_accessor.rb'

# Offense count: 2
# Cop supports --auto-correct.
Style/SelfAssignment:
  Exclude:
    - 'lib/git_blame.rb'
    - 'lib/partitioner/default.rb'

# Offense count: 1906
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiterals:
  Enabled: false

# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiteralsInInterpolation:
  Exclude:
    - 'lib/remote_server/stash.rb'

# Offense count: 14
# Cop supports --auto-correct.
# Configuration parameters: MinSize, SupportedStyles.
# SupportedStyles: percent, brackets
Style/SymbolArray:
  EnforcedStyle: brackets

# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method
Style/SymbolProc:
  Exclude:
    - 'app/controllers/dashboards_controller.rb'
    - 'app/helpers/project_stats_helper.rb'
    - 'app/models/branch.rb'
    - 'app/models/build.rb'
    - 'db/seeds.rb'
    - 'lib/partitioner/maven.rb'

# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment.
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
Style/TernaryParentheses:
  Exclude:
    - 'app/models/build.rb'

# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: AllowNamedUnderscoreVariables.
Style/TrailingUnderscoreVariable:
  Exclude:
    - 'app/mailers/build_mailer.rb'

# Offense count: 18
# Cop supports --auto-correct.
# Configuration parameters: SupportedStyles, WordRegex.
# SupportedStyles: percent, brackets
Style/WordArray:
  EnforcedStyle: percent
  MinSize: 3


================================================
FILE: .ruby-version
================================================
2.4.3


================================================
FILE: .travis.yml
================================================
sudo: false
cache: bundler
language: ruby
rvm:
  - 2.4.4
  - 2.5.1
before_install:
  # some ruby versions come with a broken version of rubygems, update to
  # consistent version
  - gem update --system 2.7.6
  - gem install bundler -v '>= 1.16.1'
script:
  - RAILS_ENV=test bundle exec rake --trace db:create db:migrate
  - bundle exec rspec
  - bundle exec rubocop
  - bundle exec haml-lint app/views/


================================================
FILE: CONTRIBUTING.md
================================================
Contributing
============

If you would like to contribute code to Kochiku, thank you! You can do so through
GitHub by forking the repository and sending a pull request. However,
before your code can be accepted into the project we need you to sign Square's (super
simple) [Individual Contributor License Agreement (CLA)][1].

[1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1


================================================
FILE: Capfile
================================================
# Load DSL and Setup Up Stages
require 'capistrano/setup'

# Includes default deployment tasks
require 'capistrano/deploy'

# Includes tasks from other gems included in your Gemfile
require 'capistrano/bundler'
require 'capistrano/rails'

# If you would like to use a Ruby version manager with kochiku
# require it from a .cap file in lib/capistrano/tasks/.
#
# For more information see:
# http://capistranorb.com/documentation/frameworks/rbenv-rvm-chruby/

# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.cap').sort.each { |r| import r }


================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'

gem 'actionpack-action_caching', '> 1.1.1'

gem 'activemodel-serializers-xml' # required for xml serialization
gem 'rails-controller-testing' # Included to provide 'assigns' method

gem 'dynamic_form'
gem 'passenger', '~> 4.0.41', group: :production
gem 'rails', '~> 5.1.0'
gem 'rails-observers'

gem 'carrierwave'
gem 'draper', '~> 3.0.1'
gem 'mysql2', '>= 0.4.4'

gem 'compass-rails'
gem 'haml-rails'
gem 'jquery-rails'
gem 'sass-rails'
gem 'uglifier'

# therubyracer is a JS runtime required by execjs, which is in turn required
# by uglifier. therubyracer is not the fastest option but it is the most portable.
gem 'therubyracer'

gem 'hiredis' # better Redis performance for usage as cache
gem 'readthis'
gem 'redis', require: ["redis", "redis/connection/hiredis"]

gem 'resque', '~> 1.27.4'
gem 'resque-retry'
gem 'resque-scheduler', require: false

gem 'json' # used by resque

gem 'awesome_print', require: false
gem 'chunky_png'
gem 'cocaine'
gem 'nokogiri', '~> 1.8', '>= 1.8.4' # 1.8.3 and below have known vulnerabilities
gem 'posix-spawn'  # used by cocaine

gem 'pry-byebug'
gem 'pry-rails'

group :test, :development do
  gem 'factory_bot_rails'
  gem 'haml_lint', require: false
  gem 'rspec-collection_matchers'
  gem 'rspec-rails', '~> 3.0'
  gem 'rubocop', require: false
end

group :development do
  gem 'bullet'
  gem 'capistrano', '~> 3.0', require: false
  gem 'capistrano-bundler', '~> 1.1', require: false
  gem 'capistrano-rails', '~> 1.1', require: false
  gem 'capistrano-rvm', '~> 0.1', require: false
  gem 'rails-erd'
  gem 'thin'
end

group :test do
  gem 'capybara', '~> 2.3'
  gem 'fakeredis', :require => "fakeredis/rspec"
  gem 'webmock', require: false
end


================================================
FILE: LICENSE.txt
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
Kochiku - Distributed tests made easy
=====================================

Kochiku is a distributed platform for test automation. It has three main components:

- A **web server**, which lets you inspect builds and manage repositories
- **Background jobs** that divide builds into distributable parts
- **Workers** that run individual parts of a build

A single machine typically runs the web server and background jobs, whereas many machines run workers.

Use Kochiku to distribute large test suites quickly and easily. It's language agnostic; Use it for Ruby, Rails, Node.js, Ember, Java, C, C++ or anything else that runs in a unix environment.

### Git integration

Kochiku currently integrates with git repositories stored in Github (including Github Enterprise) or Atlassian Bitbucket (formerly known as Stash). This lets Kochiku automatically run test suites for pull requests and commits to the master branch. Kochiku can also build any git revision on request.

Support for headless git servers is coming soon.

## User Guide

- [Installation & Deployment](https://github.com/square/kochiku/wiki/Installation-&-Deployment)
- [Adding a repository](https://github.com/square/kochiku/wiki/How-to-add-a-repository-to-Kochiku)
- [Initiating a build](https://github.com/square/kochiku/wiki/How-to-initiate-a-build-on-Kochiku)
- [Hacking on Kochiku](https://github.com/square/kochiku/wiki/Hacking-on-Kochiku)
- [Changelog](https://github.com/square/kochiku/wiki/CHANGELOG)
- [Additional documentation](https://github.com/square/kochiku/wiki/_pages)


================================================
FILE: Rakefile
================================================
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require File.expand_path('../config/application', __FILE__)
require 'rake'

Kochiku::Application.load_tasks


================================================
FILE: app/assets/javascripts/application.js
================================================
//= require jquery
//= require jquery_ujs
//= require jquery.tipTip
//= require jquery.tablesorter
//= require jquery.timeago
//= require jquery.flot
//= require jquery.flot.errorbars
//= require jquery.flot.categories
//= require moment

//= require_self

moment.lang('en', {
  calendar: {
    sameDay: 'h:mma',
    lastDay: 'ddd ha',
    lastWeek: 'ddd',
    sameElse: 'M/D'
  }
});

Kochiku = {};

StartTimes = {};

Kochiku.delayedRefresh = function(updateInfo) {
  var now = new Date();
  $(updateInfo.table).find('tr:has(.running)').each( function() {
      var startTime = new Date(Date.parse(StartTimes[$(this).data('id')]));
      $(this).find('.elapsed').text(
        Math.floor((now-startTime)/60000) + ":" + ("00" + (Math.round((now-startTime)/1000)%60)).slice(-2));
  });
  setTimeout(function() {
    if($('input#refresh').is(':checked')) {
      $.getJSON(document.URL + '/modified_time', function( data ) {
        var buildTime = Date.parse(data);
        var renderTime = updateInfo.renderTime;
        if(buildTime > renderTime) {
          Kochiku.buildInfo.renderTime = buildTime;
          //keep the updated at display up to date
          var timeAgo = new Date(renderTime).toISOString();
          var updateDisplay = $("#time-since-update");
          updateDisplay.timeago("update", timeAgo);
          updateDisplay.prop("title", timeAgo);
          //ajax in changed parts
          Kochiku.updateBuildParts(renderTime);
        } else if ($(".queue-position-value").length > 0) {
          // if there are displayed queue positions refresh
          Kochiku.updateBuildParts(renderTime);
        }
      });
      Kochiku.delayedRefresh(Kochiku.buildInfo);
    }
  }, 5000);
};

jQuery(document).ready(function() {
  jQuery("abbr.timeago").timeago();
});

Kochiku.updateBuildParts = function(renderTime) {
  $.getJSON(document.URL + '/refresh_build_part_info', { modified_time: renderTime }, function( data ) {
    $.each(data,function(index, el) {
      if (el.state != Kochiku.buildInfo.state) {
        if ( $.inArray(el.state, Kochiku.terminalStates) != -1) {
        switch(el.state) {
          case "succeeded":
          case "passed":
            status = "✅ " + el.state;
            break;
          case "failed":
            status = "🚫 " + el.state;
            break;
          default:
            status = el.state;
        }
        Kochiku.notify(status + " " + Kochiku.doneMessage + Kochiku.buildInfo.repo + "/" + Kochiku.buildInfo.branch);
        }
        window.location.reload();
      }
      var row;
      row = $(Kochiku.buildInfo.table).find("[data-id='" + el.id + "']");
      if (row) {
        row.replaceWith(el.content);
      }
    });
    //reload the table after its updated
    $("table.tablesorter").trigger("update", [true]);
  });
}

Kochiku.notify = function(message) {
  options = {body: message}
  if ( "Notification" in window && Notification.permission !== "denied") {
    Notification.requestPermission(function (permission) {
      if (permission === "granted") {
        var notification = new Notification("Kochiku Build Status", options);
      }
    });
  }
};

Kochiku.graphBuildTimes = function(repositoryPath, branchName) {
  var url = '/' + repositoryPath + '/' + branchName + '/build-time-history',
    colors = {
      cucumber:     'hsl(87,  63%, 47%)',
      spec:         'hsl(187, 63%, 47%)',
      jasmine:      'hsl(27,  63%, 47%)',
      maven:        'hsl(207, 63%, 47%)',
      unit:         'hsl(187, 63%, 47%)',
      integration:  'hsl(87,  63%, 47%)',
      acceptance:   'hsl(207, 63%, 47%)'
    };

  $.getJSON(url, function(data) {
    var plot = $('#plot'),
      series = [];
    for (var label in data) {
      var points = data[label].slice(-20),
        lastTime = null;
      for (var i = 0; i < points.length; i++) {
        var ref = $('<a>')
              .attr('href', '/' + repositoryPath + '/builds/' + points[i][4])
              .attr('class', 'build-status ' + points[i][5])
              .text(points[i][0]).wrap('<div>'),
                time = moment(points[i][6]).calendar().replace(/m$/,'');
        if (time != lastTime) {
          ref.after($('<time>').text(time));
          lastTime = time;
        }
        points[i][0] = ref.parent().html();
      }
      series.push({
        label: label,
        data: points,
        color: colors[label]
      });
    }

    $.plot(plot, series, {
      xaxis: {
        mode: 'categories',
        color: 'transparent'
      },
      yaxis: {
        color: '#f3f3f3'
      },
      points: {
        show: true,
        lineWidth: 1.5,
        radius: 3,
        shadowSize: 0,
        errorbars: 'y',
        yerr: {
          show: true,
          asymmetric: true,
          lineWidth: 1,
          lowerCap: '-'
        }
      },
      grid: {
        borderWidth: 0,
        clickable: true,
        labelMargin: 20,
        margin: {
          left: 20
        }
      },
      legend: {
        show: true,
        position: 'nw',
        noColumns: series.length
      }
    });

    $('<div class="axis-label y">')
      .text('Minutes (Min to Max)')
      .appendTo(plot);
  });
};

(function() {
  var statuses = [
    'Errored', 'Aborted', 'Failed', 'Running', 'Runnable', 'Passed'
  ];

  $.tablesorter.addParser({
    id:     'state',
    type:   'numeric',
    is:     function(s) { return statuses.indexOf(s) !== -1; },
    format: function(s) { return statuses.indexOf(s.replace(/^\s+|\s+$/g, '')); }
  });
})();

function timeToSeconds(time) {
  var timeArr = time.split(':')
  if (timeArr.length === 2) {
    return Number(timeArr[0])*60 + Number(timeArr[1])
  } else {
    return Number(timeArr[0])*3600 + Number(timeArr[1])*60 + Number(timeArr[2])
  }
}

(function() {
  $.tablesorter.addParser({
    id:     'elapsedTime',
    type:   'numeric',
    is:     function(s) { return /^([0-9]*:(?=[0-9]{2}:))?([0-5]?[0-9])(:[0-5][0-9])$/.test(s); },
    format: function(s) { return timeToSeconds(s); }
  });
})();


================================================
FILE: app/assets/stylesheets/screen.sass
================================================
@import compass
@import compass/reset
@import compass/css3/border-radius

/* SQ Market font
@font-face
  font-family: "SQ Market"
  src: url("/fonts/SQMarket-Regular.otf") format("opentype")

/* Variables
$font-base: Helvetica Neue, Helvetica, Arial, sans-serif
$font-code: Inconsolata, Menlo, Monaco, monospace
$color-base: #52585D
$color-title: #52585D
$color-link: #2D81C5

$color-passed: hsl(90, 90%, 70%)
$color-runnable: hsl(216, 40%, 90%)
$color-running: hsl(216, 90%, 70%)
$color-failed: hsl(0, 90%, 70%)
$color-errored: hsl(48, 90%, 70%)
$color-aborted: hsl(0, 0%, 70%)

/* Mixins
=has-layout
  display: block
  zoom: 1

=envelope
  +has-layout

  position: relative
  overflow: hidden

=safe-envelope
  +has-layout

  &:after
    content: " "
    display: block
    height: 0
    clear: both
    overflow: hidden
    visibility: hidden

=text-shadow
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5)

=box-sizing($box-sizing: border-box)
  box-sizing: $box-sizing
  -webkit-box-sizing: $box-sizing
  -moz-box-sizing: $box-sizing

=border-radius($radius: 0)
  -webkit-border-radius: $radius
  -moz-border-radius: $radius
  border-radius: $radius

/* Styles
html, body
  height: 100%

body, input
  font-family: $font-base
  font-size: 12px

#page
  margin: 1em 40px
  min-height: 100%

h1, h2, h3, h4, h5, h6
  font-weight: 300

a
  color: $color-link
  text-decoration: none

strong
  font-weight: bold

code
  font-family: $font-code

input[type=text],
input[type=email],
input[type=password]
  font-family: $font-base
  outline: none !important
  width: 400px
  border-radius: 3px
  -webkit-box-shadow: 0 2px 2px rgba(black, 0.1) inset
  -moz-box-shadow: 0 2px 2px rgba(black, 0.1) inset
  border: solid 1px rgba(black, 0.3)
  padding: 4px
  color: #202122

  &:focus
    border-color: hsla(207, 63%, 47%, 0.6)

input[type=submit], button, .button
  +border-radius(3px)

  box-shadow: 0 1px 0 rgba(white, 0.1) inset, 0 0 3px rgba(black, 0.2)
  border: solid 1px rgba(black, 0.2)
  background: $color-link linear-gradient(to bottom, transparent, rgba(black, 0.2))
  color: white
  text-shadow: 0 -1px 0 rgba(black, 0.2)
  padding: 4px 8px

  a
    color: white

  &:active
    box-shadow: 0 1px 3px rgba(black, 0.2) inset
    color: rgba(white, 0.95)

// Tooltip overrides
#tiptip_content
  font-size: 14px

/* Index
.section-wrapper
  overflow: hidden
  border-bottom: solid 1px #e2e2e2

.section
  +envelope

  margin: 1em

.flash
  text-align: center
  font-size: 14px
  padding: 10px
  border-radius: 12px
  margin-bottom: 10px
  font-weight: bold

  &.message
    background-color: #91f991

  &.error
    background-color: #ff9999

  &.warn
    background-color: #edfa3f

#disabled-repo-alert
  color: #8a6d3b
  background-color: #fcf8e3
  border-color: #faebcc
  font-size: 14px

#header
  a.logo
    float: left

    h1
      font-family: "SQ Market", $font-base
      font-size: 28px
      height: 37px
      color: $color-title + #666

      b
        color: $color-title

      .translation
        font-size: 14px

  ul.links
    display: inline-block

    li
      display: inline-block
      margin-right: 1em

  form
    display: inline-block

#nav
  padding-bottom: 30px

h2.subheader
  color: $color-title + #222
  font-size: 175%
  padding: 0 0 25px

  .info, .actions
    font-size: 12px
    font-weight: normal

  .actions
    float: right
    padding-top: 5px

  form
    display: inline

  label
    margin-left: 1em
    min-width: 0

h3
  color: $color-title + #222
  font-size: 125%
  padding: 0 0 10px

.info + .info
  margin-left: 8px
  padding-left: 8px
  border-left: solid 1px rgba(0, 0, 0, 0.3)

  form
    display: inline-block

.log_contents
  font-family: monospace
  min-height: 300px
  white-space: pre-wrap

.performance
  font-size: 1.1em
  float: right
  width: 300px
  text-align: right

  .great
    color: $color-passed

  .decent
    color: $color-errored

  .bad
    color: $color-failed

  .label
    cursor: help

.build-stats
  margin-bottom: 2em
  width: 700px

#plot
  margin-bottom: 2em
  min-width: 1000px
  height: 180px

  .legend table
    width: auto

    td
      padding: 2px

  .xAxis
    text-align: center
    font-size: 12px

    a
      font-family: $font-code

    .build-status
      position: relative

    .build-status:before
      position: absolute
      left: 50%
      top: -15px
      width: 8px
      height: 8px
      font-size: 8px
      margin: 0
      margin-left: -5px
      border-radius: 2px

    time
      display: block
      font-size: 10px
      margin-top: 2px

  .axis-label
    position: absolute
    color: #666

    &.y
      -webkit-transform: rotate(-90deg)
      left: -45px
      top: 45%

  .flot-overlay, .flot-y-axis
    // make the x-axis clickable
    z-index: -1

#tooltip
  position: absolute
  display: none
  border: 1px solid #52585D
  padding: 2px
  background-color: #B8BEC3
  font-size: 130%
  opacity: 0.8

.build-state
  .state
    font-weight: bold

  .queue
    font-weight: bold

.build
  overflow: hidden
  margin: 0 0 50px

  .build-wrapper
    +envelope

    color: #666
    display: block

    .build-info
      float: left

      .ref
        font-size: 175%
        font-family: $font-code
        line-height: 40px
        letter-spacing: 1px

        &:hover
          color: $color-link

    .times
      float: right
      margin: 10px 20px
      line-height: 15px
      text-align: right

    .build-id
      +text-shadow

      font-family: $font-base
      float: right
      font-size: 400%
      font-weight: bold
      text-align: right

$part-margin: 2px

.parts
  +envelope

  margin: 10px (-$part-margin)

  .part
    overflow: hidden
    float: left
    border: 1px solid rgba(0, 0, 0, 0.1)
    border-radius: 3px
    margin: $part-margin
    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3)

  .part.runnable
    background-color: $color-runnable

  .part.running
    background-color: $color-running

  .part.passed
    background-color: $color-passed

  .part.failed
    background-color: $color-failed

  .part.errored
    background-color: $color-errored

  .part.aborted
    background-color: $color-aborted

  .part-wrapper
    +envelope

    display: block
    margin: 5px
    width: 115px
    height: 25px
    color: #333

    .kind, .attempts
      display: inline-block

    .kind
      font-size: 175%
      font-weight: bold
      line-height: 27px

.attempts
  .attempt
    overflow: hidden

.paths-tooltip
  border: 1px solid rgba(0, 0, 0, 0.5)
  background-color: #fff
  color: #333
  font-size: 120%
  font-family: $font-code
  max-width: 500px !important

  li
    margin: 5px 0

.build-status, .part-status, .attempt-status
  &:before
    content: " "
    border: 1px solid rgba(black, 0.4)
    border-radius: 3px
    display: inline-block
    width: 10px
    height: 10px
    text-align: center
    margin-right: 2px
    box-shadow: 0 1px 1px rgba(black, 0.1)
    font-size: 10px
    font-family: verdana, sans-serif
    font-weight: bold
    color: rgba(black, 0.4)

  &.runnable:before, &.partitioning:before
    background-color: $color-runnable

  &.running:before
    background-color: $color-running

  &.failed:before, &.errored:before, &.aborted:before, &.doomed:before
    content: "!"

  &.failed:before, &.doomed:before
    background-color: $color-failed

  &.errored:before
    background-color: $color-errored

  &.aborted:before
    background-color: $color-aborted

  &.passed:before, &.succeeded:before
    background-color: $color-passed

h2 .build-status:before
  vertical-align: middle

/* New build in header
.header-right
  float: right
  line-height: 32px
  margin-top: 5px

  input.ref
    margin: 0
    width: 200px
    font-size: 100%

/* New build page
input.ref
  width: 500px
  font-family: $font-code
  font-size: 150%

input.build-button
  font-size: 120%

input[disabled]
  background-color: #e8e8e8
  background-image: linear-gradient(#fcfcfc,#e8e8e8)
  border: 1px solid #e8e8e8
  border-top-color: #e8e8e8
  color: #999

/* health pretends to be a button
.health
  float: right
  margin: 8px 5px

table
  table-layout: fixed
  width: 100%

  tr:nth-child(even)
    background-color: rgba(0, 0, 0, 0.05)

  tbody tr:hover
    background-color: #e4edfa !important

  th
    font-weight: bold
    border-bottom: 1px solid rgba(0, 0, 0, 0.1)
    padding: 0 5px 5px
    cursor: pointer
    white-space: nowrap

    &.headerSortDown:after
      content: " ▲"
      font-size: 8px

    &.headerSortUp:after
      content: " ▼"
      font-size: 8px

    code
      font-size: 15px

    &.id
      width: 50px

    &.whisker
      width: 45px

    &.queue-position
      width: 50px

    &.status
      width: 70px

    &.ruby-version
      width: 100px

    &.type
      width: 156px

    &.worker
      width: 156px

    &.time
      width: 80px

    &.count
      width: 50px

    &.actions
      width: 70px

    &.first-path
      width: 100px

    &.date
      width: 180px

  td
    padding: 5px
    white-space: nowrap
    overflow-x: scroll
    /* Fix chrome 67 formating issue */
    position: relative

    &::-webkit-scrollbar
      display: none

    &.whisker
      padding-right: 2px

      .part-status:before
        content: ""
        width: 1px
        height: 10px
        margin-right: -1px
        border-color: rgba(black, 0.2)

      .part-status.attempt-0:before
        height: 1px
        border-color: transparent
        -webkit-box-shadow: none

      .part-status.attempt-1:before
        height: 1px

      .part-status.attempt-2:before
        height: 3px

      .part-status.attempt-3:before
        height: 5px

      .part-status.attempt-4:before
        height: 7px

      .part-status.attempt-5:before
        height: 9px

  th.right, td.right
    text-align: right

  td .paths
    color: #999

    .root
      color: black

  td.wrap
    white-space: normal
    line-height: 1.6

  tr:target td
    background-color: #ffc

/* Search by build revision
.select_commit
  margin-bottom: 20px

#build_ref_input
  width: 100px

/* Build show
.build-info-subheader
  margin: (-15px) 0 25px

.build-summary
  margin-bottom: 10px

/* Build parts show
table.build-part-info
  margin-bottom: 20px

ol#build-paths
  margin-bottom: 20px
  list-style: square inside none
  line-height: 150%

.new-repository-link
  padding-bottom: 20px

.projects-grid
  text-align: center

.projects
  +pie-clearfix

  margin-right: 0.75em
  margin-left: 0.75em

  li.build-info
    margin: 0.3em 0

    &.bold
      font-weight: bold

  .ci-build-info
    position: relative
    display: inline-block
    width: 188px
    height: 188px
    border-radius: 10px
    text-align: center
    vertical-align: top
    margin: 0.5em
    color: rgba(black, 0.8)
    text-shadow: rgba(white, 0.1) 0 1px 0

    +box-shadow(0 1px 2px rgba(black, 0.5), inset 0 0 3px rgba(black, 0.3))

    a
      color: rgba(white, 0.95)
      text-shadow: rgba(black, 0.2) 0 -1px 0

    .project-name
      font-size: 26px
      font-weight: 300

      a
        display: block
        padding: 55px 0 10px
        letter-spacing: 0.05em

    .state
      padding-top: 6px

    .project-link
      display: none
      position: absolute
      bottom: 10px
      width: 100%

    &:hover
      .project-link
        display: block

.ci-errored, .ci-doomed, .ci-failed
  background-color: desaturate(darken($color-failed, 10%), 20%)
  font-weight: bold

.ci-partitioning, .ci-runnable, .ci-running
  background-color: desaturate(darken($color-running, 10%), 20%)

.ci-succeeded
  background-color: desaturate(darken($color-passed, 20%), 20%)

.ci-unknown, .ci-aborted
  background-color: desaturate(darken($color-aborted, 10%), 20%)
  font-weight: bold

/* Repository form styles

fieldset
  legend
    font-weight: bold

  padding: 0.5em 0
  margin: 1em 0

#repository-form label
  display: inline-block
  width: 220px

// Give more spacing to the checkboxes
#repository-form > div, #repository-form fieldset > div
  min-height: 28px

#repository-form input[type='checkbox']
  margin-top: 8px

#repository-form .short
  width: 150px

.delete-form
  float: right
  margin-top: -28px

.danger-button
  background-color: $color-failed !important

#branch-delete-warning
  color: #B8BEC3

/* END Repository form styles

.build-error
  pre
    font-family: monospace
    background-color: rgba(0, 0, 0, 0.05)
    padding: 1em
    margin-bottom: 2em

  h2
    padding: 0.5em
    font-size: 1.5em
    font-weight: bolder
    color: darken($color-failed, 20%)

.build-empty
  div
    display: block
    padding: 1.2em
    margin-bottom: 2em
    background-color: rgba(0, 0, 0, 0.05)

  h2
    padding: 0.5em
    font-size: 1.5em
    font-weight: bolder

.hint
  font-style: italic

p
  line-height: 1.4em

#worker-health-wrap
  overflow: auto

.worker-health
  table-layout: auto

// Firefox doesn't support a fixed table with
// a scroll overflow, so just hide the overflow on Firefox.
// It also doesn't react to just overflow-x, we need to hide
// overflow in both axes
@-moz-document url-prefix()
  table
    td
      overflow: hidden


================================================
FILE: app/controllers/application_controller.rb
================================================
class ApplicationController < ActionController::Base
  include BuildHelper

  rescue_from ActiveRecord::RecordNotFound do |exception|
    render file: "#{Rails.public_path}/404.html", layout: false, status: 404
  end
end


================================================
FILE: app/controllers/branches_controller.rb
================================================
class BranchesController < ApplicationController
  caches_action :show, :build_time_history, cache_path: proc {
    load_repository_and_branch
    { :modified => [@branch.updated_at.to_i, @repository.updated_at.to_i].max }
  }

  caches_action :status_report, expires_in: 15.seconds

  # lists all convergence branches as well the 100 most recently active
  # branches
  def index
    load_repository
    @convergence_branches = @repository.branches.where(convergence: true)
    @recently_active_branches = @repository.branches.where(convergence: false).order('updated_at DESC').limit(100)
  end

  def show
    load_repository_and_branch
    @build = @branch.builds.build
    @builds = @branch.builds.includes(build_parts: :build_attempts).last(12)
    @current_build = @builds.last

    @build_parts = {}
    @builds.reverse_each do |build|
      build.build_parts.each do |build_part|
        key = [build_part.paths.first, build_part.kind, build_part.options['ruby']]
        (@build_parts[key] ||= {})[build] = build_part
      end
    end

    @branch = @branch.decorate

    respond_to do |format|
      format.html
      # Note: appending .rss to the end of the url will not return RSS format
      # due to the very permissive branch id constraint. Instead users will
      # have to specify a query param of format=rss to receive the RSS feed.
      format.rss { @builds = @builds.reverse } # most recent first
      format.json
    end
  end

  def request_new_build
    load_repository_and_branch

    ref = @repository.sha_for_branch(@branch.name)

    existing_build = @repository.build_for_commit(ref)

    if existing_build.present?
      flash[:warn] = "Did not find a new commit on the #{@branch.name} branch to build"
      redirect_to repository_branch_path(@repository, @branch)
    else
      build = @branch.builds.build(ref: ref, state: 'partitioning')

      if build.save
        flash[:message] = "New build started for #{build.ref} on #{@branch.name}"
        redirect_to repository_build_path(@repository, build)
      else
        flash[:error] = "Error adding build! #{build.errors.full_messages.to_sentence}"
        redirect_to repository_branch_path(@repository, @branch)
      end
    end
  end

  def health
    load_repository_and_branch
    initialize_stats_variables
    load_build_stats

    @builds = @branch.builds.includes(:build_parts => :build_attempts).last(params[:count] || 12)

    build_part_attempts = Hash.new(0)
    build_part_failures = Hash.new(0)
    failed_parts = {}
    @builds.each do |build|
      build.build_parts.each do |build_part|
        key = [build_part.paths.sort, build_part.kind]
        build_part.build_attempts.each do |build_attempt|
          if build_attempt.successful?
            build_part_attempts[key] = build_part_attempts[key] + 1
          elsif build_attempt.unsuccessful?
            build_part_attempts[key] = build_part_attempts[key] + 1
            build_part_failures[key] = build_part_failures[key] + 1
            failed_parts[key] = (failed_parts[key] || []) << build_part
          end
        end
      end
    end

    @part_climate = {}
    failed_parts.each do |key, parts|
      part_error_rate = (build_part_failures[key] * 100 / build_part_attempts[key])
      @part_climate[[part_error_rate, key]] = parts.uniq
    end

    @branch = @branch.decorate
  end

  def build_time_history
    load_repository_and_branch

    respond_to do |format|
      format.json do
        render json: @branch.decorate.build_time_history.to_json
      end
    end
  end

  # GET /XmlStatusReport.aspx
  #
  # This action returns the current build status for all of the convergence branches
  # in the system
  def status_report
    @branches = Branch.includes(:repository).where(convergence: true).decorate
  end

  def badge
    @repository || load_repository
    @branch ||= @repository.branches.where(name: params[:branch]).first!
    build = @branch.most_recent_build
    if build.succeeded?
      send_file('public/images/passing.svg', type: 'image/svg+xml', disposition: 'inline')
    elsif build.failed?
      send_file('public/images/failing.svg', type: 'image/svg+xml', disposition: 'inline')
    else # in progress
      send_file('public/images/pending.svg', type: 'image/svg+xml', disposition: 'inline')
    end
  end

  private

  def load_repository
    r_namespace, r_name = params[:repository_path].split('/')
    @repository = Repository.where(namespace: r_namespace, name: r_name).first!
  end

  def load_repository_and_branch
    @repository || load_repository
    @branch ||= @repository.branches.where(name: params[:id]).first!
  end

  # set the various stats variables to reasonable null values in case
  # the load_build_stats method short-circuits
  def initialize_stats_variables
    @days_since_first_build = 0
    @total_build_count = 0
    @total_failure_count = 0
    @total_pass_rate = '—'
    @last30_build_count = 0
    @last30_failure_count = 0
    @last30_pass_rate = '—'
    @last7_build_count = 0
    @last7_failure_count = 0
    @last7_pass_rate = '—'
  end

  def load_build_stats
    @first_built_date = @branch.builds.first.try(:created_at)
    return if @first_built_date.nil?

    @days_since_first_build = (Time.zone.today - @first_built_date.to_date).to_i

    @total_build_count = @branch.builds.count
    @total_failure_count = @branch.builds.where.not(state: 'succeeded').count
    @total_pass_rate = (@total_build_count - @total_failure_count) * 100 / @total_build_count

    @last30_build_count = @branch.builds.where('created_at >= ?', Time.zone.today - 30.days).count
    return if @last30_build_count.zero?
    @last30_failure_count = @last30_build_count - @branch.builds.where('state = "succeeded" AND created_at >= ?', Time.zone.today - 30.days).count
    @last30_pass_rate = (@last30_build_count - @last30_failure_count) * 100 / @last30_build_count

    @last7_build_count = @branch.builds.where('created_at >= ?', Time.zone.today - 7.days).count
    return if @last7_build_count.zero?
    @last7_failure_count = @last7_build_count - @branch.builds.where('state = "succeeded" AND created_at >= ?', Time.zone.today - 7.days).count
    @last7_pass_rate = (@last7_build_count - @last7_failure_count) * 100 / @last7_build_count
  end
end


================================================
FILE: app/controllers/build_artifacts_controller.rb
================================================
class BuildArtifactsController < ApplicationController

  def create
    @build_artifact = BuildArtifact.new
    @build_artifact.build_attempt_id = params[:build_attempt_id]
    @build_artifact.log_file = params[:build_artifact].try(:[], :log_file)

    respond_to do |format|
      if @build_artifact.save
        format.xml  { head :created, :location => @build_artifact.log_file.url }
      else
        format.xml  { render :xml => @build_artifact.errors, :status => :unprocessable_entity }
      end
    end
  end

  # A redirect is preferable to direct linking if logs are stored remotely with expiring urls.
  def show
    build_artifact = BuildArtifact.find(params[:id])

    redirect_to build_artifact.log_file.url
  end
end


================================================
FILE: app/controllers/build_attempts_controller.rb
================================================
require 'json'
require 'net/http'

class BuildAttemptsController < ApplicationController

  def start
    @build_attempt = BuildAttempt.find(params[:id])

    respond_to do |format|
      if @build_attempt.aborted?
        format.json { render :json => @build_attempt }
      elsif @build_attempt.start!(params[:builder])
        @build_attempt.log_streamer_port = params[:logstreamer_port]
        @build_attempt.instance_type = params[:instance_type] if params[:instance_type].present?
        @build_attempt.save
        format.json { render :json => @build_attempt }
      else
        format.json { render :json => @build_attempt.errors, :status => :unprocessable_entity }
      end
    end
  end

  def finish
    @build_attempt = BuildAttempt.find(params[:id])

    respond_to do |format|
      if @build_attempt.finish!(params[:state])
        format.json { head :ok }
        format.html do
          redirect_to repository_build_part_url(@build_attempt.build_part.build_instance.repository,
                                                @build_attempt.build_part.build_instance,
                                                @build_attempt.build_part)
        end
      else
        format.json { render :json => @build_attempt.errors, :status => :unprocessable_entity }
      end
    end
  end

  # Redirects to the build_part page since we don't have a page for a single build attempt.
  # Added as a shortcut method to use when the IDs of the relation chain is not handy.
  def show
    @build_attempt = BuildAttempt.find(params[:id])

    redirect_to repository_build_part_url(
      @build_attempt.build_part.build_instance.repository,
      @build_attempt.build_part.build_instance,
      @build_attempt.build_part,
      anchor: helpers.dom_id(@build_attempt))
  end

  def stream_logs
    @build_attempt = BuildAttempt.find(params[:id])
    unless @build_attempt.log_streamer_port || @build_attempt.builder
      render plain: "No log streaming available for this build attempt", status: 404
    end

    # if full log has already been uploaded, redirect there
    if (stdout_log = @build_attempt.build_artifacts.stdout_log.try(:first))
      redirect_to stdout_log
      return
    end

    @build = @build_attempt.build_instance
    @repository = @build.repository
    @build_part = @build_attempt.build_part
  end

  # basically proxies request to the appropriate worker
  def stream_logs_chunk
    @build_attempt = BuildAttempt.find(params[:id])
    start = params.fetch(:start, 0)
    max_bytes = params.fetch(:maxBytes, 250000)

    port = @build_attempt.log_streamer_port
    builder = @build_attempt.builder
    if !port || !builder
      render json: {"error" => "No log streaming available for this build attempt"}, status: 500
      return
    end

    # logstreamer_base_url = "http://#{builder}:#{port}"

    http = Net::HTTP.new(builder, port)
    http.read_timeout = 5

    response = begin
                 http.get("/build_attempts/#{@build_attempt.id}/log/stdout.log?start=#{start}&maxBytes=#{max_bytes}")
               rescue
                 false
               end

    if !response || response.code !~ /^2/
      render json: {"error" => "unable to reach log streamer"}, status: 500
      return
    end

    output_json = JSON.parse(response.body)
    output_json['state'] = @build_attempt.state
    render json: output_json
  end
end


================================================
FILE: app/controllers/build_parts_controller.rb
================================================
class BuildPartsController < ApplicationController
  before_action :load_repository_build_and_part, only: [:rebuild, :show, :modified_time, :refresh_build_part_info]
  before_action only: [:show, :refresh_build_part_info] do
    calculate_build_attempts_position(@build_part.build_attempts, @build_part.queue)
  end

  include BuildAttemptsQueuePosition

  caches_action :show, cache_path: proc {
    {
      modified: [@build_part.updated_at.to_i, @repository.updated_at.to_i].max,
      queue_position: Digest::SHA1.hexdigest(@build_attempts_rank.values.join(','))
    }
  }

  def show
    respond_to do |format|
      format.html
      format.json do
        render :json => @build_part, include: { build_attempts: { methods: :files } }
      end
    end
  end

  def rebuild
    begin
      @build_part.rebuild!
    rescue GitRepo::RefNotFoundError
      flash[:error] = "It appears the commit #{@build.ref} no longer exists."
    end

    redirect_to [@repository, @build]
  end

  def modified_time
    respond_to do |format|
      format.json do
        render :json => @build_part.updated_at
      end
    end
  end

  def refresh_build_part_info
    updates = []
    if @build_part.finished_at
      updates << { state: @build_part.status }
    else
      @build_part.build_attempts.each_with_index do |attempt, index|
        html = ApplicationController.render(partial: 'build_parts/build_attempts', locals: {  index: index,
                                                                                              attempt: attempt,
                                                                                              build_attempts_rank: @build_attempts_rank})
        updates << {id: index, content: html, state: @build_part.status}
      end
    end
    respond_to do |format|
      format.json do
        render :json => updates
      end
    end
  end

  private

  def load_repository_build_and_part
    r_namespace, r_name = params[:repository_path].split('/')
    @repository = Repository.where(namespace: r_namespace, name: r_name).first!
    @build = Build.joins(:branch_record).where('branches.repository_id' => @repository.id).find(params[:build_id])
    @build_part = @build.build_parts.find(params[:id])
  end
end


================================================
FILE: app/controllers/builds_controller.rb
================================================
require 'git_repo'

class BuildsController < ApplicationController
  before_action :load_repository, :only => [:show, :retry_partitioning, :rebuild_failed_parts, :request_build, :abort, :toggle_merge_on_success, :build_status, :modified_time, :refresh_build_part_info, :resend_status]
  before_action only: [:show, :refresh_build_part_info] do
    @build = Build.includes(build_parts: :build_attempts)
                  .joins(:branch_record).where('branches.repository_id' => @repository.id)
                  .find(params[:id])
    calculate_build_parts_position(@build)
    format_build_parts_position
  end

  include BuildAttemptsQueuePosition

  caches_action :show, cache_path: proc {
    updated_at = Build.select(:updated_at).find(params[:id]).updated_at
    {
      build_modified: [updated_at.to_i, @repository.updated_at.to_i].max,
      queue_position: Digest::SHA1.hexdigest(@build_attempts_rank.values.join(','))
    }
  }

  def show
    respond_to do |format|
      format.html
      format.json { render :json => @build, include: { build_parts: { methods: [:status] } } }
      format.png do
        # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21
        headers['Expires'] = CGI.rfc1123_date(Time.now.utc)

        send_data(@build.to_png, :type => 'image/png', :disposition => 'inline')
      end
    end
  end

  # Public: Kickoff a build from the kochiku CLI script
  #
  # repo_url         - The remote url for the git repository
  # git_sha          - (optional) the SHA of the specific git commit the user is requesting to build
  # git_branch       - String name of the git branch to perform the build of. If
  #                    'git_sha' is not specified then it will use HEAD of the git branch.
  # merge_on_success - Bool. Request kochiku automatically merge the branch if the build succeeds.
  #
  def create
    merge_on_success = (params[:merge_on_success] || false)
    repository = Repository.lookup_by_url(params[:repo_url])
    unless repository
      raise ActiveRecord::RecordNotFound, "Repository for #{params[:repo_url]} not found"
    end

    if params[:git_sha].present?
      build = repository.build_for_commit(params[:git_sha])
      if build
        head :ok, :location => repository_build_url(repository, build)
        return
      end
    end

    branch = repository.branches.where(name: params[:git_branch]).first_or_create!

    ref_to_build = if params[:git_sha].present?
                     params[:git_sha]
                   else
                     repository.sha_for_branch(branch.name)
                   end

    build = branch.builds.build(ref: ref_to_build, state: 'partitioning', merge_on_success: merge_on_success)

    if build.save
      head :ok, :location => repository_build_url(repository, build)
    else
      render :plain => build.errors.full_messages.join('\n'), :status => :unprocessable_entity
    end
  end

  def retry_partitioning
    @build = Build.joins(:branch_record).where('branches.repository_id' => @repository.id).find(params[:id])

    # This means there was an error with the partitioning job; redo it
    if @build.build_parts.empty?
      @build.update_attributes! :state => 'partitioning', :error_details => nil
      @build.enqueue_partitioning_job
    end

    redirect_to [@repository, @build]
  end

  def rebuild_failed_parts
    @build = Build.includes(build_parts: :build_attempts)
                  .joins(:branch_record).where('branches.repository_id' => @repository.id)
                  .find(params[:id])
    @build.build_parts.failed_errored_or_aborted.each do |part|
      # There is an exceptional case in Kochiku where a build part's prior attempt may have
      # passed but the latest attempt failed. We do not want to rebuild those parts.
      part.rebuild! if part.unsuccessful?
    end
    @build.update_attributes! state: 'running'

    redirect_to [@repository, @build]
  end

  def abort
    @build = Build.joins(:branch_record).where('branches.repository_id' => @repository.id).find(params[:id])
    @build.abort!
    redirect_to repository_build_path(@repository, @build)
  end

  def toggle_merge_on_success
    @build = Build.joins(:branch_record).where('branches.repository_id' => @repository.id).find(params[:id])
    @build.update_attributes!(:merge_on_success => params[:merge_on_success])
    redirect_to repository_build_path(@repository, @build)
  end

  def build_status
    @build = @repository ? @repository.builds.find(params[:id]) : Build.find(params[:id])

    respond_to do |format|
      format.json do
        render :json => @build
      end
    end
  end

  def modified_time
    updated_at = Build.joins(:branch_record).where('branches.repository_id' => @repository.id)
                      .find(params[:id]).updated_at
    respond_to do |format|
      format.json do
        render :json => updated_at
      end
    end
  end

  def resend_status
    @build = Build.joins(:branch_record).where('branches.repository_id' => @repository.id).find(params[:id])
    BuildStateUpdateJob.enqueue(@build.id)
    redirect_to repository_build_path(@repository, @build)
  end

  def refresh_build_part_info
    updates = []
    last_modified = Time.zone.at(params[:modified_time].to_i / 1000.0)
    if @build.completed?
      updates << { state: @build.state }
    else
      updatd_parts = @build.build_parts.where("updated_at > ? OR id in (?)", last_modified, @build_parts_position.keys)
      updatd_parts.each do |part|
        html = ApplicationController.render(partial: 'builds/build_parts', locals: { part: part.decorate,
                                                                                     build: @build,
                                                                                     build_parts_position: @build_parts_position,
                                                                                     repository: @repository })
        updates << {id: part.id, content: html, state: @build.state}
      end
    end
    respond_to do |format|
      format.json do
        render :json => updates
      end
    end
  end

  def build_redirect
    build_instance = Build.find(params[:id])
    redirect_to repository_build_path(build_instance.repository, build_instance)
  end

  def build_ref_redirect
    # search prefix so that entire git ref does not have to be provided.
    build_instance = Build.where("ref LIKE ?", "#{params[:ref]}%").first
    redirect_to repository_build_path(build_instance.repository, build_instance)
  end

  private

  def load_repository
    if params[:repository_path]
      r_namespace, r_name = params[:repository_path].split('/')
      @repository = Repository.where(namespace: r_namespace, name: r_name).first!
    end
  end

  def format_build_parts_position
    @build_parts_position = {}
    @build_attempts_rank&.each do |build_attempt_id, position|
      next if position.nil?
      build_part_id = BuildAttempt.find(build_attempt_id).build_part.id
      if @build_parts_position[build_part_id].nil?
        @build_parts_position[build_part_id] = position
      elsif @build_parts_position[build_part_id] > position
        @build_parts_position[build_part_id] = position
      end
    end
  end
end


================================================
FILE: app/controllers/concerns/build_attempts_queue_position.rb
================================================
module BuildAttemptsQueuePosition
  extend ActiveSupport::Concern

  # keep_rank is only true if we are calling calculate_build_attempts_position multiple times on the
  # same build because that build has multiple queues
  def calculate_build_attempts_position(build_attempts, queue, keep_rank: false)
    @build_attempts_rank = {} unless keep_rank
    jobs = Resque.redis.lrange("queue:#{queue}", 0, -1)
    return if jobs.blank?
    build_attempts&.each do |build_attempt|
      next unless build_attempt.state == 'runnable'
      id = build_attempt.id.to_s
      @build_attempts_rank[id] = jobs.index { |job| /"build_attempt_id\":#{id}/.match(job) }
    end
  end

  def calculate_build_parts_position(build)
    @build_attempts_rank = {}
    parts_by_queue = Hash.new([])
    build_attempts = build.build_attempts.includes(:build_part).where(state: 'runnable')
    build_attempts.each do |attempt|
      parts_by_queue[attempt.build_part.queue] += [attempt]
    end

    parts_by_queue.each do |queue, attempts|
      calculate_build_attempts_position(attempts, queue, keep_rank: true)
    end
  end
end


================================================
FILE: app/controllers/dashboards_controller.rb
================================================
class DashboardsController < ApplicationController

  def build_history_by_worker
    build_attempts = BuildAttempt.where("builder IS NOT NULL").order('id DESC').limit(params[:count] || 2000).select(:id, :builder, :state)

    @workers = build_attempts.group_by { |ba| ba.builder }

    @partition_jobs = Build.order('id DESC').limit(150).select(:id, :state).includes(:build_parts)
  end

end


================================================
FILE: app/controllers/pull_requests_controller.rb
================================================
require 'remote_server'

class PullRequestsController < ApplicationController
  def build
    if params['payload']
      # from stash
      handle_stash_request(JSON.parse(params['payload']))
    else
      # from github
      handle_github_request(params)
    end
    render json: {message: "Thanks!"}
  end

  def handle_stash_request(payload)
    @repo = get_repo(payload['repository']['url'])

    if payload['pull_request'] && active_pull_request?(payload['action'])
      branch_name = get_branch_name(payload['pull_request']['head']['ref'])
      sha = payload['pull_request']['head']['sha']
      handle_pull_request(branch_name, sha)
    elsif payload['ref']
      branch_name = get_branch_name(payload['ref'])
      sha = payload['after']
      handle_repo_push_request(branch_name, sha)
    end
  end

  def handle_github_request(payload)
    @repo = get_repo(payload['repository']['ssh_url'])

    pull_request = payload['pull_request']
    if payload['pull_request'] && active_pull_request?(pull_request['state'])
      branch_name = get_branch_name(pull_request['head']['ref'])
      sha = pull_request['head']['sha']
      handle_pull_request(branch_name, sha)
    elsif payload['ref']
      branch_name = get_branch_name(payload['ref'])
      sha = payload['head_commit']['id']
      handle_repo_push_request(branch_name, sha)
    end
  end

  private

  def get_repo(url)
    Repository.lookup_by_url(url)
  end

  def handle_repo_push_request(branch_name, sha)
    return unless @repo

    if @repo.run_ci?
      branch = fetch_branch(branch_name)
      branch.kickoff_new_build_unless_currently_busy(sha) if branch.present? && branch.convergence?
    end
  end

  def handle_pull_request(branch_name, sha)
    return unless @repo

    if @repo.build_pull_requests
      branch = fetch_branch(branch_name, true)
      build = @repo.ensure_build_exists(sha, branch)
      branch.abort_in_progress_builds_behind_build(build)
    end
  end

  def get_branch_name(ref)
    ref.sub(%r{\Arefs/heads/}, '')
  end

  def fetch_branch(name, auto_create = false)
    auto_create ? @repo.branches.where(name: name).first_or_create! : @repo.branches.where(name: name).first
  end

  def active_pull_request?(action)
    action && action != "closed"
  end
end


================================================
FILE: app/controllers/repositories_controller.rb
================================================
class RepositoriesController < ApplicationController

  def create
    if params.fetch(:repository)[:url].blank?
      redirect_to new_repository_path, error: "Missing required value: Repository URL"
      return
    end

    @repository = Repository.new(repository_params)

    # persist the repository and then create initial Branch records for the
    # convergence branches
    if @repository.save && update_convergence_branches
      redirect_to repository_branches_path(@repository)
    else
      @current_convergence_branches = params.fetch(:convergence_branches, "").split(',')
      render template: 'repositories/new'
    end
  end

  def new
    @repository = Repository.new
    @repository.run_ci = true
    @current_convergence_branches = ['master']
  end

  def destroy
    ActiveRecord::Base.no_touching do
      Repository.destroy(params[:id])
    end
    redirect_to repositories_path
  end

  def update
    @repository = Repository.find(params[:id])

    if @repository.update_attributes(repository_params) && update_convergence_branches
      flash[:message] = "Settings updated."
      redirect_to repository_edit_url(@repository)
    else
      @current_convergence_branches = params.fetch(:convergence_branches, "").split(',')
      render template: 'repositories/edit'
    end
  end

  def edit
    r_namespace, r_name = params[:repository_path].split('/')
    @repository = Repository.where(namespace: r_namespace, name: r_name).first!

    @current_convergence_branches = @repository.branches.where(convergence: true).select(:name).collect(&:name)
  end

  def index
    @repositories = Repository.all
  end

  def dashboard
    @branches =
      Branch.joins(:repository)
            .includes(:repository)
            .where(name: 'master')
            .order('repositories.name')
            .decorate
  end

  # build_ref is intended to be used by the Stash webhooks plugin
  # https://marketplace.atlassian.com/plugins/com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin
  def build_ref
    repository = Repository.find(params[:id])

    # Query string parameters are provided for easy integrations, since it the
    # simplest to implement.
    changes = if params[:refChanges]
                params[:refChanges].map do |change|
                  [
                    change[:refId].gsub(/^refs\/heads\//, ''),
                    change[:toHash]
                  ]
                end
              else
                [params.values_at(:ref, :sha)]
              end

    result = changes.map do |ref, sha|
      ensure_build(repository, ref, sha)
    end

    render json: {
      builds: result.map { |build|
        {
          id:        build.id,
          build_url: repository_build_url(repository, build)
        }
      }
    }
  end

  def ensure_build(repository, branch_name, sha)
    branch = repository.branches.where(name: branch_name).first_or_create!

    build = repository.ensure_build_exists(sha, branch)
    branch.abort_in_progress_builds_behind_build(build) unless branch.convergence?

    build
  end

  private

  def repository_params
    params.require(:repository)
          .permit(:enabled, :url, :timeout, :build_pull_requests,
                  :run_ci, :on_green_update, :send_build_success_email,
                  :send_build_failure_email, :allows_kochiku_merges,
                  :email_on_first_failure, :send_merge_successful_email,
                  :assume_lost_after)
  end

  # update_convergence_branches is called by both create and update. This
  # method does more work than is necessary for create but it is used to avoid
  # duplicating code.
  def update_convergence_branches
    new_branch_names = params.fetch(:convergence_branches, "").split(',').map(&:strip)
    current_convergence_branches = @repository.branches.where(convergence: true).all
    current_branch_names = current_convergence_branches.collect(&:name)
    remove_convergence_from = current_branch_names - new_branch_names
    add_convergence_to = new_branch_names - current_branch_names

    remove_convergence_from.each do |name|
      current_convergence_branches.detect { |branch|
        branch.name == name
      }.update!(convergence: false)
    end

    add_convergence_to.each do |name|
      branch = @repository.branches.where(name: name).first_or_create!
      branch.update!(convergence: true)
    end
    true
  end
end


================================================
FILE: app/controllers/status_controller.rb
================================================
class StatusController < ApplicationController

  def available
    if File.exist?(Rails.root.join("tmp/maintenance"))
      head :service_unavailable
    else
      head :ok
    end
  end

end


================================================
FILE: app/decorators/branch_decorator.rb
================================================
require 'set'

class BranchDecorator < Draper::Decorator
  delegate_all

  def most_recent_build_state
    object.most_recent_build.try(:state) || 'unknown'
  end

  def last_build_duration
    object.last_completed_build.try(:elapsed_time)
  end

  # Recent build timing information grouped by test types.
  def build_time_history(fuzzy_limit = 1000)
    result = Hash.new { |hash, key| hash[key] = [] }

    builds = {}
    build_types = Set.new
    object.timing_data_for_recent_builds.each do |timing_data|
      next if timing_data.empty?
      build_type = timing_data.shift # the type of test that was executed (e.g. cucumber)
      build_id = timing_data[4] # e.g 65874
      build_types.add(build_type)
      builds[build_id] ||= {}
      builds[build_id][build_type] = timing_data
    end

    builds.keys.sort.each do |build|
      build_types.each do |build_type|
        timing_data = builds[build][build_type] || [] # jquery.flot dislikes missing data
        result[build_type] << timing_data
      end
    end

    result
  end
end


================================================
FILE: app/decorators/build_part_decorator.rb
================================================
class BuildPartDecorator < Draper::Decorator
  delegate_all

  def most_recent_stdout_artifact
    BuildArtifact
      .joins(:build_attempt => :build_part)
      .where(
        'build_attempts.build_part_id' => object.id,
        'build_attempts.state' => BuildAttempt::COMPLETED_BUILD_STATES
      ).stdout_log.last
  end
end


================================================
FILE: app/helpers/application_helper.rb
================================================
module ApplicationHelper
  def duration_strftime(duration_in_seconds, format = "%H:%M:%S")
    return "N/A" if duration_in_seconds.nil? ||
                    (duration_in_seconds.respond_to?(:nan?) && duration_in_seconds.nan?)
    (Time.mktime(0) + duration_in_seconds).strftime(format).sub(/^00[ :h]+0?/, "")
  end

  def time_for(time, format = "%H:%M")
    time.strftime(format)
  end

  def build_success_in_words(build)
    case build.state
    when 'succeeded'
      'success'
    when 'errored', 'doomed'
      'failed'
    else
      build.state.to_s
    end
  end

  def build_activity(build)
    return "Unknown" unless build.is_a?(Build)

    case build.state
    when 'partitioning', 'runnable', 'running'
      "Building"
    when 'doomed', 'failed', 'succeeded', 'errored'
      "CheckingModifications"
    end
  end

  def link_to_commit(repo, commit_sha)
    link_to(commit_sha[0, 7], show_link_to_commit(repo, commit_sha))
  end

  def link_to_branch(build)
    branch_record = build.branch_record
    branch_name = branch_record.name
    link_to(branch_name, branch_record.repository.get_branch_url(branch_name))
  end

  def show_link_to_commit(repo, commit_sha)
    repo.remote_server.href_for_commit(commit_sha).to_s
  end

  def show_link_to_compare(build, first_commit_hash, second_commit_hash)
    repo = build.repository
    attrs_from_remote_server = RemoteServer.for_url(repo.url)

    if attrs_from_remote_server.class == RemoteServer::Stash
      second_commit_hash = repo.on_green_update.blank? ? "" : repo.on_green_update.split(',').first
    end
    attrs_from_remote_server.url_for_compare(first_commit_hash, second_commit_hash)
  end

  def show_link_to_create_pull_request(build)
    build.repository.open_pull_request_url(build.branch_record.name)
  end

  def timeago(time, options = {})
    options[:class] ||= "timeago"
    content_tag(:abbr, time.to_s, options.merge(:title => time.getutc.iso8601)) if time
  end
end


================================================
FILE: app/helpers/build_helper.rb
================================================
module BuildHelper
  def build_metadata_headers(build, display_ruby_version)
    headers = []
    headers << "Ruby Version" if display_ruby_version

    if is_a_build_with_one_part?(build)
      headers << "Target"
    else
      headers << "Paths"
    end
    headers
  end

  def build_metadata_values(build, build_part, display_ruby_version)
    values = []
    values << build_part.options["ruby"] if display_ruby_version
    values << format_paths(build_part)
    values
  end

  def format_paths(build_part)
    if build_part.options['total_workers'] && build_part.options['worker_chunk']
      build_part.paths.first + " - Chunk #{build_part.options['worker_chunk']} of #{build_part.options['total_workers']}"
    elsif build_part.paths.size == 1
      if build_part.paths.first == "/dev/null"
        build_part.kind
      else
        build_part.paths.first
      end
    else
      first, *rest = build_part.paths
      first = first.sub(/([^\/]+)/, '<b class="root">\1</b>')
      paths = [first, rest].join(', ')
      "#{build_part.paths.length} <span class=\"paths\" title=\"#{build_part.paths.join(', ')}\">(#{paths})</span>".html_safe
    end
  end

  def multiple_ruby_versions?(build)
    build.build_parts.map { |bp| bp.options['ruby'] }.compact.uniq.size > 1
  end

  def is_a_build_with_one_part?(build)
    build.build_parts.none? { |build_part| build_part.paths.size > 1 }
  end

  def eligible_for_merge_on_success?(build)
    !build.succeeded? && !build.branch_record.convergence? && build.repository.allows_kochiku_merges?
  end
end


================================================
FILE: app/helpers/mail_helper.rb
================================================
module MailHelper
  def failed_build_part_sentence(build_part)
    stdout_log = build_part.most_recent_stdout_artifact
    str = "failed after #{build_part.elapsed_time.to_i / 60} minutes"
    if stdout_log
      str += ", for details you can go directly to the #{link_to('stdout', build_artifact_url(stdout_log))} log."
    end
    str.html_safe
  end

  def failed_build_paths(build_part)
    paths = build_part.paths

    str = if build_part.kind.include?('spec')
            paths.map { |path| path.split('/').last }
          else
            paths
          end

    str.join(', ').truncate(200)
  end
end


================================================
FILE: app/helpers/project_stats_helper.rb
================================================
module ProjectStatsHelper
  def pass_rate_css_class(rate)
    case rate.to_i
    when 0..39 then 'bad'
    when 40..75 then 'decent'
    else 'great'
    end
  end

  def rebuild_count_css_class(attempts)
    case attempts
    when 0..1 then 'great'
    when 1..4 then 'decent'
    else 'bad'
    end
  end

  # A string representing the percentage of builds that eventually passed
  def eventual_pass_rate(builds)
    pass_rate_text(builds.select(&:succeeded?).size / builds.size.to_f)
  end

  # A string representing the percentage of the builds that had
  # all tests pass on the first try.
  def error_free_pass_rate(builds)
    error_free_count = builds.to_a.count do |build|
      build.succeeded? && build.build_parts.all_passed_on_first_try?
    end
    total_count = builds.to_a.count(&:completed?)
    pass_rate_text(error_free_count / total_count.to_f)
  end

  def pass_rate_text(number)
    format("%1.0f%%", 100 * number)
  end

  # Calculates the average number of rebuilds required before builds succeed.
  # Only considers builds that are successful because builds that are not yet
  # successful would skew the calculation.
  def average_number_of_rebuilds(builds)
    successful_builds = builds.select(&:succeeded?)
    total_build_parts, total_build_attempts = 0, 0

    successful_builds.each do |build|
      total_build_attempts += build.build_attempts.count
      total_build_parts += build.build_parts.count
    end

    (total_build_attempts - total_build_parts) / successful_builds.size.to_f
  end

  def median_elapsed_time(builds)
    successful_builds = builds.select(&:succeeded?)
    elapsed_times = successful_builds.map { |build| build.elapsed_time || 0 }
    times = elapsed_times.length
    if times.zero?
      nil
    else
      elapsed_times.sort!
      (elapsed_times[(times - 1) / 2] + elapsed_times[times / 2]) / 2.0
    end
  end

  def seconds_to_minutes(seconds)
    (seconds / 60).round if seconds.is_a?(Numeric)
  end
end


================================================
FILE: app/jobs/build_attempt_job.rb
================================================
require 'job_base'

# Keep this interface so we can easily enqueue new jobs.
# The job is handled by kochiku-worker
class BuildAttemptJob < JobBase
  class WrongBuildAttemptJobClassError < StandardError; end

  def initialize(build_options)
    raise WrongBuildAttemptJobClassError, "BuildAttemptJob was processed by the BuildAttemptJob shim in Kochiku instead of real class in Kochiku-worker."
  end

  def perform
  end
end


================================================
FILE: app/jobs/build_initiated_by_job.rb
================================================
require 'job_base'
require 'git_repo'

class BuildInitiatedByJob < JobBase
  extend Resque::Plugins::Retry
  @queue = :low

  @retry_limit = 5
  @retry_exceptions = {GitRepo::RefNotFoundError => [60, 60, 60, 180, 360],
                       Cocaine::ExitStatusError => [30, 60, 60, 60, 60] }

  def initialize(build_id)
    @build = Build.find(build_id)
  end

  def perform
    return if @build.initiated_by
    email = GitBlame.last_email_in_branch(@build).first
    if email.present?
      @build.update_attributes(initiated_by: email)
    end
  end
end


================================================
FILE: app/jobs/build_partitioning_job.rb
================================================
require 'job_base'
require 'git_repo'
require 'partitioner'

class BuildPartitioningJob < JobBase
  extend Resque::Plugins::Retry
  @queue = :partition

  @retry_limit = 5
  @retry_exceptions = {GitRepo::RefNotFoundError => [60, 60, 60, 180, 360],
                       Cocaine::ExitStatusError => [30, 60, 60, 60, 60] }

  def initialize(build_id)
    @build = Build.find(build_id)
  end

  def perform
    if @build.test_command.blank?
      error_message = "No test_command specified in kochiku.yml."
      @build.update!(:error_details => { :message => error_message, :backtrace => nil }, :state => 'errored')
    else
      partitioner = Partitioner.for_build(@build)
      parts = partitioner.partitions
      if parts.empty? && partitioner.partitioner_type == "Go"
        @build.update!(:state => 'succeeded')
      else
        @build.partition(parts)
      end
    end
    @build.update_commit_status!
  end

  def on_exception(e)
    if self.class.retry_exception?(e) && !self.class.retry_limit_reached?
      @build.update_attributes!(:state => :waiting_for_sync)
    else
      @build.update_attributes!(
        :state => 'errored',
        :error_details => { :message => e.to_s, :backtrace => e.backtrace.join("\n") }
      )
      @build.update_commit_status!
    end
    super
  end
end


================================================
FILE: app/jobs/build_state_update_job.rb
================================================
require 'job_base'
require 'git_repo'
require 'github_commit_status'

# this job updates the remote repo. it is enqueued when a build's state changes.
class BuildStateUpdateJob < JobBase
  @queue = :high

  def initialize(build_id)
    @build_id = build_id
  end

  def perform
    build = Build.find(@build_id)

    # notify github/stash that the build status has changed
    build.update_commit_status!

    # trigger another build for this branch if there is unbuilt commits
    if build.branch_record.convergence? && build.completed?
      sha = build.repository.sha_for_branch(build.branch_record.name)
      build.branch_record.kickoff_new_build_unless_currently_busy(sha)
    end

    build.send_build_status_email!

    if build.succeeded?
      if !build.on_success_script_log_file.present? && build.on_success_script.present?
        BuildStrategy.run_success_script(build)
      end
    end

    if build.promotable?
      build.promote!
    elsif build.merge_on_success_enabled?
      if build.mergable_by_kochiku?
        # ACHTUNG merge to master isn't right anymore. This part my have been changed by shenil
        build.merge_to_master!
      else
        Rails.logger.warn("Build #{build.id} has merge_on_success enabled but cannot be merged.")
      end
    end
  end
end


================================================
FILE: app/jobs/enforce_timeouts_job.rb
================================================
# The EnforceTimeoutsJob searches for BuildAttempts that were picked up by a
# kochiku worker but never heard back from again. It compares (Time.now -
# started_at) against the timeout value of the repository. If the maximum time
# has elapsed, it will mark the BuildAttempt as errored and kick off a rebuild.
class EnforceTimeoutsJob
  def self.perform
    # The EnforceTimeoutsJob runs frequently so we do not check BuildAttempts greater than 1 day old
    BuildAttempt.where("created_at > ? AND state = 'running' AND started_at IS NOT NULL", 1.day.ago).each do |attempt|
      lenient_timeout = attempt.build_instance.repository.timeout + 5
      if attempt.elapsed_time > lenient_timeout.minutes
        # Error artifact creation taken from kochiku-worker
        message = StringIO.new
        message.puts("This BuildAttempt has not been updated by its worker,\n" \
                     "and has been running longer then the timeout so it has\n" \
                     "been considered lost by Kochiku.")
        message.rewind
        def message.path
          'error.txt'
        end

        BuildArtifact.create(:build_attempt_id => attempt.id, :log_file => message)
        attempt.update!(state: 'errored', finished_at: Time.current)
        Rails.logger.error "Errored BuildAttempt:#{attempt.id} due to timeout"

        # Enqueue another BuildAttempt if this is the most recent attempt for the BuildPart
        part = attempt.build_part
        part.rebuild! if part.build_attempts.last == attempt
      end
    end
  end
end


================================================
FILE: app/jobs/job_base.rb
================================================
class JobBase
  class << self
    def enqueue(*args)
      Resque.enqueue(self, *args)
    end

    def enqueue_on(build_queue, *args)
      Resque::Job.create(build_queue, self, *args)
      Resque::Plugin.after_enqueue_hooks(self).each do |hook|
        klass.send(hook, *args)
      end
    end

    def perform(*args)
      job = new(*args)
      job.perform
    rescue => e
      if job
        job.on_exception(e)
      else
        raise e
      end
    end
  end

  def on_exception(e)
    raise e
  end
end


================================================
FILE: app/jobs/poll_repositories_job.rb
================================================
class PollRepositoriesJob
  def self.perform
    Repository.where(enabled: true).find_each(batch_size: 10) do |repo|
      branch = repo.convergence_branches.first || repo.branches.where(name: 'master').first

      if branch.nil?
        Rails.logger.warn("[PollRepositoriesJob] Could not find a branch to check for repo #{repo.name_with_namespace}")
      end

      begin
        head = repo.sha_for_branch(branch.name)
      rescue RemoteServer::AccessDenied, RemoteServer::RefDoesNotExist, Zlib::BufError => e
        Rails.logger.error("[PollRepositoriesJob] Exception #{e} occurred for repo #{repo.id}:#{repo.name_with_namespace}. Automatically setting the repository to disabled.")
        repo.update!(enabled: false)
        next
      end

      unless repo.build_for_commit(head)
        branch.builds.create!(ref: head, state: 'partitioning')
        Rails.logger.info "Build created for #{repo.namespace}/#{repo.name}:#{branch.name} at #{head}"
      end

      sleep 0.5 # take a breath
    end
  end
end


================================================
FILE: app/jobs/timeout_stuck_builds_job.rb
================================================
class TimeoutStuckBuildsJob < JobBase
  @queue = :high

  def self.perform
    clean_lost_builds
    clean_runnable_not_queued
  end

  def self.clean_runnable_not_queued
    # check for builds in runnable that are no longer in the queue
    missing = []
    BuildAttempt.select("build_attempts.id", " build_parts.queue as queue").joins(:build_part)
                .where("build_attempts.state = 'runnable' AND build_attempts.created_at < ? AND build_attempts.created_at > ?", 5.minutes.ago, 1.day.ago)
                .group_by(&:queue)
                .each do |queue, attempts|
                  current_queue = Resque.redis.lrange("queue:#{queue}", 0, -1).to_s
                  missing += attempts.reject { |attempt| current_queue.match(/build_attempt_id\\*\"\:#{attempt.id}[^0-9]/) }
                end

    missing.select! { |build_attempt_partial| BuildAttempt.find(build_attempt_partial.id).state == 'runnable' }
    missing.each { |build_attempt_partial| BuildAttempt.find(build_attempt_partial.id).finish!('errored') }
  end

  def self.clean_lost_builds
    # check for builds that have hit their assume_lost_after
    Repository.where("assume_lost_after IS NOT NULL").find_each do |repo|
      repo.build_attempts.where("build_attempts.state = 'running' AND build_attempts.started_at < ?", repo.assume_lost_after.minutes.ago).each do |build_attempt|
        build_attempt.finish!('errored')
      end
    end
  end
end


================================================
FILE: app/mailers/build_mailer.rb
================================================
class BuildMailer < ActionMailer::Base
  helper :application, :mail

  default :from => Proc.new { Settings.sender_email_address }

  private

  def pull_request_link(build)
    @build = build

    remote_server = @build.repository.remote_server
    if remote_server.class == RemoteServer::Stash && !@build.branch_record.convergence?
      begin
        id, _ = remote_server.get_pr_id_and_version(@build.branch_record.name)
        return "#{remote_server.base_html_url}/pull-requests/#{id}/overview"
      rescue RemoteServer::StashAPIError
        # not all branches will have an open pull request
        return nil
      end
    end
    nil
  end

  public

  def error_email(build_attempt, error_text = nil)
    @build_part = build_attempt.build_part
    @builder = build_attempt.builder
    @error_text = error_text
    mail :to => Settings.kochiku_notifications_email_address,
         :subject => "[kochiku] Build part errored on #{@builder}",
         :from => Settings.sender_email_address
  end

  def build_break_email(build)
    @build = build

    # Allow the partitioner to be selective about who is emailed
    partitioner = Partitioner.for_build(@build)
    @responsible_email_and_files = partitioner.emails_for_commits_causing_failures
    @emails = @responsible_email_and_files.keys
    if @emails.empty?
      @emails = if @build.branch_record.convergence?
                  GitBlame.emails_since_last_green(@build)
                else
                  GitBlame.emails_in_branch(@build)
                end
    end

    @git_changes = if @build.branch_record.convergence?
                     GitBlame.changes_since_last_green(@build)
                   else
                     GitBlame.changes_in_branch(@build)
                   end

    @failed_build_parts = @build.build_parts.failed_or_errored.decorate
    @pr_link = pull_request_link(build)

    mail :to => @emails,
         :bcc => Settings.kochiku_notifications_email_address,
         :subject => "[kochiku] Failure - #{@build.branch_record.name} build for #{@build.repository.name}",
         :from => Settings.sender_email_address
  end

  def build_success_email(build)
    @build = build
    @email = GitBlame.last_email_in_branch(@build)
    @git_changes = GitBlame.changes_in_branch(@build)
    @pr_link = pull_request_link(build)

    mail :to => @email,
         :bcc => Settings.kochiku_notifications_email_address,
         :subject => "[kochiku] Success - #{@build.branch_record.name} build for #{@build.repository.name}",
         :from => Settings.sender_email_address
  end
end


================================================
FILE: app/mailers/merge_mailer.rb
================================================
class MergeMailer < ActionMailer::Base
  helper :application

  default :from => Proc.new { Settings.sender_email_address }

  def merge_successful(build, merge_commit, emails, stdout_and_stderr)
    @build = build
    @merge_commit = merge_commit
    @stdout_and_stderr = stdout_and_stderr

    mail(:to => emails,
         :bcc => Settings.kochiku_notifications_email_address,
         :subject => "[kochiku] Merged #{@build.branch_record.name} branch for #{@build.repository.name}")
  end

  def merge_failed(build, emails, stdout_and_stderr)
    @build = build
    @stdout_and_stderr = stdout_and_stderr
    mail(:to => emails,
         :bcc => Settings.kochiku_notifications_email_address,
         :subject => "[kochiku] Failed to merge #{@build.branch_record.name} branch for #{@build.repository.name}")
  end
end


================================================
FILE: app/models/branch.rb
================================================
class Branch < ActiveRecord::Base
  belongs_to :repository
  has_many :builds, :dependent => :destroy, :inverse_of => :branch_record

  validates :name, :presence => true

  def to_param
    self.name
  end

  def kickoff_new_build_unless_currently_busy(ref)
    last_build = builds.last
    if last_build && !last_build.completed?
      last_build
    else
      builds.create_with(state: 'partitioning').find_or_create_by!(ref: ref)
    end
  end

  def abort_in_progress_builds_behind_build(current_build)
    builds.where(state: Build::IN_PROGRESS_STATES).readonly(false)
          .reject { |build| build.id >= current_build.id }
          .each { |build| build.abort! }
  end

  def most_recent_build
    @most_recent_build ||= builds.last
  end

  def last_completed_build
    @last_completed_build ||= builds.completed.last
  end

  # The fuzzy_limit is used to set a upper bound on the amount of time that the
  # sql query will take
  def timing_data_for_recent_builds(fuzzy_limit = 1000)
    id_cutoff = builds.maximum(:id).to_i - fuzzy_limit

    self.class.connection.execute(build_time_history_sql(id_cutoff))
  end

  private

  def build_time_history_sql(min_build_id)
    return <<-SQL
      SELECT build_parts.kind AS kind,
             SUBSTR(builds.ref, 1, 5) AS ref,
             IFNULL(FLOOR(ROUND(MAX(UNIX_TIMESTAMP(build_attempts.finished_at) - UNIX_TIMESTAMP(build_attempts.started_at)) / 60)), 0) AS max,
             IFNULL(FLOOR(ROUND(MAX(UNIX_TIMESTAMP(build_attempts.finished_at) - UNIX_TIMESTAMP(build_attempts.started_at)) / 60)) - FLOOR(ROUND(MIN(UNIX_TIMESTAMP(build_attempts.finished_at) - UNIX_TIMESTAMP(build_attempts.started_at)) / 60)), 0) AS min_diff,
             0 AS max_diff,
             builds.id,
             builds.state,
             builds.created_at
        FROM builds
   LEFT JOIN build_parts ON build_parts.build_id = builds.id
   LEFT JOIN build_attempts ON build_attempts.build_part_id = build_parts.id
       WHERE builds.branch_id = #{id}
         AND builds.id >= #{min_build_id}
         AND (build_attempts.id IS NULL OR build_attempts.id = (
               SELECT id
                 FROM build_attempts
                WHERE build_part_id = build_parts.id
             ORDER BY id DESC
                LIMIT 1
             ))
    GROUP BY builds.id, build_parts.kind, builds.state, builds.created_at
    SQL
  end
end


================================================
FILE: app/models/build.rb
================================================
require 'on_success_uploader'
require 'fileless_io'
require 'build_partitioning_job'
require 'build_initiated_by_job'

class Build < ActiveRecord::Base
  # using 'branch_record' instead of 'branch' because Build has a legacy 'branch' string type column. The legacy column will be removed soon.
  belongs_to :branch_record, :class_name => "Branch", :foreign_key => "branch_id", :inverse_of => :builds, :touch => true
  has_one :repository, :through => :branch_record
  has_many :build_parts, :dependent => :destroy, :inverse_of => :build_instance do
    def not_passed_and_last_attempt_in_state(*state)
      joins(:build_attempts).joins(<<-EOSQL).where("build_attempts.state" => state, "passed_attempt.id" => nil, "newer_attempt.id" => nil)
        LEFT JOIN build_attempts
          AS passed_attempt
          ON build_attempts.build_part_id = passed_attempt.build_part_id
            AND passed_attempt.state = 'passed'
        LEFT JOIN build_attempts
          AS newer_attempt
          ON build_attempts.build_part_id = newer_attempt.build_part_id
            AND newer_attempt.id > build_attempts.id
      EOSQL
    end

    def passed
      joins(:build_attempts).where("build_attempts.state" => 'passed').group("build_parts.id")
    end

    def failed
      not_passed_and_last_attempt_in_state('failed')
    end

    def failed_or_errored
      not_passed_and_last_attempt_in_state('failed', 'errored')
    end

    def failed_errored_or_aborted
      not_passed_and_last_attempt_in_state('failed', 'errored', 'aborted')
    end

    def errored
      not_passed_and_last_attempt_in_state('errored')
    end

    def all_passed_on_first_try?
      successful_build_attempts = joins(:build_attempts).where("build_attempts.state" => 'passed').count
      unsuccessful_build_attempts = joins(:build_attempts).where("build_attempts.state != ?", 'passed').count
      successful_build_attempts > 0 && unsuccessful_build_attempts == 0
    end
  end
  has_many :build_attempts, :through => :build_parts
  TERMINAL_STATES = %w[failed succeeded errored aborted].freeze
  FAILED_STATES = %w[failed errored doomed].freeze
  IN_PROGRESS_STATES = %w[waiting_for_sync partitioning runnable running doomed].freeze
  STATES = IN_PROGRESS_STATES + TERMINAL_STATES
  validates :state, inclusion: { in: STATES }
  serialize :error_details, Hash
  serialize :kochiku_yml_config, Hash

  validates :branch_id, presence: true
  validates :ref, presence: true,
                  length: { is: 40, allow_blank: true },
                  uniqueness: { scope: :branch_id, allow_blank: true }

  mount_uploader :on_success_script_log_file, OnSuccessUploader

  after_commit :enqueue_partitioning_job, :on => :create
  after_commit :enqueue_initiated_by, on: :create

  scope :completed, -> { where(state: TERMINAL_STATES) }

  def test_command
    tc = self[:test_command]
    if tc.nil?
      tc = (kochiku_yml && kochiku_yml.key?('test_command')) ? kochiku_yml['test_command'] : repository.test_command
      self.update_attributes(test_command: tc)
    end
    tc
  end

  def on_success_script
    (kochiku_yml && kochiku_yml.key?('on_success_script')) ? kochiku_yml['on_success_script'] : nil
  end

  def previous_build
    branch_record.builds.where("id < ?", self.id).order("id DESC").first
  end

  def previous_successful_build
    Build.where(branch_id: self.branch_id, state: 'succeeded').where("id < ?", self.id).order("id DESC").first
  end

  def enqueue_partitioning_job
    Resque.enqueue(BuildPartitioningJob, self.id) if repository.enabled?
  end

  def kochiku_yml
    if @kochiku_yml.nil?
      # try to load the kochiku.yml info from the build's repo, if it is not in the DB already
      update_attributes!(kochiku_yml_config: GitRepo.load_kochiku_yml(repository, ref)) if kochiku_yml_config.empty?

      # if there's actually no kochiku.yml file for the build, the kochiku_yml_config
      # attribute would still be empty, even after the above update.
      @kochiku_yml = kochiku_yml_config.empty? ? false : kochiku_yml_config
    else
      @kochiku_yml
    end
  end

  def partition(parts)
    return unless repository.enabled?
    transaction do
      update_attributes!(:state => 'runnable')
      parts.each do |part|
        build_parts.create!(:kind => part['type'],
                            :paths => part['files'],
                            :queue => part['queue'],
                            :retry_count => part['retry_count'],
                            :options => part['options'])
      end
    end

    build_parts.each { |build_part| build_part.create_and_enqueue_new_build_attempt! }
  end

  def update_state_from_parts!
    return if build_parts.empty?

    errored = build_parts.errored
    passed = build_parts.passed
    failed = build_parts.failed
    next_state = case
                 when (build_parts - passed).empty?
                   'succeeded'
                 when self.state == 'aborted'
                   'aborted'
                 when errored.any?
                   'errored'
                 when (passed | failed).count == build_parts.count
                   'failed'
                 else
                   failed.empty? ? 'running' : 'doomed'
                 end

    previous_state = self.state
    update_attributes!(:state => next_state) unless previous_state == next_state
    [previous_state, next_state]
  end

  def update_commit_status!
    repository.remote_server.update_commit_status!(self)
  end

  # As implemented, finished_at will return the wrong value if there is a
  # unsuccessful attempt following a successful one. Left this way for
  # performance and simplicity.
  def finished_at
    build_attempts.maximum(:finished_at)
  end

  def elapsed_time
    last_finished_at = finished_at
    return nil if last_finished_at.blank?
    last_finished_at - created_at
  end

  def linear_time
    build_parts.inject(0) do |sum, part|
      sum + (part.elapsed_time || 0)
    end
  end

  def retry_count
    build_parts.sum(0) do |part|
      part.build_attempts.count - 1
    end
  end

  def max_retries
    build_parts.max_by { |part| part.build_attempts.count }.build_attempts.count - 1
  end

  # This can be used as `building_time` under the assumption that
  # all parts executed in parallel.
  def longest_build_part
    build_parts.max_by { |part| part.elapsed_time || 0 }.elapsed_time
  end

  def idle_time
    (elapsed_time || 0) - (longest_build_part || 0)
  end

  def succeeded?
    state == 'succeeded'
  end

  def failed?
    FAILED_STATES.include?(state)
  end

  # has a build part with failed attempts but no successful ones yet
  def already_failed?
    build_parts.any? { |part| part.build_attempts.unsuccessful.exists? && !part.build_attempts.where(state: 'passed').exists? }
  end

  def aborted?
    state == 'aborted'
  end

  def promotable?
    succeeded? && branch_record.convergence?
  end

  def mergable_by_kochiku?
    succeeded? && merge_on_success_enabled? && repository.allows_kochiku_merges? && !newer_branch_build_exists?
  end

  def merge_on_success_enabled?
    !branch_record.convergence? && self.merge_on_success
  end

  def newer_branch_build_exists?
    most_recent_build = branch_record.most_recent_build
    most_recent_build.id != self.id
  end

  def merge_to_master!
    BuildStrategy.merge_ref(self)
  end

  def promote!
    unless promoted?
      BuildStrategy.promote_build(self)
      update!(promoted: true)
    end
  end

  def completed?
    TERMINAL_STATES.include?(state)
  end

  # Changes the build state to 'aborted'. Sets merge_on_success to false to
  # protect against accidental merges. Updates the state of all of the build's
  # 'runnable' build_parts to be 'aborted'.
  def abort!
    update!(state: 'aborted', merge_on_success: false)

    BuildAttempt
      .joins(:build_part)
      .where(:state => 'runnable', 'build_parts.build_id' => self.id)
      .update_all(state: 'aborted', updated_at: Time.current)
  end

  def to_color
    case state
    when 'succeeded'
      :green
    when 'failed', 'errored', 'aborted', 'doomed'
      :red
    else
      :blue
    end
  end

  def to_png
    case to_color
    when :green
      status_png(179, 247, 110)
    when :red
      status_png(247, 110, 110)
    when :blue
      status_png(110, 165, 247)
    end
  end

  def send_build_status_email!
    return if branch_record.convergence? && !previous_successful_build

    if completed?
      if failed? && !build_failure_email_sent? && repository.send_build_failure_email?
        unless build_failure_email_sent?
          BuildMailer.build_break_email(self).deliver_now
          update(build_failure_email_sent: true)
        end
      elsif succeeded? && !branch_record.convergence? && !build_success_email_sent? && repository.send_build_success_email?
        BuildMailer.build_success_email(self).deliver_now
        update(build_success_email_sent: true)
      end
    elsif !branch_record.convergence? && repository.email_on_first_failure && already_failed? && repository.send_build_failure_email?
      unless build_failure_email_sent?
        # due to race condition, update attribute before sending email
        update(build_failure_email_sent: true)
        BuildMailer.build_break_email(self).deliver_now
      end
    end
  end

  def is_running?
    IN_PROGRESS_STATES.include?(self.state)
  end

  def as_json(options = {})
    # exclude test_command by default
    options[:except] ||= [:test_command]
    super(options.reverse_merge(methods: :elapsed_time))
  end

  private

  def enqueue_initiated_by
    Resque.enqueue(BuildInitiatedByJob, self.id)
  end

  def status_png(r, g, b)
    ChunkyPNG::Canvas.new(13, 13, ChunkyPNG::Color::TRANSPARENT)
                     .circle(6, 6, 5, ChunkyPNG::Color::BLACK, ChunkyPNG::Color.rgb(r, g, b))
  end
end


================================================
FILE: app/models/build_artifact.rb
================================================
require 'log_file_uploader'

class BuildArtifact < ActiveRecord::Base
  belongs_to :build_attempt, :inverse_of => :build_artifacts, :touch => true
  mount_uploader :log_file, LogFileUploader
  skip_callback :commit, :after, :remove_log_file!
  validates :log_file, presence: true

  scope :stdout_log, -> { where(:log_file => ['stdout.log.gz', 'stdout.log']) }
  scope :error_txt, -> { where(:log_file => 'error.txt') }

  def as_json
    super(except: "log_file").tap do |hash|
      log_file = {"url" => Rails.application.routes.url_helpers.build_artifact_path(self), "name" => self.log_file.path}
      hash["build_artifact"]["log_file"] = log_file
    end
  end
end


================================================
FILE: app/models/build_attempt.rb
================================================
class BuildAttempt < ActiveRecord::Base
  has_many :build_artifacts, :dependent => :destroy, :inverse_of => :build_attempt
  belongs_to :build_part, :inverse_of => :build_attempts, :touch => true
  has_one :build_instance, through: :build_part

  FAILED_BUILD_STATES = %w[failed errored].freeze
  COMPLETED_BUILD_STATES = %w[passed aborted] + FAILED_BUILD_STATES
  IN_PROGRESS_BUILD_STATES = %w[runnable running].freeze
  STATES = IN_PROGRESS_BUILD_STATES + COMPLETED_BUILD_STATES

  validates :state, inclusion: { in: STATES }

  scope :unsuccessful, -> { where(state: FAILED_BUILD_STATES) }

  def elapsed_time
    if finished_at && started_at
      finished_at - started_at
    elsif started_at
      Time.current - started_at
    end
  end

  def start!(builder)
    return false unless update_attributes(:state => 'running', :started_at => Time.current, :builder => builder)

    build = build_part.build_instance
    previous_state, new_state = build.update_state_from_parts!

    if previous_state == new_state
      # bump build's update_at because update_state_from_parts did not alter the build record
      build.touch
    end

    if previous_state != new_state
      Rails.logger.info("Build #{build.id} state is now #{build.state}")
      BuildStateUpdateJob.enqueue(build.id)
    end

    true
  end

  def finish!(state)
    return false unless update_attributes(:state => state, :finished_at => Time.current)

    if should_reattempt?
      # Will only send email if email_on_first_failure is enabled.
      build_part.build_instance.send_build_status_email!
      build_part.rebuild!
    elsif state == 'errored'
      BuildMailer.error_email(self, error_txt).deliver_now
    end

    build = build_part.build_instance

    previous_state, new_state = build.update_state_from_parts!

    if previous_state == new_state
      # bump build's update_at because update_state_from_parts did not alter the build record
      build.touch
    end

    if previous_state != new_state
      Rails.logger.info("Build #{build.id} state is now #{build.state}")
      BuildStateUpdateJob.enqueue(build.id)
    end

    true
  end

  def unsuccessful?
    FAILED_BUILD_STATES.include?(state)
  end

  def successful?
    state == 'passed'
  end

  def aborted?
    state == 'aborted'
  end

  def running?
    state == 'running'
  end

  def stopped?
    COMPLETED_BUILD_STATES.include?(state)
  end

  def errored?
    state == 'errored'
  end

  def should_reattempt?
    unsuccessful? && build_part.should_reattempt?
  end

  def error_txt
    error_artifact = build_artifacts.error_txt.first
    error_artifact.log_file.read if error_artifact
  end

  def files
    build_artifacts.as_json
  end
end


================================================
FILE: app/models/build_part.rb
================================================
class BuildPart < ActiveRecord::Base
  # using 'build_instance' instead of 'build' because AR defines `build` for associations, and it wins
  belongs_to :build_instance, :class_name => "Build", :foreign_key => "build_id", :inverse_of => :build_parts
  has_many :build_attempts, :dependent => :destroy, :inverse_of => :build_part
  validates :kind, :paths, :queue, presence: true

  serialize :paths, Array
  serialize :options, Hash

  def last_attempt
    build_attempts.last
  end

  def create_and_enqueue_new_build_attempt!
    build_attempt = build_attempts.create!(:state => 'runnable')
    BuildAttemptJob.enqueue_on(queue.to_s, job_args(build_attempt))
    build_instance.touch # invalidate the cache of builds#show
    build_attempt
  rescue GitRepo::RefNotFoundError
    # delete the dud build_attempt and re-raise
    build_attempt.destroy if build_attempt

    raise
  end
  alias rebuild! create_and_enqueue_new_build_attempt!

  def job_args(build_attempt)
    repository = build_instance.repository
    {
      "build_attempt_id" => build_attempt.id,
      "build_kind" => kind,
      "build_ref" => build_instance.ref,
      "branch" => build_instance.branch_record.name,
      "test_files" => paths,
      "repo_name" => "#{repository.name}-cache",  # need to pass -cache for now for compatibility with current kochiku-worker
      "test_command" => build_instance.test_command,
      "repo_url" => repository.url_for_fetching,
      "remote_name" => "origin",
      "timeout" => repository.timeout.minutes,
      "options" => options,
      "kochiku_env" => Rails.env,
    }
  end

  def status
    if successful?
      'passed'
    else
      last_attempt.try(:state) || 'unknown'
    end
  end

  def successful?
    build_attempts.any?(&:successful?)
  end

  def unsuccessful?
    !successful?
  end

  def running?
    started_at && !finished_at
  end

  def not_finished?
    !finished_at
  end

  def to_color
    case status
    when 'passed'
      :green
    when 'failed', 'errored', 'aborted'
      :red
    else
      :blue
    end
  end

  def started_at
    last_attempt.try(:started_at)
  end

  def finished_at
    last_attempt.try(:finished_at)
  end

  def elapsed_time
    if finished_at && started_at
      finished_at - started_at
    elsif started_at
      Time.current - started_at
    end
  end

  def as_json(options = {})
    super(options.reverse_merge(methods: :status))
  end

  def should_reattempt?
    if successful?
      false
    elsif (build_attempts.unsuccessful.count - 1) < retry_count
      true
    # automatically retry build parts that errored in less than 60 seconds
    elsif elapsed_time && elapsed_time < 60 && last_attempt.errored? &&
          build_attempts.unsuccessful.count < 5
      true
    else
      false
    end
  end
end


================================================
FILE: app/models/repository.rb
================================================
require 'remote_server'

# This Repository class should only concern itself with persisting and acting on
# Repository records in the database. All non-database operations should go
# through the RemoteServer classes.
class Repository < ActiveRecord::Base
  has_many :branches, :dependent => :destroy
  has_many :convergence_branches, -> { where(convergence: true) }, class_name: "Branch"
  has_many :builds, through: :branches
  has_many :build_parts, through: :builds
  has_many :build_attempts, through: :build_parts
  validates :host, :name, :url, presence: true
  validates :name, uniqueness: { scope: :namespace, message: "^Namespace + Name combination already exists",
                                 case_sensitive: false }
  validates :timeout, numericality: { :only_integer => true }
  validates :timeout, inclusion: { in: 0..1440, message: 'The maximum timeout allowed is 1440 minutes' }
  validates :assume_lost_after, numericality: { :only_integer => true }, :allow_nil => true
  validates :url, uniqueness: true, allow_blank: true
  validate :validate_url_against_remote_servers

  def self.lookup_by_url(url)
    remote_server = RemoteServer.for_url(url)
    repository_namespace = remote_server.attributes.fetch(:repository_namespace)
    repository_name = remote_server.attributes.fetch(:repository_name)
    repository_host_and_aliases = remote_server.attributes.fetch(:possible_hosts)

    Repository.find_by(host: repository_host_and_aliases,
                       namespace: repository_namespace,
                       name: repository_name)
  end

  def self.lookup(host:, namespace:, name:)
    git_server_settings = Settings.git_server(host)

    Repository.find_by(host: [git_server_settings.host, *git_server_settings.aliases].compact,
                       namespace: namespace,
                       name: name)
  end

  # Setting a URL will extract values for host, namespace, and name. This
  # should not overwrite values for those attributes that were set in the same
  # session.
  def url=(value)
    # this column is deprecated; eventually url will just be a virtual attribute
    self[:url] = value

    return unless RemoteServer.parseable_url?(value)
    return unless RemoteServer.valid_git_host?(value)

    attrs_from_remote_server = RemoteServer.for_url(value).attributes
    self.host = attrs_from_remote_server[:host] unless host_changed?
    self.namespace = attrs_from_remote_server[:repository_namespace] unless namespace_changed?
    self.name = attrs_from_remote_server[:repository_name] unless name_changed?
  end

  def remote_server
    @remote_server ||= RemoteServer.for_url(url)
  end

  delegate :base_html_url, :base_api_url, :sha_for_branch, :url_for_fetching, :get_branch_url, :open_pull_request_url, to: :remote_server

  def promotion_refs
    on_green_update.split(",").map(&:strip).reject(&:blank?)
  end

  def interested_github_events
    event_types = ['pull_request']
    event_types << 'push' if run_ci
    event_types
  end

  def scm_type
    Settings.git_server(self.url).type
  end

  # Public: attempts to lookup a build for the commit under any of the
  # repository's branches. This is done as an optimization since the contents
  # of the commit are guaranteed to not have changed.
  #
  # Returns: Build AR object or nil
  def build_for_commit(sha)
    Build.joins(:branch_record).find_by(:ref => sha, 'branches.repository_id' => self.id)
  end

  # Public: looks across all of a repository's builds for one with the given
  # SHA. If one does not exist it creates one on the branch given
  #
  # sha    - String: git sha of the commit in question
  # branch - String or AR Branch: if an existing build is not found a new one will be created on this branch
  #
  # Returns: Build AR object
  def ensure_build_exists(sha, branch)
    build = build_for_commit(sha)
    unless build.present?
      build = branch.builds.create!(ref: sha, state: 'partitioning')
    end
    build
  end

  def name_with_namespace
    "#{namespace}/#{name}"
  end
  alias to_param name_with_namespace

  private

  def validate_url_against_remote_servers
    return unless url.present?

    if RemoteServer.parseable_url?(url)
      unless RemoteServer.valid_git_host?(url)
        errors.add(:url, "host is not in Kochiku's list of git servers")
      end
    else
      errors.add(:url, 'is not in a format supported by Kochiku')
    end
  end
end


================================================
FILE: app/models/repository_observer.rb
================================================
class RepositoryObserver < ActiveRecord::Observer
  observe :repository

  def after_save(record)
    record.remote_server.install_post_receive_hook!(record) if setup_hook?
  end

  def setup_hook?
    Rails.env.production? || Rails.env.staging?
  end
end


================================================
FILE: app/uploaders/base_log_file_uploader.rb
================================================
class BaseLogFileUploader < CarrierWave::Uploader::Base
  storage :file

  def cache_dir
    Rails.root.join('tmp', 'uploads')
  end
end


================================================
FILE: app/uploaders/log_file_uploader.rb
================================================
require 'base_log_file_uploader'

class LogFileUploader < BaseLogFileUploader
  def store_dir
    build_attempt_id = model.build_attempt_id
    build_part_id = model.build_attempt.build_part_id
    build_id = model.build_attempt.build_part.build_id

    # temporary backwards compatibility for old build artifacts created before the deploy on 08/25/2015
    if model.build_attempt.created_at < Time.parse("2015-08-25 04:12:46 UTC").utc &&
       (project_id = model.build_attempt.build_part.build_instance.project_id)
      project_param = ActiveRecord::Base.connection.select_value("select name from projects where id = #{project_id}")
      return File.join(project_param, "build_#{build_id}", "part_#{build_part_id}", "attempt_#{build_attempt_id}")
    end

    repository_param = model.build_attempt.build_part.build_instance.repository.to_param
    Rails.public_path.join("log_files", repository_param, "build_#{build_id}", "part_#{build_part_id}", "attempt_#{build_attempt_id}")
  end
end


================================================
FILE: app/uploaders/on_success_uploader.rb
================================================
require 'base_log_file_uploader'

class OnSuccessUploader < BaseLogFileUploader
  def store_dir
    build_id = model.id
    repository_param = model.repository.to_param
    Rails.root.join("public", "log_files", repository_param, "build_#{build_id}")
  end
end


================================================
FILE: app/views/branches/health.html.haml
================================================
= content_for :title, "Health of #{@branch.name} branch of #{@repository.name_with_namespace}"
= content_for :favicon do
  - if @current_build
    = favicon_link_tag image_path("#{@current_build.to_color}.png"), type: 'image/png'

- content_for :header do
  %ul.links
    %li= link_to("Settings", repository_edit_path(@repository), class: "info")
    %li= link_to("Branches", repository_branches_path(@repository))

- cache(@branch) do
  - rate = error_free_pass_rate(@builds)
  - avg_rebuilds = average_number_of_rebuilds(@builds)
  - median_seconds_to_success = median_elapsed_time(@builds)
  .performance
    - if median_seconds_to_success
      %div{title: "Median elapsed time for successful builds on #{@branch.name}"}
        %span.label Median time:
        %span.number #{seconds_to_minutes(median_seconds_to_success)} minutes

    - unless @builds.empty?
      %div{title: "Average number of build parts reattempted to get to a successful build", class: rebuild_count_css_class(avg_rebuilds)}
        %span.number= format("%0.1f", avg_rebuilds)
        %span.label rebuilds required on average

      %div{title: "Percentage of builds with all parts succeeding on the first try", class: pass_rate_css_class(rate)}
        %span.number= rate
        %span.label pass rate on first try

  .stats
    %h2.subheader Build statistics
    - if @first_built_date
      %p First build created on #{@first_built_date.strftime("%Y-%m-%d")}
    %table.build-stats
      %thead
        %tr
          %th
          %th Total
          %th Failures
          %th Pass Rate
      %tbody
        %tr
          %td All Time (#{@days_since_first_build} days)
          %td= @total_build_count
          %td= @total_failure_count
          %td #{@total_pass_rate}%
        %tr
          %td Past 30 days
          %td= @last30_build_count
          %td= @last30_failure_count
          %td #{@last30_pass_rate}%
        %tr
          %td Past 7 days
          %td= @last7_build_count
          %td= @last7_failure_count
          %td #{@last7_pass_rate}%

- if @part_climate.count > 0
  %h2.subheader #{@repository.name}/#{@branch.name} part failure stats over #{@builds.count} builds
  %table.project-part-info
    %thead
      %tr
        %th.right.whisker Rate
        %th Part Info
    - @part_climate.sort.reverse_each do |key, parts_with_failures|
      %tr
        %td.right #{key[0]}%
        %td= format_paths(parts_with_failures.first)
      %tr
        %td
        %td
          - parts_with_failures.each do |part|
            = link_to repository_build_part_path(@repository, part.build_instance, part) do
              %span.part-status{class: [part.status, "attempt-#{part.build_attempts.size}"]}
- else
  %h2.subheader #{@repository.name}/#{@branch.name} hasn't failed in #{@builds.count} builds


================================================
FILE: app/views/branches/index.html.haml
================================================
- content_for :header do
  %ul.links
    %li= link_to("Repositories", repositories_path)

.projects
  %ul
    - @convergence_branches.each do |branch|
      %li.build-info.bold
        = link_to(branch.name, repository_branch_path(branch.repository, branch))
    - @recently_active_branches.each do |branch|
      %li.build-info
        = link_to(branch.name, repository_branch_path(branch.repository, branch))


================================================
FILE: app/views/branches/show.html.haml
================================================
= content_for :title, "#{@repository.name} : #{@branch.name}"
= content_for :favicon do
  - if @current_build
    = favicon_link_tag image_path("#{@current_build.to_color}.png"), type: 'image/png'

- content_for :header do
  %ul.links
    %li= link_to("Settings", repository_edit_path(@repository), class: "info")
    %li= link_to("Branches", repository_branches_path(@repository))
  = form_for @build, url: request_new_build_repository_branch_path(@repository, @branch) do |f|
    - if @repository.enabled?
      = f.submit "Build", class: 'build-button'
    - else
      = f.submit "Build", class: 'build-button', disabled: 'true'

- cache(@branch) do
  %div.health.button= link_to('Health', health_repository_branch_path(@repository, @branch, 'count' => 12))
  - rate = error_free_pass_rate(@builds)
  - avg_rebuilds = average_number_of_rebuilds(@builds)
  - median_seconds_to_success = median_elapsed_time(@builds)
  .performance
    - if median_seconds_to_success
      %div{title: "Median elapsed time for successful builds on #{@branch.name}"}
        %span.label Median time:
        %span.number #{seconds_to_minutes(median_seconds_to_success)} minutes
    - else
      %div{title: "Median elapsed time for successful builds on #{@branch.name}"}
        %span.label Never built

    - unless @builds.empty?
      %div{title: "Average number of build parts reattempted to get to a successful build", class: rebuild_count_css_class(avg_rebuilds)}
        %span.number= format('%0.1f', avg_rebuilds)
        %span.label rebuilds required on average

      %div{title: "Percentage of builds with all parts succeeding on the first try", class: pass_rate_css_class(rate)}
        %span.number= rate
        %span.label completion rate on first try

%h2.subheader
  = @repository.namespace + '/' + @repository.name
  &ndash;
  = @branch.name

#plot

.select_commit
  %input{type: "text", id: "build_ref_input", placeholder: "Commit Revision"}
  %button{onClick: "goto_ref();"} Lookup Commit

= content_for :javascript do
  :javascript
    $(document).ready(Kochiku.graphBuildTimes("#{escape_javascript(@repository.to_param)}", "#{escape_javascript(@branch.name)}"));
    $(function() {
      var whisker = $('th.whisker');
      $('table')
        .on('mouseenter', '.whisker .part-status', function() {
          whisker.text($(this).data('ref'));
        })
        .on('mouseleave', '.whisker', function() {
          whisker.text('Previous');
        });
    });

    var goto_ref = function() {
      window.location.href = "//" + location.host + "/builds/" + $('#build_ref_input').val();
    };

- if @current_build
  %table.project-part-info
    %thead
      %tr
        %th.right.whisker Previous
        %th.status
          %code.build-status{class: @current_build.state}
            = link_to @current_build.ref[0, 5], repository_build_path(@repository, @current_build)
        - display_ruby_version = multiple_ruby_versions?(@current_build)
        - build_metadata_headers(@current_build, display_ruby_version).each do |header|
          %th{class: header.downcase.gsub(/\W+/, '-')}= header
        %th.type Type
        %th.right.time Elapsed
        %th.right.count Attempt
    - @build_parts.each do |_key, build_parts_by_build|
      - part = build_parts_by_build.values.first
      - build_part = build_parts_by_build[@current_build]
      - cache(part) do
        %tr{:id => dom_id(part)}
          %td.right.whisker
            - total_attempts = 0
            - @builds[0..-2].each do |previous_build|
              - previous_part = build_parts_by_build[previous_build]
              - if previous_part.present?
                - attempts = previous_part.build_attempts.size
                - total_attempts += attempts
                = link_to "/#{@repository.to_param}/builds/#{previous_build.to_param}/parts/#{previous_part.to_param}" do
                  %span.part-status{class: [previous_part.status, "attempt-#{attempts}"], title: pluralize(attempts, 'attempt'), data: { ref: previous_build.ref[0, 5] }}
              - else
                %span.part-status.attempt-0
          %td
            - if build_part
              %span.part-status{class: build_part.status}
                = link_to build_part.status.to_s.capitalize, "/#{@repository.to_param}/builds/#{@current_build.to_param}/parts/#{build_part.to_param}"
          - build_metadata_values(@current_build, part, display_ruby_version).each do |value|
            %td= value
          %td= part.kind.to_s
          %td.right.elapsed= build_part.elapsed_time ? duration_strftime(build_part.elapsed_time) : '' if build_part
          %td.right
            = build_part.build_attempts.size if build_part

- if @current_build
  = content_for :javascript do
    :javascript
      (function() {
        var startTimes = #{
          start_times = {}
          @current_build.build_parts.each { |part| start_times[dom_id(part)] = part.started_at if part.running? }
          start_times.to_json
        };
        var now = new Date();
        for(var partDomId in startTimes) {
          if(!startTimes.hasOwnProperty(partDomId)) {
            continue;
          }
          var startTime = new Date(Date.parse(startTimes[partDomId]));
          $('.project-part-info tbody').find('tr#' + partDomId + ' > .elapsed').text(
            Math.round((now-startTime)/60000) + ":" + ("00" + (Math.round((now-startTime)/1000)%60)).slice(-2));
        }
      })()


================================================
FILE: app/views/branches/show.json.erb
================================================
<%
  json_data = @branch.attributes
  json_data['recent_builds'] = @builds
%>
<%= json_data.to_json.html_safe %>


================================================
FILE: app/views/branches/show.rss.builder
================================================
xml.rss({:version => "2.0"}) do
  xml.channel do
    xml.title("Kochiku RSS Feed")
    xml.link(repository_branch_url(@repository, @branch))
    xml.language("en")
    xml.ttl(10)

    @builds.each do |build|
      xml.item do
        xml.title("Build Number #{build.id} #{build_success_in_words(build)}")
        xml.pubDate(build.created_at.to_s)
        xml.guid(repository_build_url(@repository, build))
        xml.link(repository_build_url(@repository, build))
      end
    end
  end
end


================================================
FILE: app/views/branches/status_report.xml.builder
================================================
xml.Projects do
  @branches.each do |branch|
    # currently cimonitor only utilizes the activity attribute
    xml.Project({
      :name => branch.repository.to_param + (branch.name == 'master' ? '' : ('/' + branch.name)),
      :activity => build_activity(branch.builds.last),
      :lastBuildLabel => branch.builds.last.object_id,
      :webUrl => repository_branch_url(branch.repository, branch),
      :lastBuildStatus => (branch.last_completed_build.try(:succeeded?) ? "Success" : "Failure"),
      :lastBuildTime => branch.last_completed_build.try(:finished_at).try(:strftime, "%Y-%m-%dT%H:%M:%SZ")
    })
  end
end


================================================
FILE: app/views/build_attempts/_build_attempt.html.haml
================================================
.attempt{:class => build_attempt.state}
  = build_attempt.state


================================================
FILE: app/views/build_attempts/stream_logs.html.haml
================================================
%h2.subheader
  = @repository.name_with_namespace
  &ndash;
  = link_to @build.branch_record.name, repository_branch_path(@repository, @build.branch_record)
  &ndash;
  = link_to repository_build_path(@repository, @build) do
    %code.build-status{class: @build.state, title: @build.ref}
      = @build.ref[0, 7]
  &ndash; Part #{@build_part.id}
.flash.error{'id' => 'errorMessage', 'style' => "display: none;"}
  Error streaming logs
%label
  = check_box_tag :refresh, true, true
  Refresh
%div{'id' => 'loadFull', 'style' => 'display: none;'}
  (skipping n bytes)

%br

.log_contents{'id' => 'log_content_display'}
%img{:src => image_url('loader.gif'), 'id' => "loading_img"}

= content_for :javascript do
  :javascript
    var currentPos = -1;
    var finished = false;
    var refreshIntervalId;
    var refreshInterval = 5000;
    var badRequests = 0;
    var startPos = -1;

    // autoscroll to the bottom to follow tail of log
    var scrolled_to_bottom = function() {
      return ((window.innerHeight + window.scrollY) >= document.body.scrollHeight);
    }

    var get_logs_chunk = function() {
      if($('input#refresh').is(':checked') && !finished) {
        $.getJSON("#{stream_logs_chunk_path(@build_attempt.id)}?start=" + currentPos, function( data ) {
          log_entry = data['Contents'];
          current_value = $('#log_content_display').text();
          var scrolled = scrolled_to_bottom();
          $('#log_content_display').text(current_value + log_entry);
          if (scrolled) {
            window.scrollTo(0,document.body.scrollHeight);
          }

          // first request: use it to determine whether any bytes have been skipped
          if (currentPos == -1) {
            startPos = data['Start'];
            if (data['Start'] > 0) {
              $('#loadFull').text("(skipping " + startPos + " bytes)");
              $('#loadFull').show();
            }
          }
          currentPos = data['Start'] + data['BytesRead'];

          if (data['state'] != 'running' && data['BytesRead'] == 0) {
            finished = true;
            $('#loading_img').hide();
          }
        })
          .fail(function() {
            clearInterval(refreshIntervalId);
            badRequests += 1;
            if (badRequests < 3) {
              refreshInterval *= 1.25;
              refreshIntervalId = window.setInterval(get_logs_chunk, refreshInterval);
            }
            else {
              $('#errorMessage').show();
              $('#loading_img').hide();
            }
          });
      }
    };

    $('input#refresh').click(function () {
      if ($('input#refresh').is(':checked')) {
        if (!finished) {
          $('#loading_img').show();
        }
      } else {
        $('#loading_img').hide();
      }
    });

    $(document).ready(function() {
      window.scrollTo(0,document.body.scrollHeight);
      get_logs_chunk();
      refreshIntervalId = window.setInterval(get_logs_chunk, refreshInterval);
    });


================================================
FILE: app/views/build_mailer/build_break_email.html.haml
================================================
%html{xmlns: "http://www.w3.org/1999/html"}
  %head
    %meta{'content' => 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type'}
  %body
    %h1 #{@build.branch_record.name} build failed for #{@build.repository.name}
    = link_to('Link to build.', repository_build_url(@build.repository, @build))
    - if @pr_link
      = link_to('Link to PR.', @pr_link)
    - if @build.build_parts.count > 1
      The build was sharded into #{@build.build_parts.count} parts and took #{@build.elapsed_time.to_i / 60} minutes.
      (#{@build.idle_time.to_i / 60}m idle, #{@build.longest_build_part.to_i / 60}m running.)
      %br
      Without sharding the build would have taken #{@build.linear_time.to_i / 60} minutes to run.
      %br
    - else
      The build took #{@build.elapsed_time.to_i / 60} minutes.
      (#{@build.idle_time.to_i / 60}m idle, #{@build.longest_build_part.to_i / 60}m running.)
      %br
    %h2 Failed build parts:
    %ul
      - @failed_build_parts.each do |failed_build_part|
        %li
          = link_to("Part: #{failed_build_part.kind}, number #{failed_build_part.id}", repository_build_part_url(@build.repository, @build, failed_build_part))
          = failed_build_part_sentence(failed_build_part)
        %span.broken-path{style: "font-size: smaller; color: gray;"} - #{failed_build_paths(failed_build_part)}
    %br
    - @responsible_email_and_files.each do |email, files|
      #{email} was emailed because of changes to:
      %ul
        - files.each do |file|
          %li= file
      %br

    %h2 Changes #{@build.branch_record.convergence? ? 'since last success' : 'included in build'}
    - @git_changes.each do |git_change|
      %b SHA: #{link_to(git_change[:hash], @build.repository.remote_server.href_for_commit(git_change[:hash]))}
      %br
      %b Committer:
      = git_change[:author]
      %br
      %b Date:
      = git_change[:date]
      %br
      %pre= git_change[:message]
      %br
      %br


================================================
FILE: app/views/build_mailer/build_break_email.text.erb
================================================
<%= @build.branch_record.name %> build failed for <%= @build.repository.name %>
<%= repository_build_url(@build.repository, @build) %>

<% if @build.build_parts.count > 1 %>
The build was sharded into <%= @build.build_parts.count %> parts and took <%= @build.elapsed_time.to_i/60 %> minutes. (<%= @build.idle_time.to_i/60 %>m idle, <%= @build.longest_build_part.to_i/60 %>m running.)
Without sharding the build would have taken <%= @build.linear_time.to_i/60 %> minutes to run.
<% else %>
The build took <%= @build.elapsed_time.to_i/60 %> minutes. (<%= @build.idle_time.to_i/60 %>m idle, <%= @build.longest_build_part.to_i/60 %>m running.)
<% end %>

<% @responsible_email_and_files.each do |email, files| %>
<%= email %> was emailed because of changes to <%= files.join(", ") %>
<% end %>

--------------------------------------------------------------------------------
<%= "Changes #{@build.branch_record.convergence? ? 'since last success' : 'included in build'}" %>
--------------------------------------------------------------------------------

<% @git_changes.each do |git_change| %>
  SHA: <%= git_change[:hash] %>
  Committer: <%= git_change[:author] %>
  Date: <%=  git_change[:date] %>

      <%= git_change[:message] %>


<% end %>


================================================
FILE: app/views/build_mailer/build_success_email.html.haml
================================================
%html{xmlns: "http://www.w3.org/1999/html"}
  %head
    %meta{'content' => 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type'}
  %body
    %h1 #{@build.branch_record.name} build succeeded for #{@build.repository.name}
    = link_to('Link to build.', repository_build_url(@build.repository, @build))
    - if @pr_link
      = link_to('Link to PR.', @pr_link)
    - if @build.build_parts.count > 1
      The build was sharded into #{@build.build_parts.count} parts and took #{@build.elapsed_time.to_i / 60} minutes.
      (#{@build.idle_time.to_i / 60}m idle, #{@build.longest_build_part.to_i / 60}m running#{@build.retry_count > 0 ? ", requiring #{@build.retry_count} retries.)" : ".)"}
      %br
      Without sharding the build would have taken #{(@build.linear_time.to_i / 60) * (1 + @build.max_retries)} minutes to run.
      %br
      - if @build.retry_count > 0
        (#{@build.linear_time.to_i / 60}m building, requiring #{@build.max_retries} retries.)
    - else
      The build took #{@build.elapsed_time.to_i / 60} minutes.
      (#{@build.idle_time.to_i / 60}m idle, #{@build.longest_build_part.to_i / 60}m running#{@build.retry_count > 0 ? ", requiring #{@build.retry_count} retries.)" : ".)"}
      %br
    %h2 Changes included in build
    - @git_changes.each do |git_change|
      %b SHA: #{link_to(git_change[:hash], @build.repository.remote_server.href_for_commit(git_change[:hash]))}
      %br
      %b Committer:
      = git_change[:author]
      %b Date:
      = git_change[:date]
      %pre= git_change[:message]
      %br
      %br


================================================
FILE: app/views/build_mailer/build_success_email.text.erb
================================================
<%= @build.branch_record.name %> build succeeded for <%= @build.repository.name %>
<%= repository_build_url(@build.repository, @build) %>
<% if @build.build_parts.count > 1 %>
  The build was sharded into <%= @build.build_parts.count %> parts and took <%= @build.elapsed_time.to_i/60 %> minutes.
  (<%= @build.idle_time.to_i/60 %>m idle, <%= @build.longest_build_part.to_i/60 %>m
  <% if @build.retry_count > 0 %>
    running, requiring <%= @build.retry_count %> retries.)
  <% else %>
    running.)
  <% end %>
  Without sharding the build would have taken <%= (@build.linear_time.to_i/60) * (1 + @build.max_retries) %> minutes to run.<br>
  <% if @build.retry_count > 0 %>
    (<%= @build.linear_time.to_i/60 %>m building, requiring <%= @build.max_retries %> retries.)
  <% end %>
<% else %>
  The build took <%= @build.elapsed_time.to_i/60 %> minutes.
  (<%= @build.idle_time.to_i/60 %>m idle, <%= @build.longest_build_part.to_i/60 %>m
  <% if @build.retry_count > 0 %>
    running, requiring <%= @build.retry_count %> retries.)
  <% else %>
    running.)
  <% end %>
<% end %>

--------------------------------------------------------------------------------
Changes included in build
--------------------------------------------------------------------------------

<% @git_changes.each do |git_change| %>
  SHA: <%= git_change[:hash] %>
  Committer: <%= git_change[:author] %>
  Date: <%=  git_change[:date] %>

      <%= git_change[:message] %>


<% end %>


================================================
FILE: app/views/build_mailer/error_email.html.haml
================================================
%html{xmlns: "http://www.w3.org/1999/html"}
  %head
    %meta{'content' => 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type'}
  %body
    %h2 Kochiku error on #{@builder}
    = repository_build_part_url(@build_part.build_instance.repository, @build_part.build_instance, @build_part)

    %h2 Error text
    %pre= @error_text


================================================
FILE: app/views/build_mailer/error_email.text.erb
================================================
Kochiku error on <%= @builder %> for <%= repository_build_part_url(@build_part.build_instance.repository, @build_part.build_instance, @build_part) %>

<%= @error_text %>


================================================
FILE: app/views/build_parts/_build_attempts.html.haml
================================================
%tr{id: dom_id(attempt), :"data-id" => index + 1}
  %td.right= link_to(index + 1, attempt)
  %td
    %span.attempt-status{:class => attempt.state}= attempt.state.to_s.capitalize
  %td.rank= build_attempts_rank[attempt.id.to_s]
  %td= attempt.started_at
  %td.right.elapsed= duration_strftime(attempt.elapsed_time)
  %td.right= attempt.builder ? attempt.builder.sub(".#{Settings.domain_name}", '') : "pending"
  %td
    - if attempt.running? && attempt.log_streamer_port.present?
      = link_to("stdout.log (in progress)", stream_logs_path(attempt.id))
    - else
      - attempt.build_artifacts.sort_by { |artifact| artifact.log_file.path }.each do |artifact|
        = link_to File.basename(artifact.log_file.path), artifact
        %br
  %td.wrap
    - unless attempt.stopped?
      = link_to("Abandon", finish_build_attempt_path(attempt, :state => 'aborted'), :method => :post)


================================================
FILE: app/views/build_parts/_build_part.html.haml
================================================
.part{:class => build_part.status, :title => build_part.paths.map{|path| "-#{path}"}.join("<br>")}
  -# build_part.build_instance.repository is important to prevent n+1 queries here. Using the :through does a bunch of SQL.
  %a.part-wrapper{:href => repository_build_part_path(build_part.build_instance.repository, build_part.build_instance, build_part)}
    .kind
      - case build_part.kind
      - when "spec"
        Specs
      - when "cucumber"
        Cukes
      - else
        = build_part.kind
    - if build_part.build_attempts.any?
      .attempts
        = render build_part.last_attempt
        - if build_part.build_attempts.size > 1
          = "..."


================================================
FILE: app/views/build_parts/show.html.haml
================================================
= content_for :title do
  = @build.ref[0, 7]
  &ndash;
  = @repository.name
= content_for :favicon do
  = favicon_link_tag image_path("#{@build_part.to_color}.png"), :type => 'image/png'

%h2.subheader
  = link_to(@build.repository.name_with_namespace, repository_branches_path(@build.repository))
  &ndash;
  = link_to(@build.branch_record.name, repository_branch_path(@build.repository, @build.branch_record))
  &ndash;
  = link_to repository_build_path(@repository, @build) do
    %code.build-status{class: @build.state, title: @build.ref}
      = @build.ref[0, 7]
  &ndash; #{@build_part.kind} (part #{@build_part.id})

  .actions
    %label
      - if @repository.enabled?
        = link_to("Rebuild", rebuild_repository_build_part_path(@repository, @build, @build_part), method: :post, class: "rebuild button")
    %label
      = check_box_tag :refresh, true, @build_part.not_finished?
      Refresh

.build-info.build-info-subheader
  %span.info
    %span.status{:class => 'build-part-' + @build_part.status.to_s}= @build_part.status.to_s.capitalize
    on
    %span.queue #{@build_part.queue} queue

%table.build-part-info
  %thead
    %tr
      %th.right.count Attempt
      %th.status Status
      %th.queue-position Position
      %th Started At
      %th.right.time Elapsed Time
      %th.right.worker Worker
      %th Build Artifacts
      %th.right.actions Actions
  %tbody
    - @build_part.build_attempts.each_with_index do |attempt, index|
      = render partial: 'build_parts/build_attempts', locals: {attempt: attempt, index: index, build_attempts_rank: @build_attempts_rank}

%ol#build-paths
  - if @build_part.options['total_workers'] && @build_part.options['worker_chunk']
    %li Chunk #{@build_part.options['worker_chunk']} of #{@build_part.options['total_workers']}
  - @build_part.paths.each do |path|
    %li= path

= content_for :javascript do
  :javascript
    if ($('.build-part-info tbody tr').length > 0) {
      $('.build-part-info').tablesorter({ sortList: [ [0, 0] ] });
      StartTimes = #{
        # rubocop:disable Style/IndentationConsistency
        start_times = {}
        @build_part.build_attempts.each_with_index { |attempt, index| start_times[index + 1] = attempt.started_at }
        start_times.to_json
      };
    }

    if ( "Notification" in window && Notification.permission == "default") {
      Notification.requestPermission();
    }

    Kochiku.buildInfo = {table: '.build-part-info tbody', renderTime: Date.parse("#{raw @build_part.updated_at}"), state: "#{@build.state}"};

    Kochiku.buildInfo.id = #{@build.id};
    Kochiku.buildInfo.branch = "#{@build.branch_record.name}";
    Kochiku.buildInfo.repo = "#{@build.repository.name}";

    Kochiku.terminalStates = #{raw BuildAttempt::COMPLETED_BUILD_STATES};
    Kochiku.doneMessage = "BuildPart on "

    Kochiku.delayedRefresh(Kochiku.buildInfo);


================================================
FILE: app/views/builds/_build.html.haml
================================================
.build
  %a.build-wrapper{:href => repository_build_path(build.repository, build)}
    .build-info
      .ref= build.ref
    %h3.build-id{:class => build.state}= build.id
    .times
      .time-started
        Started at
        = time_for(build.created_at, "%m/%d %I:%M%P")
      .time-elapsed
        - if build.completed?
          Built in
          %strong
            = duration_strftime(build.elapsed_time, "%Hh %Mm %Ss")

  .build-state
    %span.info
      %span.state{:class => 'build-' + build.state.to_s}= build.state.to_s.capitalize
      on
      %span.queue= build.queue.to_s.capitalize
    - if build.branch_record.convergence?
      %a.info{:href => show_link_to_compare(build, build.previous_successful_build.try(:ref), build.ref), :title => 'show changes since last green build'}
        Compare to last green build
    - elsif build.succeeded?
      %a.info{:href => show_link_to_create_pull_request(build), :title => 'create a pull request against master'}
        Create pull request
    - if build.on_success_script_log_file.present?
      = link_to File.basename(build.on_success_script_log_file.to_s), build.on_success_script_log_file.url, :class => :info
    %a.info.last{:href => show_link_to_commit(build.repository, build.ref)}
      Show HEAD commit

  .parts= render build.build_parts


================================================
FILE: app/views/builds/_build_parts.html.haml
================================================
- display_ruby_version = multiple_ruby_versions?(build)
%tr{:"data-id" => part.id}
  %td.right= link_to(part.id, repository_build_part_path(build.repository, build, part))
  %td
    %span.part-status{:class => part.status}
      - text = part.status.to_s.capitalize
      - if part.status == 'running' && part.last_attempt.log_streamer_port.present?
        = link_to(text, stream_logs_path(part.last_attempt.id))
      - elsif (artifact = part.most_recent_stdout_artifact)
        = link_to(text, artifact, :title => 'Last completed stdout.log')
      - else
        = text
  - position = build_parts_position[part.id]
  - if position.present?
    %td{:class => 'queue-position-value'}
      = position
  - else
    %td
  - build_metadata_values(build, part, display_ruby_version).each do |value|
    %td= value
  %td= part.kind.to_s
  %td.right
    - builder = part.last_attempt.try(:builder)
    = builder ? builder.sub(".#{Settings.domain_name}", '') : "pending"
  %td.right.elapsed= part.elapsed_time ? duration_strftime(part.elapsed_time) : "pending"
  %td.right= part.build_attempts.size
  %td.right
    - if part.unsuccessful? && repository.enabled?
      = link_to("Rebuild", rebuild_repository_build_part_path(build.repository, build, part), :method => :post)


================================================
FILE: app/views/builds/show.html.haml
================================================
= content_for :title do
  = @build.ref[0, 7]
  &ndash;
  = @build.repository.name
= content_for :favicon do
  = favicon_link_tag image_path("#{@build.to_color}.png"), :type => 'image/png'

%h2.subheader
  = @build.repository.name
  &ndash;
  = link_to(@build.branch_record.name, repository_branch_path(@build.repository, @build.branch_record))
  &ndash;
  %code.build-status{class: @build.state, title: @build.ref}
    = @build.ref[0, 7]
  %a.info{:href => show_link_to_commit(@build.repository, @build.ref)}
    Show
  - if @build.branch_record.convergence?
    %a.info{:href => show_link_to_compare(@build, @build.previous_successful_build.try(:ref), @build.ref), :title => 'show changes since last green build'}
      Compare to last green build

  .actions
    - if @build.succeeded?
      = button_to "Sync status to #{@build.repository.scm_type}", resend_status_repository_build_path(@build.repository, @build), :method => :post
    - if @build.repository.allows_kochiku_merges?
      %form{action: toggle_merge_on_success_repository_build_path(@build.repository, @build), method: :post}
        %label
          = check_box_tag :merge_on_success, true, @build.merge_on_success_enabled?, disabled: !eligible_for_merge_on_success?(@build), onchange: 'this.form.submit()'
          Merge on Success

    %label
      = check_box_tag :refresh, true, @build.is_running?
      Refresh

.build-info.build-info-subheader
  - if @build.succeeded? && !@build.branch_record.convergence?
    %a.info{:href => show_link_to_create_pull_request(@build), :title => 'create a pull request against master'}
      Create pull request
  %span.info
    Created
    = timeago(@build.created_at)
  %span.info
    Updated
    = timeago(@build.updated_at, :id => "time-since-update")
  - if @build.completed?
    %span.info
      Built in #{duration_strftime(@build.elapsed_time, "%Hh %Mm %Ss")}
  - if @build.completed? && @build.failed? && @build.build_parts.present?
    %span.info
      #{@build.build_parts.failed.count} out of #{@build.build_parts.count} build parts failed
  - if @build.is_running?
    %span.info
      = button_to "Abort Build", abort_repository_build_path(@build.repository, @build), method: :patch, class: "abort-build"
  - if @repository.enabled? && (@build.failed? || @build.aborted?)
    %span.info
      - if @build.build_parts.empty? || !@build.error_details.empty?
        = button_to "Retry Partitioning", retry_partitioning_repository_build_path(@build.repository, @build), :method => :post, :form_class => "retry-partitioning"
      - else
        = button_to "Rebuild failed parts", rebuild_failed_parts_repository_build_path(@build.repository, @build), :method => :post, :form_class => "rebuild-parts"

- if @build.error_details.present?
  .build-error
    %h2 Build error
    %pre= [@build.error_details[:message], @build.error_details[:backtrace]].join("\n")
- if @build.succeeded? && @build.build_parts.count == 0
  .build-empty
    %h2 Build Empty
    %span.info
      Partitioner did not return any work for this build.
%table.build-summary#build-summary
  %thead
    %tr
      %th.right.id Part
      %th.status Status
      %th.queue-position Position
      - display_ruby_version = multiple_ruby_versions?(@build)
      - build_metadata_headers(@build, display_ruby_version).each do |header|
        %th{class: header.downcase.gsub(/\W+/, '-')}= header
      %th.type Type
      %th.right.worker Worker
      %th.right.time Elapsed Time
      %th.right.count Attempt
      %th.right.actions Actions
  %tbody
    - @build.build_parts.decorate.each do |part|
      = render partial: 'builds/build_parts', locals: {part: part, build: @build, build_parts_position: @build_parts_position, repository: @repository}

- if @build.on_success_script_log_file.url
  = link_to(File.basename(@build.on_success_script_log_file.path), @build.on_success_script_log_file.url)
= content_for :javascript do
  :javascript
    if ($('#build-summary tbody tr').length > 0) {
      $('#build-summary').tablesorter({ sortList: [ [1, 0] ] });
      StartTimes = #{
        # rubocop:disable Style/IndentationConsistency
        start_times = {}
        @build.build_parts.each { |part| start_times[part.id] = part.started_at }
        start_times.to_json
      };
    }

    if ( "Notification" in window && Notification.permission == "default") {
      Notification.requestPermission();
    }

    Kochiku.buildInfo = {table: '.build-summary tbody', renderTime: Date.parse(#{raw @build.updated_at.to_json}), state: "#{@build.state}"};
    Kochiku.buildInfo.id = #{@build.id};
    Kochiku.buildInfo.branch = "#{@build.branch_record.name}";
    Kochiku.buildInfo.repo = "#{@build.repository.name}";

    Kochiku.terminalStates = #{raw Build::TERMINAL_STATES};
    Kochiku.delayedRefresh(Kochiku.buildInfo);
    Kochiku.doneMessage = "Build on "

    $('abbr.timeago').click(function() {
      // swap the relative time with the absolute time
      var originalText = $(this).text();
      $(this).text($(this).attr('title'));
      $(this).attr('title', originalText);
    });


================================================
FILE: app/views/dashboards/build_history_by_worker.html.haml
================================================
#worker-health-wrap
  %table{:class => "worker-health"}
    %thead
      %th.right Worker
      %th Partition Attempts
    %tbody
      %tr
        %td.right= "Partition workers"
        %td
          - @partition_jobs.each do |partition_job|
            = link_to build_redirect_path(partition_job) do
              - if !partition_job.build_parts.empty?
                %span.attempt-status{:class => :passed}
                // ugly hack because in this table, partitioning means "in progress", whereas in
                // the following build attempts table, it means not started yet
              - elsif partition_job.state == 'partitioning'
                %span.attempt-status{:class => :running}
              - else
                %span.attempt-status{:class => partition_job.state}
  %br
  %table{:class => "worker-health"}
    %thead
      %th.right Worker
      %th Build Attempts
    %tbody
      - @workers.each do |worker_name, build_attempts|
        %tr
          %td.right= worker_name
          %td
            - build_attempts.each do |build_attempt|
              = link_to build_attempt do
                %span.attempt-status{:class => build_attempt.state}


================================================
FILE: app/views/layouts/application.html.haml
================================================
!!!
%html{:lang => 'en'}
  %head
    %meta{:charset => 'utf-8'}
    %meta{:name => 'google', :value => 'notranslate'}
    %title
      - if (title = yield(:title)).present?
        #{title} &ndash;
      Kochiku
    = stylesheet_link_tag 'tablesorter.theme.kochiku.css'
    = stylesheet_link_tag 'tipTip.css', :media => 'screen'
    = stylesheet_link_tag 'screen.css', :media => 'all'
    = csrf_meta_tag
    - if (favicon = yield(:favicon)).present?
      = favicon
    - else
      = favicon_link_tag '/favicon.ico'
  %body
    #page
      .section-wrapper#header
        .section
          %a.logo{:href => root_path, :title => "Home"}
            %h1
              %b Kochiku
              %ruby.translation
                構 <rt>こう</rt>
                築 <rt>ちく</rt>
          .header-right
            = yield :header
      - if @repository && !@repository.enabled?
        .section-wrapper#disabled-repo-alert
          .section
            .warn This repository is currently disabled.
      .section-wrapper#content
        .section
          - if flash[:error].present?
            .flash.error
              = flash[:error]
          - if flash[:warn].present?
            .flash.warn
              = flash[:warn]
          - if flash[:message].present?
            .flash.message
              = flash[:message]
          = yield

      #nav
        .section= link_to("Build taking too long? (Resque Admin)", "/resque")
        .section= link_to("Worker Health", build_history_by_worker_path(count: 5000))

  = javascript_include_tag 'application'
  :javascript
    $(document).ready(function() {
      $('.part').tipTip({
        delay: 100,
        maxWidth: "auto",
        edgeOffset: 10,
        fadeIn: 100,
        fadeOut: 100
      });
    });
  = yield :javascript


================================================
FILE: app/views/merge_mailer/merge_failed.text.erb
================================================
Kochiku build automatically merged build: <%= [@build.repository.to_param, @build.id, @build.branch_record.name].join(", ") %>.

stdout & stderr:

<%= @stdout_and_stderr %>


================================================
FILE: app/views/merge_mailer/merge_successful.html.erb
================================================
<p>
  Kochiku automatically merged build:
  <%= @build.repository.to_param %>, <%= @build.id %>, <%= link_to_branch @build %>.
</p>

<p>
  The ref for the merge is <%= link_to_commit(@build.repository, @merge_commit) %>.
</p>

stdout &amp; stderr:

<pre>
<%= @stdout_and_stderr %>
</pre>


================================================
FILE: app/views/repositories/_form.html.haml
================================================
= form_for @repository, :url => form_url, :html => { :id => 'repository-form' } do |f|
  = f.error_messages
  %div
    %label{:for => "url"} Repository URL:
    = f.text_field :url, :placeholder => '', :autocapitalize => 'off', :autocorrect => 'off', :spellcheck => 'false'
  %div
    %label{:for => "convergence_branches"} Convergence Branches:
    = text_field_tag :convergence_branches, @current_convergence_branches.join(', '), placeholder: "master", autocapitalize: 'off', autocorrect: 'off', spellcheck: 'false'
  - if @repository.test_command.present?
    %div{title: 'Test command should now be specified in the kochiku.yml'}
      %label{:for => "test_command"} Test Command: (Deprecated)
      = f.text_field :test_command, :id => 'test_command', :disabled => true
  %div
    %label{:for => "timeout"} Timeout a build part after:
    = f.text_field :timeout, :id => "timeout", :class => "short"
    minutes
  %div
    %label{:for => "assume_lost_after"} Assume that a build has been lost if its still running after:
    = f.text_field :assume_lost_after, :id => "assume_lost_after", :class => "short"
    minutes
  %div
    %label{:for => "run_ci"} Trigger build on push to master:
    = f.check_box :run_ci, :id => "run_ci"
  %div
    %label{:for => "enabled"} Enable repository:
    = f.check_box :enabled, :id => "enabled"


  %fieldset
    %legend Pull Requests
    %div
      %label{:for => "build_pull_requests"} Build pull requests:
      = f.check_box :build_pull_requests, :id => "build_pull_requests"
    %div
      %label{:for => "allows_kochiku_merges"} Allow developers to request branches be merged into master on success:
      = f.check_box :allows_kochiku_merges, :id => "allows_kochiku_merges"

      - display_css = @repository.allows_kochiku_merges ? '' : 'display: none'
      %span{:id => 'branch-delete-warning', :style => display_css} Warning: Kochiku will delete the branch from Git after merging.
    %div
      %label{:for => "send_merge_successful_email"} Send email on automatic merge success:
      = f.check_box :send_merge_successful_email, :id => "send_merge_successful_email", :disabled => @repository.allows_kochiku_merges ? nil : true

  %fieldset
    %legend On a green build
    %div
      %label{:for => "on_green_update"} Update branches to last green commit:
      = f.text_field :on_green_update, :id => "on_green_update", :placeholder => "Comma separated list of branch names"
    %div
      %label{:for => "send_build_success_email"} Send email to contributers:
      = f.check_box :send_build_success_email, :id => "send_build_success_email"

  %fieldset
    %legend On a red build
    %div
      %label{:for => "send_build_failure_email"} Send email to build breakers:
      = f.check_box :send_build_failure_email, :id => "send_build_failure_email"
    %div
      %label{:for => "email_on_first_failure"} Email on first build part failure for branch builds:
      = f.check_box :email_on_first_failure, :id => "email_on_first_failure"

  = f.submit @repository.new_record? ? "Create" : "Update"

- unless @repository.new_record?
  = button_to "Delete", repository_path(@repository.id), method: :delete, form_class: "delete-form", class: "danger-button", data: {confirm: "This is a permanent destructive action, are you sure?"}

= content_for :javascript do
  :javascript
    $('#allows_kochiku_merges').change(function(){
      $('#branch-delete-warning').toggle($("#allows_kochiku_merges").is(':checked'));
      $('#send_merge_successful_email').prop("disabled", !$("#allows_kochiku_merges").is(':checked'));
    });
    $('#repository-form').submit(function(event) {
      // Manually update the hidden element generated by the Rails check_box helper.
      //
      // This workaround is neccessary for send_merge_successful_email to
      // maintain it's value when its input is is 'disabled'.
      $("input[name='repository[send_merge_successful_email]'][type='hidden']").val(
        $("input[name='repository[send_merge_successful_email]'][type='checkbox']").is(':checked')
      );
    });


================================================
FILE: app/views/repositories/dashboard.html.haml
================================================
- content_for :header do
  %ul.links
    %li= link_to("Repositories", repositories_path)

.projects.projects-grid
  - @branches.each do |branch|
    - cache(branch) do
      %div.ci-build-info{:class => "ci-#{branch.most_recent_build_state}"}
        %div.project-name
          = link_to(branch.repository.name, repository_branch_path(branch.repository, branch))
        - if branch.most_recent_build.try(:is_running?)
          %div.state{:class => "build-#{branch.most_recent_build_state}"}
            = branch.most_recent_build_state.to_s.capitalize
        - if branch.last_completed_build && branch.last_completed_build.finished_at
          %div.state
            Last built
            = timeago(branch.last_completed_build.finished_at)
        - else
          %div.state Never built
        - if branch.last_completed_build
          %div.state{:class => "build-#{branch.last_completed_build.state}"}
            = branch.last_completed_build.state.to_s.capitalize
            = "in " + distance_of_time_in_words(branch.last_build_duration) if branch.last_build_duration
        %div.project-link
          = link_to("all branches", repository_branches_path(branch.repository))


================================================
FILE: app/views/repositories/edit.html.haml
================================================
= render 'form', form_url: repository_url(@repository.id)

%br
%h3 Web Hooks
%p
  %strong Build SHA
  %br
  = link_to build_ref_repository_url(@repository.id, ref: 'master', sha: 'abc123')
  %br
  %em.hint
    POST to this URL from your source control system to trigger a build
    of the given branch/SHA.


================================================
FILE: app/views/repositories/index.html.haml
================================================
.repositories
  .new-repository-link
    = link_to("Add Repository", new_repository_path)

  %ul
    - @repositories.each do |repository|
      %li.build-info
        = link_to(repository.url, repository_edit_path(repository))


================================================
FILE: app/views/repositories/new.html.haml
================================================
= render 'form', form_url: repositories_url


================================================
FILE: bin/bundle
================================================
#!/usr/bin/env ruby
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
load Gem.bin_path('bundler', 'bundle')


================================================
FILE: bin/rails
================================================
#!/usr/bin/env ruby
begin
  load File.expand_path('../spring', __FILE__)
rescue LoadError => e
  raise unless e.message.include?('spring')
end
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'


================================================
FILE: bin/rake
================================================
#!/usr/bin/env ruby
begin
  load File.expand_path('../spring', __FILE__)
rescue LoadError => e
  raise unless e.message.include?('spring')
end
require_relative '../config/boot'
require 'rake'
Rake.application.run


================================================
FILE: bin/setup
================================================
#!/usr/bin/env ruby
require 'pathname'

# path to your application root.
APP_ROOT = Pathname.new File.expand_path('../../',  __FILE__)

Dir.chdir APP_ROOT do
  # This script is a starting point to setup your application.
  # Add necessary setup steps to this file:

  puts "== Installing dependencies =="
  system "gem install bundler --conservative"
  system "bundle check || bundle install"

  # puts "\n== Copying sample files =="
  # unless File.exist?("config/database.yml")
  #   system "cp config/database.yml.sample config/database.yml"
  # end

  puts "\n== Preparing database =="
  system "bin/rake db:setup"

  puts "\n== Removing old logs and tempfiles =="
  system "rm -f log/*"
  system "rm -rf tmp/cache"

  puts "\n== Restarting application server =="
  system "touch tmp/restart.txt"
end


================================================
FILE: bin/spring
================================================
#!/usr/bin/env ruby

# This file loads spring without using Bundler, in order to be fast.
# It gets overwritten when you run the `spring binstub` command.

unless defined?(Spring)
  require 'rubygems'
  require 'bundler'

  if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^    (?:  )*spring \((.*?)\)$.*?^$/m))
    Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) }
    gem 'spring', match[1]
    require 'spring/binstub'
  end
end


================================================
FILE: config/application.dev.yml
================================================
# Email address to use in the 'from' field for emails sent by Kochiku.
sender_email_address: 'kochiku@example.com'

# Email address where kochiku should send problems with the build system (for example, errors),
# as distinct from failures in a particular test (which go to the people who committed code).
kochiku_notifications_email_address: 'kochiku-notifications@example.com'

# Domain name to use in constructing generic addresses. For example noreply@example.com in git commits.
domain_name: 'example.com'

# Set to true if Kochiku is served over https
use_https: false

# Host name where Kochiku is serving web pages.
kochiku_host: 'kochiku.example.com'

# If you commit with hitch/git-pair, etc, set this in order to send email to each person in the pair.
# For example, github+joe+bob@example.com will turn into emails to joe@example.com and bob@example.com
# if git_pair_email_prefix is set to 'github'.
git_pair_email_prefix: 'github'

# Mail server which will accept mail on port 25 (standard SMTP port). If you need to use another port,
# or other settings, you currently need to edit the kochiku source (config.action_mailer settings in
# config/environments/production.rb).
smtp_server: 'localhost'

# Host and port to connect to for Redis communication.
redis_host: '127.0.0.1'
redis_port: 6379

# List your git servers (at least for now, they need to be either github, github enterprise, or
# Atlassian Stash for things like constructing URLs to pages on those servers. Would be nice to
# just turn off the fancy features for a vanilla git server instead, but that isn't yet possible).
# possible values for type are: github or stash
git_servers:
  github.com:
    type: github

# It is highly recommended that you create an OAuth token for Kochiku on
# Github. This will allow Kochiku to do many things including display build
# status on pull requests.
#  github.com:
#    type: github
#    oauth_token_file: /path/to/github_oauth_token

# If you would like Kochiku to clone and fetch repositories from a git mirror
# define the repository and fill in the url to your mirror.
#  git.example.com:
#    mirror: 'git://git-mirror.example.com/'

# If you have multiple domains pointing at your git server then define them as aliases
#  git.example.com:
#    aliases:
#      - alias.example
#      - git.alias.com

# Example of Atlassian Stash integration.
#  stash.example.com:
#    type: stash
#    username: kochiku-robot
#    password_file: config/secrets/kochiku-robot-password


================================================
FILE: config/application.rb
================================================
require File.expand_path('../boot', __FILE__)

require 'rails/all'

Bundler.require(:default, Rails.env)

I18n.enforce_available_locales = true

module Kochiku
  class Application < Rails::Application

    config.generators do |g|
      g.template_engine :haml
      g.test_framework :rspec
      g.helper false
    end

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Custom directories with classes and modules you want to be autoloadable.
    # ACHTUNG: intentionally empty to help catch missing requires for config.threadsafe!
    # config.autoload_paths += %W()

    # Only load the plugins named here, in the order given (default is alphabetical).
    # :all can be used as a placeholder for all plugins not explicitly named.
    # config.plugins = [ :exception_notification, :ssl_requirement, :all ]

    # Activate observers that should always be running.
    config.active_record.observers = :repository_observer

    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
    config.time_zone = 'Pacific Time (US & Canada)'

    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
    # config.i18n.default_locale = :de

    # Configure the default encoding used in templates for Ruby 1.9.
    config.encoding = "utf-8"

    # Configure sensitive parameters which will be filtered from the log file.
    # config.filter_parameters += [:password]

    # Enable escaping HTML in JSON.
    config.active_support.escape_html_entities_in_json = true

    # Use SQL instead of Active Record's schema dumper when creating the database.
    # This is necessary if your schema can't be completely dumped by the schema dumper,
    # like if you have constraints or database-specific column types
    # config.active_record.schema_format = :sql

    # Version of your assets, change this if you want to expire all your assets
    config.assets.version = '1.0'

    config.assets.precompile << Proc.new{ |path| !File.basename(path).starts_with?('_') }
  end
end


================================================
FILE: config/application.test.yml
================================================
#########################################################################
#                                                                       #
# This version of the application.yml is used by the Kochiku test suite #
#                                                                       #
#########################################################################

# The descriptions for these settings are in config/application.dev.yml

sender_email_address: 'kochiku@example.com'
kochiku_notifications_email_address: 'kochiku-notifications@example.com'
domain_name: 'example.com'
use_https: false
kochiku_host: 'kochiku.example.com'
git_pair_email_prefix: 'github'
smtp_server: 'localhost'
redis_host: '127.0.0.1'

git_servers:
  github.com:
    type: github
  git.example.com:
    type: github
  git.squareup.com:
    type: github
  stash.example.com:
    type: stash


================================================
FILE: config/application.yml
================================================
# Place your production Kochiku application config here.
#
# Start by copying the contents of config/application.dev.yml and modify as
# desired.


================================================
FILE: config/boot.rb
================================================
require 'rubygems'

# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)

require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])


================================================
FILE: config/compass.rb
================================================
# This configuration file works with both the Compass command line tool and within Rails.
# Require any additional compass plugins here.
project_type = :rails

# Set this to the root of your project when deployed:
http_path = "/"

# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed

# To enable relative paths to assets via compass helper functions. Uncomment:
# relative_assets = true

# To disable debugging comments that display the original location of your selectors. Uncomment:
# line_comments = false

preferred_syntax = :sass


================================================
FILE: config/database.production.yml.sample
================================================
production:
  adapter: mysql2
  encoding: utf8
  reconnect: true
  username: kochiku
  password: the_password
  database: kochiku
  host: localhost


================================================
FILE: config/database.yml
================================================
development: &defaults
  adapter: mysql2
  encoding: utf8
  reconnect: false
  database: kochiku_development
  pool: 15
  username: root
  password:

test: &TEST
  <<: *defaults
  database: kochiku_test
  host: 127.0.0.1


================================================
FILE: config/deploy/production.rb
================================================
# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }

# Server that is running the Kochiku Rails app
server 'kochiku.example.com', user: 'kochiku', roles: %w{web app db worker}


================================================
FILE: config/deploy.rb
================================================
# Lock version to protect against cap command being called without bundle exec
# and executing with another version
lock '3.4.0'

set :application, "Kochiku"
set :repo_url, "https://github.com/square/kochiku.git"
set :user, "kochiku"

ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }

# Default value for :format is :pretty
# set :format, :pretty

# Default value for :log_level is :debug
# set :log_level, :debug

# Default value for :pty is false
# set :pty, true

set :deploy_to, "/app/#{fetch(:user)}/kochiku"
set :deploy_via, :remote_cache
set :linked_dirs, %w{log}

# Reference Capistrano's flow diagram for help choosing hooks
# http://capistranorb.com/documentation/getting-started/flow/
before "deploy:started", "kochiku:setup"
after  "deploy:symlink:shared", "kochiku:symlinks"
before "deploy:updated", "deploy:overwrite_database_yml"

# warn if a legacy deploy deploy.custom.rb is in place
if File.exist?(File.expand_path('deploy.custom.rb', File.dirname(__FILE__)))
  warn "Kochiku has upgraded to Capistrano 3. Placing custom capistrano config in deploy.custom.rb is no longer supported. Please move Capistrano settings to config/deploy/production.rb and remove deploy.custom.rb to make this message go away."
  exit(1)
end


================================================
FILE: config/environment.rb
================================================
# Load the rails application
require File.expand_path('../application', __FILE__)

# Load application settings for Kochiku
require File.expand_path('../../lib/settings_accessor', __FILE__)

CONF_FILE =
  if Rails.env.test?
    File.expand_path('../application.test.yml', __FILE__)
  elsif Rails.env.development?
    File.expand_path('../application.dev.yml', __FILE__)
  else
    File.expand_path('../application.yml', __FILE__)
  end

raise("#{CONF_FILE} is required to start Kochiku") unless File.exist?(CONF_FILE)

Settings = SettingsAccessor.new(File.read(CONF_FILE))

# Disable symbol and yaml parsing in the XML parser to avoid
# other code paths being exploited.
# https://www.ruby-forum.com/attachment/8029/cve-2013-0156-poc.txt
ActiveSupport::XmlMini::PARSING.delete("symbol")
ActiveSupport::XmlMini::PARSING.delete("yaml")

# Initialize the rails application
Kochiku::Application.initialize!


================================================
FILE: config/environments/development.rb
================================================
Kochiku::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb

  # In the development environment your application's code is reloaded on
  # every request.  This slows down response time but is perfect for development
  # since you don't have to restart the webserver when you make code changes.
  config.cache_classes = false

  config.eager_load = false

  # Show full error reports
  config.consider_all_requests_local = true

  # Enable page, action, and fragment caching
  #
  # Important to have enabled in development to keep cache related bugs from
  # slipping through.
  config.action_controller.perform_caching = true
  config.cache_store = :memory_store, { size: 67108864 } # 64.megabytes

  # Uncomment to use Redis caching in development
  #
  # config.cache_store = :readthis_store, {
  #   expires_in: 2.days.to_i,
  #   namespace: 'cache',
  #   marshal: JSON,
  #   redis: {
  #     host: Settings.redis_host,
  #     port: Settings.redis_port,
  #     db: 1, # use different db than Resque
  #     driver: :hiredis
  #   }
  # }

  # Don't care if the mailer can't send
  config.action_mailer.raise_delivery_errors = false

  # Print deprecation notices to the Rails logger
  config.active_support.deprecation = :log

  # Raise an error on page load if there are pending migrations
  config.active_record.migration_error = :page_load

  # Debug mode disables concatenation and preprocessing of assets.
  # This option may cause significant delays in view rendering with a large
  # number of complex assets.
  config.assets.debug = true

  # suppress output of asset requests. Formerly handled by quiet_assets gem
  config.assets.quiet = true

  # Generate digests for assets URLs
  # config.assets.digest = false

  config.sass.preferred_syntax = :sass
  Rails.application.routes.default_url_options[:host] = "localhost:3000"
  config.action_mailer.default_url_options = {:host => "localhost:3000"}

  config.after_initialize do
    Bullet.enable = true
    Bullet.bullet_logger = true
    Bullet.console = true
    Bullet.rails_logger = true

    # Added because Branches#show.rss does not use the build_attempts but Branches#show.html does use them
    Bullet.add_whitelist :type => :unused_eager_loading, :class_name => "BuildPart", :association => :build_attempts
  end
end


================================================
FILE: config/environments/production.rb
================================================
Kochiku::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb

  # Code is not reloaded between requests
  config.cache_classes = true

  # Eager load code on boot. This eager loads most of Rails and
  # your application in memory, allowing both thread web servers
  # and those relying on copy on write to perform better.
  # Rake tasks automatically ignore this option for performance.
  config.eager_load = true

  # Full error reports are disabled and caching is turned on
  config.consider_all_requests_local = true   # internal service; safe to show errors
  config.action_controller.perform_caching = true

  config.cache_store = :readthis_store, {
    expires_in: 2.days.to_i,
    namespace: 'cache',
    marshal: JSON,
    redis: {
      host: Settings.redis_host,
      port: Settings.redis_port,
      db: 1, # use different db than Resque
      driver: :hiredis
    }
  }

  # Disable Rails's static asset server (Apache or nginx will already do this)
  config.serve_static_files = false

  # Compress JavaScripts and CSS
  config.assets.js_compressor = :uglifier

  # Don't fallback to assets pipeline if a precompiled asset is missed
  config.assets.compile = false

  # Generate digests for assets URLs
  config.assets.digest = true

  # Specifies the header that your server uses for sending files
  # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
  # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx

  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  config.force_ssl = true

  # See everything in the log (default is :debug)
  config.log_level = :info

  # Prepend all log lines with the following tags
  # config.log_tags = [ :subdomain, :uuid ]

  # Use a different logger for distributed setups
  # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)

  # Enable serving of images, stylesheets, and javascripts from an asset server
  # config.action_controller.asset_host = "http://assets.example.com"

  # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
  # config.assets.precompile += %w( search.js )

  # Disable delivery errors, bad email addresses will be ignored
  # config.action_mailer.raise_delivery_errors = false

  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
  # the I18n.default_locale when a translation can not be found)
  config.i18n.fallbacks = true

  # Send deprecation notices to registered listeners
  config.active_support.deprecation = :notify

  # Disable automatic flushing of the log to improve performance.
  # config.autoflush_log = false

  # Use default logging formatter so that PID and timestamp are not suppressed.
  config.log_formatter = ::Logger::Formatter.new

  Rails.application.routes.default_url_options[:host] = Settings.kochiku_host
  Rails.application.routes.default_url_options[:protocol] = Settings.kochiku_protocol
  config.action_mailer.default_url_options = {:host => Settings.kochiku_host, :protocol => Settings.kochiku_protocol}

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :address => Settings.smtp_server,
    :port => 25
  }
end


================================================
FILE: config/environments/staging.rb
================================================
Kochiku::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb

  config.cache_classes = true
  config.eager_load = true

  config.consider_all_requests_local = true   # internal service; safe to show errors
  config.action_controller.perform_caching = true

  config.cache_store = :readthis_store, {
    expires_in: 2.days.to_i,
    namespace: 'cache',
    marshal: JSON,
    redis: {
      host: Settings.redis_host,
      port: Settings.redis_port,
      db: 1, # use different db than Resque
      driver: :hiredis
    }
  }

  # Disable Rails's static asset server (Apache or nginx will already do this)
  config.serve_static_files = false

  # Compress JavaScripts and CSS
  config.assets.js_compressor = :uglifier

  # Don't fallback to assets pipeline if a precompiled asset is missed
  config.assets.compile = false

  # Generate digests for assets URLs
  config.assets.digest = true

  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  config.force_ssl = true

  # See everything in the log (default is :info)
  # config.log_level = :debug

  # Disable delivery errors, bad email addresses will be ignored
  # config.action_mailer.raise_delivery_errors = false

  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
  # the I18n.default_locale when a translation can not be found)
  config.i18n.fallbacks = true

  # Send deprecation notices to registered listeners
  config.active_support.deprecation = :notify

  # Disable automatic flushing of the log to improve performance.
  # config.autoflush_log = false

  # Use default logging formatter so that PID and timestamp are not suppressed.
  config.log_formatter = ::Logger::Formatter.new

  Rails.application.routes.default_url_options[:host] = Settings.kochiku_host
  Rails.application.routes.default_url_options[:protocol] = Settings.kochiku_protocol
  config.action_mailer.default_url_options = {:host => Settings.kochiku_host, :protocol => Settings.kochiku_protocol}

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :address => Settings.smtp_server,
    :port => 25
  }
end


================================================
FILE: config/environments/test.rb
================================================
Kochiku::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb

  # The test environment is used exclusively to run your application's
  # test suite.  You never need to work with it otherwise.  Remember that
  # your test database is "scratch space" for the test suite and is wiped
  # and recreated between test runs.  Don't rely on the data there!
  config.cache_classes = true

  # Do not eager load code on boot. This avoids loading your whole application
  # just for the purpose of running a single test. If you are using a tool that
  # preloads Rails for running tests, you may have to set it to true.
  config.eager_load = false

  # Configure static asset server for tests with Cache-Control for performance
  config.public_file_server.enabled = true
  config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }

  # Show full error reports and disable caching
  config.consider_all_requests_local = true
  config.action_controller.perform_caching = false

  # Raise exceptions instead of rendering exception templates
  config.action_dispatch.show_exceptions = false

  # Disable request forgery protection in test environment
  config.action_controller.allow_forgery_protection = false

  # Tell Action Mailer not t
Download .txt
gitextract_m1o94eo4/

├── .gitignore
├── .haml-lint.yml
├── .rspec
├── .rubocop.yml
├── .rubocop_todo.yml
├── .ruby-version
├── .travis.yml
├── CONTRIBUTING.md
├── Capfile
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── app/
│   ├── assets/
│   │   ├── javascripts/
│   │   │   └── application.js
│   │   └── stylesheets/
│   │       └── screen.sass
│   ├── controllers/
│   │   ├── application_controller.rb
│   │   ├── branches_controller.rb
│   │   ├── build_artifacts_controller.rb
│   │   ├── build_attempts_controller.rb
│   │   ├── build_parts_controller.rb
│   │   ├── builds_controller.rb
│   │   ├── concerns/
│   │   │   └── build_attempts_queue_position.rb
│   │   ├── dashboards_controller.rb
│   │   ├── pull_requests_controller.rb
│   │   ├── repositories_controller.rb
│   │   └── status_controller.rb
│   ├── decorators/
│   │   ├── branch_decorator.rb
│   │   └── build_part_decorator.rb
│   ├── helpers/
│   │   ├── application_helper.rb
│   │   ├── build_helper.rb
│   │   ├── mail_helper.rb
│   │   └── project_stats_helper.rb
│   ├── jobs/
│   │   ├── build_attempt_job.rb
│   │   ├── build_initiated_by_job.rb
│   │   ├── build_partitioning_job.rb
│   │   ├── build_state_update_job.rb
│   │   ├── enforce_timeouts_job.rb
│   │   ├── job_base.rb
│   │   ├── poll_repositories_job.rb
│   │   └── timeout_stuck_builds_job.rb
│   ├── mailers/
│   │   ├── build_mailer.rb
│   │   └── merge_mailer.rb
│   ├── models/
│   │   ├── branch.rb
│   │   ├── build.rb
│   │   ├── build_artifact.rb
│   │   ├── build_attempt.rb
│   │   ├── build_part.rb
│   │   ├── repository.rb
│   │   └── repository_observer.rb
│   ├── uploaders/
│   │   ├── base_log_file_uploader.rb
│   │   ├── log_file_uploader.rb
│   │   └── on_success_uploader.rb
│   └── views/
│       ├── branches/
│       │   ├── health.html.haml
│       │   ├── index.html.haml
│       │   ├── show.html.haml
│       │   ├── show.json.erb
│       │   ├── show.rss.builder
│       │   └── status_report.xml.builder
│       ├── build_attempts/
│       │   ├── _build_attempt.html.haml
│       │   └── stream_logs.html.haml
│       ├── build_mailer/
│       │   ├── build_break_email.html.haml
│       │   ├── build_break_email.text.erb
│       │   ├── build_success_email.html.haml
│       │   ├── build_success_email.text.erb
│       │   ├── error_email.html.haml
│       │   └── error_email.text.erb
│       ├── build_parts/
│       │   ├── _build_attempts.html.haml
│       │   ├── _build_part.html.haml
│       │   └── show.html.haml
│       ├── builds/
│       │   ├── _build.html.haml
│       │   ├── _build_parts.html.haml
│       │   └── show.html.haml
│       ├── dashboards/
│       │   └── build_history_by_worker.html.haml
│       ├── layouts/
│       │   └── application.html.haml
│       ├── merge_mailer/
│       │   ├── merge_failed.text.erb
│       │   └── merge_successful.html.erb
│       └── repositories/
│           ├── _form.html.haml
│           ├── dashboard.html.haml
│           ├── edit.html.haml
│           ├── index.html.haml
│           └── new.html.haml
├── bin/
│   ├── bundle
│   ├── rails
│   ├── rake
│   ├── setup
│   └── spring
├── config/
│   ├── application.dev.yml
│   ├── application.rb
│   ├── application.test.yml
│   ├── application.yml
│   ├── boot.rb
│   ├── compass.rb
│   ├── database.production.yml.sample
│   ├── database.yml
│   ├── deploy/
│   │   └── production.rb
│   ├── deploy.rb
│   ├── environment.rb
│   ├── environments/
│   │   ├── development.rb
│   │   ├── production.rb
│   │   ├── staging.rb
│   │   └── test.rb
│   ├── initializers/
│   │   ├── backtrace_silencers.rb
│   │   ├── cocaine.rb
│   │   ├── inflections.rb
│   │   ├── load_build_strategy.rb
│   │   ├── mime_types.rb
│   │   ├── readthis.rb
│   │   ├── redis.rb
│   │   ├── resque.rb
│   │   ├── secret_token.rb
│   │   ├── session_store.rb
│   │   └── wrap_parameters.rb
│   ├── kochiku.yml
│   ├── kochiku.yml.sample
│   ├── locales/
│   │   └── en.yml
│   ├── resque_schedule.yml
│   └── routes.rb
├── config.ru
├── db/
│   ├── migrate/
│   │   ├── 20110621212000_create_schema.rb
│   │   ├── 20110624003418_change_artifact_type_to_name.rb
│   │   ├── 20110624015709_rename_build_part_result_result_to_state.rb
│   │   ├── 20110708203120_change_build_artifacts_for_carrier_wave.rb
│   │   ├── 20110713175724_rename_build_part_result_to_build_part_run.rb
│   │   ├── 20110713191536_add_foreign_key_indexes.rb
│   │   ├── 20110719204508_create_projects.rb
│   │   ├── 20110719205413_add_project_id_to_builds.rb
│   │   ├── 20110721185201_rename_builds_sha_to_ref.rb
│   │   ├── 20110801215540_rename_error_state_to_errored.rb
│   │   ├── 20120803005242_add_merge_bool_to_build.rb
│   │   ├── 20120817225343_add_branch_to_build.rb
│   │   ├── 20121008211955_create_repositories.rb
│   │   ├── 20121017173936_add_github_repository_id_to_repository.rb
│   │   ├── 20121017182543_fix_repository_schema.rb
│   │   ├── 20121017184946_remove_options_from_repository.rb
│   │   ├── 20121017222538_add_target_name_to_builds.rb
│   │   ├── 20121017224003_add_command_flag_to_repositories.rb
│   │   ├── 20121018182435_add_options_to_build_part.rb
│   │   ├── 20121024005715_add_send_build_failure_email_to_repository.rb
│   │   ├── 20121024164929_record_build_failure_email_sent.rb
│   │   ├── 20121024210129_add_success_script_to_repositories.rb
│   │   ├── 20121024212949_add_on_success_log_file_to_build.rb
│   │   ├── 20121030213442_add_queue_to_repository.rb
│   │   ├── 20121101220831_add_timeout_to_repository.rb
│   │   ├── 20130226232844_add_index_to_build_ref.rb
│   │   ├── 20130409144945_add_on_success_note_to_repositories.rb
│   │   ├── 20130511012855_add_deployable_map_to_build.rb
│   │   ├── 20130626183046_add_maven_modules_to_build.rb
│   │   ├── 20130627194433_add_index_to_build_part_paths.rb
│   │   ├── 20130709123456_add_upload_artifacts_to_build_parts.rb
│   │   ├── 20130822191419_add_queue_to_build_part.rb
│   │   ├── 20130822231850_remove_upload_artifacts_from_build_parts.rb
│   │   ├── 20130823210844_add_retry_count_to_build_part.rb
│   │   ├── 20130823231854_remove_java_specific_stuff.rb
│   │   ├── 20130823234546_remove_queue_override_from_repositories.rb
│   │   ├── 20130910190203_add_repository_name_as_column.rb
│   │   ├── 20131217022000_add_error_text_to_build.rb
│   │   ├── 20140123234208_add_allows_kochiku_merges_to_repository.rb
│   │   ├── 20140128180258_rename_auto_merge_on_build.rb
│   │   ├── 20140415001051_remove_use_branches_on_green_from_repositories.rb
│   │   ├── 20140415011144_remove_command_flag_from_repositories.rb
│   │   ├── 20140506012721_unique_index_on_builds_ref.rb
│   │   ├── 20140507184819_add_host_and_namespace_to_repositories.rb
│   │   ├── 20140617214701_add_success_email.rb
│   │   ├── 20140715225910_remove_notes.rb
│   │   ├── 20141031234747_add_email_first_failure_to_repositories.rb
│   │   ├── 20150324001246_remove_on_success_script_from_repositories.rb
│   │   ├── 20150331160909_add_send_merge_successful_email.rb
│   │   ├── 20150714234635_add_log_port_to_build_attempt.rb
│   │   ├── 20150717214656_create_branches.rb
│   │   ├── 20150717220149_assign_builds_to_branches.rb
│   │   ├── 20150717231250_remove_branch_string_from_builds.rb
│   │   ├── 20150719130110_index_repositories_namespace_and_name.rb
│   │   ├── 20151111080255_remove_repo_cache_dir_from_repositories.rb
│   │   ├── 20151114185514_fix_convergence_index.rb
│   │   ├── 20160408214135_index_created_at_on_build_attempts.rb
│   │   ├── 20170804214538_add_enabled_bool_to_repositories.rb
│   │   ├── 20180208202524_add_test_command_to_builds.rb
│   │   ├── 20180220185338_add_assume_lost_after_to_repository.rb
│   │   ├── 20180227222254_add_initiated_by_to_builds.rb
│   │   ├── 20180301221320_add_instance_type_to_build_attempts.rb
│   │   └── 20180619210823_add_kochiku_yml_config_to_builds.rb
│   ├── schema.rb
│   └── seeds.rb
├── lib/
│   ├── build_strategies/
│   │   ├── no_op_build_strategy.rb
│   │   └── production_build_strategy.rb
│   ├── capistrano/
│   │   └── tasks/
│   │       ├── deploy.cap
│   │       └── kochiku.cap
│   ├── fileless_io.rb
│   ├── git_blame.rb
│   ├── git_merge_executor.rb
│   ├── git_repo.rb
│   ├── github_commit_status.rb
│   ├── github_post_receive_hook.rb
│   ├── github_request.rb
│   ├── partitioner/
│   │   ├── base.rb
│   │   ├── default.rb
│   │   ├── dependency_map.rb
│   │   ├── go.rb
│   │   ├── maven.rb
│   │   └── topological_sorter.rb
│   ├── partitioner.rb
│   ├── remote_server/
│   │   ├── github.rb
│   │   └── stash.rb
│   ├── remote_server.rb
│   ├── server_settings.rb
│   ├── settings_accessor.rb
│   ├── stash_merge_executor.rb
│   └── tasks/
│       ├── .gitkeep
│       ├── kochiku.rake
│       └── resque.rake
├── public/
│   ├── 404.html
│   ├── 422.html
│   ├── 500.html
│   ├── fonts/
│   │   └── SQMarket-Regular.otf
│   └── robots.txt
├── script/
│   ├── ci
│   └── kochiku-build.sh.sample
├── spec/
│   ├── controllers/
│   │   ├── branches_controller_spec.rb
│   │   ├── build_artifacts_controller_spec.rb
│   │   ├── build_attempts_controller_spec.rb
│   │   ├── build_parts_controller_spec.rb
│   │   ├── builds_controller_spec.rb
│   │   ├── dashboards_controller_spec.rb
│   │   ├── pull_requests_controller_spec.rb
│   │   ├── repositories_controller_spec.rb
│   │   └── status_controller_spec.rb
│   ├── decorators/
│   │   ├── branch_decorator_spec.rb
│   │   └── build_part_decorator_spec.rb
│   ├── features/
│   │   └── integration_spec.rb
│   ├── fixtures/
│   │   ├── build_artifact.log
│   │   ├── sample_github_webhook_payload.json
│   │   └── stdout.log
│   ├── helpers/
│   │   ├── application_helper_spec.rb
│   │   ├── build_helper_spec.rb
│   │   └── project_stats_helper_spec.rb
│   ├── jobs/
│   │   ├── build_partitioning_job_spec.rb
│   │   ├── build_state_update_job_spec.rb
│   │   ├── enforce_timeouts_job_spec.rb
│   │   ├── poll_repositories_job_spec.rb
│   │   └── timeout_stuck_builds_job_spec.rb
│   ├── lib/
│   │   ├── build_strategies/
│   │   │   └── production_build_strategy_spec.rb
│   │   ├── git_blame_spec.rb
│   │   ├── git_merge_executor_spec.rb
│   │   ├── git_repo_spec.rb
│   │   ├── github_commit_status_spec.rb
│   │   ├── github_post_receive_hook_spec.rb
│   │   ├── github_request_spec.rb
│   │   ├── partitioner/
│   │   │   ├── default_spec.rb
│   │   │   ├── dependency_map_spec.rb
│   │   │   ├── go_spec.rb
│   │   │   ├── maven_spec.rb
│   │   │   └── shared_default_behavior.rb
│   │   ├── partitioner_spec.rb
│   │   ├── remote_server/
│   │   │   ├── github_spec.rb
│   │   │   └── stash_spec.rb
│   │   ├── remote_server_spec.rb
│   │   ├── server_settings_spec.rb
│   │   ├── settings_accessor_spec.rb
│   │   └── stash_merge_executor_spec.rb
│   ├── mailers/
│   │   ├── build_mailer_spec.rb
│   │   ├── merge_mailer_spec.rb
│   │   └── previews/
│   │       └── build_mailer_preview.rb
│   ├── models/
│   │   ├── branch_spec.rb
│   │   ├── build_artifact_spec.rb
│   │   ├── build_attempt_spec.rb
│   │   ├── build_part_spec.rb
│   │   ├── build_spec.rb
│   │   ├── repository_observer_spec.rb
│   │   └── repository_spec.rb
│   ├── routes_spec.rb
│   ├── spec_helper.rb
│   └── support/
│       ├── command_stubber.rb
│       ├── custom_argument_matchers.rb
│       ├── factories.rb
│       ├── git_spec_helper.rb
│       └── sha_helper.rb
└── vendor/
    └── assets/
        ├── javascripts/
        │   ├── jquery.flot.categories.js
        │   ├── jquery.flot.errorbars.js
        │   ├── jquery.flot.js
        │   ├── jquery.tablesorter.js
        │   ├── jquery.timeago.js
        │   ├── jquery.tipTip.js
        │   └── moment.js
        └── stylesheets/
            ├── tablesorter.theme.kochiku.css
            └── tipTip.scss
Download .txt
SYMBOL INDEX (726 symbols across 143 files)

FILE: app/assets/javascripts/application.js
  function timeToSeconds (line 195) | function timeToSeconds(time) {

FILE: app/controllers/application_controller.rb
  class ApplicationController (line 1) | class ApplicationController < ActionController::Base

FILE: app/controllers/branches_controller.rb
  class BranchesController (line 1) | class BranchesController < ApplicationController
    method index (line 11) | def index
    method show (line 17) | def show
    method request_new_build (line 43) | def request_new_build
    method health (line 66) | def health
    method build_time_history (line 100) | def build_time_history
    method status_report (line 114) | def status_report
    method badge (line 118) | def badge
    method load_repository (line 133) | def load_repository
    method load_repository_and_branch (line 138) | def load_repository_and_branch
    method initialize_stats_variables (line 145) | def initialize_stats_variables
    method load_build_stats (line 158) | def load_build_stats

FILE: app/controllers/build_artifacts_controller.rb
  class BuildArtifactsController (line 1) | class BuildArtifactsController < ApplicationController
    method create (line 3) | def create
    method show (line 18) | def show

FILE: app/controllers/build_attempts_controller.rb
  class BuildAttemptsController (line 4) | class BuildAttemptsController < ApplicationController
    method start (line 6) | def start
    method finish (line 23) | def finish
    method show (line 42) | def show
    method stream_logs (line 52) | def stream_logs
    method stream_logs_chunk (line 70) | def stream_logs_chunk

FILE: app/controllers/build_parts_controller.rb
  class BuildPartsController (line 1) | class BuildPartsController < ApplicationController
    method show (line 16) | def show
    method rebuild (line 25) | def rebuild
    method modified_time (line 35) | def modified_time
    method refresh_build_part_info (line 43) | def refresh_build_part_info
    method load_repository_build_and_part (line 64) | def load_repository_build_and_part

FILE: app/controllers/builds_controller.rb
  class BuildsController (line 3) | class BuildsController < ApplicationController
    method show (line 23) | def show
    method create (line 44) | def create
    method retry_partitioning (line 76) | def retry_partitioning
    method rebuild_failed_parts (line 88) | def rebuild_failed_parts
    method abort (line 102) | def abort
    method toggle_merge_on_success (line 108) | def toggle_merge_on_success
    method build_status (line 114) | def build_status
    method modified_time (line 124) | def modified_time
    method resend_status (line 134) | def resend_status
    method refresh_build_part_info (line 140) | def refresh_build_part_info
    method build_redirect (line 162) | def build_redirect
    method build_ref_redirect (line 167) | def build_ref_redirect
    method load_repository (line 175) | def load_repository
    method format_build_parts_position (line 182) | def format_build_parts_position

FILE: app/controllers/concerns/build_attempts_queue_position.rb
  type BuildAttemptsQueuePosition (line 1) | module BuildAttemptsQueuePosition
    function calculate_build_attempts_position (line 6) | def calculate_build_attempts_position(build_attempts, queue, keep_rank...
    function calculate_build_parts_position (line 17) | def calculate_build_parts_position(build)

FILE: app/controllers/dashboards_controller.rb
  class DashboardsController (line 1) | class DashboardsController < ApplicationController
    method build_history_by_worker (line 3) | def build_history_by_worker

FILE: app/controllers/pull_requests_controller.rb
  class PullRequestsController (line 3) | class PullRequestsController < ApplicationController
    method build (line 4) | def build
    method handle_stash_request (line 15) | def handle_stash_request(payload)
    method handle_github_request (line 29) | def handle_github_request(payload)
    method get_repo (line 46) | def get_repo(url)
    method handle_repo_push_request (line 50) | def handle_repo_push_request(branch_name, sha)
    method handle_pull_request (line 59) | def handle_pull_request(branch_name, sha)
    method get_branch_name (line 69) | def get_branch_name(ref)
    method fetch_branch (line 73) | def fetch_branch(name, auto_create = false)
    method active_pull_request? (line 77) | def active_pull_request?(action)

FILE: app/controllers/repositories_controller.rb
  class RepositoriesController (line 1) | class RepositoriesController < ApplicationController
    method create (line 3) | def create
    method new (line 21) | def new
    method destroy (line 27) | def destroy
    method update (line 34) | def update
    method edit (line 46) | def edit
    method index (line 53) | def index
    method dashboard (line 57) | def dashboard
    method build_ref (line 68) | def build_ref
    method ensure_build (line 98) | def ensure_build(repository, branch_name, sha)
    method repository_params (line 109) | def repository_params
    method update_convergence_branches (line 121) | def update_convergence_branches

FILE: app/controllers/status_controller.rb
  class StatusController (line 1) | class StatusController < ApplicationController
    method available (line 3) | def available

FILE: app/decorators/branch_decorator.rb
  class BranchDecorator (line 3) | class BranchDecorator < Draper::Decorator
    method most_recent_build_state (line 6) | def most_recent_build_state
    method last_build_duration (line 10) | def last_build_duration
    method build_time_history (line 15) | def build_time_history(fuzzy_limit = 1000)

FILE: app/decorators/build_part_decorator.rb
  class BuildPartDecorator (line 1) | class BuildPartDecorator < Draper::Decorator
    method most_recent_stdout_artifact (line 4) | def most_recent_stdout_artifact

FILE: app/helpers/application_helper.rb
  type ApplicationHelper (line 1) | module ApplicationHelper
    function duration_strftime (line 2) | def duration_strftime(duration_in_seconds, format = "%H:%M:%S")
    function time_for (line 8) | def time_for(time, format = "%H:%M")
    function build_success_in_words (line 12) | def build_success_in_words(build)
    function build_activity (line 23) | def build_activity(build)
    function link_to_commit (line 34) | def link_to_commit(repo, commit_sha)
    function link_to_branch (line 38) | def link_to_branch(build)
    function show_link_to_commit (line 44) | def show_link_to_commit(repo, commit_sha)
    function show_link_to_compare (line 48) | def show_link_to_compare(build, first_commit_hash, second_commit_hash)
    function show_link_to_create_pull_request (line 58) | def show_link_to_create_pull_request(build)
    function timeago (line 62) | def timeago(time, options = {})

FILE: app/helpers/build_helper.rb
  type BuildHelper (line 1) | module BuildHelper
    function build_metadata_headers (line 2) | def build_metadata_headers(build, display_ruby_version)
    function build_metadata_values (line 14) | def build_metadata_values(build, build_part, display_ruby_version)
    function format_paths (line 21) | def format_paths(build_part)
    function multiple_ruby_versions? (line 38) | def multiple_ruby_versions?(build)
    function is_a_build_with_one_part? (line 42) | def is_a_build_with_one_part?(build)
    function eligible_for_merge_on_success? (line 46) | def eligible_for_merge_on_success?(build)

FILE: app/helpers/mail_helper.rb
  type MailHelper (line 1) | module MailHelper
    function failed_build_part_sentence (line 2) | def failed_build_part_sentence(build_part)
    function failed_build_paths (line 11) | def failed_build_paths(build_part)

FILE: app/helpers/project_stats_helper.rb
  type ProjectStatsHelper (line 1) | module ProjectStatsHelper
    function pass_rate_css_class (line 2) | def pass_rate_css_class(rate)
    function rebuild_count_css_class (line 10) | def rebuild_count_css_class(attempts)
    function eventual_pass_rate (line 19) | def eventual_pass_rate(builds)
    function error_free_pass_rate (line 25) | def error_free_pass_rate(builds)
    function pass_rate_text (line 33) | def pass_rate_text(number)
    function average_number_of_rebuilds (line 40) | def average_number_of_rebuilds(builds)
    function median_elapsed_time (line 52) | def median_elapsed_time(builds)
    function seconds_to_minutes (line 64) | def seconds_to_minutes(seconds)

FILE: app/jobs/build_attempt_job.rb
  class BuildAttemptJob (line 5) | class BuildAttemptJob < JobBase
    class WrongBuildAttemptJobClassError (line 6) | class WrongBuildAttemptJobClassError < StandardError; end
    method initialize (line 8) | def initialize(build_options)
    method perform (line 12) | def perform

FILE: app/jobs/build_initiated_by_job.rb
  class BuildInitiatedByJob (line 4) | class BuildInitiatedByJob < JobBase
    method initialize (line 12) | def initialize(build_id)
    method perform (line 16) | def perform

FILE: app/jobs/build_partitioning_job.rb
  class BuildPartitioningJob (line 5) | class BuildPartitioningJob < JobBase
    method initialize (line 13) | def initialize(build_id)
    method perform (line 17) | def perform
    method on_exception (line 33) | def on_exception(e)

FILE: app/jobs/build_state_update_job.rb
  class BuildStateUpdateJob (line 6) | class BuildStateUpdateJob < JobBase
    method initialize (line 9) | def initialize(build_id)
    method perform (line 13) | def perform

FILE: app/jobs/enforce_timeouts_job.rb
  class EnforceTimeoutsJob (line 5) | class EnforceTimeoutsJob
    method perform (line 6) | def self.perform

FILE: app/jobs/job_base.rb
  class JobBase (line 1) | class JobBase
    method enqueue (line 3) | def enqueue(*args)
    method enqueue_on (line 7) | def enqueue_on(build_queue, *args)
    method perform (line 14) | def perform(*args)
    method on_exception (line 26) | def on_exception(e)

FILE: app/jobs/poll_repositories_job.rb
  class PollRepositoriesJob (line 1) | class PollRepositoriesJob
    method perform (line 2) | def self.perform

FILE: app/jobs/timeout_stuck_builds_job.rb
  class TimeoutStuckBuildsJob (line 1) | class TimeoutStuckBuildsJob < JobBase
    method perform (line 4) | def self.perform
    method clean_runnable_not_queued (line 9) | def self.clean_runnable_not_queued
    method clean_lost_builds (line 24) | def self.clean_lost_builds

FILE: app/mailers/build_mailer.rb
  class BuildMailer (line 1) | class BuildMailer < ActionMailer::Base
    method pull_request_link (line 8) | def pull_request_link(build)
    method error_email (line 26) | def error_email(build_attempt, error_text = nil)
    method build_break_email (line 35) | def build_break_email(build)
    method build_success_email (line 65) | def build_success_email(build)

FILE: app/mailers/merge_mailer.rb
  class MergeMailer (line 1) | class MergeMailer < ActionMailer::Base
    method merge_successful (line 6) | def merge_successful(build, merge_commit, emails, stdout_and_stderr)
    method merge_failed (line 16) | def merge_failed(build, emails, stdout_and_stderr)

FILE: app/models/branch.rb
  class Branch (line 1) | class Branch < ActiveRecord::Base
    method to_param (line 7) | def to_param
    method kickoff_new_build_unless_currently_busy (line 11) | def kickoff_new_build_unless_currently_busy(ref)
    method abort_in_progress_builds_behind_build (line 20) | def abort_in_progress_builds_behind_build(current_build)
    method most_recent_build (line 26) | def most_recent_build
    method last_completed_build (line 30) | def last_completed_build
    method timing_data_for_recent_builds (line 36) | def timing_data_for_recent_builds(fuzzy_limit = 1000)
    method build_time_history_sql (line 44) | def build_time_history_sql(min_build_id)

FILE: app/models/build.rb
  class Build (line 6) | class Build < ActiveRecord::Base
    method not_passed_and_last_attempt_in_state (line 11) | def not_passed_and_last_attempt_in_state(*state)
    method passed (line 24) | def passed
    method failed (line 28) | def failed
    method failed_or_errored (line 32) | def failed_or_errored
    method failed_errored_or_aborted (line 36) | def failed_errored_or_aborted
    method errored (line 40) | def errored
    method all_passed_on_first_try? (line 44) | def all_passed_on_first_try?
    method test_command (line 71) | def test_command
    method on_success_script (line 80) | def on_success_script
    method previous_build (line 84) | def previous_build
    method previous_successful_build (line 88) | def previous_successful_build
    method enqueue_partitioning_job (line 92) | def enqueue_partitioning_job
    method kochiku_yml (line 96) | def kochiku_yml
    method partition (line 109) | def partition(parts)
    method update_state_from_parts! (line 125) | def update_state_from_parts!
    method update_commit_status! (line 149) | def update_commit_status!
    method finished_at (line 156) | def finished_at
    method elapsed_time (line 160) | def elapsed_time
    method linear_time (line 166) | def linear_time
    method retry_count (line 172) | def retry_count
    method max_retries (line 178) | def max_retries
    method longest_build_part (line 184) | def longest_build_part
    method idle_time (line 188) | def idle_time
    method succeeded? (line 192) | def succeeded?
    method failed? (line 196) | def failed?
    method already_failed? (line 201) | def already_failed?
    method aborted? (line 205) | def aborted?
    method promotable? (line 209) | def promotable?
    method mergable_by_kochiku? (line 213) | def mergable_by_kochiku?
    method merge_on_success_enabled? (line 217) | def merge_on_success_enabled?
    method newer_branch_build_exists? (line 221) | def newer_branch_build_exists?
    method merge_to_master! (line 226) | def merge_to_master!
    method promote! (line 230) | def promote!
    method completed? (line 237) | def completed?
    method abort! (line 244) | def abort!
    method to_color (line 253) | def to_color
    method to_png (line 264) | def to_png
    method send_build_status_email! (line 275) | def send_build_status_email!
    method is_running? (line 297) | def is_running?
    method as_json (line 301) | def as_json(options = {})
    method enqueue_initiated_by (line 309) | def enqueue_initiated_by
    method status_png (line 313) | def status_png(r, g, b)

FILE: app/models/build_artifact.rb
  class BuildArtifact (line 3) | class BuildArtifact < ActiveRecord::Base
    method as_json (line 12) | def as_json

FILE: app/models/build_attempt.rb
  class BuildAttempt (line 1) | class BuildAttempt < ActiveRecord::Base
    method elapsed_time (line 15) | def elapsed_time
    method start! (line 23) | def start!(builder)
    method finish! (line 42) | def finish!(state)
    method unsuccessful? (line 70) | def unsuccessful?
    method successful? (line 74) | def successful?
    method aborted? (line 78) | def aborted?
    method running? (line 82) | def running?
    method stopped? (line 86) | def stopped?
    method errored? (line 90) | def errored?
    method should_reattempt? (line 94) | def should_reattempt?
    method error_txt (line 98) | def error_txt
    method files (line 103) | def files

FILE: app/models/build_part.rb
  class BuildPart (line 1) | class BuildPart < ActiveRecord::Base
    method last_attempt (line 10) | def last_attempt
    method create_and_enqueue_new_build_attempt! (line 14) | def create_and_enqueue_new_build_attempt!
    method job_args (line 27) | def job_args(build_attempt)
    method status (line 45) | def status
    method successful? (line 53) | def successful?
    method unsuccessful? (line 57) | def unsuccessful?
    method running? (line 61) | def running?
    method not_finished? (line 65) | def not_finished?
    method to_color (line 69) | def to_color
    method started_at (line 80) | def started_at
    method finished_at (line 84) | def finished_at
    method elapsed_time (line 88) | def elapsed_time
    method as_json (line 96) | def as_json(options = {})
    method should_reattempt? (line 100) | def should_reattempt?

FILE: app/models/repository.rb
  class Repository (line 6) | class Repository < ActiveRecord::Base
    method lookup_by_url (line 21) | def self.lookup_by_url(url)
    method lookup (line 32) | def self.lookup(host:, namespace:, name:)
    method url= (line 43) | def url=(value)
    method remote_server (line 56) | def remote_server
    method promotion_refs (line 62) | def promotion_refs
    method interested_github_events (line 66) | def interested_github_events
    method scm_type (line 72) | def scm_type
    method build_for_commit (line 81) | def build_for_commit(sha)
    method ensure_build_exists (line 92) | def ensure_build_exists(sha, branch)
    method name_with_namespace (line 100) | def name_with_namespace
    method validate_url_against_remote_servers (line 107) | def validate_url_against_remote_servers

FILE: app/models/repository_observer.rb
  class RepositoryObserver (line 1) | class RepositoryObserver < ActiveRecord::Observer
    method after_save (line 4) | def after_save(record)
    method setup_hook? (line 8) | def setup_hook?

FILE: app/uploaders/base_log_file_uploader.rb
  class BaseLogFileUploader (line 1) | class BaseLogFileUploader < CarrierWave::Uploader::Base
    method cache_dir (line 4) | def cache_dir

FILE: app/uploaders/log_file_uploader.rb
  class LogFileUploader (line 3) | class LogFileUploader < BaseLogFileUploader
    method store_dir (line 4) | def store_dir

FILE: app/uploaders/on_success_uploader.rb
  class OnSuccessUploader (line 3) | class OnSuccessUploader < BaseLogFileUploader
    method store_dir (line 4) | def store_dir

FILE: config/application.rb
  type Kochiku (line 9) | module Kochiku
    class Application (line 10) | class Application < Rails::Application

FILE: db/migrate/20110621212000_create_schema.rb
  class CreateSchema (line 1) | class CreateSchema < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 38) | def self.down

FILE: db/migrate/20110624003418_change_artifact_type_to_name.rb
  class ChangeArtifactTypeToName (line 1) | class ChangeArtifactTypeToName < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 6) | def self.down

FILE: db/migrate/20110624015709_rename_build_part_result_result_to_state.rb
  class RenameBuildPartResultResultToState (line 1) | class RenameBuildPartResultResultToState < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 6) | def self.down

FILE: db/migrate/20110708203120_change_build_artifacts_for_carrier_wave.rb
  class ChangeBuildArtifactsForCarrierWave (line 1) | class ChangeBuildArtifactsForCarrierWave < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 7) | def self.down

FILE: db/migrate/20110713175724_rename_build_part_result_to_build_part_run.rb
  class RenameBuildPartResultToBuildPartRun (line 1) | class RenameBuildPartResultToBuildPartRun < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 7) | def self.down

FILE: db/migrate/20110713191536_add_foreign_key_indexes.rb
  class AddForeignKeyIndexes (line 1) | class AddForeignKeyIndexes < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 8) | def self.down

FILE: db/migrate/20110719204508_create_projects.rb
  class CreateProjects (line 1) | class CreateProjects < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 12) | def self.down

FILE: db/migrate/20110719205413_add_project_id_to_builds.rb
  class AddProjectIdToBuilds (line 1) | class AddProjectIdToBuilds < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 7) | def self.down

FILE: db/migrate/20110721185201_rename_builds_sha_to_ref.rb
  class RenameBuildsShaToRef (line 1) | class RenameBuildsShaToRef < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 6) | def self.down

FILE: db/migrate/20110801215540_rename_error_state_to_errored.rb
  class RenameErrorStateToErrored (line 1) | class RenameErrorStateToErrored < ActiveRecord::Migration[5.0]
    method up (line 2) | def self.up
    method down (line 7) | def self.down

FILE: db/migrate/20120803005242_add_merge_bool_to_build.rb
  class AddMergeBoolToBuild (line 1) | class AddMergeBoolToBuild < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20120817225343_add_branch_to_build.rb
  class AddBranchToBuild (line 1) | class AddBranchToBuild < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121008211955_create_repositories.rb
  class CreateRepositories (line 1) | class CreateRepositories < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121017173936_add_github_repository_id_to_repository.rb
  class AddGithubRepositoryIdToRepository (line 1) | class AddGithubRepositoryIdToRepository < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121017182543_fix_repository_schema.rb
  class FixRepositorySchema (line 1) | class FixRepositorySchema < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121017184946_remove_options_from_repository.rb
  class RemoveOptionsFromRepository (line 1) | class RemoveOptionsFromRepository < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121017222538_add_target_name_to_builds.rb
  class AddTargetNameToBuilds (line 1) | class AddTargetNameToBuilds < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121017224003_add_command_flag_to_repositories.rb
  class AddCommandFlagToRepositories (line 1) | class AddCommandFlagToRepositories < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121018182435_add_options_to_build_part.rb
  class AddOptionsToBuildPart (line 1) | class AddOptionsToBuildPart < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121024005715_add_send_build_failure_email_to_repository.rb
  class AddSendBuildFailureEmailToRepository (line 1) | class AddSendBuildFailureEmailToRepository < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121024164929_record_build_failure_email_sent.rb
  class RecordBuildFailureEmailSent (line 1) | class RecordBuildFailureEmailSent < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121024210129_add_success_script_to_repositories.rb
  class AddSuccessScriptToRepositories (line 1) | class AddSuccessScriptToRepositories < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121024212949_add_on_success_log_file_to_build.rb
  class AddOnSuccessLogFileToBuild (line 1) | class AddOnSuccessLogFileToBuild < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121030213442_add_queue_to_repository.rb
  class AddQueueToRepository (line 1) | class AddQueueToRepository < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20121101220831_add_timeout_to_repository.rb
  class AddTimeoutToRepository (line 1) | class AddTimeoutToRepository < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20130226232844_add_index_to_build_ref.rb
  class AddIndexToBuildRef (line 1) | class AddIndexToBuildRef < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20130409144945_add_on_success_note_to_repositories.rb
  class AddOnSuccessNoteToRepositories (line 1) | class AddOnSuccessNoteToRepositories < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20130511012855_add_deployable_map_to_build.rb
  class AddDeployableMapToBuild (line 1) | class AddDeployableMapToBuild < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20130626183046_add_maven_modules_to_build.rb
  class AddMavenModulesToBuild (line 1) | class AddMavenModulesToBuild < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20130627194433_add_index_to_build_part_paths.rb
  class AddIndexToBuildPartPaths (line 1) | class AddIndexToBuildPartPaths < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20130709123456_add_upload_artifacts_to_build_parts.rb
  class AddUploadArtifactsToBuildParts (line 1) | class AddUploadArtifactsToBuildParts < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20130822191419_add_queue_to_build_part.rb
  class AddQueueToBuildPart (line 1) | class AddQueueToBuildPart < ActiveRecord::Migration[5.0]
    method up (line 2) | def up
    method down (line 11) | def down

FILE: db/migrate/20130822231850_remove_upload_artifacts_from_build_parts.rb
  class RemoveUploadArtifactsFromBuildParts (line 1) | class RemoveUploadArtifactsFromBuildParts < ActiveRecord::Migration[5.0]
    method up (line 2) | def up
    method down (line 6) | def down

FILE: db/migrate/20130823210844_add_retry_count_to_build_part.rb
  class AddRetryCountToBuildPart (line 1) | class AddRetryCountToBuildPart < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20130823231854_remove_java_specific_stuff.rb
  class RemoveJavaSpecificStuff (line 1) | class RemoveJavaSpecificStuff < ActiveRecord::Migration[5.1]
    method up (line 2) | def up
    method down (line 7) | def down

FILE: db/migrate/20130823234546_remove_queue_override_from_repositories.rb
  class RemoveQueueOverrideFromRepositories (line 1) | class RemoveQueueOverrideFromRepositories < ActiveRecord::Migration[5.0]
    method up (line 2) | def up
    method down (line 6) | def down

FILE: db/migrate/20130910190203_add_repository_name_as_column.rb
  class AddRepositoryNameAsColumn (line 1) | class AddRepositoryNameAsColumn < ActiveRecord::Migration[5.0]
    class Repository (line 11) | class Repository < ActiveRecord::Base
    method project_params (line 14) | def project_params(url)
    method old_style_repository_name (line 35) | def old_style_repository_name(url)
    method up (line 39) | def up
    method down (line 64) | def down

FILE: db/migrate/20131217022000_add_error_text_to_build.rb
  class AddErrorTextToBuild (line 1) | class AddErrorTextToBuild < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20140123234208_add_allows_kochiku_merges_to_repository.rb
  class AddAllowsKochikuMergesToRepository (line 1) | class AddAllowsKochikuMergesToRepository < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20140128180258_rename_auto_merge_on_build.rb
  class RenameAutoMergeOnBuild (line 1) | class RenameAutoMergeOnBuild < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20140415001051_remove_use_branches_on_green_from_repositories.rb
  class RemoveUseBranchesOnGreenFromRepositories (line 1) | class RemoveUseBranchesOnGreenFromRepositories < ActiveRecord::Migration...
    method change (line 2) | def change

FILE: db/migrate/20140415011144_remove_command_flag_from_repositories.rb
  class RemoveCommandFlagFromRepositories (line 1) | class RemoveCommandFlagFromRepositories < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20140506012721_unique_index_on_builds_ref.rb
  class UniqueIndexOnBuildsRef (line 1) | class UniqueIndexOnBuildsRef < ActiveRecord::Migration[5.0]
    method up (line 2) | def up
    method down (line 11) | def down

FILE: db/migrate/20140507184819_add_host_and_namespace_to_repositories.rb
  class AddHostAndNamespaceToRepositories (line 1) | class AddHostAndNamespaceToRepositories < ActiveRecord::Migration[5.0]
    method up (line 2) | def up
    method down (line 21) | def down

FILE: db/migrate/20140617214701_add_success_email.rb
  class AddSuccessEmail (line 1) | class AddSuccessEmail < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20140715225910_remove_notes.rb
  class RemoveNotes (line 1) | class RemoveNotes < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20141031234747_add_email_first_failure_to_repositories.rb
  class AddEmailFirstFailureToRepositories (line 1) | class AddEmailFirstFailureToRepositories < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20150324001246_remove_on_success_script_from_repositories.rb
  class RemoveOnSuccessScriptFromRepositories (line 1) | class RemoveOnSuccessScriptFromRepositories < ActiveRecord::Migration[5.0]
    method up (line 2) | def up
    method down (line 24) | def down

FILE: db/migrate/20150331160909_add_send_merge_successful_email.rb
  class AddSendMergeSuccessfulEmail (line 1) | class AddSendMergeSuccessfulEmail < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20150714234635_add_log_port_to_build_attempt.rb
  class AddLogPortToBuildAttempt (line 1) | class AddLogPortToBuildAttempt < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20150717214656_create_branches.rb
  class CreateBranches (line 1) | class CreateBranches < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20150717220149_assign_builds_to_branches.rb
  class AssignBuildsToBranches (line 3) | class AssignBuildsToBranches < ActiveRecord::Migration[5.0]
    method up (line 4) | def up
    method down (line 31) | def down

FILE: db/migrate/20150717231250_remove_branch_string_from_builds.rb
  class RemoveBranchStringFromBuilds (line 1) | class RemoveBranchStringFromBuilds < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20150719130110_index_repositories_namespace_and_name.rb
  class IndexRepositoriesNamespaceAndName (line 1) | class IndexRepositoriesNamespaceAndName < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20151111080255_remove_repo_cache_dir_from_repositories.rb
  class RemoveRepoCacheDirFromRepositories (line 1) | class RemoveRepoCacheDirFromRepositories < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20151114185514_fix_convergence_index.rb
  class FixConvergenceIndex (line 3) | class FixConvergenceIndex < ActiveRecord::Migration[5.0]
    method change (line 4) | def change

FILE: db/migrate/20160408214135_index_created_at_on_build_attempts.rb
  class IndexCreatedAtOnBuildAttempts (line 1) | class IndexCreatedAtOnBuildAttempts < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20170804214538_add_enabled_bool_to_repositories.rb
  class AddEnabledBoolToRepositories (line 1) | class AddEnabledBoolToRepositories < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20180208202524_add_test_command_to_builds.rb
  class AddTestCommandToBuilds (line 1) | class AddTestCommandToBuilds < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20180220185338_add_assume_lost_after_to_repository.rb
  class AddAssumeLostAfterToRepository (line 1) | class AddAssumeLostAfterToRepository < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20180227222254_add_initiated_by_to_builds.rb
  class AddInitiatedByToBuilds (line 1) | class AddInitiatedByToBuilds < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20180301221320_add_instance_type_to_build_attempts.rb
  class AddInstanceTypeToBuildAttempts (line 1) | class AddInstanceTypeToBuildAttempts < ActiveRecord::Migration[5.0]
    method change (line 2) | def change

FILE: db/migrate/20180619210823_add_kochiku_yml_config_to_builds.rb
  class AddKochikuYmlConfigToBuilds (line 1) | class AddKochikuYmlConfigToBuilds < ActiveRecord::Migration[5.1]
    method change (line 2) | def change

FILE: db/seeds.rb
  function artifact_directory (line 32) | def artifact_directory
  function write_the_sample_stdout_log_file (line 36) | def write_the_sample_stdout_log_file
  function sample_stdout_log_file (line 45) | def sample_stdout_log_file
  function create_build_artifact (line 49) | def create_build_artifact(attempt)
  function create_build_part (line 56) | def create_build_part(build, kind, paths, build_attempt_state)
  function create_build (line 78) | def create_build(branch, test_types, build_attempt_state: 'passed')
  function populate_builds_for (line 100) | def populate_builds_for(branch, repo_info)

FILE: lib/build_strategies/no_op_build_strategy.rb
  class BuildStrategy (line 1) | class BuildStrategy
    method promote_build (line 3) | def promote_build(build)
    method merge_ref (line 6) | def merge_ref(ref)
    method run_success_script (line 9) | def run_success_script(build)

FILE: lib/build_strategies/production_build_strategy.rb
  class BuildStrategy (line 3) | class BuildStrategy
    method promote_build (line 16) | def promote_build(build)
    method run_success_script (line 26) | def run_success_script(build)
    method merge_ref (line 39) | def merge_ref(build)
    method update_branch (line 58) | def update_branch(branch_name, ref_to_promote)
    method on_success_command (line 62) | def on_success_command(build)

FILE: lib/fileless_io.rb
  class FilelessIO (line 2) | class FilelessIO < StringIO

FILE: lib/git_blame.rb
  class GitBlame (line 4) | class GitBlame
    method emails_since_last_green (line 6) | def emails_since_last_green(build)
    method emails_in_branch (line 10) | def emails_in_branch(build)
    method last_email_in_branch (line 14) | def last_email_in_branch(build)
    method changes_since_last_green (line 18) | def changes_since_last_green(build)
    method changes_in_branch (line 26) | def changes_in_branch(build)
    method files_changed_since_last_build (line 34) | def files_changed_since_last_build(build, fetch_emails: false, sync: t...
    method files_changed_since_last_green (line 41) | def files_changed_since_last_green(build, fetch_emails: false)
    method files_changed_in_branch (line 49) | def files_changed_in_branch(build, fetch_emails: false, sync: true)
    method net_files_changed_in_branch (line 59) | def net_files_changed_in_branch(build, sync: true)
    method email_from_git_email (line 73) | def email_from_git_email(email)
    method git_names_and_emails_since_last_green (line 83) | def git_names_and_emails_since_last_green(build)
    method git_names_and_emails_in_branch (line 89) | def git_names_and_emails_in_branch(build)
    method last_git_name_and_email_in_branch (line 99) | def last_git_name_and_email_in_branch(build)
    method lookup_git_names_and_emails (line 105) | def lookup_git_names_and_emails(git_names_and_emails)
    method parse_git_changes (line 112) | def parse_git_changes(output)
    method parse_git_files_changes (line 120) | def parse_git_files_changes(output, fetch_emails: false)
    method parse_git_changes_by_name_status (line 140) | def parse_git_changes_by_name_status(output)

FILE: lib/git_merge_executor.rb
  class GitMergeExecutor (line 3) | class GitMergeExecutor
    class GitFetchFailedError (line 4) | class GitFetchFailedError < StandardError; end
    class GitMergeFailedError (line 5) | class GitMergeFailedError < StandardError; end
    class GitPushFailedError (line 6) | class GitPushFailedError < StandardError; end
    method initialize (line 8) | def initialize(build)
    method merge_and_push (line 18) | def merge_and_push
    method delete_branch (line 40) | def delete_branch
    method git_fetch_and_reset (line 56) | def git_fetch_and_reset
    method merge_to_master (line 63) | def merge_to_master
    method push_to_remote (line 76) | def push_to_remote
    method raise_and_log (line 86) | def raise_and_log(error_class, error_info, command_output)
    method merge_env (line 92) | def merge_env

FILE: lib/git_repo.rb
  class GitRepo (line 4) | class GitRepo
    class RefNotFoundError (line 5) | class RefNotFoundError < StandardError; end
    method inside_copy (line 10) | def inside_copy(repository, sha)
    method inside_repo (line 28) | def inside_repo(repository, sync: true)
    method load_kochiku_yml (line 38) | def load_kochiku_yml(repository, ref)
    method included_in_promotion_ref? (line 46) | def included_in_promotion_ref?(build_ref, promotion_ref)
    method branch_exist? (line 55) | def branch_exist?(branch)
    method read_repo_config (line 69) | def read_repo_config(ref)
    method cached_repo_for (line 79) | def cached_repo_for(repository)
    method harmonize_remote_url (line 93) | def harmonize_remote_url(cached_repo_path, expected_url)
    method synchronize_cache_repo (line 104) | def synchronize_cache_repo(cached_repo_path)
    method clone_bare_repo (line 111) | def clone_bare_repo(repo, cached_repo_path)
    method synchronize_with_remote (line 119) | def synchronize_with_remote(name)

FILE: lib/github_commit_status.rb
  class GithubCommitStatus (line 3) | class GithubCommitStatus
    method initialize (line 4) | def initialize(build, oauth_token)
    method update_commit_status! (line 11) | def update_commit_status!
    method mark_as (line 23) | def mark_as(state, description)

FILE: lib/github_post_receive_hook.rb
  class GithubPostReceiveHook (line 4) | class GithubPostReceiveHook
    method initialize (line 7) | def initialize(repository, oauth_token)
    method subscribe! (line 17) | def subscribe!
    method update_repository_hook! (line 27) | def update_repository_hook!
    method synchronize_or_create! (line 39) | def synchronize_or_create!
    method create_hook (line 57) | def create_hook

FILE: lib/github_request.rb
  class GithubRequest (line 4) | class GithubRequest
    class ResponseError (line 5) | class ResponseError < RuntimeError
    method get (line 9) | def self.get(url, oauth_token)
    method post (line 17) | def self.post(url, data, oauth_token)
    method patch (line 27) | def self.patch(url, data, oauth_token)
    method make_request (line 37) | def self.make_request(uri, request_object)

FILE: lib/partitioner.rb
  type Partitioner (line 6) | module Partitioner
    function for_build (line 7) | def self.for_build(build)

FILE: lib/partitioner/base.rb
  type Partitioner (line 1) | module Partitioner
    class Base (line 2) | class Base
      method initialize (line 3) | def initialize(build, kochiku_yml)
      method partitions (line 8) | def partitions
      method emails_for_commits_causing_failures (line 19) | def emails_for_commits_causing_failures
      method partitioner_type (line 23) | def partitioner_type

FILE: lib/partitioner/default.rb
  type Partitioner (line 3) | module Partitioner
    class Default (line 5) | class Default < Base
      method partitions (line 6) | def partitions
      method max_build_time (line 19) | def max_build_time
      method build_partitions (line 30) | def build_partitions
      method build_targets (line 40) | def build_targets(ruby_version = nil)
      method get_file_parts_for (line 52) | def get_file_parts_for(subset)
      method partitions_for (line 76) | def partitions_for(subset)
      method time_greedy_partitions_for (line 99) | def time_greedy_partitions_for(file_to_times_hash, all_files, workers)
      method load_manifest (line 127) | def load_manifest(file_name)
      type Strategies (line 131) | module Strategies
        function alphabetically (line 133) | def alphabetically(files, workers)
        function isolated (line 137) | def isolated(files, workers)
        function round_robin (line 141) | def round_robin(files, workers)
        function shuffle (line 145) | def shuffle(files, workers)
        function size (line 149) | def size(files, workers)
        function size_greedy_partitioning (line 153) | def size_greedy_partitioning(files, workers)
        function size_average_partitioning (line 166) | def size_average_partitioning(files, workers)

FILE: lib/partitioner/dependency_map.rb
  type Partitioner (line 4) | module Partitioner
    class DependencyMap (line 50) | class DependencyMap < Default
      method should_run_all_tests (line 57) | def should_run_all_tests
      method get_file_parts_for (line 73) | def get_file_parts_for(subset)

FILE: lib/partitioner/go.rb
  type Partitioner (line 9) | module Partitioner
    class Go (line 29) | class Go < Base
      class DependencyError (line 30) | class DependencyError < StandardError; end
      method initialize (line 31) | def initialize(build, kochiku_yml)
      method partitions (line 45) | def partitions
      method file_to_packages (line 69) | def file_to_packages(file_path)
      method failed_convergence_tests (line 81) | def failed_convergence_tests
      method all_packages_target_types (line 91) | def all_packages_target_types
      method top_level_packages_target_types (line 96) | def top_level_packages_target_types
      method all_packages (line 100) | def all_packages
      method top_level_package_map (line 106) | def top_level_package_map
      method package_folders_map (line 111) | def package_folders_map(packages)
      method package_to_folder (line 116) | def package_to_folder(package)
      method filter_test (line 120) | def filter_test(packages)
      method package_dependency_map (line 124) | def package_dependency_map
      method depends_on_map (line 159) | def depends_on_map
      method package_info_map (line 216) | def package_info_map
      method add_partitions (line 245) | def add_partitions(packages)
      method add_with_split (line 274) | def add_with_split(package_list, target_type, workers)
      method partition_info (line 286) | def partition_info(packages, type)

FILE: lib/partitioner/maven.rb
  type Partitioner (line 7) | module Partitioner
    class Maven (line 9) | class Maven < Base
      method initialize (line 12) | def initialize(build, kochiku_yml)
      method partitions (line 23) | def partitions
      method emails_for_commits_causing_failures (line 59) | def emails_for_commits_causing_failures
      method maven_modules (line 90) | def maven_modules
      method all_partitions (line 96) | def all_partitions
      method pom_for (line 100) | def pom_for(mvn_module)
      method add_options (line 104) | def add_options(group_modules)
      method group_modules (line 135) | def group_modules(mvn_modules)
      method sort_modules (line 147) | def sort_modules(mvn_modules)
      method partition_info (line 152) | def partition_info(mvn_modules)
      method depends_on_map (line 166) | def depends_on_map
      method module_dependency_map (line 183) | def module_dependency_map
      method transitive_dependency_map (line 220) | def transitive_dependency_map
      method transitive_dependencies (line 228) | def transitive_dependencies(mvn_module, dependency_map)
      method file_to_module (line 241) | def file_to_module(file_path)

FILE: lib/partitioner/topological_sorter.rb
  type Partitioner (line 3) | module Partitioner
    class TopologicalSorter (line 4) | class TopologicalSorter
      method initialize (line 7) | def initialize(dependency_map)
      method tsort_each_node (line 11) | def tsort_each_node(&block)
      method tsort_each_child (line 15) | def tsort_each_child(project, &block)

FILE: lib/remote_server.rb
  type RemoteServer (line 4) | module RemoteServer
    class AccessDenied (line 8) | class AccessDenied < StandardError
      method initialize (line 9) | def initialize(url, action, original_message = nil)
      method to_s (line 15) | def to_s
    function for_url (line 20) | def self.for_url(url)
    function parseable_url? (line 35) | def self.parseable_url?(url)
    function valid_git_host? (line 41) | def self.valid_git_host?(url)

FILE: lib/remote_server/github.rb
  type RemoteServer (line 6) | module RemoteServer
    class Github (line 8) | class Github
      method initialize (line 15) | def initialize(url, server)
      method attributes (line 21) | def attributes
      method merge_executor (line 38) | def merge_executor
      method canonical_repository_url (line 44) | def canonical_repository_url
      method url_for_compare (line 48) | def url_for_compare(first_commit_hash, second_commit_hash)
      method url_for_fetching (line 54) | def url_for_fetching
      method sha_for_branch (line 62) | def sha_for_branch(branch)
      method update_commit_status! (line 74) | def update_commit_status!(build)
      method install_post_receive_hook! (line 78) | def install_post_receive_hook!(repo)
      method base_api_url (line 82) | def base_api_url
      method href_for_commit (line 90) | def href_for_commit(sha)
      method base_html_url (line 94) | def base_html_url
      method get_branch_url (line 98) | def get_branch_url(branch_name)
      method open_pull_request_url (line 102) | def open_pull_request_url(branch_name)

FILE: lib/remote_server/stash.rb
  type RemoteServer (line 4) | module RemoteServer
    class StashAPIError (line 5) | class StashAPIError < StandardError; end
    class Stash (line 8) | class Stash
      method initialize (line 18) | def initialize(url, server)
      method attributes (line 25) | def attributes
      method merge_executor (line 46) | def merge_executor
      method canonical_repository_url (line 52) | def canonical_repository_url
      method url_for_compare (line 59) | def url_for_compare(first_commit_branch, second_commit_branch)
      method url_for_fetching (line 69) | def url_for_fetching
      method sha_for_branch (line 77) | def sha_for_branch(branch)
      method update_commit_status! (line 94) | def update_commit_status!(build)
      method install_post_receive_hook! (line 106) | def install_post_receive_hook!(repo)
      method base_api_url (line 110) | def base_api_url
      method base_html_url (line 114) | def base_html_url
      method href_for_commit (line 118) | def href_for_commit(sha)
      method get_branch_url (line 122) | def get_branch_url(branch_name)
      method open_pull_request_url (line 126) | def open_pull_request_url(branch_name)
      method merge (line 136) | def merge(branch)
      method head_commit (line 150) | def head_commit(branch)
      method delete_branch (line 162) | def delete_branch(branch, dryRun = false)
      method get_pr_id_and_version (line 182) | def get_pr_id_and_version(branch)
      method can_merge? (line 195) | def can_merge?(pr_id)
      method perform_merge (line 215) | def perform_merge(pr_id, pr_version)
      method stash_status_for (line 224) | def stash_status_for(build)
      class StashRequest (line 234) | class StashRequest
        method initialize (line 235) | def initialize(settings)
        method setup_auth! (line 241) | def setup_auth!(req)
        method get (line 245) | def get(url)
        method post (line 252) | def post(url, body = {})
        method delete (line 260) | def delete(url, body)
        method make_request (line 269) | def make_request(method, url, args = [])

FILE: lib/server_settings.rb
  class ServerSettings (line 1) | class ServerSettings
    method initialize (line 5) | def initialize(raw_settings, host)

FILE: lib/settings_accessor.rb
  class SettingsAccessor (line 5) | class SettingsAccessor
    method initialize (line 6) | def initialize(yaml)
    method sender_email_address (line 10) | def sender_email_address
    method kochiku_notifications_email_address (line 14) | def kochiku_notifications_email_address
    method domain_name (line 18) | def domain_name
    method kochiku_protocol (line 22) | def kochiku_protocol
    method kochiku_host (line 26) | def kochiku_host
    method kochiku_host_with_protocol (line 30) | def kochiku_host_with_protocol
    method git_servers (line 34) | def git_servers
    method git_server (line 47) | def git_server(url)
    method smtp_server (line 54) | def smtp_server
    method redis_host (line 58) | def redis_host
    method redis_port (line 62) | def redis_port
    method git_pair_email_prefix (line 66) | def git_pair_email_prefix

FILE: lib/stash_merge_executor.rb
  class StashMergeExecutor (line 4) | class StashMergeExecutor < GitMergeExecutor
    method merge_and_push (line 7) | def merge_and_push
    method delete_branch (line 21) | def delete_branch

FILE: spec/controllers/pull_requests_controller_spec.rb
  function github_push_payload (line 245) | def github_push_payload(options = {})
  function github_pull_request_payload (line 259) | def github_pull_request_payload(options = {})
  function stash_push_payload (line 280) | def stash_push_payload(options = {})
  function stash_pull_request_payload (line 297) | def stash_pull_request_payload(options = {})

FILE: spec/controllers/repositories_controller_spec.rb
  function verify_response_creates_build (line 228) | def verify_response_creates_build(response, branch_name, ref)

FILE: spec/helpers/project_stats_helper_spec.rb
  function create_some_builds_with_build_attempts (line 8) | def create_some_builds_with_build_attempts(count)

FILE: spec/lib/github_commit_status_spec.rb
  function commit_status_response (line 59) | def commit_status_response

FILE: spec/lib/github_post_receive_hook_spec.rb
  function github_hooks (line 61) | def github_hooks

FILE: spec/lib/remote_server/github_spec.rb
  function make_server (line 6) | def make_server(url)

FILE: spec/lib/remote_server/stash_spec.rb
  function make_server (line 63) | def make_server(url)

FILE: spec/mailers/previews/build_mailer_preview.rb
  class GitBlame (line 5) | class GitBlame
    method emails_since_last_green (line 7) | def emails_since_last_green(build)
    method emails_in_branch (line 11) | def emails_in_branch(build)
    method last_email_in_branch (line 15) | def last_email_in_branch(build)
    method changes_since_last_green (line 19) | def changes_since_last_green(build)
    method changes_in_branch (line 35) | def changes_in_branch(build)
  type Partitioner (line 54) | module Partitioner
    function for_build (line 55) | def self.for_build(build)
    class Base (line 59) | class Base
      method initialize (line 60) | def initialize(build, kochiku_yml)
      method emails_for_commits_causing_failures (line 65) | def emails_for_commits_causing_failures
  class BuildMailerPreview (line 71) | class BuildMailerPreview < ActionMailer::Preview
    method build_break_email (line 72) | def build_break_email
    method build_success_email (line 76) | def build_success_email

FILE: spec/support/command_stubber.rb
  class CommandStubber (line 1) | class CommandStubber
    method initialize (line 6) | def initialize
    method create_stubbed_process_status (line 14) | def create_stubbed_process_status(exitstatus = 0)
    method stub_capture2e_failure (line 21) | def stub_capture2e_failure(fail_on_cmd)
    method stub_capture2e (line 36) | def stub_capture2e
    method check_cmd_executed (line 40) | def check_cmd_executed(expected_cmd)

FILE: spec/support/git_spec_helper.rb
  function suppressed_git_init (line 4) | def suppressed_git_init

FILE: spec/support/sha_helper.rb
  function to_40 (line 1) | def to_40(short)

FILE: vendor/assets/javascripts/jquery.flot.categories.js
  function processRawData (line 56) | function processRawData(plot, series, data, datapoints) {
  function getNextIndex (line 97) | function getNextIndex(categories) {
  function categoriesTickGenerator (line 107) | function categoriesTickGenerator(axis) {
  function setupCategoriesForAxis (line 120) | function setupCategoriesForAxis(series, axis, datapoints) {
  function transformPointsOnAxis (line 146) | function transformPointsOnAxis(datapoints, axis, categories) {
  function processDatapoints (line 174) | function processDatapoints(plot, series, datapoints) {
  function init (line 179) | function init(plot) {

FILE: vendor/assets/javascripts/jquery.flot.errorbars.js
  function processRawData (line 76) | function processRawData(plot, series, data, datapoints){
  function parseErrors (line 107) | function parseErrors(series, i){
  function drawSeriesErrors (line 162) | function drawSeriesErrors(plot, ctx, s){
  function drawError (line 275) | function drawError(ctx,err,x,y,upper,lower,drawUpper,drawLower,radius,of...
  function drawPath (line 322) | function drawPath(ctx, pts){
  function draw (line 330) | function draw(plot, ctx){
  function init (line 342) | function init(plot) {

FILE: vendor/assets/javascripts/jquery.flot.js
  function H (line 32) | function H(J,K,I){return K<J?J:(K>I?I:K)}
  function Canvas (line 51) | function Canvas(cls, container) {
  function Plot (line 430) | function Plot(placeholder, data_, options_, plugins) {
  function floorInBase (line 2976) | function floorInBase(n, base) {

FILE: vendor/assets/javascripts/jquery.tablesorter.js
  function log (line 147) | function log() {
  function benchmark (line 157) | function benchmark(s, d) {
  function isEmptyObject (line 165) | function isEmptyObject(obj) {
  function getElementText (line 173) | function getElementText(table, node, cellIndex) {
  function detectParserForColumn (line 194) | function detectParserForColumn(table, rows, rowIndex, cellIndex) {
  function buildParserCache (line 224) | function buildParserCache(table) {
  function buildCache (line 286) | function buildCache(table) {
  function appendToTable (line 383) | function appendToTable(table, init) {
  function formatSortingOrder (line 431) | function formatSortingOrder(v) {
  function buildHeaders (line 436) | function buildHeaders(table) {
  function commonUpdate (line 495) | function commonUpdate(table, resort, callback) {
  function updateHeader (line 506) | function updateHeader(table) {
  function setHeadersCss (line 527) | function setHeadersCss(table) {
  function fixColumnWidth (line 581) | function fixColumnWidth(table) {
  function updateHeaderSortCount (line 595) | function updateHeaderSortCount(table, list) {
  function getCachedSortType (line 640) | function getCachedSortType(parsers, i) {
  function initSort (line 644) | function initSort(table, cell, event){
  function multisort (line 753) | function multisort(table) { /*jshint loopfunc:true */
  function resortComplete (line 819) | function resortComplete($table, callback){
  function checkResort (line 829) | function checkResort($table, flag, callback) {
  function bindMethods (line 843) | function bindMethods(table){

FILE: vendor/assets/javascripts/jquery.timeago.js
  function substitute (line 95) | function substitute(stringOrFunction, number) {
  function refresh (line 179) | function refresh() {
  function prepareData (line 198) | function prepareData(element) {
  function inWords (line 212) | function inWords(date) {
  function distance (line 216) | function distance(date) {

FILE: vendor/assets/javascripts/jquery.tipTip.js
  function active_tiptip (line 100) | function active_tiptip(){
  function deactive_tiptip (line 183) | function deactive_tiptip(){

FILE: vendor/assets/javascripts/moment.js
  function padToken (line 171) | function padToken(func, count) {
  function ordinalizeToken (line 176) | function ordinalizeToken(func) {
  function Language (line 197) | function Language() {
  function Moment (line 202) | function Moment(config) {
  function Duration (line 207) | function Duration(duration) {
  function extend (line 264) | function extend(a, b) {
  function absRound (line 273) | function absRound(number) {
  function leftZeroFill (line 283) | function leftZeroFill(number, targetLength) {
  function addOrSubtractDurationFromMoment (line 292) | function addOrSubtractDurationFromMoment(mom, duration, isAdding) {
  function isArray (line 313) | function isArray(input) {
  function compareArrays (line 318) | function compareArrays(array1, array2) {
  function loadLang (line 487) | function loadLang(key, values) {
  function getLangDefinition (line 502) | function getLangDefinition(key) {
  function removeFormattingTokens (line 518) | function removeFormattingTokens(input) {
  function makeFormatFunction (line 525) | function makeFormatFunction(format) {
  function formatMoment (line 546) | function formatMoment(m, format) {
  function getParseRegexForToken (line 571) | function getParseRegexForToken(token) {
  function addTimeToArrayFromToken (line 620) | function addTimeToArrayFromToken(token, input, config) {
  function dateFromArray (line 718) | function dateFromArray(config) {
  function makeDateFromStringAndFormat (line 747) | function makeDateFromStringAndFormat(config) {
  function makeDateFromStringAndArray (line 778) | function makeDateFromStringAndArray(config) {
  function makeDateFromString (line 811) | function makeDateFromString(config) {
  function makeDateFromInput (line 831) | function makeDateFromInput(config) {
  function substituteTimeAgo (line 856) | function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
  function relativeTime (line 860) | function relativeTime(milliseconds, withoutSuffix, lang) {
  function weekOfYear (line 895) | function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
  function makeMoment (line 916) | function makeMoment(config) {
  function makeGetterAndSetter (line 1283) | function makeGetterAndSetter(name, key) {
  function makeDurationGetter (line 1338) | function makeDurationGetter(name) {
  function makeDurationAsGetter (line 1344) | function makeDurationAsGetter(name, factor) {
Condensed preview — 285 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (916K chars).
[
  {
    "path": ".gitignore",
    "chars": 175,
    "preview": "/.bundle\nlog/*.log\ntmp/\npublic/uploads\npublic/log_files\nvendor/ruby\n\n# file with the real db config for production\n/conf"
  },
  {
    "path": ".haml-lint.yml",
    "chars": 348,
    "preview": "linters:\n  ConsecutiveSilentScripts:\n    enabled: false\n\n  IdNames:\n    enabled: false\n\n  InlineStyles:\n    enabled: fal"
  },
  {
    "path": ".rspec",
    "chars": 9,
    "preview": "--color\n\n"
  },
  {
    "path": ".rubocop.yml",
    "chars": 1396,
    "preview": "inherit_from: .rubocop_todo.yml\nAllCops:\n  TargetRubyVersion: 2.3\n  TargetRailsVersion: 4.2\n  DisplayCopNames: true\n  In"
  },
  {
    "path": ".rubocop_todo.yml",
    "chars": 15286,
    "preview": "# This configuration was generated by\n# `rubocop --auto-gen-config`\n# on 2017-12-08 16:49:35 -0800 using RuboCop version"
  },
  {
    "path": ".ruby-version",
    "chars": 6,
    "preview": "2.4.3\n"
  },
  {
    "path": ".travis.yml",
    "chars": 404,
    "preview": "sudo: false\ncache: bundler\nlanguage: ruby\nrvm:\n  - 2.4.4\n  - 2.5.1\nbefore_install:\n  # some ruby versions come with a br"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 436,
    "preview": "Contributing\n============\n\nIf you would like to contribute code to Kochiku, thank you! You can do so through\nGitHub by f"
  },
  {
    "path": "Capfile",
    "chars": 598,
    "preview": "# Load DSL and Setup Up Stages\nrequire 'capistrano/setup'\n\n# Includes default deployment tasks\nrequire 'capistrano/deplo"
  },
  {
    "path": "Gemfile",
    "chars": 1725,
    "preview": "source 'https://rubygems.org'\n\ngem 'actionpack-action_caching', '> 1.1.1'\n\ngem 'activemodel-serializers-xml' # required "
  },
  {
    "path": "LICENSE.txt",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 1553,
    "preview": "Kochiku - Distributed tests made easy\n=====================================\n\nKochiku is a distributed platform for test "
  },
  {
    "path": "Rakefile",
    "chars": 267,
    "preview": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they wil"
  },
  {
    "path": "app/assets/javascripts/application.js",
    "chars": 6007,
    "preview": "//= require jquery\n//= require jquery_ujs\n//= require jquery.tipTip\n//= require jquery.tablesorter\n//= require jquery.ti"
  },
  {
    "path": "app/assets/stylesheets/screen.sass",
    "chars": 13086,
    "preview": "@import compass\n@import compass/reset\n@import compass/css3/border-radius\n\n/* SQ Market font\n@font-face\n  font-family: \"S"
  },
  {
    "path": "app/controllers/application_controller.rb",
    "chars": 221,
    "preview": "class ApplicationController < ActionController::Base\n  include BuildHelper\n\n  rescue_from ActiveRecord::RecordNotFound d"
  },
  {
    "path": "app/controllers/branches_controller.rb",
    "chars": 6279,
    "preview": "class BranchesController < ApplicationController\n  caches_action :show, :build_time_history, cache_path: proc {\n    load"
  },
  {
    "path": "app/controllers/build_artifacts_controller.rb",
    "chars": 734,
    "preview": "class BuildArtifactsController < ApplicationController\n\n  def create\n    @build_artifact = BuildArtifact.new\n    @build_"
  },
  {
    "path": "app/controllers/build_attempts_controller.rb",
    "chars": 3382,
    "preview": "require 'json'\nrequire 'net/http'\n\nclass BuildAttemptsController < ApplicationController\n\n  def start\n    @build_attempt"
  },
  {
    "path": "app/controllers/build_parts_controller.rb",
    "chars": 2253,
    "preview": "class BuildPartsController < ApplicationController\n  before_action :load_repository_build_and_part, only: [:rebuild, :sh"
  },
  {
    "path": "app/controllers/builds_controller.rb",
    "chars": 7243,
    "preview": "require 'git_repo'\n\nclass BuildsController < ApplicationController\n  before_action :load_repository, :only => [:show, :r"
  },
  {
    "path": "app/controllers/concerns/build_attempts_queue_position.rb",
    "chars": 1109,
    "preview": "module BuildAttemptsQueuePosition\n  extend ActiveSupport::Concern\n\n  # keep_rank is only true if we are calling calculat"
  },
  {
    "path": "app/controllers/dashboards_controller.rb",
    "chars": 393,
    "preview": "class DashboardsController < ApplicationController\n\n  def build_history_by_worker\n    build_attempts = BuildAttempt.wher"
  },
  {
    "path": "app/controllers/pull_requests_controller.rb",
    "chars": 2265,
    "preview": "require 'remote_server'\n\nclass PullRequestsController < ApplicationController\n  def build\n    if params['payload']\n     "
  },
  {
    "path": "app/controllers/repositories_controller.rb",
    "chars": 4402,
    "preview": "class RepositoriesController < ApplicationController\n\n  def create\n    if params.fetch(:repository)[:url].blank?\n      r"
  },
  {
    "path": "app/controllers/status_controller.rb",
    "chars": 194,
    "preview": "class StatusController < ApplicationController\n\n  def available\n    if File.exist?(Rails.root.join(\"tmp/maintenance\"))\n "
  },
  {
    "path": "app/decorators/branch_decorator.rb",
    "chars": 1048,
    "preview": "require 'set'\n\nclass BranchDecorator < Draper::Decorator\n  delegate_all\n\n  def most_recent_build_state\n    object.most_r"
  },
  {
    "path": "app/decorators/build_part_decorator.rb",
    "chars": 329,
    "preview": "class BuildPartDecorator < Draper::Decorator\n  delegate_all\n\n  def most_recent_stdout_artifact\n    BuildArtifact\n      ."
  },
  {
    "path": "app/helpers/application_helper.rb",
    "chars": 1958,
    "preview": "module ApplicationHelper\n  def duration_strftime(duration_in_seconds, format = \"%H:%M:%S\")\n    return \"N/A\" if duration_"
  },
  {
    "path": "app/helpers/build_helper.rb",
    "chars": 1559,
    "preview": "module BuildHelper\n  def build_metadata_headers(build, display_ruby_version)\n    headers = []\n    headers << \"Ruby Versi"
  },
  {
    "path": "app/helpers/mail_helper.rb",
    "chars": 612,
    "preview": "module MailHelper\n  def failed_build_part_sentence(build_part)\n    stdout_log = build_part.most_recent_stdout_artifact\n "
  },
  {
    "path": "app/helpers/project_stats_helper.rb",
    "chars": 1970,
    "preview": "module ProjectStatsHelper\n  def pass_rate_css_class(rate)\n    case rate.to_i\n    when 0..39 then 'bad'\n    when 40..75 t"
  },
  {
    "path": "app/jobs/build_attempt_job.rb",
    "chars": 426,
    "preview": "require 'job_base'\n\n# Keep this interface so we can easily enqueue new jobs.\n# The job is handled by kochiku-worker\nclas"
  },
  {
    "path": "app/jobs/build_initiated_by_job.rb",
    "chars": 558,
    "preview": "require 'job_base'\nrequire 'git_repo'\n\nclass BuildInitiatedByJob < JobBase\n  extend Resque::Plugins::Retry\n  @queue = :l"
  },
  {
    "path": "app/jobs/build_partitioning_job.rb",
    "chars": 1306,
    "preview": "require 'job_base'\nrequire 'git_repo'\nrequire 'partitioner'\n\nclass BuildPartitioningJob < JobBase\n  extend Resque::Plugi"
  },
  {
    "path": "app/jobs/build_state_update_job.rb",
    "chars": 1291,
    "preview": "require 'job_base'\nrequire 'git_repo'\nrequire 'github_commit_status'\n\n# this job updates the remote repo. it is enqueued"
  },
  {
    "path": "app/jobs/enforce_timeouts_job.rb",
    "chars": 1542,
    "preview": "# The EnforceTimeoutsJob searches for BuildAttempts that were picked up by a\n# kochiku worker but never heard back from "
  },
  {
    "path": "app/jobs/job_base.rb",
    "chars": 516,
    "preview": "class JobBase\n  class << self\n    def enqueue(*args)\n      Resque.enqueue(self, *args)\n    end\n\n    def enqueue_on(build"
  },
  {
    "path": "app/jobs/poll_repositories_job.rb",
    "chars": 1020,
    "preview": "class PollRepositoriesJob\n  def self.perform\n    Repository.where(enabled: true).find_each(batch_size: 10) do |repo|\n   "
  },
  {
    "path": "app/jobs/timeout_stuck_builds_job.rb",
    "chars": 1434,
    "preview": "class TimeoutStuckBuildsJob < JobBase\n  @queue = :high\n\n  def self.perform\n    clean_lost_builds\n    clean_runnable_not_"
  },
  {
    "path": "app/mailers/build_mailer.rb",
    "chars": 2579,
    "preview": "class BuildMailer < ActionMailer::Base\n  helper :application, :mail\n\n  default :from => Proc.new { Settings.sender_email"
  },
  {
    "path": "app/mailers/merge_mailer.rb",
    "chars": 821,
    "preview": "class MergeMailer < ActionMailer::Base\n  helper :application\n\n  default :from => Proc.new { Settings.sender_email_addres"
  },
  {
    "path": "app/models/branch.rb",
    "chars": 2382,
    "preview": "class Branch < ActiveRecord::Base\n  belongs_to :repository\n  has_many :builds, :dependent => :destroy, :inverse_of => :b"
  },
  {
    "path": "app/models/build.rb",
    "chars": 9827,
    "preview": "require 'on_success_uploader'\nrequire 'fileless_io'\nrequire 'build_partitioning_job'\nrequire 'build_initiated_by_job'\n\nc"
  },
  {
    "path": "app/models/build_artifact.rb",
    "chars": 670,
    "preview": "require 'log_file_uploader'\n\nclass BuildArtifact < ActiveRecord::Base\n  belongs_to :build_attempt, :inverse_of => :build"
  },
  {
    "path": "app/models/build_attempt.rb",
    "chars": 2707,
    "preview": "class BuildAttempt < ActiveRecord::Base\n  has_many :build_artifacts, :dependent => :destroy, :inverse_of => :build_attem"
  },
  {
    "path": "app/models/build_part.rb",
    "chars": 2799,
    "preview": "class BuildPart < ActiveRecord::Base\n  # using 'build_instance' instead of 'build' because AR defines `build` for associ"
  },
  {
    "path": "app/models/repository.rb",
    "chars": 4410,
    "preview": "require 'remote_server'\n\n# This Repository class should only concern itself with persisting and acting on\n# Repository r"
  },
  {
    "path": "app/models/repository_observer.rb",
    "chars": 256,
    "preview": "class RepositoryObserver < ActiveRecord::Observer\n  observe :repository\n\n  def after_save(record)\n    record.remote_serv"
  },
  {
    "path": "app/uploaders/base_log_file_uploader.rb",
    "chars": 137,
    "preview": "class BaseLogFileUploader < CarrierWave::Uploader::Base\n  storage :file\n\n  def cache_dir\n    Rails.root.join('tmp', 'upl"
  },
  {
    "path": "app/uploaders/log_file_uploader.rb",
    "chars": 995,
    "preview": "require 'base_log_file_uploader'\n\nclass LogFileUploader < BaseLogFileUploader\n  def store_dir\n    build_attempt_id = mod"
  },
  {
    "path": "app/uploaders/on_success_uploader.rb",
    "chars": 261,
    "preview": "require 'base_log_file_uploader'\n\nclass OnSuccessUploader < BaseLogFileUploader\n  def store_dir\n    build_id = model.id\n"
  },
  {
    "path": "app/views/branches/health.html.haml",
    "chars": 2803,
    "preview": "= content_for :title, \"Health of #{@branch.name} branch of #{@repository.name_with_namespace}\"\n= content_for :favicon do"
  },
  {
    "path": "app/views/branches/index.html.haml",
    "chars": 411,
    "preview": "- content_for :header do\n  %ul.links\n    %li= link_to(\"Repositories\", repositories_path)\n\n.projects\n  %ul\n    - @converg"
  },
  {
    "path": "app/views/branches/show.html.haml",
    "chars": 5446,
    "preview": "= content_for :title, \"#{@repository.name} : #{@branch.name}\"\n= content_for :favicon do\n  - if @current_build\n    = favi"
  },
  {
    "path": "app/views/branches/show.json.erb",
    "chars": 113,
    "preview": "<%\n  json_data = @branch.attributes\n  json_data['recent_builds'] = @builds\n%>\n<%= json_data.to_json.html_safe %>\n"
  },
  {
    "path": "app/views/branches/show.rss.builder",
    "chars": 495,
    "preview": "xml.rss({:version => \"2.0\"}) do\n  xml.channel do\n    xml.title(\"Kochiku RSS Feed\")\n    xml.link(repository_branch_url(@r"
  },
  {
    "path": "app/views/branches/status_report.xml.builder",
    "chars": 623,
    "preview": "xml.Projects do\n  @branches.each do |branch|\n    # currently cimonitor only utilizes the activity attribute\n    xml.Proj"
  },
  {
    "path": "app/views/build_attempts/_build_attempt.html.haml",
    "chars": 64,
    "preview": ".attempt{:class => build_attempt.state}\n  = build_attempt.state\n"
  },
  {
    "path": "app/views/build_attempts/stream_logs.html.haml",
    "chars": 2981,
    "preview": "%h2.subheader\n  = @repository.name_with_namespace\n  &ndash;\n  = link_to @build.branch_record.name, repository_branch_pat"
  },
  {
    "path": "app/views/build_mailer/build_break_email.html.haml",
    "chars": 1953,
    "preview": "%html{xmlns: \"http://www.w3.org/1999/html\"}\n  %head\n    %meta{'content' => 'text/html; charset=UTF-8', 'http-equiv' => '"
  },
  {
    "path": "app/views/build_mailer/build_break_email.text.erb",
    "chars": 1246,
    "preview": "<%= @build.branch_record.name %> build failed for <%= @build.repository.name %>\n<%= repository_build_url(@build.reposito"
  },
  {
    "path": "app/views/build_mailer/build_success_email.html.haml",
    "chars": 1563,
    "preview": "%html{xmlns: \"http://www.w3.org/1999/html\"}\n  %head\n    %meta{'content' => 'text/html; charset=UTF-8', 'http-equiv' => '"
  },
  {
    "path": "app/views/build_mailer/build_success_email.text.erb",
    "chars": 1464,
    "preview": "<%= @build.branch_record.name %> build succeeded for <%= @build.repository.name %>\n<%= repository_build_url(@build.repos"
  },
  {
    "path": "app/views/build_mailer/error_email.html.haml",
    "chars": 334,
    "preview": "%html{xmlns: \"http://www.w3.org/1999/html\"}\n  %head\n    %meta{'content' => 'text/html; charset=UTF-8', 'http-equiv' => '"
  },
  {
    "path": "app/views/build_mailer/error_email.text.erb",
    "chars": 170,
    "preview": "Kochiku error on <%= @builder %> for <%= repository_build_part_url(@build_part.build_instance.repository, @build_part.bu"
  },
  {
    "path": "app/views/build_parts/_build_attempts.html.haml",
    "chars": 882,
    "preview": "%tr{id: dom_id(attempt), :\"data-id\" => index + 1}\n  %td.right= link_to(index + 1, attempt)\n  %td\n    %span.attempt-statu"
  },
  {
    "path": "app/views/build_parts/_build_part.html.haml",
    "chars": 668,
    "preview": ".part{:class => build_part.status, :title => build_part.paths.map{|path| \"-#{path}\"}.join(\"<br>\")}\n  -# build_part.build"
  },
  {
    "path": "app/views/build_parts/show.html.haml",
    "chars": 2862,
    "preview": "= content_for :title do\n  = @build.ref[0, 7]\n  &ndash;\n  = @repository.name\n= content_for :favicon do\n  = favicon_link_t"
  },
  {
    "path": "app/views/builds/_build.html.haml",
    "chars": 1316,
    "preview": ".build\n  %a.build-wrapper{:href => repository_build_path(build.repository, build)}\n    .build-info\n      .ref= build.ref"
  },
  {
    "path": "app/views/builds/_build_parts.html.haml",
    "chars": 1270,
    "preview": "- display_ruby_version = multiple_ruby_versions?(build)\n%tr{:\"data-id\" => part.id}\n  %td.right= link_to(part.id, reposit"
  },
  {
    "path": "app/views/builds/show.html.haml",
    "chars": 5079,
    "preview": "= content_for :title do\n  = @build.ref[0, 7]\n  &ndash;\n  = @build.repository.name\n= content_for :favicon do\n  = favicon_"
  },
  {
    "path": "app/views/dashboards/build_history_by_worker.html.haml",
    "chars": 1183,
    "preview": "#worker-health-wrap\n  %table{:class => \"worker-health\"}\n    %thead\n      %th.right Worker\n      %th Partition Attempts\n "
  },
  {
    "path": "app/views/layouts/application.html.haml",
    "chars": 1786,
    "preview": "!!!\n%html{:lang => 'en'}\n  %head\n    %meta{:charset => 'utf-8'}\n    %meta{:name => 'google', :value => 'notranslate'}\n  "
  },
  {
    "path": "app/views/merge_mailer/merge_failed.text.erb",
    "chars": 173,
    "preview": "Kochiku build automatically merged build: <%= [@build.repository.to_param, @build.id, @build.branch_record.name].join(\","
  },
  {
    "path": "app/views/merge_mailer/merge_successful.html.erb",
    "chars": 288,
    "preview": "<p>\n  Kochiku automatically merged build:\n  <%= @build.repository.to_param %>, <%= @build.id %>, <%= link_to_branch @bui"
  },
  {
    "path": "app/views/repositories/_form.html.haml",
    "chars": 4058,
    "preview": "= form_for @repository, :url => form_url, :html => { :id => 'repository-form' } do |f|\n  = f.error_messages\n  %div\n    %"
  },
  {
    "path": "app/views/repositories/dashboard.html.haml",
    "chars": 1189,
    "preview": "- content_for :header do\n  %ul.links\n    %li= link_to(\"Repositories\", repositories_path)\n\n.projects.projects-grid\n  - @b"
  },
  {
    "path": "app/views/repositories/edit.html.haml",
    "chars": 307,
    "preview": "= render 'form', form_url: repository_url(@repository.id)\n\n%br\n%h3 Web Hooks\n%p\n  %strong Build SHA\n  %br\n  = link_to bu"
  },
  {
    "path": "app/views/repositories/index.html.haml",
    "chars": 227,
    "preview": ".repositories\n  .new-repository-link\n    = link_to(\"Add Repository\", new_repository_path)\n\n  %ul\n    - @repositories.eac"
  },
  {
    "path": "app/views/repositories/new.html.haml",
    "chars": 44,
    "preview": "= render 'form', form_url: repositories_url\n"
  },
  {
    "path": "bin/bundle",
    "chars": 129,
    "preview": "#!/usr/bin/env ruby\nENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)\nload Gem.bin_path('bundler', '"
  },
  {
    "path": "bin/rails",
    "chars": 268,
    "preview": "#!/usr/bin/env ruby\nbegin\n  load File.expand_path('../spring', __FILE__)\nrescue LoadError => e\n  raise unless e.message."
  },
  {
    "path": "bin/rake",
    "chars": 213,
    "preview": "#!/usr/bin/env ruby\nbegin\n  load File.expand_path('../spring', __FILE__)\nrescue LoadError => e\n  raise unless e.message."
  },
  {
    "path": "bin/setup",
    "chars": 805,
    "preview": "#!/usr/bin/env ruby\nrequire 'pathname'\n\n# path to your application root.\nAPP_ROOT = Pathname.new File.expand_path('../.."
  },
  {
    "path": "bin/spring",
    "chars": 488,
    "preview": "#!/usr/bin/env ruby\n\n# This file loads spring without using Bundler, in order to be fast.\n# It gets overwritten when you"
  },
  {
    "path": "config/application.dev.yml",
    "chars": 2496,
    "preview": "# Email address to use in the 'from' field for emails sent by Kochiku.\nsender_email_address: 'kochiku@example.com'\n\n# Em"
  },
  {
    "path": "config/application.rb",
    "chars": 2407,
    "preview": "require File.expand_path('../boot', __FILE__)\n\nrequire 'rails/all'\n\nBundler.require(:default, Rails.env)\n\nI18n.enforce_a"
  },
  {
    "path": "config/application.test.yml",
    "chars": 877,
    "preview": "#########################################################################\n#                                             "
  },
  {
    "path": "config/application.yml",
    "chars": 146,
    "preview": "# Place your production Kochiku application config here.\n#\n# Start by copying the contents of config/application.dev.yml"
  },
  {
    "path": "config/boot.rb",
    "chars": 190,
    "preview": "require 'rubygems'\n\n# Set up gems listed in the Gemfile.\nENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __F"
  },
  {
    "path": "config/compass.rb",
    "chars": 640,
    "preview": "# This configuration file works with both the Compass command line tool and within Rails.\n# Require any additional compa"
  },
  {
    "path": "config/database.production.yml.sample",
    "chars": 148,
    "preview": "production:\n  adapter: mysql2\n  encoding: utf8\n  reconnect: true\n  username: kochiku\n  password: the_password\n  database"
  },
  {
    "path": "config/database.yml",
    "chars": 221,
    "preview": "development: &defaults\n  adapter: mysql2\n  encoding: utf8\n  reconnect: false\n  database: kochiku_development\n  pool: 15\n"
  },
  {
    "path": "config/deploy/production.rb",
    "chars": 214,
    "preview": "# Default value for default_env is {}\n# set :default_env, { path: \"/opt/ruby/bin:$PATH\" }\n\n# Server that is running the "
  },
  {
    "path": "config/deploy.rb",
    "chars": 1250,
    "preview": "# Lock version to protect against cap command being called without bundle exec\n# and executing with another version\nlock"
  },
  {
    "path": "config/environment.rb",
    "chars": 902,
    "preview": "# Load the rails application\nrequire File.expand_path('../application', __FILE__)\n\n# Load application settings for Kochi"
  },
  {
    "path": "config/environments/development.rb",
    "chars": 2355,
    "preview": "Kochiku::Application.configure do\n  # Settings specified here will take precedence over those in config/application.rb\n\n"
  },
  {
    "path": "config/environments/production.rb",
    "chars": 3308,
    "preview": "Kochiku::Application.configure do\n  # Settings specified here will take precedence over those in config/application.rb\n\n"
  },
  {
    "path": "config/environments/staging.rb",
    "chars": 2215,
    "preview": "Kochiku::Application.configure do\n  # Settings specified here will take precedence over those in config/application.rb\n\n"
  },
  {
    "path": "config/environments/test.rb",
    "chars": 1820,
    "preview": "Kochiku::Application.configure do\n  # Settings specified here will take precedence over those in config/application.rb\n\n"
  },
  {
    "path": "config/initializers/backtrace_silencers.rb",
    "chars": 404,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# You can add backtrace silencers for libraries that you're"
  },
  {
    "path": "config/initializers/cocaine.rb",
    "chars": 43,
    "preview": "Cocaine::CommandLine.logger = Rails.logger\n"
  },
  {
    "path": "config/initializers/inflections.rb",
    "chars": 533,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# Add new inflection rules using the following format\n# (al"
  },
  {
    "path": "config/initializers/load_build_strategy.rb",
    "chars": 159,
    "preview": "if Rails.env.test? || Rails.env.development?\n  require 'build_strategies/no_op_build_strategy'\nelse\n  require 'build_str"
  },
  {
    "path": "config/initializers/mime_types.rb",
    "chars": 205,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# Add new mime types for use in respond_to blocks:\n# Mime::"
  },
  {
    "path": "config/initializers/readthis.rb",
    "chars": 203,
    "preview": "if Rails.env.staging? || Rails.env.production?\n  # Allow Rails to continue serving requests if Redis crashes\n  # https:/"
  },
  {
    "path": "config/initializers/redis.rb",
    "chars": 78,
    "preview": "REDIS = Redis.new(\n  host: Settings.redis_host,\n  port: Settings.redis_port\n)\n"
  },
  {
    "path": "config/initializers/resque.rb",
    "chars": 495,
    "preview": "require 'resque-scheduler'\nrequire 'resque-retry'\nrequire 'resque/failure/redis'\nrequire 'resque-retry/server'\n\nResque.r"
  },
  {
    "path": "config/initializers/secret_token.rb",
    "chars": 486,
    "preview": "# Be sure to restart your server when you modify this file.\n\n# Your secret key is used for verifying the integrity of si"
  },
  {
    "path": "config/initializers/session_store.rb",
    "chars": 416,
    "preview": "# Be sure to restart your server when you modify this file.\n\nKochiku::Application.config.session_store :cookie_store, :k"
  },
  {
    "path": "config/initializers/wrap_parameters.rb",
    "chars": 485,
    "preview": "# Be sure to restart your server when you modify this file.\n#\n# This file contains settings for ActionController::Params"
  },
  {
    "path": "config/kochiku.yml",
    "chars": 110,
    "preview": "test_command: 'script/ci'\n\nruby:\n - 2.4.3\n\ntargets:\n  - type: spec\n    glob: spec/**/*_spec.rb\n    workers: 1\n"
  },
  {
    "path": "config/kochiku.yml.sample",
    "chars": 939,
    "preview": "# By listing ruby versions, all of you tests can be run against multiple versions\nruby:\n  - 2.1.2\n\n# You can list additi"
  },
  {
    "path": "config/locales/en.yml",
    "chars": 214,
    "preview": "# Sample localization file for English. Add more files in this directory for other locales.\n# See https://github.com/sve"
  },
  {
    "path": "config/resque_schedule.yml",
    "chars": 395,
    "preview": "poll_repositories_for_changes:\n  every:\n    - \"10m\"\n    - :first_in: \"5s\"\n  class: \"PollRepositoriesJob\"\n  queue: low\n  "
  },
  {
    "path": "config/routes.rb",
    "chars": 4165,
    "preview": "require 'resque/server'\n\nKochiku::Application.routes.draw do\n  mount Resque::Server.new, :at => '/resque'\n\n  if Rails.en"
  },
  {
    "path": "config.ru",
    "chars": 157,
    "preview": "# This file is used by Rack-based servers to start the application.\n\nrequire ::File.expand_path('../config/environment',"
  },
  {
    "path": "db/migrate/20110621212000_create_schema.rb",
    "chars": 885,
    "preview": "class CreateSchema < ActiveRecord::Migration[5.0]\n  def self.up\n    create_table :builds do |t|\n      t.string :sha\n    "
  },
  {
    "path": "db/migrate/20110624003418_change_artifact_type_to_name.rb",
    "chars": 207,
    "preview": "class ChangeArtifactTypeToName < ActiveRecord::Migration[5.0]\n  def self.up\n    rename_column :build_artifacts, :type, :"
  },
  {
    "path": "db/migrate/20110624015709_rename_build_part_result_result_to_state.rb",
    "chars": 229,
    "preview": "class RenameBuildPartResultResultToState < ActiveRecord::Migration[5.0]\n  def self.up\n    rename_column :build_part_resu"
  },
  {
    "path": "db/migrate/20110708203120_change_build_artifacts_for_carrier_wave.rb",
    "chars": 322,
    "preview": "class ChangeBuildArtifactsForCarrierWave < ActiveRecord::Migration[5.0]\n  def self.up\n    rename_column :build_artifacts"
  },
  {
    "path": "db/migrate/20110713175724_rename_build_part_result_to_build_part_run.rb",
    "chars": 382,
    "preview": "class RenameBuildPartResultToBuildPartRun < ActiveRecord::Migration[5.0]\n  def self.up\n    rename_table :build_part_resu"
  },
  {
    "path": "db/migrate/20110713191536_add_foreign_key_indexes.rb",
    "chars": 406,
    "preview": "class AddForeignKeyIndexes < ActiveRecord::Migration[5.0]\n  def self.up\n    add_index :build_parts, :build_id\n    add_in"
  },
  {
    "path": "db/migrate/20110719204508_create_projects.rb",
    "chars": 285,
    "preview": "class CreateProjects < ActiveRecord::Migration[5.0]\n  def self.up\n    create_table :projects do |t|\n      t.string :name"
  },
  {
    "path": "db/migrate/20110719205413_add_project_id_to_builds.rb",
    "chars": 273,
    "preview": "class AddProjectIdToBuilds < ActiveRecord::Migration[5.0]\n  def self.up\n    add_column :builds, :project_id, :integer\n  "
  },
  {
    "path": "db/migrate/20110721185201_rename_builds_sha_to_ref.rb",
    "chars": 181,
    "preview": "class RenameBuildsShaToRef < ActiveRecord::Migration[5.0]\n  def self.up\n    rename_column :builds, :sha, :ref\n  end\n\n  d"
  },
  {
    "path": "db/migrate/20110801215540_rename_error_state_to_errored.rb",
    "chars": 402,
    "preview": "class RenameErrorStateToErrored < ActiveRecord::Migration[5.0]\n  def self.up\n    execute(\"UPDATE build_attempts SET stat"
  },
  {
    "path": "db/migrate/20120803005242_add_merge_bool_to_build.rb",
    "chars": 126,
    "preview": "class AddMergeBoolToBuild < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :auto_merge, :boolean\n  en"
  },
  {
    "path": "db/migrate/20120817225343_add_branch_to_build.rb",
    "chars": 118,
    "preview": "class AddBranchToBuild < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :branch, :string\n  end\nend\n"
  },
  {
    "path": "db/migrate/20121008211955_create_repositories.rb",
    "chars": 353,
    "preview": "class CreateRepositories < ActiveRecord::Migration[5.0]\n  def change\n    create_table :repositories do |t|\n      t.strin"
  },
  {
    "path": "db/migrate/20121017173936_add_github_repository_id_to_repository.rb",
    "chars": 163,
    "preview": "class AddGithubRepositoryIdToRepository < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :githu"
  },
  {
    "path": "db/migrate/20121017182543_fix_repository_schema.rb",
    "chars": 427,
    "preview": "class FixRepositorySchema < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :run_ci, :boolean\n  "
  },
  {
    "path": "db/migrate/20121017184946_remove_options_from_repository.rb",
    "chars": 130,
    "preview": "class RemoveOptionsFromRepository < ActiveRecord::Migration[5.0]\n  def change\n    remove_column :repositories, :options\n"
  },
  {
    "path": "db/migrate/20121017222538_add_target_name_to_builds.rb",
    "chars": 128,
    "preview": "class AddTargetNameToBuilds < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :target_name, :string\n  "
  },
  {
    "path": "db/migrate/20121017224003_add_command_flag_to_repositories.rb",
    "chars": 142,
    "preview": "class AddCommandFlagToRepositories < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :command_fl"
  },
  {
    "path": "db/migrate/20121018182435_add_options_to_build_part.rb",
    "chars": 127,
    "preview": "class AddOptionsToBuildPart < ActiveRecord::Migration[5.0]\n  def change\n    add_column :build_parts, :options, :text\n  e"
  },
  {
    "path": "db/migrate/20121024005715_add_send_build_failure_email_to_repository.rb",
    "chars": 181,
    "preview": "class AddSendBuildFailureEmailToRepository < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :se"
  },
  {
    "path": "db/migrate/20121024164929_record_build_failure_email_sent.rb",
    "chars": 148,
    "preview": "class RecordBuildFailureEmailSent < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :build_failure_ema"
  },
  {
    "path": "db/migrate/20121024210129_add_success_script_to_repositories.rb",
    "chars": 193,
    "preview": "class AddSuccessScriptToRepositories < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :on_succe"
  },
  {
    "path": "db/migrate/20121024212949_add_on_success_log_file_to_build.rb",
    "chars": 148,
    "preview": "class AddOnSuccessLogFileToBuild < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :on_success_script_"
  },
  {
    "path": "db/migrate/20121030213442_add_queue_to_repository.rb",
    "chars": 136,
    "preview": "class AddQueueToRepository < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :queue_override, :s"
  },
  {
    "path": "db/migrate/20121101220831_add_timeout_to_repository.rb",
    "chars": 148,
    "preview": "class AddTimeoutToRepository < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :timeout, :intege"
  },
  {
    "path": "db/migrate/20130226232844_add_index_to_build_ref.rb",
    "chars": 107,
    "preview": "class AddIndexToBuildRef < ActiveRecord::Migration[5.0]\n  def change\n    add_index :builds, :ref\n  end\nend\n"
  },
  {
    "path": "db/migrate/20130409144945_add_on_success_note_to_repositories.rb",
    "chars": 147,
    "preview": "class AddOnSuccessNoteToRepositories < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :on_succe"
  },
  {
    "path": "db/migrate/20130511012855_add_deployable_map_to_build.rb",
    "chars": 131,
    "preview": "class AddDeployableMapToBuild < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :deployable_map, :text"
  },
  {
    "path": "db/migrate/20130626183046_add_maven_modules_to_build.rb",
    "chars": 129,
    "preview": "class AddMavenModulesToBuild < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :maven_modules, :text\n "
  },
  {
    "path": "db/migrate/20130627194433_add_index_to_build_part_paths.rb",
    "chars": 148,
    "preview": "class AddIndexToBuildPartPaths < ActiveRecord::Migration[5.0]\n  def change\n    add_index :build_parts, :paths, :length ="
  },
  {
    "path": "db/migrate/20130709123456_add_upload_artifacts_to_build_parts.rb",
    "chars": 148,
    "preview": "class AddUploadArtifactsToBuildParts < ActiveRecord::Migration[5.0]\n  def change\n    add_column :build_parts, :upload_ar"
  },
  {
    "path": "db/migrate/20130822191419_add_queue_to_build_part.rb",
    "chars": 492,
    "preview": "class AddQueueToBuildPart < ActiveRecord::Migration[5.0]\n  def up\n    add_column :build_parts, :queue, :string\n\n    exec"
  },
  {
    "path": "db/migrate/20130822231850_remove_upload_artifacts_from_build_parts.rb",
    "chars": 217,
    "preview": "class RemoveUploadArtifactsFromBuildParts < ActiveRecord::Migration[5.0]\n  def up\n    remove_column :build_parts, :uploa"
  },
  {
    "path": "db/migrate/20130823210844_add_retry_count_to_build_part.rb",
    "chars": 149,
    "preview": "class AddRetryCountToBuildPart < ActiveRecord::Migration[5.0]\n  def change\n    add_column :build_parts, :retry_count, :i"
  },
  {
    "path": "db/migrate/20130823231854_remove_java_specific_stuff.rb",
    "chars": 276,
    "preview": "class RemoveJavaSpecificStuff < ActiveRecord::Migration[5.1]\n  def up\n    remove_column :builds, :deployable_map\n    rem"
  },
  {
    "path": "db/migrate/20130823234546_remove_queue_override_from_repositories.rb",
    "chars": 214,
    "preview": "class RemoveQueueOverrideFromRepositories < ActiveRecord::Migration[5.0]\n  def up\n    remove_column :repositories, :queu"
  },
  {
    "path": "db/migrate/20130910190203_add_repository_name_as_column.rb",
    "chars": 1786,
    "preview": "class AddRepositoryNameAsColumn < ActiveRecord::Migration[5.0]\n  Rails.logger = Logger.new(STDOUT)\n\n  URL_PARSERS = {\n  "
  },
  {
    "path": "db/migrate/20131217022000_add_error_text_to_build.rb",
    "chars": 126,
    "preview": "class AddErrorTextToBuild < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :error_details, :text\n  en"
  },
  {
    "path": "db/migrate/20140123234208_add_allows_kochiku_merges_to_repository.rb",
    "chars": 173,
    "preview": "class AddAllowsKochikuMergesToRepository < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :allo"
  },
  {
    "path": "db/migrate/20140128180258_rename_auto_merge_on_build.rb",
    "chars": 141,
    "preview": "class RenameAutoMergeOnBuild < ActiveRecord::Migration[5.0]\n  def change\n    rename_column :builds, :auto_merge, :merge_"
  },
  {
    "path": "db/migrate/20140415001051_remove_use_branches_on_green_from_repositories.rb",
    "chars": 167,
    "preview": "class RemoveUseBranchesOnGreenFromRepositories < ActiveRecord::Migration[5.0]\n  def change\n    remove_column :repositori"
  },
  {
    "path": "db/migrate/20140415011144_remove_command_flag_from_repositories.rb",
    "chars": 206,
    "preview": "class RemoveCommandFlagFromRepositories < ActiveRecord::Migration[5.0]\n  def change\n    remove_column :repositories, :co"
  },
  {
    "path": "db/migrate/20140506012721_unique_index_on_builds_ref.rb",
    "chars": 454,
    "preview": "class UniqueIndexOnBuildsRef < ActiveRecord::Migration[5.0]\n  def up\n    remove_index :builds, column: :ref\n\n    # set l"
  },
  {
    "path": "db/migrate/20140507184819_add_host_and_namespace_to_repositories.rb",
    "chars": 1104,
    "preview": "class AddHostAndNamespaceToRepositories < ActiveRecord::Migration[5.0]\n  def up\n    rename_column :repositories, :reposi"
  },
  {
    "path": "db/migrate/20140617214701_add_success_email.rb",
    "chars": 1051,
    "preview": "class AddSuccessEmail < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :build_success_email_sent, :bo"
  },
  {
    "path": "db/migrate/20140715225910_remove_notes.rb",
    "chars": 131,
    "preview": "class RemoveNotes < ActiveRecord::Migration[5.0]\n  def change\n    remove_column :repositories, :on_success_note, :string"
  },
  {
    "path": "db/migrate/20141031234747_add_email_first_failure_to_repositories.rb",
    "chars": 188,
    "preview": "class AddEmailFirstFailureToRepositories < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :emai"
  },
  {
    "path": "db/migrate/20150324001246_remove_on_success_script_from_repositories.rb",
    "chars": 936,
    "preview": "class RemoveOnSuccessScriptFromRepositories < ActiveRecord::Migration[5.0]\n  def up\n    # Guard against deleting any dat"
  },
  {
    "path": "db/migrate/20150331160909_add_send_merge_successful_email.rb",
    "chars": 185,
    "preview": "class AddSendMergeSuccessfulEmail < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :send_merge_"
  },
  {
    "path": "db/migrate/20150714234635_add_log_port_to_build_attempt.rb",
    "chars": 146,
    "preview": "class AddLogPortToBuildAttempt < ActiveRecord::Migration[5.0]\n  def change\n    add_column :build_attempts, :log_streamer"
  },
  {
    "path": "db/migrate/20150717214656_create_branches.rb",
    "chars": 495,
    "preview": "class CreateBranches < ActiveRecord::Migration[5.0]\n  def change\n    create_table :branches do |t|\n      t.references :r"
  },
  {
    "path": "db/migrate/20150717220149_assign_builds_to_branches.rb",
    "chars": 1285,
    "preview": "# In this migration intentionally go out of our way to not use the Project\n# model so that it can be removed from the co"
  },
  {
    "path": "db/migrate/20150717231250_remove_branch_string_from_builds.rb",
    "chars": 353,
    "preview": "class RemoveBranchStringFromBuilds < ActiveRecord::Migration[5.0]\n  def change\n    # The previous migration (AssignBuild"
  },
  {
    "path": "db/migrate/20150719130110_index_repositories_namespace_and_name.rb",
    "chars": 157,
    "preview": "class IndexRepositoriesNamespaceAndName < ActiveRecord::Migration[5.0]\n  def change\n    add_index :repositories, [:names"
  },
  {
    "path": "db/migrate/20151111080255_remove_repo_cache_dir_from_repositories.rb",
    "chars": 153,
    "preview": "class RemoveRepoCacheDirFromRepositories < ActiveRecord::Migration[5.0]\n  def change\n    remove_column :repositories, :r"
  },
  {
    "path": "db/migrate/20151114185514_fix_convergence_index.rb",
    "chars": 346,
    "preview": "# In order for the index on convergence col to be useful it needs to be\n# namespaced by repository_id\nclass FixConvergen"
  },
  {
    "path": "db/migrate/20160408214135_index_created_at_on_build_attempts.rb",
    "chars": 133,
    "preview": "class IndexCreatedAtOnBuildAttempts < ActiveRecord::Migration[5.0]\n  def change\n    add_index :build_attempts, :created_"
  },
  {
    "path": "db/migrate/20170804214538_add_enabled_bool_to_repositories.rb",
    "chars": 166,
    "preview": "class AddEnabledBoolToRepositories < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :enabled, :"
  },
  {
    "path": "db/migrate/20180208202524_add_test_command_to_builds.rb",
    "chars": 130,
    "preview": "class AddTestCommandToBuilds < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :test_command, :string\n"
  },
  {
    "path": "db/migrate/20180220185338_add_assume_lost_after_to_repository.rb",
    "chars": 150,
    "preview": "class AddAssumeLostAfterToRepository < ActiveRecord::Migration[5.0]\n  def change\n    add_column :repositories, :assume_l"
  },
  {
    "path": "db/migrate/20180227222254_add_initiated_by_to_builds.rb",
    "chars": 130,
    "preview": "class AddInitiatedByToBuilds < ActiveRecord::Migration[5.0]\n  def change\n    add_column :builds, :initiated_by, :string\n"
  },
  {
    "path": "db/migrate/20180301221320_add_instance_type_to_build_attempts.rb",
    "chars": 147,
    "preview": "class AddInstanceTypeToBuildAttempts < ActiveRecord::Migration[5.0]\n  def change\n    add_column :build_attempts, :instan"
  },
  {
    "path": "db/migrate/20180619210823_add_kochiku_yml_config_to_builds.rb",
    "chars": 139,
    "preview": "class AddKochikuYmlConfigToBuilds < ActiveRecord::Migration[5.1]\n  def change\n    add_column :builds, :kochiku_yml_confi"
  },
  {
    "path": "db/schema.rb",
    "chars": 5374,
    "preview": "# This file is auto-generated from the current state of the database. Instead\n# of editing this file, please use the mig"
  },
  {
    "path": "db/seeds.rb",
    "chars": 3948,
    "preview": "# Eagerly load all of the models to avoid errors related to multiple threads\nDir[Rails.root.join(\"app/models/*.rb\")].eac"
  },
  {
    "path": "lib/build_strategies/no_op_build_strategy.rb",
    "chars": 158,
    "preview": "class BuildStrategy\n  class << self\n    def promote_build(build)\n    end\n\n    def merge_ref(ref)\n    end\n\n    def run_su"
  },
  {
    "path": "lib/build_strategies/production_build_strategy.rb",
    "chars": 2621,
    "preview": "require 'git_blame'\n\nclass BuildStrategy\n  class << self\n    # The primary function of promote_build is to update the br"
  },
  {
    "path": "lib/capistrano/tasks/deploy.cap",
    "chars": 992,
    "preview": "# Users may choose to:\n#\n# A) edit the deploy tasks directly inside this file\n# B) create another .cap file and define y"
  },
  {
    "path": "lib/capistrano/tasks/kochiku.cap",
    "chars": 751,
    "preview": "namespace :kochiku do\n  task :setup do\n    on roles([:app, :worker]) do\n      SSHKit.config.command_map.prefix[:gem].pop"
  },
  {
    "path": "lib/fileless_io.rb",
    "chars": 86,
    "preview": "require 'stringio'\nclass FilelessIO < StringIO\n  attr_accessor :original_filename\nend\n"
  },
  {
    "path": "lib/git_blame.rb",
    "chars": 6326,
    "preview": "require 'cocaine'\nrequire 'git_repo'\n\nclass GitBlame\n  class << self\n    def emails_since_last_green(build)\n      lookup"
  },
  {
    "path": "lib/git_merge_executor.rb",
    "chars": 3190,
    "preview": "require 'open3'\n\nclass GitMergeExecutor\n  class GitFetchFailedError < StandardError; end\n  class GitMergeFailedError < S"
  },
  {
    "path": "lib/git_repo.rb",
    "chars": 4320,
    "preview": "require 'cocaine'\nrequire 'fileutils'\n\nclass GitRepo\n  class RefNotFoundError < StandardError; end\n\n  WORKING_DIR = Rail"
  },
  {
    "path": "lib/github_commit_status.rb",
    "chars": 735,
    "preview": "require 'github_request'\n\nclass GithubCommitStatus\n  def initialize(build, oauth_token)\n    @oauth_token = oauth_token\n "
  },
  {
    "path": "lib/github_post_receive_hook.rb",
    "chars": 1783,
    "preview": "# frozen_string_literal: true\nrequire 'github_request'\n\nclass GithubPostReceiveHook\n  SUBSCRIBE_NAME = \"web\"\n\n  def init"
  },
  {
    "path": "lib/github_request.rb",
    "chars": 1789,
    "preview": "require 'uri'\nrequire 'net/http'\n\nclass GithubRequest\n  class ResponseError < RuntimeError\n    attr_accessor :response\n "
  },
  {
    "path": "lib/partitioner/base.rb",
    "chars": 524,
    "preview": "module Partitioner\n  class Base\n    def initialize(build, kochiku_yml)\n      @build = build\n      @kochiku_yml = kochiku"
  },
  {
    "path": "lib/partitioner/default.rb",
    "chars": 6165,
    "preview": "require 'partitioner/base'\n\nmodule Partitioner\n  # This is the origional partitioner behavior, which is somewhat ruby ta"
  },
  {
    "path": "lib/partitioner/dependency_map.rb",
    "chars": 5557,
    "preview": "require 'partitioner/default'\nrequire 'git_blame'\n\nmodule Partitioner\n  # A variation on Partitioner::Default, which all"
  },
  {
    "path": "lib/partitioner/go.rb",
    "chars": 10509,
    "preview": "# frozen_string_literal: true\n\nrequire 'cocaine'\nrequire 'fileutils'\nrequire 'json'\nrequire 'set'\nrequire 'partitioner/b"
  },
  {
    "path": "lib/partitioner/maven.rb",
    "chars": 8579,
    "preview": "# frozen_string_literal: true\nrequire 'nokogiri'\nrequire 'set'\nrequire 'partitioner/base'\nrequire 'partitioner/topologic"
  },
  {
    "path": "lib/partitioner/topological_sorter.rb",
    "chars": 354,
    "preview": "require 'tsort'\n\nmodule Partitioner\n  class TopologicalSorter\n    include TSort\n\n    def initialize(dependency_map)\n    "
  }
]

// ... and 85 more files (download for full content)

About this extraction

This page contains the full source code of the square/kochiku GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 285 files (831.4 KB), approximately 221.6k tokens, and a symbol index with 726 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!