Hog Hog2025.2-3
create_badges.tcl
Go to the documentation of this file.
1 #!/usr/bin/env tclsh
2 # Copyright 2018-2025 The University of Birmingham
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 # @file
17 # Create and uploads GitLab badges for chosen projects
18 
19 
20 proc generate_prj_badge {prj_name ver color file} {
21  set font_size 11.0
22  set max_characters 20.0
23  puts [string length $prj_name]
24  if { [expr {[string length $prj_name] > $max_characters}] } {
25  set scaling_factor [expr {$max_characters / [string length $prj_name]}]
26  puts $font_size
27  set font_size [expr {ceil($scaling_factor * $font_size)}]
28  puts $scaling_factor
29  puts $font_size
30  }
31 
32  set svg_content "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
33 <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"250\" height=\"20\">
34  <linearGradient id=\"b\" x2=\"0\" y2=\"100%\">
35  <stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>
36  <stop offset=\"1\" stop-opacity=\".1\"/>
37  </linearGradient>
38  <mask id=\"hog_prj_badge\">
39  <rect width=\"250\" height=\"20\" rx=\"10\" fill=\"#fff\"/>
40  </mask>
41  <g mask=\"url(#hog_prj_badge)\">
42  <path fill=\"$color\" d=\"M0 0h250v20H0z\"/>
43  <path fill=\"#262626\" d=\"M160 0h90v20H160z\"/>
44  <path fill=\"#262626\" d=\"M250,20 a1,1 0 0,0 0,-16\"/>
45  <path fill=\"url(#b)\" d=\"M0 0h250v20H0z\"/>
46  </g>
47  <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"$font_size\">
48  <text x=\"80\" y=\"14\">$prj_name</text>
49  </g>
50  <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"11\">
51  <text x=\"205\" y=\"14\">$ver</text>
52  </g>
53 </svg>"
54 
55  if {
56  [catch {
57  set fh [open $file w]
58  puts $fh $svg_content
59  close $fh
60  } error_msg]
61  } {
62  error "Failed to write to file: $error_msg"
63  }
64 }
65 
66 proc generate_res_badge {res res_value color file} {
67  set svg_content "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
68 <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"120\" height=\"20\">
69  <linearGradient id=\"b\" x2=\"0\" y2=\"100%\">
70  <stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>
71  <stop offset=\"1\" stop-opacity=\".1\"/>
72  </linearGradient>
73  <mask id=\"hog_res_badge\">
74  <rect width=\"120\" height=\"20\" rx=\"3\" fill=\"#fff\"/>
75  </mask>
76  <g mask=\"url(#hog_res_badge)\">
77  <path fill=\"#555\" d=\"M0 0h60v20H0z\"/>
78  <path fill=\"$color\" d=\"M60 0h60v20H60z\"/>
79  <path fill=\"url(#b)\" d=\"M0 0h120v20H0z\"/>
80  </g>
81  <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"11\">
82  <text x=\"30\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">$res</text>
83  <text x=\"30\" y=\"14\">$res</text>
84  </g>
85  <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"11\">
86  <text x=\"90\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">$res_value</text>
87  <text x=\"90\" y=\"14\">$res_value</text>
88  </g>
89 </svg>"
90 
91  if {
92  [catch {
93  set fh [open $file w]
94  puts $fh $svg_content
95  close $fh
96  } error_msg]
97  } {
98  error "Failed to write to file: $error_msg"
99  }
100 }
101 
102 set OldPath [pwd]
103 set TclPath [file dirname [info script]]/..
104 set repo_path [file normalize "$TclPath/../.."]
105 source $TclPath/hog.tcl
106 
107 set usage "- CI script that creates GitLab badges with utilisation and timing results for a chosen Hog project.\n\
108 USAGE: $::argv0 <push token> <Gitlab api url> <Gitlab project id> <Gitlab project url> <GitLab Server URL> <Hog project> <ext_path>"
109 
110 if {[llength $argv] < 7} {
111  Msg Info [cmdline::usage $usage]
112  cd $OldPath
113  return
114 }
115 
116 set result [catch {package require json} JsonFound]
117 if {"$result" != "0"} {
118  Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
119  return -1
120 }
121 
122 set push_token [lindex $argv 0]
123 set api_url [lindex $argv 1]
124 set project_id [lindex $argv 2]
125 set project_url [lindex $argv 3]
126 set gitlab_url [lindex $argv 4]
127 set project [lindex $argv 5]
128 set ext_path [lindex $argv 6]
129 
130 set resources [dict create "LUTs" "LUTs" "Registers" "FFs" "Block" "BRAM" "URAM" "URAM" "DSPs" "DSPs"]
131 set ver [GetProjectVersion $repo_path/Top/$project $repo_path $ext_path 0]
132 
133 set accumulated ""
134 set current_badges [dict create]
135 set page 0
136 
137 Msg Info "Retrieving current badges..."
138 while {1} {
139  lassign [ExecuteRet curl --header "PRIVATE-TOKEN: $push_token" "$api_url/projects/${project_id}/badges?page=$page" --request GET] ret content
140  set content_dict [json::json2dict $content]
141  if {[llength $content_dict] > 0} {
142  foreach it $content_dict {
143  dict set current_badges [DictGet $it name] [DictGet $it id]
144  }
145  incr page
146  } else {
147  break
148  }
149 }
150 
151 
152 if {[catch {glob -types d $repo_path/bin/$project-${ver}} prj_dir]} {
153  Msg CriticalWarning "Cannot find $project binaries in artifacts"
154  return
155 }
156 
157 cd $prj_dir
158 if {[file exists utilization.txt]} {
159  set fp [open utilization.txt]
160  set lines [split [read $fp] "\n"]
161  close $fp
162  set new_badges [dict create]
163  set prj_name [string map {/ _} $project]
164 
165  # Timing Badge
166  if {[file exists timing_error.txt]} {
167  generate_prj_badge $prj_name $ver "#E05D44" "timing-$prj_name.svg"
168  } elseif {[file exists timing_ok.txt]} {
169  generate_prj_badge $prj_name $ver "#006400" "timing-$prj_name.svg"
170  } else {
171  generate_prj_badge $prj_name $ver "#696969" "timing-$prj_name.svg"
172  }
173  dict set new_badges "timing-$prj_name" "timing-$prj_name"
174 
175  set usage_dict [dict create]
176  # Resource Badges
177  foreach line $lines {
178  set str [string map {| ""} $line]
179  set str [string map {"<" ""} $str]
180  set str [string trim $str]
181 
182  set usage [lindex [split $str] end]
183  foreach res [dict keys $resources] {
184  if {[string first $res $str] > -1} {
185  set res_name [dict get $resources $res]
186  dict set usage_dict $res_name $usage
187  }
188  }
189  }
190  foreach res [dict keys $usage_dict] {
191  set usage [DictGet $usage_dict $res]
192  set res_value "$usage\% "
193  if {[expr {$usage < 50.0}]} {
194  generate_res_badge $res $res_value "#90CAF9" "$res-$prj_name.svg"
195  } elseif {[expr {$usage < 80.0}]} {
196  generate_res_badge $res $res_value "#1565C0" "$res-$prj_name.svg"
197  } else {
198  generate_res_badge $res $res_value "#0D2B6B" "$res-$prj_name.svg"
199  }
200  dict set new_badges "$res-$prj_name" "$res-$prj_name"
201  }
202 
203  foreach badge_name [dict keys $new_badges] {
204  set badge_found 0
205  Msg Info "Uploading badge image $badge_name.svg ...."
206  # tclint-disable-next-line line-length
207  lassign [ExecuteRet curl --request POST --header "PRIVATE-TOKEN: ${push_token}" --form "file=@$badge_name.svg" $api_url/projects/$project_id/uploads] ret content
208  set image_url [ParseJSON $content full_path]
209  set image_url $gitlab_url/$image_url
210  if {[dict exists $current_badges $badge_name]} {
211  Msg Info "Badge $badge_name exists, updating it..."
212  set badge_id [DictGet $current_badges $badge_name]
213  Execute curl --header "PRIVATE-TOKEN: $push_token" "$api_url/projects/${project_id}/badges/$badge_id" --request PUT --data "image_url=$image_url"
214  } else {
215  Msg Info "Badge $badge_name does not exist yet. Creating it..."
216  # tclint-disable-next-line line-length
217  Execute curl --header "PRIVATE-TOKEN: $push_token" --request POST --data "link_url=$project_url/-/releases&image_url=$image_url&name=$badge_name" "$api_url/projects/$project_id/badges"
218  }
219  }
220 }
221 
222 cd $OldPath