summaryrefslogtreecommitdiff
path: root/app/models/project_services/gitlab_ci_service.rb
blob: 19b5859d5c90f39ba5242c872a2aa9b080f7465b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# == Schema Information
#
# Table name: services
#
#  id                    :integer          not null, primary key
#  type                  :string(255)
#  title                 :string(255)
#  project_id            :integer
#  created_at            :datetime
#  updated_at            :datetime
#  active                :boolean          default(FALSE), not null
#  properties            :text
#  template              :boolean          default(FALSE)
#  push_events           :boolean          default(TRUE)
#  issues_events         :boolean          default(TRUE)
#  merge_requests_events :boolean          default(TRUE)
#  tag_push_events       :boolean          default(TRUE)
#  note_events           :boolean          default(TRUE), not null
#

class GitlabCiService < CiService
  API_PREFIX = "api/v1"

  prop_accessor :project_url, :token
  validates :project_url, presence: true, if: :activated?
  validates :token, presence: true, if: :activated?

  after_save :compose_service_hook, if: :activated?

  def compose_service_hook
    hook = service_hook || build_service_hook
    hook.url = [project_url, "/build", "?token=#{token}"].join("")
    hook.save
  end

  def supported_events
    %w(push tag_push)
  end

  def execute(data)
    return unless supported_events.include?(data[:object_kind])

    sha = data[:checkout_sha]

    if sha.present?
      file = ci_yaml_file(sha)

      if file && file.data
        data.merge!(ci_yaml_file: file.data)
      end
    end

    service_hook.execute(data)
  end

  def commit_status_path(sha, ref)
    URI::encode(project_url + "/refs/#{ref}/commits/#{sha}/status.json?token=#{token}")
  end

  def get_ci_build(sha, ref)
    @ci_builds ||= {}
    @ci_builds[sha] ||= HTTParty.get(commit_status_path(sha, ref), verify: false)
  end

  def commit_status(sha, ref)
    response = get_ci_build(sha, ref)

    if response.code == 200 and response["status"]
      response["status"]
    else
      :error
    end
  end

  def fork_registration(new_project, private_token)
    params = {
      id:                  new_project.id,
      name_with_namespace: new_project.name_with_namespace,
      web_url:             new_project.web_url,
      default_branch:      new_project.default_branch,
      ssh_url_to_repo:     new_project.ssh_url_to_repo
    }

    HTTParty.post(
      fork_registration_path,
      body: {
        project_id: project.id,
        project_token: token,
        private_token: private_token,
        data: params },
      verify: false
    )
  end

  def commit_coverage(sha, ref)
    response = get_ci_build(sha, ref)

    if response.code == 200 and response["coverage"]
      response["coverage"]
    end
  end

  def build_page(sha, ref)
    URI::encode(project_url + "/refs/#{ref}/commits/#{sha}")
  end

  def builds_path
    project_url + "?ref=" + project.default_branch
  end

  def status_img_path
    project_url + "/status.png?ref=" + project.default_branch
  end

  def title
    'GitLab CI'
  end

  def description
    'Continuous integration server from GitLab'
  end

  def to_param
    'gitlab_ci'
  end

  def fields
    [
      { type: 'text', name: 'token', placeholder: 'GitLab CI project specific token' },
      { type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3' }
    ]
  end

  private

  def ci_yaml_file(sha)
    repository.blob_at(sha, '.gitlab-ci.yml')
  end

  def fork_registration_path
    project_url.sub(/projects\/\d*/, "#{API_PREFIX}/forks")
  end

  def repository
    project.repository
  end
end