cijobs.pl 14 KB

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