plz / ci / ci_trigger.v
106 lines · 87 sloc · 2.97 KB · c1be7a1408ed30cff2e8e359cf7e1ef69d66e988
Raw
1module main
2
3import x.json2 as json
4import net.http
5import os
6import git
7
8struct CiTriggerPayload {
9 repo_id int
10 commit_hash string
11 branch string
12 repo_path string
13 yaml_config string
14 callback_url string
15}
16
17struct CiTriggerResponse {
18 success bool
19 result CiTriggerResult
20}
21
22struct CiTriggerResult {
23 id int
24 status string
25}
26
27// trigger_ci_if_configured checks if the repo has a .gitly-ci.yml and triggers a CI run
28fn (mut app App) trigger_ci_if_configured(repo_id int, branch_name string) {
29 repo := app.find_repo_by_id(repo_id) or { return }
30
31 if app.config.ci_service_url == '' {
32 return
33 }
34
35 // Read .gitly-ci.yml from the repo using git show (works with bare repos)
36 show_result := git.Git.exec_in_dir(repo.git_dir, ['show', '${branch_name}:.gitly-ci.yml'])
37 if show_result.exit_code != 0 || show_result.output.trim_space() == '' {
38 app.info('No .gitly-ci.yml found in ${repo.name}/${branch_name}')
39 return
40 }
41 yaml_config := show_result.output
42
43 app.info('Found .gitly-ci.yml in ${repo.name}/${branch_name}, triggering CI')
44 app.send_ci_trigger(repo, branch_name, yaml_config)
45}
46
47// trigger_ci_with_config triggers CI with a known YAML config (e.g. when the file was just created via web UI)
48fn (mut app App) trigger_ci_with_config(repo_id int, branch_name string, yaml_config string) {
49 repo := app.find_repo_by_id(repo_id) or { return }
50
51 if app.config.ci_service_url == '' {
52 return
53 }
54
55 app.info('Triggering CI for ${repo.name}/${branch_name} with provided config')
56 app.send_ci_trigger(repo, branch_name, yaml_config)
57}
58
59fn (mut app App) send_ci_trigger(repo Repo, branch_name string, yaml_config string) {
60 // Get the latest commit hash for this branch
61 commit_hash := repo.get_last_branch_commit_hash(branch_name)
62
63 // Build callback URL
64 callback_url := 'http://localhost:${app.port}/api/v1/ci/status'
65
66 // Get the absolute path to the git directory
67 repo_path := os.real_path(repo.git_dir)
68
69 payload := json.encode(CiTriggerPayload{
70 repo_id: repo.id
71 commit_hash: commit_hash
72 branch: branch_name
73 repo_path: repo_path
74 yaml_config: yaml_config
75 callback_url: callback_url
76 })
77
78 // Record pending status
79 app.upsert_ci_status(repo.id, commit_hash, branch_name, .pending, 0) or {
80 app.warn('Failed to create CI status: ${err}')
81 }
82
83 // Trigger CI service
84 ci_url := '${app.config.ci_service_url}/api/v1/trigger'
85 app.info('Posting CI trigger to ${ci_url}')
86
87 response := http.post_json(ci_url, payload) or {
88 app.warn('Failed to trigger CI: ${err}')
89 return
90 }
91
92 if response.status_code == 200 {
93 result := json.decode[CiTriggerResponse](response.body) or {
94 app.warn('Failed to parse CI trigger response')
95 return
96 }
97 if result.success {
98 app.upsert_ci_status(repo.id, commit_hash, branch_name, .pending, result.result.id) or {
99 app.warn('Failed to update CI status with run id')
100 }
101 app.info('CI run ${result.result.id} triggered for ${repo.name}')
102 }
103 } else {
104 app.warn('CI trigger returned status ${response.status_code}: ${response.body}')
105 }
106}
107