cijobs.pl 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. #!/usr/bin/perl
  2. #***************************************************************************
  3. # _ _ ____ _
  4. # Project ___| | | | _ \| |
  5. # / __| | | | |_) | |
  6. # | (__| |_| | _ <| |___
  7. # \___|\___/|_| \_\_____|
  8. #
  9. # Copyright (C) 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
  10. #
  11. # This software is licensed as described in the file COPYING, which
  12. # you should have received as part of this distribution. The terms
  13. # are also available at https://curl.se/docs/copyright.html.
  14. #
  15. # You may opt to use, copy, modify, merge, publish, distribute and/or sell
  16. # copies of the Software, and permit persons to whom the Software is
  17. # furnished to do so, under the terms of the COPYING file.
  18. #
  19. # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  20. # KIND, either express or implied.
  21. #
  22. ###########################################################################
  23. my %filelevel= ('file' => 1,
  24. 'service' => 1);
  25. my $jobid = 1;
  26. sub submit {
  27. my ($jref)=@_;
  28. my %job = %$jref;
  29. printf "\n##### job %u \n", $jobid++;
  30. for my $k (sort keys %job) {
  31. printf "%s: %s\n", $k, $job{$k} if($job{$k});
  32. undef $$jref{$k} if(!$filelevel{$k});
  33. }
  34. }
  35. sub githubactions {
  36. my ($tag)=@_;
  37. my @files= `git ls-tree -r --name-only $tag .github/workflows 2>/dev/null`;
  38. my $c = 0;
  39. foreach my $f (sort @files) {
  40. my $j = 0;
  41. my $m = -1;
  42. my $done = 0;
  43. chomp $f;
  44. open(G, "git show $tag:$f 2>/dev/null|");
  45. # start counting file jobs
  46. undef %job;
  47. $job{'file'} = $f;
  48. $job{'service'} = "gha";
  49. my @cc;
  50. my $os;
  51. my $topname;
  52. my $line = 1;
  53. while(<G>) {
  54. $job{'line'} = $line;
  55. if($_ =~ /^name: (.*)/) {
  56. $topname=$1;
  57. }
  58. elsif($_ =~ /runs-on: (.*)/) {
  59. my $r = $1;
  60. #print "runs-on: $r\n";
  61. if($r =~ /ubuntu/) {
  62. $os = "linux";
  63. }
  64. elsif($r =~ /macos/) {
  65. $os = "macos";
  66. }
  67. # commit previously counted jobs
  68. $c += $j;
  69. # non-matrix job
  70. $j = 1;
  71. }
  72. elsif($_ =~ /matrix:/) {
  73. # switch to matrix mode
  74. $m = 0;
  75. $j = 0;
  76. }
  77. elsif($_ =~ /^ - run: .* apt-get install (.*)/) {
  78. $job{'install'} = $1;
  79. }
  80. elsif($m >= 0) {
  81. if($_ =~ /^ - name: (.*)/) {
  82. # matrix job
  83. #print "name: $1\n";
  84. $job{'name'} = $1;
  85. $j += ($m?$m:1);
  86. }
  87. elsif($_ =~ /install: (.*)/) {
  88. $job{'install'} = $1;
  89. }
  90. elsif($_ =~ /( |curl-)configure: (.*)/) {
  91. $job{'configure'} = $2;
  92. $job{'os'}=$os;
  93. submit(\%job);
  94. $done++;
  95. }
  96. elsif($_ =~ /generate: (.*)/) {
  97. $job{'cmake'} = $1;
  98. if($m) {
  99. # matrix mode, multiple copies
  100. my %dupe = %job;
  101. for my $cc (@cc) {
  102. %job = %dupe;
  103. $job{'cc'} = $cc;
  104. $job{'os'}=$os;
  105. submit(\%job);
  106. $done++;
  107. }
  108. }
  109. else {
  110. $job{'os'}=$os;
  111. submit(\%job);
  112. $done++;
  113. }
  114. }
  115. elsif($_ =~ /- CC: (.*)/) {
  116. # matrix multiplier
  117. push @cc, $1;
  118. $m++;
  119. }
  120. elsif($_ =~ /steps:/) {
  121. # disable matrix mode
  122. $m = -1;
  123. }
  124. }
  125. $line++;
  126. }
  127. close(G);
  128. # commit final counted jobs
  129. $c += $j;
  130. if(!$done) {
  131. $job{'name'} = $topname? $topname : '[unnamed]';
  132. $job{'os'}=$os;
  133. submit(\%job);
  134. $done++;
  135. }
  136. # reset internal job counter
  137. $j = 0;
  138. }
  139. #print "Jobs: $c\n";
  140. return $c;
  141. }
  142. sub azurepipelines {
  143. my ($tag)=@_;
  144. open(G, "git show $tag:.azure-pipelines.yml 2>/dev/null|");
  145. my $c = 0;
  146. my $j = 0;
  147. my $m = -1;
  148. my $image;
  149. my %job;
  150. my $line = 1;
  151. my $os;
  152. $job{'file'} = ".azure-pipelines.yml";
  153. $job{'service'} = "azure";
  154. while(<G>) {
  155. if($_ =~ /^ vmImage: (.*)/) {
  156. my $i = $1;
  157. if($i =~ /ubuntu/) {
  158. $os = "linux";
  159. }
  160. elsif($i =~ /windows/) {
  161. $os = "windows";
  162. }
  163. }
  164. elsif($_ =~ /^- stage: (.*)/) {
  165. my $topname = $1;
  166. if($topname !~ /(windows|linux)/) {
  167. $job{'name'} = $topname;
  168. $job{'line'}=$line;
  169. submit(\%job);
  170. }
  171. }
  172. elsif($_ =~ /job:/) {
  173. # commit previously counted jobs
  174. $c += $j;
  175. # initial value for non-matrix job
  176. $j = 1;
  177. }
  178. elsif($_ =~ /matrix:/) {
  179. # start of new matrix list(!)
  180. $m = 0;
  181. $j = 0;
  182. }
  183. elsif($m >= 0) {
  184. if($_ =~ /^ name: (.*)/) {
  185. # single matrix list entry job
  186. $j++;
  187. $job{'name'} = $1;
  188. }
  189. # azure matrix is a simple list,
  190. # therefore no multiplier needed
  191. elsif($_ =~ /steps:/) {
  192. # disable matrix mode
  193. $m = -1;
  194. }
  195. elsif($_ =~ /^ configure: (.*)/) {
  196. $job{'configure'} = $1;
  197. $job{'line'}=$line;
  198. $job{'os'}=$os;
  199. submit(\%job);
  200. }
  201. }
  202. $line++;
  203. }
  204. close(G);
  205. # commit final counted jobs
  206. $c += $j;
  207. return $c;
  208. }
  209. sub appveyor {
  210. my ($tag)=@_;
  211. open(G, "git show $tag:appveyor.yml 2>/dev/null|");
  212. my $c = 0;
  213. my %job;
  214. my $line=0;
  215. $job{'file'} = "appveyor.yml";
  216. $job{'service'} = "appveyor";
  217. while(<G>) {
  218. $line++;
  219. if($_ =~ /^( - |install)/) {
  220. if($job{'image'}) {
  221. $job{'os'} = "windows";
  222. submit(\%job);
  223. $c++;
  224. }
  225. }
  226. $job{'line'} = $line;
  227. if($_ =~ /^ - APPVEYOR_BUILD_WORKER_IMAGE: \"(.*)\"/) {
  228. $job{'image'}= $1;
  229. }
  230. elsif($_ =~ /^ BUILD_SYSTEM: (.*)/) {
  231. $job{'build'} = lc($1);
  232. }
  233. elsif($_ =~ /^ PRJ_GEN: \"(.*)\"/) {
  234. $job{'compiler'} = $1;
  235. }
  236. elsif($_ =~ /^ PRJ_CFG: (.*)/) {
  237. $job{'config'} = $1;
  238. }
  239. elsif($_ =~ /^ OPENSSL: (.*)/) {
  240. $job{'openssl'} = $1 eq "ON" ? "true": "false";
  241. }
  242. elsif($_ =~ /^ SCHANNEL: (.*)/) {
  243. $job{'schannel'} = $1 eq "ON" ? "true": "false";
  244. }
  245. elsif($_ =~ /^ ENABLE_UNICODE: (.*)/) {
  246. $job{'unicode'} = $1 eq "ON" ? "true": "false";
  247. }
  248. elsif($_ =~ /^ HTTP_ONLY: (.*)/) {
  249. $job{'http-only'} = $1 eq "ON" ? "true": "false";
  250. }
  251. elsif($_ =~ /^ TESTING: (.*)/) {
  252. $job{'testing'} = $1 eq "ON" ? "true": "false";
  253. }
  254. elsif($_ =~ /^ SHARED: (.*)/) {
  255. $job{'shared'} = $1 eq "ON" ? "true": "false";
  256. }
  257. elsif($_ =~ /^ TARGET: \"-A (.*)\"/) {
  258. $job{'target'} = $1;
  259. }
  260. }
  261. close(G);
  262. return $c;
  263. }
  264. sub cirrus {
  265. my ($tag)=@_;
  266. open(G, "git show $tag:.cirrus.yml 2>/dev/null|");
  267. my $c = 0;
  268. my %job;
  269. my $line=0;
  270. my $name = 0;
  271. my $os;
  272. $job{'file'} = ".cirrus.yml";
  273. $job{'service'} = "cirrus";
  274. while(<G>) {
  275. $line++;
  276. if($_ =~ /^ ( |-) (name|image_family|image):/) {
  277. $c++;
  278. }
  279. if($_ =~ /^ - name:/) {
  280. if($name) {
  281. $job{'os'} = $os;
  282. $job{'line'} = $line;
  283. submit(\%job);
  284. $name = 0;
  285. }
  286. }
  287. if($_ =~ /^ - name: (.*)/) {
  288. $job{'name'} = $1;
  289. $name = 1;
  290. }
  291. elsif($_ =~ /^ image_family: (.*)/) {
  292. $os = "freebsd";
  293. }
  294. elsif($_ =~ /^windows_task:/) {
  295. $os = "windows";
  296. }
  297. elsif($_ =~ /^ prepare: pacman -S --needed --noconfirm --noprogressbar (.*)/) {
  298. $job{'install'} = $1;
  299. }
  300. elsif($_ =~ /^ configure: (.*)/) {
  301. $job{'configure'} = $1;
  302. }
  303. }
  304. close(G);
  305. if($name) {
  306. $job{'os'} = $os;
  307. $job{'line'} = $line;
  308. submit(\%job);
  309. }
  310. return $c;
  311. }
  312. sub circle {
  313. my ($tag)=@_;
  314. open(G, "git show $tag:.circleci/config.yml 2>/dev/null|");
  315. my $c = 0;
  316. my $wf = 0;
  317. my %job;
  318. my %cmd;
  319. my %configure;
  320. my %target;
  321. my $line=0;
  322. my $cmds;
  323. my $jobs;
  324. my $workflow;
  325. $job{'file'} = ".circleci/config.yml";
  326. $job{'service'} = "circleci";
  327. while(<G>) {
  328. $line++;
  329. if($_ =~ /^commands:/) {
  330. # we record configure lines in this state
  331. $cmds = 1;
  332. }
  333. elsif($cmds) {
  334. if($_ =~ /^ ([^ ]*):/) {
  335. $cmdname = $1;
  336. }
  337. elsif($_ =~ /^ .*.\/configure (.*)/) {
  338. $cmd{$cmdname}=$1;
  339. }
  340. }
  341. if($_ =~ /^jobs:/) {
  342. # we record which job runs with configure here
  343. $jobs = 1;
  344. $cmds = 0;
  345. }
  346. elsif($jobs) {
  347. if($_ =~ /^ ([^ ]*):/) {
  348. $jobname = $1;
  349. }
  350. elsif($_ =~ /^ - (configure.*)/) {
  351. $configure{$jobname}=$1;
  352. }
  353. elsif($_ =~ /^ resource_class: arm.medium/) {
  354. $target{$jobname}="arm";
  355. }
  356. }
  357. if($_ =~ /^workflows:/) {
  358. $wf = 1;
  359. $cmds = 0;
  360. }
  361. elsif($wf) {
  362. if($_ =~ /^ ([^ ]+):/) {
  363. $workflow = $1;
  364. }
  365. elsif($_ =~ /^ - (.*)\n/) {
  366. my $jb = $1;
  367. my $cnfgure = $configure{$jb};
  368. my $trgt = $target{$jb};
  369. $job{'configure'} = $cmd{$cnfgure};
  370. $job{'name' }=$workflow;
  371. $job{'os'} = "linux";
  372. $job{'line'} = $line;
  373. $job{'target'} = $trgt if($trgt);
  374. submit(\%job);
  375. }
  376. if($_ =~ / *jobs:/) {
  377. $c++;
  378. }
  379. }
  380. }
  381. close(G);
  382. return $c;
  383. }
  384. sub zuul {
  385. my ($tag)=@_;
  386. open(G, "git show $tag:zuul.d/jobs.yaml 2>/dev/null|");
  387. my $c = 0;
  388. my %job;
  389. my $line=0;
  390. my $type;
  391. $job{'file'} = "zuul.d/jobs.yaml";
  392. $job{'service'} = "zuul";
  393. while(<G>) {
  394. $line++;
  395. #print "L: ($jobmode / $env) $_";
  396. if($_ =~ /^- job:/) {
  397. $jobmode = 1; # start a new
  398. $type="configure";
  399. }
  400. if($jobmode) {
  401. if($apt) {
  402. if($_ =~ /^ - (.*)/) {
  403. my $value = $1;
  404. $job{'install'} .= "$value ";
  405. }
  406. else {
  407. $apt = 0; # end of curl_apt_packages
  408. }
  409. }
  410. if($env) {
  411. if($envcont) {
  412. if($_ =~ /^ (.*)/) {
  413. $job{$envcont} .= "$1 ";
  414. }
  415. else {
  416. $envcont = "";
  417. }
  418. }
  419. if($_ =~ /^ ([^:]+): (.*)/) {
  420. my ($var, $value) = ($1, $2);
  421. if($var eq "C") {
  422. $var = $type;
  423. }
  424. elsif($var eq "T") {
  425. $var = "tests";
  426. if($value eq "cmake") {
  427. # otherwise it remains configure
  428. $type = "cmake";
  429. }
  430. }
  431. elsif($var eq "CC") {
  432. $var = "compiler";
  433. }
  434. elsif($var eq "CHECKSRC") {
  435. $job{'checksrc'} = $value ? "true": "false";
  436. $var = "";
  437. }
  438. else {
  439. $var = "";
  440. }
  441. if($value eq ">-") {
  442. $envcont = $var;
  443. }
  444. elsif($var) {
  445. $job{$var} = $value;
  446. }
  447. }
  448. elsif($_ !~ /^ /) {
  449. # end of envs
  450. $env = 0;
  451. }
  452. }
  453. if($_ =~ /^ curl_env:/) {
  454. $env = 1; # start of envs
  455. }
  456. elsif($_ =~ /^ curl_apt_packages:/) {
  457. $apt = 1; # start of apt packages
  458. }
  459. elsif($_ =~ /^ name: (.*)/) {
  460. my $n = $1;
  461. if($n eq "curl-base") {
  462. # not counted
  463. $jobmode = 0;
  464. next;
  465. }
  466. $job{'name'} = $n;
  467. }
  468. elsif($_ =~ /^\n\z/) {
  469. # a job is complete
  470. $job{'line'}=$line;
  471. $job{'os'}="linux";
  472. submit(\%job);
  473. $jobmode = 0;
  474. $c++;
  475. }
  476. }
  477. }
  478. close(G);
  479. return $c;
  480. }
  481. my $tag = `git rev-parse --abbrev-ref HEAD 2>/dev/null` || "master";
  482. chomp $tag;
  483. githubactions($tag);
  484. azurepipelines($tag);
  485. appveyor($tag);
  486. zuul($tag);
  487. cirrus($tag);
  488. circle($tag);